/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.celements.web.plugin.cmd;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.apache.velocity.VelocityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.model.reference.DocumentReference;
import com.celements.css.ICssExtensionRole;
import com.celements.model.access.IModelAccessFacade;
import com.celements.model.access.exception.DocumentNotExistsException;
import com.celements.pagetype.cmd.PageTypeCommand;
import com.celements.web.css.CSS;
import com.celements.web.css.CSSEngine;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Document;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.web.Utils;
public class CssCommand {
public static final String SKINS_USER_CSS_CLASS_SPACE = "Skins";
public static final String SKINS_USER_CSS_CLASS_DOC = "UserCSS";
public static final String SKINS_USER_CSS_CLASS = SKINS_USER_CSS_CLASS_SPACE + "."
+ SKINS_USER_CSS_CLASS_DOC;
private static Logger LOGGER = LoggerFactory.getLogger(CssCommand.class);
public DocumentReference getSkinsUserCssClassRef(String wikiName) {
return new DocumentReference(wikiName, SKINS_USER_CSS_CLASS_SPACE, SKINS_USER_CSS_CLASS_DOC);
}
public List<CSS> getAllCSS(XWikiContext context) throws XWikiException {
List<CSS> cssResultList = new ArrayList<CSS>();
List<CSS> cssList = collectAllCSS(context);
LOGGER.debug("List of CSS files built. There are " + cssList.size() + " CSS files to include.");
Set<CSS> includedCSS = new HashSet<CSS>();
for (CSS css2 : cssList) {
CSS css = css2;
if (!includedCSS.contains(css) && (css != null)) {
LOGGER.debug("CSS to add to result List: " + css.toString());
cssResultList.add(css);
includedCSS.add(css);
}
}
return cssResultList;
}
private List<CSS> collectAllCSS(XWikiContext context) throws XWikiException {
List<CSS> cssList = new ArrayList<CSS>();
cssList.addAll(includeApplicationDefaultCSS());
cssList.addAll(includeCSSAfterSkin("", context));
cssList.addAll(includeCSSAfterPreferences("", context));
cssList.addAll(includeCSSAfterPageType("", context));
cssList.addAll(includeCSSAfterPageLayout("", context));
cssList.addAll(includeCSSPage("", context));
return cssList;
}
public String displayAllCSS(XWikiContext context) throws XWikiException {
String CSS = "";
List<CSS> cssList = getAllCSS(context);
for (CSS css : cssList) {
LOGGER.debug("displayAllCSS: displayInclude for [" + css.getCSS() + "].");
CSS += css.displayInclude(context);
}
return CSS;
}
public List<CSS> getRTEContentCSS(XWikiContext context) throws XWikiException {
List<CSS> cssResultList = new ArrayList<CSS>();
List<CSS> cssList = collectAllCSS(context);
LOGGER.debug("List of CSS files built. There are " + cssList.size() + " CSS files to include.");
Set<CSS> includedCSS = new HashSet<CSS>();
for (CSS css2 : cssList) {
CSS css = css2;
if ((css != null) && !includedCSS.contains(css) && css.isContentCSS()) {
LOGGER.debug("RTE content CSS to add to result List: " + css.toString());
cssResultList.add(css);
includedCSS.add(css);
}
}
return cssResultList;
}
public List<CSS> includeCSSPage(String css, XWikiContext context) {
List<BaseObject> skins = null;
if (!new PageLayoutCommand().layoutExists(
context.getDoc().getDocumentReference().getLastSpaceReference())) {
XWikiDocument doc = context.getDoc();
skins = doc.getXObjects(getSkinsUserCssClassRef(context.getDatabase()));
LOGGER.debug("CSS Page: " + doc.getDocumentReference() + " has attached " + ((skins != null)
? skins.size() : "0") + " Skins.UserCSS objects.");
}
return includeCSS(css, "cel_css_list_page", skins, context);
}
public List<CSS> includeCSSAfterPreferences(String css, XWikiContext context)
throws XWikiException {
VelocityContext vcontext = ((VelocityContext) context.get("vcontext"));
List<CSS> cssList = Collections.emptyList();
if (vcontext != null) {
String space = (String) vcontext.get("stylesheet_space");
if ((space == null) || space.trim().equals("")) {
space = context.getDoc().getSpace();
}
LOGGER.debug("WebPreferences space is: '" + space + "'");
String baseCSS = context.getWiki().getSpacePreference("stylesheet", space, "", context) + " ";
baseCSS = context.getWiki().getSpacePreference("stylesheets", space, "", context) + " ";
LOGGER.debug("CSS Prefs: has '" + baseCSS + "' as CSS to add.");
List<BaseObject> baseList = new ArrayList<BaseObject>();
DocumentReference xwikiPrefDocRef = new DocumentReference(context.getDatabase(), "XWiki",
"XWikiPreferences");
if (context.getWiki().exists(xwikiPrefDocRef, context)) {
baseList.addAll(addUserSkinCss(context.getWiki().getDocument(xwikiPrefDocRef, context)));
}
DocumentReference webPrefDocRef = new DocumentReference("WebPreferences",
context.getDoc().getDocumentReference().getLastSpaceReference());
if (context.getWiki().exists(webPrefDocRef, context)) {
baseList.addAll(addUserSkinCss(context.getWiki().getDocument(webPrefDocRef, context)));
}
cssList = includeCSS(baseCSS + css, "cel_css_list_pref", baseList, context);
}
return cssList;
}
List<CSS> includeApplicationDefaultCSS() {
List<CSS> cssList = Collections.emptyList();
List<ICssExtensionRole> cssExtList = Utils.getComponentList(ICssExtensionRole.class);
if (!cssExtList.isEmpty()) {
cssList = new Vector<>();
for (ICssExtensionRole cssExt : cssExtList) {
LOGGER.debug("includeApplicationDefaultCSS: for '{}'", cssExt.getClass());
cssList.addAll(cssExt.getCssList());
}
}
return cssList;
}
public List<CSS> includeCSSAfterSkin(String css, XWikiContext context) {
VelocityContext vcontext = ((VelocityContext) context.get("vcontext"));
List<CSS> cssList = Collections.emptyList();
if (vcontext != null) {
List<BaseObject> baseList = new ArrayList<BaseObject>();
baseList.addAll(addUserSkinCss((Document) vcontext.get("skin_doc")));
baseList.addAll(addUserSkinCss((Document) vcontext.get("after_skin_cssdoc")));
cssList = includeCSS(css, "cel_css_list_skin", baseList, context);
}
return cssList;
}
public List<CSS> includeCSSAfterPageType(String css, XWikiContext context) {
XWikiDocument pageTypeDoc = null;
try {
pageTypeDoc = PageTypeCommand.getInstance().getPageTypeObj(context.getDoc(),
context).getTemplateDocument(context);
} catch (XWikiException exp) {
LOGGER.error("Failed to include css after pageType.", exp);
}
VelocityContext vcontext = ((VelocityContext) context.get("vcontext"));
List<CSS> cssList = Collections.emptyList();
if ((pageTypeDoc != null) && (vcontext != null)) {
List<BaseObject> baseList = new ArrayList<BaseObject>();
baseList.addAll(addUserSkinCss(pageTypeDoc));
baseList.addAll(addUserSkinCss((Document) vcontext.get("after_pagetype_cssdoc")));
cssList = includeCSS(css, "cel_css_list_pagetype", baseList, context);
}
return cssList;
}
public List<CSS> includeCSSAfterPageLayout(String css, XWikiContext context) {
XWikiDocument pageLayoutDoc = null;
pageLayoutDoc = new PageLayoutCommand().getLayoutPropDoc();
VelocityContext vcontext = ((VelocityContext) context.get("vcontext"));
List<CSS> cssList = Collections.emptyList();
if ((pageLayoutDoc != null) && (vcontext != null)) {
List<BaseObject> baseList = new ArrayList<BaseObject>();
baseList.addAll(addUserSkinCss(pageLayoutDoc));
baseList.addAll(addUserSkinCss((Document) vcontext.get("after_pagelayout_cssdoc")));
baseList.addAll(addUserSkinCss((DocumentReference) vcontext.get(
"after_pagelayout_cssdocref")));
cssList = includeCSS(css, "cel_css_list_pagelayout", baseList, context);
}
return cssList;
}
/**
* CAUTION!!! needs programming rights!!
*
* @deprecated 2.81 instead use {@link addUserSkinCss(DocumentReference)}
*/
@Deprecated
private List<BaseObject> addUserSkinCss(Document docAPI) {
if ((docAPI != null) && (docAPI.getDocument() != null)) {
return addUserSkinCss(docAPI.getDocument());
}
return Collections.emptyList();
}
private List<BaseObject> addUserSkinCss(DocumentReference docRef) {
if (docRef != null) {
try {
return addUserSkinCss(getModelAccess().getDocument(docRef));
} catch (DocumentNotExistsException exp) {
LOGGER.info("addUserSkinCss: document does not exist '{}'", docRef);
}
}
return Collections.emptyList();
}
private List<BaseObject> addUserSkinCss(XWikiDocument docAPI) {
if (docAPI != null) {
List<BaseObject> objs = docAPI.getXObjects(getSkinsUserCssClassRef(
docAPI.getDocumentReference().getWikiReference().getName()));
LOGGER.debug("CSS Skin: " + docAPI.getDocumentReference() + " has attached " + ((objs != null)
? objs.size() : "0") + " Skins.UserCSS objects.");
if (objs != null) {
return objs;
}
}
return Collections.emptyList();
}
/**
* @param css
* @param field
* @param baseCSSList
* @param context
* @return the returned list is XWikiContext dependent and therefore may not be cached
* or similar. The list is as a consequence too not thread safe. TODO: Fix mix
* of API and backend. Extract business objects (controller) from CSS classes
* and use them here.
*/
private List<CSS> includeCSS(String css, String field, List<BaseObject> baseCSSList,
XWikiContext context) {
return CSSEngine.getCSSEngine(context).includeCSS(css, field, baseCSSList, context);
}
private IModelAccessFacade getModelAccess() {
return Utils.getComponent(IModelAccessFacade.class);
}
}