%--
ADOBE CONFIDENTIAL
___________________
Copyright 2015 Adobe
All Rights Reserved.
NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
and its suppliers and are protected by all applicable intellectual
property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Adobe.
--%><%
%><%@ include file="/libs/granite/ui/global.jsp" %><%
%><%@ page import="java.io.UnsupportedEncodingException,
java.io.IOException,
java.net.URLDecoder,
java.net.URLEncoder,
java.security.MessageDigest,
java.security.NoSuchAlgorithmException,
java.util.Arrays,
java.util.ArrayList,
java.util.Base64,
java.util.Collection,
java.util.Iterator,
java.util.Map,
java.util.List,
java.util.stream.Collectors,
javax.servlet.http.Cookie,
org.apache.commons.collections4.IteratorUtils,
org.apache.commons.lang3.StringUtils,
org.apache.jackrabbit.api.security.user.Authorizable,
org.apache.jackrabbit.util.Text,
org.apache.sling.api.SlingHttpServletRequest,
org.apache.sling.commons.json.JSONObject,
org.apache.sling.commons.json.io.JSONStringer,
org.apache.sling.commons.json.io.JSONWriter,
org.apache.sling.resourcemerger.api.ResourceMergerService,
com.adobe.granite.i18n.LocaleUtil,
com.adobe.granite.security.user.UserProperties,
com.adobe.granite.security.user.UserPropertiesManager,
com.adobe.granite.security.user.UserPropertiesService,
com.adobe.granite.ui.components.AttrBuilder,
com.adobe.granite.ui.components.Config,
com.adobe.granite.ui.components.ExpressionHelper,
com.adobe.granite.ui.components.ExpressionResolver,
com.adobe.granite.omnisearch.api.core.OmniSearchService,
com.adobe.granite.ui.components.FilteringResourceWrapper,
com.adobe.granite.ui.components.Tag,
com.adobe.granite.ui.components.Value" %><%--###
CollectionPage
==============
.. granite:servercomponent:: /libs/granite/ui/components/shell/collectionpage
The page to render collection pattern.
It also supports :doc:`resource filtering using FilteringResourceWrapper ` and acts as its container.
It has the following content structure:
.. gnd:gnd::
[granite:ShellCollectionPage]
/**
* A general purpose ID to uniquely identify the console.
*
* The recommended value is hierarchical separated by "-".
* e.g. "cq-commerce-report"
*/
- consoleId (StringEL)
/**
* The base title of the page.
*
* e.g. "AEM Sites"
*/
- jcr:title (String)
/**
* The URI Template of the page. It is used to generate the new URL when navigating the collection.
*
* It supports the following variables:
*
* id
* The id of the collection (:doc:`[data-foundation-collection-id] `).
*
* e.g. ``/sites.html{+id}``
*/
- pageURITemplate (StringEL)
/**
* This property is the equivalence of ``pageURITemplate`` for absolute path.
*
* For example if your template is ``{+id}.html``, since it is not starting with "/",
* the server is unable to know if it is an absolute path.
* So use this property if you want to add the context path regardless.
*/
- 'pageURITemplate.abs' (StringEL)
/**
* The value of :doc:`[data-foundation-mode-group] `
* that the collection is part of.
*/
- modeGroup (String)
/**
* The selector to the collection.
*/
- targetCollection (String)
/**
* The path to the omnisearch configuration associated with the console.
*
* e.g. ``/libs/granite/omnisearch/content/metadata/site``
*/
- omnisearchLocationPath (StringEL)
/**
* The URI Template of the preview of the selected items.
* If this property is specified, an additional preview container is added.
*
* It supports the following variables:
*
* item
* The id of the selected item. (:doc:`[data-foundation-collection-item-id] `)
* Note that this variable can be a list of items.
*
* For example, if ``item = ("item1", "item2")`` and ``itemPreviewSrc = /preview{?item*}``, the final URI will be ``/preview?item=item1&item=item2``.
*/
- itemPreviewSrc
/**
* To redirect the page, this resource can be specified.
* It will be included, where the redirect can be performed.
*/
+ redirector
/**
* A folder to specify the content of ``
`` of the page.
* Its child resources are iterated and included as is.
*/
+ head
/**
* The folder for the available views (i.e. the rendering) of the collection,
* where each can be any component implementing :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/clientlibs/foundation/vocabulary/collection`.
*
* At least one view needs to be provided.
* If there are at least two views, the following properties are needed to be able to switch the view:
*
* icon (String)
* The icon of the view.
* jcr:title (String)
* The title of the view.
* src (StringEL)
* The URI Template that is returning the HTML response of the new view.
* It supports the following variables:
*
* offset
* The item offset of the current request.
* limit
* The item limit of the pagination.
* id
* The id of the collection (:doc:`[data-foundation-collection-id] `).
*
* **View Settings**
*
* Each view is able to provide settings related to that view.
* To do this, ``settings`` component needs to be specified. The component can be a container that contains the form fields representing the settings.
* The form will be automatically generated, and the settings are saved in the user preferences.
*/
+ views mandatory
/**
* The header area just above the collection view.
* Any component can be used here.
*/
+ header
/**
* The footer area just below the collection view.
* Any component can be used here.
*/
+ footer
+ breadcrumbs
/**
* The component to render the title.
*
* Either this resource or ``breadcrumbs`` needs to be specified.
* Use this resource instead of ``breadcrumbs`` when your resource is flat (not hierarchical).
* If neither is specified, the value of ``jcr:title`` is used.
*
* If the title is just a simple string, :doc:`../title/index` can be used.
*
* The only requirement of the component is to generate a simple text without any wrapping markup.
* E.g. To have a title of "My Page", just make the component do something like ``out.print("My Page")``.
*/
+ title
/**
* A component implementing :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/clientlibs/foundation/vocabulary/collection`,
* used as a configuration for a Content Tree, which will appear in a ``rails`` panel.
*
* If ``contenttree`` is not present, the Content Tree will use a view from ``views`` named ``column``.
*
* If no such view exists, the Content Tree will not be rendered.
*/
+ contenttree
/**
* The folder for the actions applicable in the context of the collection.
*/
+ actions (granite:ShellCollectionPageActions)
/**
* A folder to specify the panels of the rail.
*/
+ rails (granite:ShellCollectionPageRails)
[granite:ShellCollectionPageActions]
/**
* The folder for primary actions.
*
* The action can be any action component such as :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/button/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/anchorbutton/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/pulldown/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/collection/index`.
*
* The ``actionBar`` variant of the components above SHOULD be used, unless ``primary`` variant is used.
*
* Usually the action is implementing :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/clientlibs/foundation/js/collection/action/index`,
* with ``relScope`` = ``collection``.
*
* The actions are wrapped inside :doc:`.foundation-collection-actionbar `
* element where ``[data-foundation-collection-actionbar-target]`` is set as the value of ``targetCollection`` property.
* This way setting the ``target`` property at individual action is not required.
*/
+ primary
/**
* The folder for secondary actions.
*
* The action can be any action component such as :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/button/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/anchorbutton/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/pulldown/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/collection/index`.
*
* The ``actionBar`` variant of the components above SHOULD be used, unless ``primary`` variant is used.
*
* Usually the action is implementing :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/clientlibs/foundation/js/collection/action/index`,
* with ``relScope`` = ``collection``.
*
* The actions are wrapped inside :doc:`.foundation-collection-actionbar `
* element where ``[data-foundation-collection-actionbar-target]`` is set as the value of ``targetCollection`` property.
* This way setting the ``target`` property at individual action is not required.
*/
+ secondary
/**
* The folder for actions applicable during selection mode. (e.g. when one of the collection item is selected)
*
* The action can be any action component such as :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/button/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/anchorbutton/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/pulldown/index`,
* :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/collection/index`.
*
* The ``actionBar`` variant of the components above SHOULD be used, unless ``primary`` variant is used.
*
* Usually the action is implementing :doc:`/jcr_root/libs/granite/ui/components/coral/foundation/clientlibs/foundation/js/collection/action/index`,
* with ``relScope`` = ``item``.
*
* The actions are wrapped inside :doc:`.foundation-collection-actionbar `
* element where ``[data-foundation-collection-actionbar-target]`` is set as the value of ``targetCollection`` property.
* This way setting the ``target`` property at individual action is not required.
*/
+ selection
[granite:ShellCollectionPageRails]
/**
* ``true`` to activate the rail initially.
*
* Note that you need to also set ``active`` property of the rail panel to ``true`` accordingly.
*/
- active (BooleanEL)
/**
* The child resources are considered as the panels, where each MUST be a :doc:`../../coral/foundation/panel/railpanel/index` (or its derivative).
*/
+ '*' (granite:PanelRailPanel)
Example::
+ /apps/my/page
- sling:resourceType = "granite/ui/components/shell/collectionpage"
- jcr:title = "AEM Sites"
- modeGroup = "cq-siteadmin-admin-childpages"
- pageURITemplate = "/sites.html{+id}"
- targetCollection = "#cq-siteadmin-admin-childpages"
+ views
+ card
- sling:resourceType = "my/card"
- granite:id = "cq-siteadmin-admin-childpages"
- icon = "viewCard"
- jcr:title = "Card View"
- modeGroup = "cq-siteadmin-admin-childpages"
- src = "/mnt/overlay/my/page/views/card{.offset,limit}.html{+id}"
- offset = "${requestPathInfo.selectors[0]}"
- limit = "${empty requestPathInfo.selectors[1] ? "20" : requestPathInfo.selectors[1]}"
- path = "${requestPathInfo.suffix}"
+ settings
- sling:resourceType = "granite/ui/components/coral/foundation/container"
+ items
+ field1
- sling:resourceType = "my/field"
+ field2
- sling:resourceType = "my/field"
+ list
- sling:resourceType = "my/list"
- granite:id = "cq-siteadmin-admin-childpages"
- icon = "viewList"
- jcr:title = "List View"
- modeGroup = "cq-siteadmin-admin-childpages"
- src = "/mnt/overlay/my/page/views/list{.offset,limit}.html{+id}"
- offset = "${requestPathInfo.selectors[0]}"
- limit = "${empty requestPathInfo.selectors[1] ? "20" : requestPathInfo.selectors[1]}"
- path = "${requestPathInfo.suffix}"
###--%><%
Config cfg = cmp.getConfig();
ExpressionHelper ex = cmp.getExpressionHelper();
if (!cfg.get("noMerge", false)) {
ResourceMergerService resourceMerger = sling.getService(ResourceMergerService.class);
if (resourceMerger != null) {
Resource uiResource = resourceMerger.getMergedResource(resource);
if (uiResource != null) {
resource = uiResource;
cfg = new Config(resource);
}
}
}
resource = new FilteringResourceWrapper(resource, sling.getService(ExpressionResolver.class), slingRequest);
Resource redirector = resource.getChild("redirector");
if (redirector != null) {
%><%
if (response.isCommitted()) {
return;
}
}
String targetCollection = cfg.get("targetCollection", String.class);
String consoleId = StringUtils.trimToNull(ex.getString(cfg.get("consoleId", String.class)));
// GRANITE-8258: Force the header to bypass the compatibility mode on intranet sites
response.setHeader("X-UA-Compatible", "IE=edge");
AttrBuilder htmlAttrs = new AttrBuilder(request, xssAPI);
htmlAttrs.addClass("skipCoral2Validation");
htmlAttrs.add("lang", LocaleUtil.toRFC4646(request.getLocale()).toLowerCase());
htmlAttrs.add("data-i18n-dictionary-src", request.getContextPath() + "/libs/cq/i18n/dict.{+locale}.json");
%>
>
<%
String origTitle = cfg.get("jcr:title", String.class);
String baseTitle = i18n.getVar(origTitle);
String title = baseTitle;
if (baseTitle != null) {
String breadcrumbTitle = getBreadcrumbActiveItemTitle(resource, cmp);
if (!breadcrumbTitle.isEmpty()) {
// Expand the base title with the navigator/breadcrumb active element title.
title = breadcrumbTitle + " | " + title;
}
String pageURITemplate = handleURITemplate(cfg, "pageURITemplate", ex, request);
AttrBuilder titleAttrs = new AttrBuilder(request, xssAPI);
titleAttrs.addClass("granite-collection-pagetitle");
titleAttrs.add("data-granite-collection-pagetitle-target", targetCollection);
titleAttrs.add("data-granite-collection-pagetitle-src", pageURITemplate);
titleAttrs.add("data-granite-collection-pagetitle-base", baseTitle);
%>><%= xssAPI.encodeForHTML(title) %><%
}
String[] pageHierarchy = getPageHierarchy(consoleId);
if (pageHierarchy == null) {
pageHierarchy = getPageHierarchyByTitle(!StringUtils.isBlank(origTitle) ? origTitle : resource.getPath());
}
String assetId = StringUtils.isNotEmpty(request.getParameter("item"))
? request.getParameter("item")
: slingRequest.getRequestPathInfo().getSuffix();
JSONObject trackingPage = new JSONObject();
trackingPage.put("type", "collection");
trackingPage.put("hierarchy", pageHierarchy[0]);
trackingPage.put("name", pageHierarchy[1]);
if (StringUtils.isNotEmpty(assetId)) {
trackingPage.put("assetId", assetId);
}
%><%
Resource globalHead = resourceResolver.getResource("/mnt/overlay/granite/ui/content/globalhead");
if (globalHead != null) {
for (Iterator it = globalHead.listChildren(); it.hasNext();) {
%><%
}
}
Authorizable auth = resourceResolver.adaptTo(Authorizable.class);
UserPropertiesManager upm = resourceResolver.adaptTo(UserPropertiesManager.class);
UserProperties userPreferences = upm.getUserProperties(auth, UserPropertiesService.PREFERENCES_PATH);
String userPreferencesPath = auth.getPath() + "/" + UserPropertiesService.PREFERENCES_PATH;
String onboardingSrcPath = "/mnt/overlay/granite/ui/content/shell/onboarding.html";
%><%-- is deprecated, use foundation-preference instead --%>
">
<%
AttrBuilder userPrefAttrs = new AttrBuilder(request, xssAPI);
userPrefAttrs.add("name", "user.preferences");
userPrefAttrs.add("content", getPreferencesJSON(userPreferences));
userPrefAttrs.addHref("data-foundation-preference-action", userPreferencesPath);
%>>
<%-- is deprecated, use foundation-preference instead --%>
"><%
if (cfg.get("coral2", false)) {
%><%
} else {
%><%
}
Resource omnisearchConfigResource = resourceResolver.getResource(ex.getString(cfg.get("omnisearchLocationPath", String.class)));
if (omnisearchConfigResource != null) {
OmniSearchService omnisearchService = sling.getService(OmniSearchService.class);
// check if OmnisearchHanlder is present
if (omnisearchService.getModuleConfiguration(resourceResolver, omnisearchConfigResource.getName()) != null) {
ValueMap props = omnisearchConfigResource.getValueMap();
%>"><%
}
}
AttrBuilder omnisearchSrcAttrs = new AttrBuilder(request, xssAPI);
omnisearchSrcAttrs.addClass("granite-omnisearch-src");
omnisearchSrcAttrs.add("data-granite-omnisearch-src", request.getContextPath() + "/mnt/overlay/granite/ui/content/shell/omnisearch.{location}.html");
omnisearchSrcAttrs.addHref("data-granite-omnisearch-search-url", "/aem/search.html");
%>><%
Resource head = resource.getChild("head");
if (head != null) {
for (Iterator it = head.listChildren(); it.hasNext();) {
%><%
}
}
%><%
// Flush head so that the browser can start downloading the clientlibs
response.flushBuffer();
String modeGroup = cfg.get("modeGroup", String.class);
String navigationId = consoleId;
if (consoleId == null) {
consoleId = generateConsoleId(resource);
}
String targetViewName = getTargetViewName(slingRequest, consoleId, userPreferences);
List viewCache = new ArrayList();
Resource currentView = null;
{
int i = 0;
for (Iterator it = resource.getChild("views").listChildren(); it.hasNext(); i++) {
Resource item = it.next();
if (i == 0 || item.getName().equals(targetViewName)) {
currentView = item;
}
viewCache.add(item);
}
}
JSONWriter cookieConfig = new JSONStringer()
.object()
.key("name").value(consoleId)
.key("expires").value(7)
.key("path").value(request.getContextPath() + "/")
.endObject();
JSONWriter availableSettings = new JSONStringer().array();
for (Resource view : viewCache) {
if (view.getChild("settings") != null) {
availableSettings.value(view.getName());
}
}
availableSettings.endArray();
AttrBuilder viewAttrs = new AttrBuilder(request, xssAPI);
viewAttrs.addClass("coral--light");
viewAttrs.addClass("shell-collectionpage-view");
viewAttrs.add("data-shell-collectionpage-view-target", targetCollection);
viewAttrs.add("data-shell-collectionpage-view-cookie", cookieConfig.toString());
viewAttrs.add("data-shell-collectionpage-view-layoutId", currentView == null ? null : currentView.getName());
viewAttrs.add("data-shell-collectionpage-view-settings", availableSettings.toString());
Resource rails = resource.getChild("rails");
String railSaveKey = "rail-" + consoleId;
String railWidthSaveKey = "rail-width-" + consoleId;
String savedRailTarget = getCookie(slingRequest, railSaveKey);
String savedRailWidth = getCookie(slingRequest, railWidthSaveKey);
boolean savedRailTargetFound = false;
boolean hasActiveRail = rails != null && cmp.getExpressionHelper().getBoolean(rails.getValueMap().get("active", "false"));
String collectionWidthSaveKey = "collection-width-" + consoleId;
String savedCollectionWidth = getCookie(slingRequest, collectionWidthSaveKey);
Resource contentTreeItem = resource.getChild("contenttree");
// If there is no specific configuration for the Content Tree, use the Column View, if it exists.
if (contentTreeItem == null) {
contentTreeItem = resource.getChild("views").getChild("column");
}
Config contentTreeItemCfg = new Config(contentTreeItem);
String rootPath = ex.getString(contentTreeItemCfg.get("rootPath", ""));
String itemPreviewSrc = handleURITemplate(cfg, "itemPreviewSrc", ex, request);
int minContentSize = 100;
// Even if no rails are configured, we need to add them when the columnview is enabled to add the tree
final boolean hasRails = rails != null || (contentTreeItem != null && !rootPath.isEmpty());
%>>
<%
Resource skipNavigationLinksRes = resource.getChild("skipnavigationlinks");
if (skipNavigationLinksRes != null) {
%><%
}
%>
">
<%
AttrBuilder actionBarAttrs = new AttrBuilder(request, xssAPI);
actionBarAttrs.add("id", "granite-shell-actionbar");
actionBarAttrs.addClass("foundation-collection-actionbar");
actionBarAttrs.add("data-foundation-collection-actionbar-target", targetCollection);
%>>
<%
Resource breadcrumbs = resource.getChild("breadcrumbs");
if (breadcrumbs != null) {
List crumbs = IteratorUtils.toList(cmp.asDataSource(breadcrumbs).iterator());
if (!crumbs.isEmpty()) {
AttrBuilder navigatorAttrs = new AttrBuilder(request, xssAPI);
navigatorAttrs.addClass("granite-collection-navigator");
navigatorAttrs.add("id", "granite-collection-breadcrumbs-toggle");
navigatorAttrs.add("trackingfeature", "aem:collectionpage");
navigatorAttrs.add("trackingelement", "breadcrumbs");
navigatorAttrs.add("data-granite-collection-navigator-target", targetCollection);
%>><%
for (int j = 0; j < crumbs.size(); j++) {
Resource item = (Resource) crumbs.get(j);
Config itemCfg = new Config(item);
AttrBuilder itemAttrs = new AttrBuilder(request, xssAPI);
String navigatorCollectionid = itemCfg.get("path", String.class);
if (navigatorCollectionid != null) {
itemAttrs.add("data-granite-collection-navigator-collectionid", navigatorCollectionid);
} else {
itemAttrs.add("data-granite-collection-navigator-href", itemCfg.get("href", String.class));
}
%>><%= xssAPI.encodeForHTML(itemCfg.get("title")) %><%
}
%><%
}
} else {
Resource titleRes = resource.getChild("title");
if (titleRes != null) {
%><%
} else {
%><%= xssAPI.encodeForHTML(baseTitle) %><%
}
}
%><%
if (hasRails) {
%>
<%= xssAPI.encodeForHTML(i18n.get("Content Only")) %><%
int railItemIndex = 1;
if (contentTreeItem != null && !rootPath.isEmpty()) {
AttrBuilder navigationAttrs = new AttrBuilder(request, xssAPI);
navigationAttrs.add("trackingelement", "contenttree");
navigationAttrs.add("data-granite-toggleable-control-action", "show");
navigationAttrs.add("data-granite-toggleable-control-name", "content-tree");
navigationAttrs.add("data-foundation-command", "alt+" + railItemIndex++);
navigationAttrs.add("data-granite-toggleable-control-target", ".shell-collectionpage-rail-panel[data-shell-collectionpage-rail-panel='content-tree']");
if (!hasActiveRail && savedRailTarget != null && savedRailTarget.equals("content-tree")) {
navigationAttrs.addSelected(true);
savedRailTargetFound = true;
}
%>><%= xssAPI.encodeForHTML(i18n.get("Content Tree")) %><%
}
if (rails != null) {
// we map all rail items to the numbers in the keyboard using control + {index}
for (Iterator it = rails.listChildren(); it.hasNext(); railItemIndex++) {
Resource item = it.next();
if (cmp.getRenderCondition(item, true).check()) {
Config itemCfg = new Config(item);
AttrBuilder itemAttrs = new AttrBuilder(request, xssAPI);
// we stop once we reach 9 since all available numbers have been used
if (railItemIndex < 10) {
itemAttrs.add("data-foundation-command", "alt+" + railItemIndex);
}
itemAttrs.add("trackingelement", item.getName());
itemAttrs.add("data-granite-toggleable-control-name", item.getName());
if (item.getName().equals("omnisearchfilter")) {
itemAttrs.add("data-granite-toggleable-control-action", "hide");
itemAttrs.add("data-granite-toggleable-control-target", "#shell-collectionpage-rail");
itemAttrs.add("data-granite-omnisearch-filter", targetCollection);
} else {
String href = ex.getString(itemCfg.get("href", String.class));
itemAttrs.add("icon", itemCfg.get("icon", String.class));
if (href != null) {
itemAttrs.add("data-granite-toggleable-control-action", "navigate");
itemAttrs.addHref("data-granite-toggleable-control-href", href);
} else {
String railPanelTarget = ".shell-collectionpage-rail-panel[data-shell-collectionpage-rail-panel='" + item.getName() + "']";
itemAttrs.add("data-granite-toggleable-control-action", "show");
itemAttrs.add("data-granite-toggleable-control-target", railPanelTarget);
}
itemAttrs.addSelected(itemCfg.get("active", false));
if (!hasActiveRail && savedRailTarget != null && savedRailTarget.equals(item.getName())) {
itemAttrs.addSelected(true);
savedRailTargetFound = true;
}
}
%>><%= outVar(xssAPI, i18n, itemCfg.get("jcr:title", String.class)) %><%
}
}
}
%><%
}
Resource primary = resource.getChild("actions/primary");
if (primary != null) {
for (Iterator it = primary.listChildren(); it.hasNext();) {
Resource item = it.next();
%><%
}
}
%><%
AttrBuilder selectAllAttrs = new AttrBuilder(request, xssAPI);
selectAllAttrs.addClass("foundation-collection-selectall");
selectAllAttrs.addClass("coral-Button--graniteActionBar");
selectAllAttrs.add("data-foundation-collection-selectall-target", targetCollection);
selectAllAttrs.add("data-foundation-command", "ctrl+a");
selectAllAttrs.add("trackingfeature", "aem:collectionpage");
selectAllAttrs.add("trackingelement", "selectall");
%><%
Resource secondary = resource.getChild("actions/secondary");
if (secondary != null) {
for (Iterator it = secondary.listChildren(); it.hasNext();) {
Resource item = it.next();
if ("create".equals(item.getName())) {
AttrBuilder createAttrs = new AttrBuilder(request, xssAPI);
createAttrs.addClass("granite-collection-create");
createAttrs.add("data-granite-collection-create-target", targetCollection);
cmp.include(item, new Tag(createAttrs));
} else {
AttrBuilder attrs = new AttrBuilder(request, xssAPI);
attrs.add("data-shell-collection-target", targetCollection);
attrs.add("data-shell-console-id", consoleId);
cmp.include(item, new Tag(attrs));
}
}
}
if (viewCache.size() > 1) {%>
<%
AttrBuilder switcherAttrs = new AttrBuilder(request, xssAPI);
switcherAttrs.addClass("granite-collection-switcher");
switcherAttrs.add("id", "granite-collection-switcher-toggle");
switcherAttrs.add("aria-labelledby", "cyclebutton-switcher-toggle-label");
switcherAttrs.add("data-granite-collection-switcher-target", targetCollection);
%>><%
for (Resource item : viewCache) {
Config itemCfg = new Config(item);
String src = ex.getString(itemCfg.get("src", String.class));
AttrBuilder itemAttrs = new AttrBuilder(request, xssAPI);
itemAttrs.add("data-granite-collection-switcher-src", handleURITemplate(src, request));
itemAttrs.add("icon", itemCfg.get("icon", String.class));
itemAttrs.addSelected(item.getName().equals(currentView.getName()));
%>><%= outVar(xssAPI, i18n, itemCfg.get("jcr:title", String.class)) %><%
}
if (!viewCache.isEmpty()) {
String viewSettingsSrcBase = "/mnt/overlay/granite/ui/content/shell/collectionpage/viewsettings.html";
String src = viewSettingsSrcBase + Text.escapePath(resource.getPath()) + "?targetCollection=" + Text.escape(targetCollection) + "&consoleId=" + Text.escape(consoleId);
AttrBuilder itemAttrs = new AttrBuilder(request, xssAPI);
itemAttrs.addClass("granite-collection-switcher-settings");
itemAttrs.addClass("foundation-toggleable-control");
itemAttrs.add("icon", "gear");
itemAttrs.addHref("data-foundation-toggleable-control-src", src);
itemAttrs.add("data-foundation-toggleable-control-action", "show");
itemAttrs.add("data-foundation-toggleable-control-cache", "false");
%>><%= xssAPI.encodeForHTML(i18n.get("View Settings")) %><%
}
%><%
}
%><%
Resource header = resource.getChild("header");
if (header != null) {
%><%
}
%>
><%
// Need to introduce `.foundation-layout-util-maximized-container` wrapper element to work around a bug
// at `.foundation-container-resizable` which requires its child to be scrollable.
AttrBuilder previewSupportAttrs = new AttrBuilder(request, xssAPI);
previewSupportAttrs.addClass("foundation-layout-util-maximized-container");
previewSupportAttrs.addClass("foundation-collection-previewsupport");
previewSupportAttrs.add("data-foundation-collection-previewsupport-collection", "child");
previewSupportAttrs.add("data-foundation-collection-previewsupport-target", "#granite-shell-collection-preview");
previewSupportAttrs.add("data-foundation-collection-previewsupport-src", itemPreviewSrc);
%>
<%
} else {
// Note that `.foundation-collection-content` is not needed and can be removed.
// However, there is a bad selector using it in Assets code base right now.
%>