/* * 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.navigation; import java.io.ByteArrayInputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.tidy.Tidy; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.context.Execution; import org.xwiki.context.ExecutionContext; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.EntityReference; import org.xwiki.model.reference.SpaceReference; import com.celements.navigation.cmd.MultilingualMenuNameCommand; import com.celements.navigation.filter.INavFilter; import com.celements.navigation.filter.InternalRightsFilter; import com.celements.navigation.presentation.IPresentationTypeRole; import com.celements.navigation.service.ITreeNodeService; import com.celements.pagetype.PageTypeReference; import com.celements.pagetype.service.IPageTypeResolverRole; import com.celements.pagetype.service.PageTypeResolverService; import com.celements.web.plugin.cmd.PageLayoutCommand; import com.celements.web.service.IWebUtilsService; import com.celements.web.utils.IWebUtils; import com.celements.web.utils.WebUtils; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.objects.BaseObject; import com.xpn.xwiki.user.api.XWikiRightService; import com.xpn.xwiki.web.Utils; import com.xpn.xwiki.web.XWikiMessageTool; public class Navigation implements INavigation { @Deprecated public static final int DEFAULT_MAX_LEVEL = NavigationConfig.DEFAULT_MAX_LEVEL; /** * @deprecated since 2.18.0 instead use NavigationClasses.NAVIGATION_CONFIG_CLASS_DOC */ @Deprecated public static final String NAVIGATION_CONFIG_CLASS_DOC = NavigationClasses.NAVIGATION_CONFIG_CLASS_DOC; /** * @deprecated since 2.18.0 instead use NavigationClasses.NAVIGATION_CONFIG_CLASS_SPACE */ @Deprecated public static final String NAVIGATION_CONFIG_CLASS_SPACE = NavigationClasses.NAVIGATION_CONFIG_CLASS_SPACE; /** * @deprecated since 2.18.0 instead use NavigationClasses.NAVIGATION_CONFIG_CLASS */ @Deprecated public static final String NAVIGATION_CONFIG_CLASS = NavigationClasses.NAVIGATION_CONFIG_CLASS; private INavigationBuilder navBuilder; @Deprecated public static final String LIST_LAYOUT_TYPE = NavigationConfig.LIST_LAYOUT_TYPE; public static final String MENU_TYPE_MENUITEM = "menuitem"; private final static Logger LOGGER = LoggerFactory.getLogger(Navigation.class); private static final String NAVIGATION_COUNTER_KEY = NavigationApi.class.getCanonicalName() + "_NavigationCounter"; private static final String LANGUAGE_MENU_DATA_TYPE = "languages"; public PageLayoutCommand pageLayoutCmd = new PageLayoutCommand(); String uniqueName; IWebUtils utils; private boolean navigationEnabled; String configName; int fromHierarchyLevel; int toHierarchyLevel; String menuPart; SpaceReference nodeSpaceRef; private int showInactiveToLevel; private int offset = 0; private int nrOfItemsPerPage = -1; private String cmCssClass; private String mainUlCssClasses; private String emptyDictKeySuffix; private String dataType; private String navInclude = null; private IPresentationTypeRole presentationType = null; private boolean _showAll; private boolean _hasLink; private INavFilter<BaseObject> navFilter; private MultilingualMenuNameCommand menuNameCmd; private String navLanguage; public ITreeNodeService injected_TreeNodeService; public IWebUtilsService injected_WebUtilsService; public PageTypeResolverService injected_PageTypeResolverService; public Navigation(String navUniqueId) { this.menuNameCmd = new MultilingualMenuNameCommand(); this.uniqueName = navUniqueId; this.navigationEnabled = true; this.fromHierarchyLevel = NavigationConfig.DEFAULT_MIN_LEVEL; this.toHierarchyLevel = DEFAULT_MAX_LEVEL; this.menuPart = ""; this.dataType = NavigationConfig.PAGE_MENU_DATA_TYPE; this._showAll = false; this._hasLink = true; try { setLayoutType(LIST_LAYOUT_TYPE); } catch (UnknownLayoutTypeException exp) { LOGGER.error("Native List Layout Type not available!", exp); throw new IllegalStateException("Native List Layout Type not available!", exp); } this.nodeSpaceRef = null; this.mainUlCssClasses = ""; this.cmCssClass = ""; utils = WebUtils.getInstance(); } /** * @deprecated since 2.18.0 instead use getNavigationConfigClassRef of NavigationClasses */ @Deprecated public static DocumentReference getNavigationConfigClassReference(String wikiName) { return new DocumentReference(wikiName, NAVIGATION_CONFIG_CLASS_SPACE, NAVIGATION_CONFIG_CLASS_DOC); } public String getLayoutType() { return navBuilder.getLayoutTypeName(); } public void setLayoutType(String layoutType) throws UnknownLayoutTypeException { // TODO implement a component role if (LIST_LAYOUT_TYPE.equals(layoutType)) { this.navBuilder = new ListBuilder(uniqueName); } else { throw new UnknownLayoutTypeException(layoutType); } } public IPresentationTypeRole getPresentationType() { if (presentationType == null) { return Utils.getComponent(IPresentationTypeRole.class); } else { return presentationType; } } public void setPresentationType(IPresentationTypeRole presentationType) { this.presentationType = presentationType; } @Override public void setPresentationType(String presentationTypeHint) { if (presentationTypeHint != null) { try { LOGGER.info("setPresentationType to [" + presentationTypeHint + "]."); setPresentationType(Utils.getComponent(IWebUtilsService.class).lookup( IPresentationTypeRole.class, presentationTypeHint)); } catch (ComponentLookupException failedToLoadException) { LOGGER.error("setPresentationType failed to load IPresentationTypeRole for hint [" + presentationTypeHint + "].", failedToLoadException); this.presentationType = null; } } else { this.presentationType = null; } } /** * setFromHierarchyLevel * * @param fromHierarchyLevel * starting (including) at Hierarchy Level 1 = mainMenu , 0 = spaceMenu * (including all first mainMenuItems of all Spaces) */ @Override public void setFromHierarchyLevel(int fromHierarchyLevel) { if (fromHierarchyLevel > 0) { this.fromHierarchyLevel = fromHierarchyLevel; } } /** * setToHierarchyLevel * * @param toHierarchyLevel * ending (including) with Hierarchy Level */ @Override public void setToHierarchyLevel(int toHierarchyLevel) { this.toHierarchyLevel = toHierarchyLevel; } @Override public void setMenuPart(String menuPart) { this.menuPart = menuPart; } /** * @param menuSpace * (default: $doc.web) * @deprecated since 2.24.0 instead use setNodeSpace */ @Override @Deprecated public void setMenuSpace(String menuSpace) { if ((menuSpace != null) && (!"".equals(menuSpace))) { setNodeSpace(getWebUtilsService().resolveSpaceReference(menuSpace)); } else { setNodeSpace(null); } } @Override public void setNodeSpace(SpaceReference newNodeSpaceRef) { this.nodeSpaceRef = newNodeSpaceRef; } /** * @deprecated since 2.24.0 use includeNavigation() instead. */ @Override @Deprecated public String includeNavigation(XWikiContext context) { return includeNavigation(); } @Override public String includeNavigation() { if (fromHierarchyLevel > 0) { DocumentReference parentRef = getWebUtilsService().getParentForLevel(fromHierarchyLevel); if ((fromHierarchyLevel == 1) || (parentRef != null)) { return includeNavigation(parentRef); } return ""; } else { throw new IllegalArgumentException("fromHierarchyLevel [" + fromHierarchyLevel + "] must be greater than zero"); } } @Override public String includeNavigation(DocumentReference parentRef) { LOGGER.debug("includeNavigation: navigationEnabled [" + navigationEnabled + "]."); if (navInclude == null) { if (navigationEnabled) { StringBuilder outStream = new StringBuilder(); if (NavigationConfig.PAGE_MENU_DATA_TYPE.equals(dataType)) { try { addNavigationForParent(outStream, parentRef, getNumLevels()); } catch (XWikiException e) { LOGGER.error("addNavigationForParent failed for [" + parentRef + "].", e); } } else if (LANGUAGE_MENU_DATA_TYPE.equals(dataType)) { navBuilder.useStream(outStream); generateLanguageMenu(navBuilder, getContext()); } navInclude = outStream.toString(); } else { navInclude = ""; } } return navInclude; } /** * @deprecated since 2.24.0 instead use getNodeSpaceRef() */ @Override @Deprecated public String getMenuSpace(XWikiContext context) { return getWebUtilsService().getRefLocalSerializer().serialize(getNodeSpaceRef()); } @Override public SpaceReference getNodeSpaceRef() { if (nodeSpaceRef == null) { SpaceReference currentSpaceRef = getContext().getDoc().getDocumentReference().getLastSpaceReference(); if (fromHierarchyLevel == 1) { if (isEmptyMainMenu(currentSpaceRef) && getWebUtilsService().hasParentSpace( currentSpaceRef.getName())) { // is main Menu and no mainMenuItem found ; user has edit rights nodeSpaceRef = getWebUtilsService().resolveSpaceReference( getWebUtilsService().getParentSpace(currentSpaceRef.getName())); } } if (nodeSpaceRef == null) { nodeSpaceRef = currentSpaceRef; } } SpaceReference theNodeSpaceRef = nodeSpaceRef; return theNodeSpaceRef; } @Override public boolean isEmptyMainMenu() { return isEmptyMainMenu(getNodeSpaceRef()); } public boolean isEmptyMainMenu(SpaceReference spaceRef) { getNavFilter().setMenuPart(getMenuPartForLevel(1)); return getTreeNodeService().getSubNodesForParent(spaceRef, getNavFilter()).size() == 0; } @Override public boolean isEmpty() { getNavFilter().setMenuPart(getMenuPartForLevel(fromHierarchyLevel)); EntityReference parentRef = getWebUtilsService().getParentForLevel(fromHierarchyLevel); LOGGER.debug("isEmpty: parentRef [" + parentRef + "] for level [" + fromHierarchyLevel + "]"); if (parentRef == null) { LOGGER.info("isEmpty: no subnode for level [" + fromHierarchyLevel + "] found."); return true; } List<TreeNode> subNodeList = getTreeNodeService().getSubNodesForParent(parentRef, getNavFilter()); LOGGER.info("isEmpty: subNodeList size [" + subNodeList.size() + "] for parentRef [" + parentRef + "] -> [" + subNodeList.isEmpty() + "]."); return subNodeList.isEmpty(); } INavFilter<BaseObject> getNavFilter() { if (navFilter == null) { navFilter = new InternalRightsFilter(); } return navFilter; } @Override public void setNavFilter(INavFilter<BaseObject> navFilter) { this.navFilter = navFilter; } private int getNumLevels() { return (toHierarchyLevel - fromHierarchyLevel) + 1; } void addNavigationForParent(StringBuilder outStream, EntityReference parentRef, int numMoreLevels) throws XWikiException { LOGGER.debug("addNavigationForParent: parent [" + parentRef + "] numMoreLevels [" + numMoreLevels + "]."); if (numMoreLevels > 0) { String parent = ""; if (parentRef != null) { parent = getWebUtilsService().getRefLocalSerializer().serialize(parentRef); } List<TreeNode> currentMenuItems = getCurrentMenuItems(numMoreLevels, parent); if (currentMenuItems.size() > 0) { outStream.append("<ul " + addUniqueContainerId(parent) + " " + getMainUlCSSClasses() + ">"); boolean isFirstItem = true; int numItem = 0; if (this.getOffset() > 0) { numItem = this.getOffset(); } for (TreeNode treeNode : currentMenuItems) { numItem = numItem + 1; DocumentReference nodeRef = treeNode.getDocumentReference(); boolean isLastItem = (currentMenuItems.lastIndexOf(treeNode) == (currentMenuItems.size() - 1)); writeMenuItemWithSubmenu(outStream, parent, numMoreLevels, nodeRef, isFirstItem, isLastItem, numItem); isFirstItem = false; } outStream.append("</ul>"); } else if ((getCurrentLevel(numMoreLevels) == 1) && hasedit()) { LOGGER.trace("addNavigationForParent: empty navigation hint for parent [" + parentRef + "] numMoreLevels [" + numMoreLevels + "], currentLevel [" + getCurrentLevel( numMoreLevels) + "]."); // is main Menu and no mainMenuItem found ; user has edit rights outStream.append("<ul class=\"cel_nav_empty\">"); openMenuItemOut(outStream, null, true, true, false, 1); outStream.append("<span " + addUniqueElementId(null) + " " + addCssClasses(null, true, true, true, false, 1) + ">" + getWebUtilsService().getAdminMessageTool().get( getEmptyDictKey()) + "</span>"); closeMenuItemOut(outStream); outStream.append("</ul>"); } else { LOGGER.debug("addNavigationForParent: empty output for parent [" + parentRef + "] numMoreLevels [" + numMoreLevels + "], currentLevel [" + getCurrentLevel( numMoreLevels) + "], hasEdit [" + hasedit() + "]."); } } } List<TreeNode> getCurrentMenuItems(int numMoreLevels, String parent) { getNavFilter().setMenuPart(getMenuPartForLevel(getCurrentLevel(numMoreLevels))); List<TreeNode> currentMenuItems = getTreeNodeService().getSubNodesForParent(parent, getMenuSpace(getContext()), getNavFilter()); int endIdx = currentMenuItems.size(); if (((offset > 0) || (nrOfItemsPerPage > 0)) && (offset < endIdx)) { if (nrOfItemsPerPage > 0) { endIdx = Math.min(endIdx, offset + nrOfItemsPerPage); } currentMenuItems = currentMenuItems.subList(offset, endIdx); } else if (offset >= endIdx) { currentMenuItems = Collections.emptyList(); } return currentMenuItems; } @Override public String getEmptyDictKey() { return getPresentationType().getEmptyDictionaryKey() + getEmptyDictKeySuffix(); } @Override public void setEmptyDictKeySuffix(String emptyDictKeySuffix) { this.emptyDictKeySuffix = emptyDictKeySuffix; } private String getEmptyDictKeySuffix() { if (emptyDictKeySuffix != null) { return emptyDictKeySuffix; } return ""; } private int getCurrentLevel(int numMoreLevels) { return (getNumLevels() - numMoreLevels) + 1; } /** * menuPart is only valid for the first level of a menu block. * * @param currentLevel * @return */ String getMenuPartForLevel(int currentLevel) { if (currentLevel == 1) { return menuPart; } else { return ""; } } String getMainUlCSSClasses() { if (!"".equals(mainUlCssClasses.trim())) { return " class=\"" + mainUlCssClasses.trim() + "\" "; } else { return ""; } } @Override public void addUlCSSClass(String cssClass) { if (!(" " + mainUlCssClasses + " ").contains(" " + cssClass + " ")) { mainUlCssClasses = mainUlCssClasses.trim() + " " + cssClass; } } private boolean hasedit() throws XWikiException { return getContext().getWiki().getRightService().hasAccessLevel("edit", getContext().getUser(), getContext().getDoc().getFullName(), getContext()); } private void writeMenuItemWithSubmenu(StringBuilder outStream, String parent, int numMoreLevels, DocumentReference docRef, boolean isFirstItem, boolean isLastItem, int numItem) throws XWikiException { boolean showSubmenu = showSubmenuForMenuItem(docRef, getCurrentLevel(numMoreLevels), getContext()); String fullName = getWebUtilsService().getRefLocalSerializer().serialize(docRef); boolean isLeaf = isLeaf(fullName, getContext()); openMenuItemOut(outStream, docRef, isFirstItem, isLastItem, isLeaf, numItem); writeMenuItemContent(outStream, isFirstItem, isLastItem, docRef, isLeaf, numItem); if (showSubmenu) { addNavigationForParent(outStream, docRef, numMoreLevels - 1); } closeMenuItemOut(outStream); } void writeMenuItemContent(StringBuilder outStream, boolean isFirstItem, boolean isLastItem, DocumentReference docRef, boolean isLeaf, int numItem) throws XWikiException { getPresentationType().writeNodeContent(outStream, isFirstItem, isLastItem, docRef, isLeaf, numItem, this); } private boolean isLeaf(String fullName, XWikiContext context) { List<TreeNode> currentMenuItems = getTreeNodeService().getSubNodesForParent(fullName, getMenuSpace(context), getNavFilter()); boolean isLeaf = (currentMenuItems.size() <= 0); return isLeaf; } @Override public String getNavLanguage() { if (this.navLanguage != null) { return this.navLanguage; } return getContext().getLanguage(); } @Override public boolean useImagesForNavigation() { return getContext().getWiki().getSpacePreferenceAsInt("use_navigation_images", 0, getContext()) > 0; } private void closeMenuItemOut(StringBuilder outStream) { outStream.append("<!-- IE6 --></li>"); } void openMenuItemOut(StringBuilder outStream, DocumentReference docRef, boolean isFirstItem, boolean isLastItem, boolean isLeaf, int numItem) { outStream.append("<li" + addCssClasses(docRef, false, isFirstItem, isLastItem, isLeaf, numItem) + ">"); } @Override public String addCssClasses(DocumentReference docRef, boolean withCM, boolean isFirstItem, boolean isLastItem, boolean isLeaf, int numItem) { String cssClasses = getCssClasses(docRef, withCM, isFirstItem, isLastItem, isLeaf, numItem); if (!"".equals(cssClasses.trim())) { return " class=\"" + cssClasses + "\""; } return ""; } @Override public String addUniqueElementId(DocumentReference docRef) { return "id=\"" + getUniqueId(docRef) + "\""; } private String addUniqueContainerId(String parent) { return "id=\"C" + getUniqueId(parent) + "\""; } @Override public String getUniqueId(DocumentReference docRef) { String fullName = null; if (docRef != null) { fullName = getWebUtilsService().getRefLocalSerializer().serialize(docRef); } return getUniqueId(fullName); } @Override public String getUniqueId(String fullName) { String theMenuSpace = getMenuSpace(getContext()); if ((fullName != null) && !"".equals(fullName)) { return uniqueName + ":" + theMenuSpace + ":" + fullName; } else { return uniqueName + ":" + theMenuSpace + ":" + menuPart + ":"; } } boolean showSubmenuForMenuItem(DocumentReference docRef, int currentLevel, XWikiContext context) { return (isShowAll() || isBelowShowAllHierarchy(currentLevel) || isActiveMenuItem(docRef)); } private boolean isBelowShowAllHierarchy(int currentLevel) { return (currentLevel < showInactiveToLevel); } String getCssClasses(DocumentReference docRef, boolean withCM, boolean isFirstItem, boolean isLastItem, boolean isLeaf, int numItem) { String cssClass = ""; if (withCM) { cssClass += getCMcssClass(); } if (isFirstItem) { cssClass += " first"; } if (isLastItem) { cssClass += " last"; } if ((numItem & 1) == 0) { cssClass += " cel_nav_even"; } else { cssClass += " cel_nav_odd"; } cssClass += " cel_nav_item" + numItem; if (isLeaf) { cssClass += " cel_nav_isLeaf"; } else { cssClass += " cel_nav_hasChildren"; } if (docRef != null) { cssClass += " cel_nav_nodeSpace_" + docRef.getLastSpaceReference().getName(); cssClass += " cel_nav_nodeName_" + docRef.getName(); if (docRef.equals(getContext().getDoc().getDocumentReference())) { cssClass += " currentPage"; } cssClass += " " + getPageTypeConfigName(docRef); String pageLayoutName = getPageLayoutName(docRef); if (!"".equals(pageLayoutName)) { cssClass += " " + pageLayoutName; } if (isActiveMenuItem(docRef)) { cssClass += " active"; } if (isRestrictedRights(docRef)) { cssClass += " cel_nav_restricted_rights"; } } return cssClass.trim(); } boolean isRestrictedRights(DocumentReference docRef) { try { String docFN = getWebUtilsService().getRefLocalSerializer().serialize(docRef); XWikiRightService rightService = getContext().getWiki().getRightService(); boolean isRestricted = !rightService.hasAccessLevel("view", "XWiki.XWikiGuest", docFN, getContext()); LOGGER.debug("isRestrictedRights for [" + docFN + "] returns [" + isRestricted + "] using rights service [" + rightService.getClass().getName() + "]."); return isRestricted; } catch (XWikiException exp) { LOGGER.error("Failed to check isRestrictedRights for [" + docRef + "].", exp); } return false; } String getPageLayoutName(DocumentReference docRef) { SpaceReference pageLayoutRef = getPresentationType().getPageLayoutForDoc(docRef); if (pageLayoutRef == null) { pageLayoutRef = pageLayoutCmd.getPageLayoutForDoc(docRef); } if (pageLayoutRef != null) { return "layout_" + pageLayoutRef.getName(); } return ""; } String getPageTypeConfigName(DocumentReference docRef) { PageTypeReference pageTypeRef = getPageTypeResolverService().getPageTypeRefForDocWithDefault( docRef); String getPageTypeConfigName = pageTypeRef.getConfigName(); return getPageTypeConfigName; } boolean isActiveMenuItem(DocumentReference docRef) { DocumentReference currentDocRef = getContext().getDoc().getDocumentReference(); List<DocumentReference> docParentList = getWebUtilsService().getDocumentParentsList( currentDocRef, true); if (LOGGER.isDebugEnabled()) { LOGGER.debug("isActiveMenuItem: for [" + docRef + "] with [" + docParentList.size() + "] parents [" + Arrays.deepToString(docParentList.toArray(new DocumentReference[0])) + "]."); } return (docRef != null) && (docParentList.contains(docRef) || docRef.equals(currentDocRef)); } @Override public String getMenuLink(DocumentReference docRef) { String docURL = getContext().getWiki().getURL(docRef, "view", getContext()); // FIX for bug in xwiki url-factory 2.7.2 if ("".equals(docURL)) { docURL = "/"; } return docURL; } /** * @deprecated since 1.142 instead use createNavigation() */ @Deprecated public static INavigation createNavigation(XWikiContext context) { return new Navigation(Navigation.newNavIdForContext()); } public static INavigation createNavigation() { return new Navigation(Navigation.newNavIdForContext()); } static String newNavIdForContext() { ExecutionContext executionContext = Utils.getComponent(Execution.class).getContext(); Long navCounter = getNavCounterFromContext(executionContext) + 1; executionContext.setProperty(NAVIGATION_COUNTER_KEY, navCounter); return "N" + navCounter; } private static Long getNavCounterFromContext(ExecutionContext executionContext) { if (executionContext.getProperty(NAVIGATION_COUNTER_KEY) == null) { return new Long(0); } java.lang.Object navCounterObj = executionContext.getProperty(NAVIGATION_COUNTER_KEY); if (navCounterObj instanceof Long) { return (Long) navCounterObj + 1; } else { throw new IllegalArgumentException("Long object in context expected but got " + navCounterObj.getClass()); } } @Override public int getMenuItemPos(String fullName, XWikiContext context) { return WebUtils.getInstance().getMenuItemPos(fullName, menuPart, context); } @Override public int getActiveMenuItemPos(int menuLevel, XWikiContext context) { return WebUtils.getInstance().getActiveMenuItemPos(menuLevel, menuPart, context); } @Override public List<com.xpn.xwiki.api.Object> getMenuItemsForHierarchyLevel(int menuLevel, XWikiContext context) { return WebUtils.getInstance().getMenuItemsForHierarchyLevel(menuLevel, menuPart, context); } @Override public String getPrevMenuItemFullName(String fullName, XWikiContext context) { BaseObject prevMenuItem = null; try { prevMenuItem = WebUtils.getInstance().getPrevMenuItem(fullName, context); } catch (XWikiException exp) { LOGGER.error("getPrevMenuItemFullName failed.", exp); } if (prevMenuItem != null) { return prevMenuItem.getName(); } else { return ""; } } @Override public String getNextMenuItemFullName(String fullName, XWikiContext context) { BaseObject nextMenuItem = null; try { nextMenuItem = WebUtils.getInstance().getNextMenuItem(fullName, context); } catch (XWikiException exp) { LOGGER.error("getNextMenuItemFullName failed.", exp); } if (nextMenuItem != null) { return nextMenuItem.getName(); } else { return ""; } } @Override public boolean isNavigationEnabled() { return navigationEnabled; } /** * Look for a Celements2.NavigationConfigClass object on the WebPreferences, * XWiki.XWikiPreferences or skin_doc in this order an take the first place where any * Celements2.NavigationConfigClass object was found. If NO object for the given * menu_element_name (configName) at the selected place is found. This navigation should * be set to disabled and includeNavigation must return an empty string. */ @Override public void loadConfigByName(String configName, XWikiContext context) { XWikiDocument doc = context.getDoc(); try { BaseObject prefObj = utils.getConfigDocByInheritance(doc, NAVIGATION_CONFIG_CLASS, context).getObject(NAVIGATION_CONFIG_CLASS, "menu_element_name", configName, false); loadConfigFromObject(prefObj); } catch (XWikiException exp) { LOGGER.error("loadConfigByName failed.", exp); } } /** * @deprecated since 1.142 instead use XObjectNavigationFactory * createNavigation(DocumentReference) */ @Override @Deprecated public void loadConfigFromObject(BaseObject prefObj) { if (prefObj != null) { configName = prefObj.getStringValue("menu_element_name"); LOGGER.debug("loadConfigFromObject: configName [" + configName + "] from doc [" + prefObj.getName() + "]."); fromHierarchyLevel = prefObj.getIntValue("from_hierarchy_level", 1); toHierarchyLevel = prefObj.getIntValue("to_hierarchy_level", DEFAULT_MAX_LEVEL); showInactiveToLevel = prefObj.getIntValue("show_inactive_to_level", 0); menuPart = prefObj.getStringValue("menu_part"); setMenuSpace(prefObj.getStringValue("menu_space")); if (!"".equals(prefObj.getStringValue("data_type")) && (prefObj.getStringValue( "data_type") != null)) { dataType = prefObj.getStringValue("data_type"); } if (!"".equals(prefObj.getStringValue("layout_type")) && (prefObj.getStringValue( "layout_type") != null)) { try { setLayoutType(prefObj.getStringValue("layout_type")); } catch (UnknownLayoutTypeException exp) { LOGGER.error("loadConfigFromObject failed on setLayoutType.", exp); } } int itemsPerPage = prefObj.getIntValue(INavigationClassConfig.ITEMS_PER_PAGE); if (itemsPerPage > 0) { nrOfItemsPerPage = itemsPerPage; } String presentationTypeStr = prefObj.getStringValue( NavigationClasses.PRESENTATION_TYPE_FIELD); if (!"".equals(presentationTypeStr)) { setPresentationType(presentationTypeStr); } setCMcssClass(prefObj.getStringValue("cm_css_class")); // setMenuTypeByTypeName(prefObj.getStringValue("menu_type")); } else { navigationEnabled = false; } } @Override public void loadConfig(@NotNull NavigationConfig config) { navigationEnabled = config.isEnabled(); if (navigationEnabled) { configName = config.getConfigName(); fromHierarchyLevel = config.getFromHierarchyLevel(); toHierarchyLevel = config.getToHierarchyLevel(); showInactiveToLevel = config.getShowInactiveToLevel(); menuPart = config.getMenuPart(); nodeSpaceRef = config.getNodeSpaceRef().orNull(); dataType = config.getDataType(); try { setLayoutType(config.getLayoutType()); } catch (UnknownLayoutTypeException exp) { LOGGER.error("loadConfig failed on setLayoutType.", exp); } nrOfItemsPerPage = config.getNrOfItemsPerPage(); presentationType = config.getPresentationType().orNull(); cmCssClass = config.getCssClass(); } } private void generateLanguageMenu(INavigationBuilder navBuilder, XWikiContext context) { List<String> langs = getWebUtilsService().getAllowedLanguages(); mainUlCssClasses += " language"; navBuilder.openLevel(mainUlCssClasses); for (String language : langs) { navBuilder.openMenuItemOut(); boolean isLastItem = (langs.lastIndexOf(language) == (langs.size() - 1)); navBuilder.appendMenuItemLink(language, "?language=" + language, getLanguageName(language, context), language.equals(getNavLanguage()), isLastItem, cmCssClass); navBuilder.closeMenuItemOut(); } navBuilder.closeLevel(); } private String getLanguageName(String lang, XWikiContext context) { XWikiMessageTool msg = context.getMessageTool(); String space = context.getDoc().getDocumentReference().getLastSpaceReference().getName(); if (!msg.get("nav_cel_" + space + "_" + lang + "_" + lang).equals("nav_cel_" + space + "_" + lang + "_" + lang)) { return msg.get("nav_cel_" + space + "_" + lang + "_" + lang); } else if (!msg.get("nav_cel_" + lang + "_" + lang).equals("nav_cel_" + lang + "_" + lang)) { return msg.get("nav_cel_" + lang + "_" + lang); } else { return msg.get("cel_" + lang + "_" + lang); } } @Override public void setCMcssClass(String cmCssClass) { this.cmCssClass = cmCssClass; } @Override public String getCMcssClass() { if ((cmCssClass == null) || "".equals(cmCssClass)) { return getPresentationType().getDefaultCssClass(); } else { return cmCssClass; } } /** * for Tests only !!! **/ public void testInjectUtils(IWebUtils utils) { this.utils = utils; } /** * for Tests only !!! **/ public INavigationBuilder getNavBuilder() { return navBuilder; } @Override public void setShowAll(boolean showAll) { this._showAll = showAll; } boolean isShowAll() { return this._showAll; } @Override public void setShowInactiveToLevel(int showInactiveToLevel) { this.showInactiveToLevel = showInactiveToLevel; } @Override public void setHasLink(boolean hasLink) { this._hasLink = hasLink; } @Override public boolean hasLink() { return this._hasLink; } @Override public MultilingualMenuNameCommand getMenuNameCmd() { return menuNameCmd; } @Override public void setLanguage(String language) { this.navLanguage = language; } public void inject_menuNameCmd(MultilingualMenuNameCommand menuNameCmd) { this.menuNameCmd = menuNameCmd; } private IWebUtilsService getWebUtilsService() { if (injected_WebUtilsService != null) { return injected_WebUtilsService; } return Utils.getComponent(IWebUtilsService.class); } private XWikiContext getContext() { return (XWikiContext) getExecution().getContext().getProperty("xwikicontext"); } private Execution getExecution() { return Utils.getComponent(Execution.class); } private ITreeNodeService getTreeNodeService() { if (injected_TreeNodeService != null) { return injected_TreeNodeService; } return Utils.getComponent(ITreeNodeService.class); } IPageTypeResolverRole getPageTypeResolverService() { if (injected_PageTypeResolverService != null) { return injected_PageTypeResolverService; } return Utils.getComponent(IPageTypeResolverRole.class); } @Override public void setOffset(int offset) { if (offset >= 0) { this.offset = offset; } else { this.offset = 0; } } @Override public int getOffset() { return this.offset; } @Override public void setNumberOfItem(int nrOfItem) { if (nrOfItem > 0) { this.nrOfItemsPerPage = nrOfItem; } else { this.nrOfItemsPerPage = -1; } } @Override public int getNumberOfItem() { return this.nrOfItemsPerPage; } @Deprecated @Override public int getEffectiveNumberOfItems() { Tidy tidy = new Tidy(); tidy.setXHTML(true); ByteArrayInputStream includeIn = new ByteArrayInputStream(includeNavigation().getBytes()); Document dom = tidy.parseDOM(includeIn, null); NodeList uls = dom.getElementsByTagName("ul"); int elems = 0; if (uls.getLength() > 0) { elems = uls.item(0).getChildNodes().getLength(); } return elems; } void inject_navInclude(String navInclude) { this.navInclude = navInclude; } @Override public boolean hasMore() { DocumentReference parentRef = getWebUtilsService().getParentForLevel(fromHierarchyLevel); String parent = ""; if (parentRef != null) { parent = getWebUtilsService().getRefLocalSerializer().serialize(parentRef); } List<TreeNode> currentMenuItems = getCurrentMenuItems(fromHierarchyLevel, parent); LOGGER.debug("hasMore: parentRef [" + parentRef + "] currentMenuItems.size() [" + currentMenuItems.size() + "] offset [" + offset + "]" + " nrOfItemsPerPage [" + nrOfItemsPerPage + "] fromHierarchyLevel [" + fromHierarchyLevel + "] parent [" + parent + "]"); return currentMenuItems.size() > 0; } }