The Client Library (ClientLib) feature in Adobe AEM (formerly Adobe CQ) makes it easy to include client libraries by category and each library can pull in other libraries through dependencies. However the documentation around "Themes" is a little thin.
This link is about all I can find on the subject. Here is an excerpt of the sample code:
<%-- theme only (theme-js + css) --%>
<cq:includeClientLib theme="cq.collab.calendar, cq.security" />
If this tag were to be used how would CQ determine what Client Libs to pull in? Does it look for a theme property of type String[]?
Or does it look for a certain directory structure in the /etc/designs section?
Or does it take the passed in categories and add theme-js to the end like so?
cq.collab.calendar.theme-js
Or is the theme invoked through the URL? In other words, the word "theme", in this case, is a token that is replaced with a selector from a URL applied theme?
Client Libraries reside in a cq:ClientLibraryFolder folder. This folder has a property called category. In the following example, cq.collab.calendar and cq.security are categories:
<cq:includeClientLib theme="cq.collab.calendar, cq.security" />
When this include is called, it is looking for any cq:ClientLibraryFolder with the category cq.collab.calendar or cq.security assigned to it. Using the theme property adds both the css and javascript of clientLibs residing in the themes folder of the parent ClientLibraryFolder. If you were to view your page source, these would be added to their own css and js files. For example, I created the following structure under the geometrixx clientLibary:
geometrixx
clientlibs
themes
myTheme (clientLibray)
css.txt
myCSS.css
js.txt
myJS.js
If, you use the theme property with this clientlib you would get a myTheme.css and myTheme.js file showing in your source/network tab.
The themed flag is a way to shut theme inclusion on and off. The following cq:include will include all the css in the clientLibrary, including stuff in the themes directory.
<cq:includeClientLib css="apps.geometrixx-main" />
However, if I add the themed flag and set it to false, anything under the theme directory is excluded:
<cq:includeClientLib css="apps.geometrixx-main" themed="false" />
So in that case, myTheme.css would not show up. One thing to note, is that the themed flag, only works on "pure css and js includes" Categories and theme properties would not work with this.
The answer to this question goes over this a bit: What exactly does currentDesign.writeCssincludes include?
It has been mentioned that theme is fetched from the request did a little digging an finally found out it tries to fetch it from request parameter named "forceTheme"
private String getDefaultThemeName(SlingHttpServletRequest request)
{
String theme = request.getParameter("forceTheme");
if (theme == null) {
theme = this.defaultUserThemeName;
}
return theme;
}
But needed request.getAttribute because using query parameters will send all requests to pub.
So guess this theme option is of no use at all.
Depends on what you mean by "theme". If you are used to wordpress, drupal, etc, what is called a theme in those systems is called a "design" in CQ5/AEM.
To set a design, you choose a "designpath" in the page properties. This will affect where information about components for each template is stored (all changes made in design mode about what components are allowed where are stored under this path) and is the convention for where CSS, JS, and non-DAM image resources are stored. It takes planning, but you can re-use code and markup in AEM/CQ5 but totally change the look by changing the design.
Related
I'm using Adobe Experience Manager and i need to apply separate styles to authoring view and publishing view for component. The reason for this is I have some JS that changes the layout of the component at desktop size, however in authoring mode this means the component is no longer usable or fully visible.
So far I have:
looked in Adobe Forums for a similar question
tried to add some styles within html file based on the condition of edit mode being true:
<sly data-sly-test.author="${wcmmode.edit}"><style><!--my code--></style></sly>
Instead of writing inline styles based on the edit mode, better way would be to define a separate client library and add that client library on your pages only in edit mode. Let's say, you have a component - "Custom Component" which has the class as - "custom-comp".
<div class="custom-component">
<!-- your custom component html code goes here -->
</div>
So I am assuming you would already have defined some CSS for this component in the project client library that should be loaded on your pages already. To style it different in author mode, you can try following steps -
In your page.html, define a special class which will identify whether your page is being loaded in Author or in Publish. Something like below -
< body class="${wcmmode.edit || wcmmode.design ? 'authoring-mode' : ''}">
Using above line of code, your pages will now have a special class - "authoring-mode" only when you open the page in Author. But when you open page in publish, this class won't appear which is exactly what you want here.
Now, you need to define a new client library in your code which will have CSS and JS files and you need to load this new client library in your customheaderlibs. Again this client library needs to be added only in author mode.
Write custom CSS rules for your custom component using the combination of two class names - "authoring-mode" and component class name - "custom-component".
Test your changes in author mode and publish mode.
Is it possible to conditionally include different clientlibs based on the user agent of the browser?
IE
<sly data-sly-use.clientLib="/libs/granite/sightly/templates/clientlib.html"
data-sly-call="${clientlib.js # categories='a'}"/>
Modern Browsers
<sly data-sly-use.clientLib="/libs/granite/sightly/templates/clientlib.html"
data-sly-call="${clientlib.js # categories='b'}"/>
AEM version: 6.3
If not, what are the other alternatives to achieve the same?
Note: I tried to get this check done in a sling rewriter server side but the problem is, with the dispatcher on, it will only hit AEM for the furst time and cache the html, any subsequent hit will not invoke any server side logic to render it. Hence, it has to be done client side IMO
For this you have to write custom clientlibs templates as described here : https://github.com/nateyolles/aem-clientlib-async.
And then in the WCMUse class you can check user agent and include clientlibs accordingly.
First of all, as you already pointed out correctly, you need asolution that works with the dispatcher cache. So Sightly is not an option.
Then, regarding the fact, that most AEM templates have paragraph systems with multiple possible components to be added to a page on the one hand and AEM clientlibs are build on a template level (and not on page level) you end up with a clientlib holding lots of unused JS and CSS most of the time, since you have to cover all the possible options of components used in your page and paragraph system.
With that in mind, clientlibs might not be a good option to be used after all.
Having static CSS and JS files in your AEM repo and referencing them client side based on a JS snippet will do the trick and - in most cases - you will not buy any side effects with that approach.
You can either:
Wrap your clientlibs with conditional comments: https://stackoverflow.com/a/11703767
Create a Use-Object that check the User-Agent header and exposes a method isIE that you can use to conditionally include the clientlibs with data-sly-test. Alternatively your Use-Object could just return the proper categiers based on user agent so you can have only one clientlib call.
You could use the <script module> and <script nomodule> to achieve that. The first one is ignored by older browsers and the second one by the modern ones. Similar to Vue's Modern Mode. Check: https://cli.vuejs.org/guide/browser-compatibility.html#modern-mode
More likely you would need some back-end to create your custom clientlib template.
I have a requirement where I have 2 clientlibs having different CSS files for my website. The business author should be capable of switching the website look and feel by just changing the path of the design under page properties. While I am able to achieve that requirement by changing the clientlib categories name referred in my JSP of base template of my site, can the same thing be achieved by the business author without actually performing a code level change? Basically, he should be able to select the design path present under the page properties section, and selecting a different design should change the look and feel of the website. Please let me know how this can be achieved.
Note: I have placed my clientlibs under /etc/design/proj-name/ path
The foundation page component is designed to include css link in the head if a file called static.css is present under the design. It's done through the design object.
If you have different css in the static.css file under different designs then the look and feel will change with the design. However you will be stuck with one file and cannot leverage the utility of client libs.
This adobe doc suggest's doing something like this for css and related images
<%= currentDesign.getPath() + "/static/img/icon.gif %>
Data from design dialogs is stored under the design , swapping designs to change look and feel will cause data inconsistencies too.
Why not add a selection widget to the page and use it's value to selectively include different client lib categories instead of relying on the design.
I'm trying to figure out exactly what css is included by the standard call to currentDesign.writeCssIncludes(pagecontext); found in headlibs.jsp. The documentation states simply that it is
Convenience method that writes the CSS include strings to the response.
Looking at what it seems to do, it will include /etc/designs/currentdesign.css which is built off the design components css, and /etc/designs/currentdesign/static.css, which is just a static file. But is this all that is will include?
In particular, what I'd like to do is include a clientLib-processed css file as part of my design. One way to do this is to manually build out the css include:
<link rel="stylesheet" href="<%= currentDesign.getPath() %>/myclientlib.css" />
But I'd prefer to let that get generated automatically, so that my designers have flexibility to structure the css files differently for different designs (i.e., for the "base" design they are fine with just a static.css file, but for the "fancy" design they want to use LESS css and break up the files more granularly). And it would be helpful to put design-specific css info with the components they affect, rather then needing to separate those.
You can use the <cq:includeClientLib> tag, combined with themes and/or categories, to mix and match bits of CSS.
But you may find it somewhat limiting; for instance, you can't specify a media attribute. If you need to do this, or your designers don't structure their CSS in a way that fits the themes/categories model, your fallback is the technique you've identified in your question, using <link> directly.
Update
An excellent question about themes! I have only seen them used in passing.
You can define a theme by just adding a new folder/node under /etc/designs/yourproject/clientlibs/themes, as a sibling to default.
You can pull in the clientlibs for a theme with the <cq:includeClientLibs> tag, perhaps under the control of some conditional logic. For instance, in one of my projects I have a theme called authoring which I only want to apply to the author instance; I pull it in with this code in headlibs.jsp:
<c:if test="${ (global['wcmmode'] eq 'EDIT') || (global['wcmmode'] eq 'PREVIEW') }">
<cq:includeClientLib theme="apps.myproject.authoring" />
</c:if>
I have not seen any documentation that would apply theme automatically to a particular subtree of the content tree, or based on the presence of a tag.
There is that cryptic statement "The theme name is extracted from the request." in the Adobe docs, which is backed up by this statement in the Sling docs, "ThemeResolverFilter Provides the Theme for the request. The theme is provided as a request attribute." So perhaps tacking &theme=apps.yourproject.foo onto a query string would apply that theme.
The list of CSS files is based on the property 'cq:designPath' of the page.
I am creating a new template and then a page from SCRATCH in CQ5. But I can't find the option to add my own CSS/images/JS to the page.
I mean a place to add/upload the actual files.
All the tutorials I've seen talk only about creating a template based on an existing template. Is there any tutorial on how to create the page from scratch ?
Your CSS and JavaScript go into nodes under /etc/designs/[your project's name]/clientlibs. (Ordinarily, you would set the page property cq:designPath of your content's home page to be /etc/designs/[your project's name] to point to this.) It's common practice to set up a subfolder of clientlibs called default, where your general-purpose style sheets and JavaScript go; you can set up other clientlibs for special-case script and style sheets. The simplest way to incorporate your script and style sheets into your page template is the <cq:includeClientLib> JSP tag.
The Adobe docs on clientlibs will also be useful to you, and explains how to use the tag.
#David , thanks for your answer, but for now, I got a better way to add and then use external files using WebDAV with CQ5.
The basic integration of WebDAV with CQ5 application is mentioned in this page