I would like to implement an extensible templating mechanism in AEM, so as to permit component users to control markup for individual projects (designs) without modifying the components' pre-defined JSPs.
I have extended the <cq:include> tag to permit this, by passing a template name, which is then retrieved from the current design, falling back to the default markup when an override does not exist in the design:
<ct:template name="listNav/prev" />
This should load the jsp script from [1], unless the location does not exist, defaulting to [2]:
/etc/designs/projectName/component_templates/listNav/prev.jsp
/etc/designs/component_templates/listNav/prev.jsp
When using the extended tag, I'm receiving the exception (yes, the file exists):
Caused by: org.apache.sling.api.SlingException: javax.servlet.ServletException: javax.servlet.jsp.JspException: Could not find script /etc/designs/component_templates/listNav/prev.jsp
This all works when the component_templates is under /apps. Is there any way to make this work? Is there a better approach? I'd prefer to keep the component_templates with the designs, if possible.
I don't think it is a good idea to put application script to etc. They should be under /apps.
But I think it could work, if you add /etc path to the "Resource Search Path" of this service:
system/console/configMgr/org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl
you can choose between different "designs" within the advanced page properties tab! afaik you should use this mechanism to declare different designts i.e. stylesheets etc. to your pages and of cause you don't need to modify anything at the jsp's to switch between different styles if implemented properly.
Have a look at this:
Adobe AEM Designs
Related
I'm using the free JS plugin from tinymce and interested in preventing an HTML injection with the tinymce text editor.
I've added this property to the INIT:
invalid_elements: 'script' (just for this example)
However nothing happens. The editor still "accepts" the script tag and pass it on.
I looked at https://www.tiny.cloud/docs/tinymce/6/content-filtering/#invalid_elements and it should work but I don't see any change once it's added.
Am I doing something wrong?
Is there a way to limit some HTML elements with this editor?
Any other tips on how to use that editor and prevent the malicious HTML..?
TinyMCE certainly has a variety of configuration options to help you control what content is created in the editor but you can never assume that data provided to you client side is "clean" or "safe". Nefarious people can bypass your front end and all of its validation if their goal is to cause harm to your system.
You should always configure your front end appropriately. TinyMCE has a variety of configuration options to assist with content filtering/validation (https://www.tiny.cloud/docs/configure/content-filtering/) to only allow those types of tags you want created, etc including:
https://www.tiny.cloud/docs/configure/content-filtering/#valid_elements
https://www.tiny.cloud/docs/configure/content-filtering/#extended_valid_elements
https://www.tiny.cloud/docs/configure/content-filtering/#valid_children
https://www.tiny.cloud/docs/configure/content-filtering/#schema
https://www.tiny.cloud/docs/configure/content-filtering/#invalid_elements
However, regardless of the front end design, you should always re-check submitted content on the server to ensure it is safe. There is simply no way around that need. What constitutes "safe" is likely a business decision based on what your application does and who uses it.
There are many different libraries you can use server side to do this sort of validation/cleansing so depending on your specific server side setup you can find libraries that allow you to "sanitize/purify" the submitted HTML.
I would note that TinyMCE (by default) should not allow <script> tags in your content so it is likely that such behavior could be due to your current configuration.
The publisher instance has the following javascript files included:
/etc/clientlibs/granite/jquery.min.js
/etc/clientlibs/granite/utils.min.js
/etc/clientlibs/granite/jquery/granite.min.js
/etc/clientlibs/foundation/main.min.js
/etc/clientlibs/granite/jquery/granite/csrf.min.js
It would be best to exclude them for performance and also the fact that I am using jQuery 2.0 as my part of AEM site.
These scripts(not including the csrf.min.js) are part of the category cq.foundation-main. You can use this utility for checking this.
http://localhost:4502/libs/granite/ui/content/dumplibs.test.html?categories=cq.foundation-main
If you create your page template components by extending the OOTB wcm/foundation/components/page (assuming you use sightly), AEM will add these scripts in the head section. More specifically these are included in headlibs.html file present under the OOTB page component.
To overcome this, you can override this file in your component, and either comment this below line or include it conditionally only when wcmmode is edit.
<sly data-sly-test="${wcmmode.edit}" data-sly-call="${clientLib.all # categories='cq.foundation-main'}" />
For JSP based components (foundation/components/page), the same thing is done in headlibs.jsp.
By the way, you wouldn't want to remove the CSRF JS. It's AEM's solution to counter CSRF issues.
What you see is the clientcontext related js'es
The script that loads the given js'es is as below (or sth similiar)
<cq:include path="clientcontext" resourceType="cq/personalization/components/clientcontext"/>
either you exclude it completely for publish (wcmMode=disabled) which would probably break sth related to analytics on your publish, or change the include to some overwrite of the clientcontext component that you'd develop.
If you however don't use any native Adobe integration you should be safe just with excluding the thing.
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.
Are there any validators for Eclipse that checks that internal links between JSF web pages in the same project refers to existing pages?
I realise this is impossible to do in more complex cases, but it should be possible to do in the standard case.
One way to achieve something similar is to create Java constants for all page source files names (for example as properties in an app scoped bean) and reference them from EL, because EL validation checks those. But to do this you have to manually add all the file names which is cumbersome.
It seems to be quite basic problem, but I still cannot find a nice solution.
I made a component that uses a dialog property.
How could I avoid setting this property for every single page if this component is used also in template?
What I already have tried:
I set name attribute in dialog.xml to absolute path - Component stops working as standalone (dropped into parsys).
Move it to design_dialog.xml - First of all it's conceptually content, so I do not like such move, and again it doeas not make much sense for standalone versions.
Change resource path to absolute, while including in template:
<cq:include path="/content/site/somepage" resourceType="/apps/portal/components/myComponent" />
For the first look it was almost it. Instances included via parsys has it's own path, and Content for template is fetched from single resource... But where to store it, to make template code independent from pages tree structure?
Is there any other nice way to do so? or at least way to improve 3.?
To the original poster, the functionality you are looking for is now supported by Shared Component Properties in ACS AEM Commons (http://adobe-consulting-services.github.io/acs-aem-commons/features/shared-component-properties.html)
Compared to your suggested solutions:
No need for absolute property path required for SCP
Agreed these are "content" properties, so they should be stored as "content" instead of "design". SCP stores these values under the homepage node of a site, making them as genuine of content as any other piece of content.
Agreed that it is bad to have a template hard-coded to a content path of a single site, especially since this makes a multi-site implementation impossible without creating a bunch of templates. SCP does not have this problem, because each site has its own homepage under which the properties are stored.
If I understand correctly, you have a component which may work in two modes:
it may be included statically in the main page renderer via <cq:include>
it may be also dropped into some parsys.
In the first mode component should have some common configuration for all pages and in the second mode it should be configured separately per-instance. The problem is how to create such common configuration.
I think your 3rd solution is perfectly fine assuming that the component configuration is shared by all sites in your CQ instance. At some point it may be too strong assumption, eg. you may have a 3 language branches under /content/site-en, /content/site-fr and /content/site-de and you'd like to make a separate configuration for each branch.
I'd suggest following improvement to the 3rd solution: you may create the shared component under some relative path which will be the same for all pages, like /content/.../configuration/shared-component (where ... may be site1, site2 or site3). Then take first two parts of the current page path, add the /configuration/shared-component suffix and use <cq:include> to include path created in such way.
You may also take a different approach and create a common configuration page referenced by all statically included components. These components may try to find their configuration automatically (via the relative path as above) or they may have a single pathfield that references configuration page.
If you don't like these options (as they assume some site structure or they need some minimal configuration for each component), consider using HierarchyNodeInheritanceValueMap. It allows you to get property from the current resource and if there is no such property, it'll look into the same resource on ancestor pages. Using this you could configure your component just once, in the site root page and inherit configuration across the whole site.