We are using template editor in AEM 6.2 to create templates , and we have followed below steps to create a template-
1.Created page template as done in we-retail site.
2.Create empty page template using above page template.
3.Created template using empty page template.
Did following modifications on top of we retail page component as per our requirement-
As we need to have header and footer as full width parsys i.e 1340 width and body as 940 width-
.site-wrapper {
width:1340px;
}
.container {
width:940px;
}
So we did following modifications in /apps//components/structure/page/partials/body.html -
<div class="site-wrapper">
<div data-sly-resource="${ # path='header', resourceType='/apps/<projectname>/components/structure/header'}"
data-sly-unwrap>
</div>
</div>
<div class="container"
data-sly-use.templatedContainer="com.day.cq.wcm.foundation.TemplatedContainer">
<sly data-sly-repeat="${templatedContainer.structureResources}"
data-sly-resource="${item.path # resourceType=item.resourceType, decorationTagName='div'}" />
</div>
<div class="site-wrapper">
<div data-sly-resource="${ # path='footer', resourceType='/apps/<projectname>/components/structure/footer'}" data-sly-unwrap></div>
</div>
Also we have few more components which will take full width on the page so i have added responsivegrid component under full width div.
But i am not able to edit the header and footer component in template as they are not under templateresource.
Also even if i add design dialog under header and footer i am not able to edit those components directly on the page in design mode even if they are unlocked.
Please let me know if i am doing anything wrong here or we cant customize body.html as in we-retail site.
I thought of using different parsys for full width and for body.
And i don't want to control using css as i have multiple components which are full width.
Regards
Ankur
First, the objective of the Template Editor is precisely to not do any static includes like what you edited on your page component, because the Template Editor now provides a UI to include such components on the page level, allowing to define which included components can be edited or not by authors on the resultant pages. That way, if some page suddenly requires another header or footer, this can be edited through the UI of the Template Editor and doesn't require a development cycle.
So I'd recommend to remove your edits of the body.html, and rather make sure that your Header and Footer components are editable: meaning that the cq:Component node must have a title (jcr:title), a group (componentGroup), as well as an cq:editConfig, a classic dialog or a classic design dialog (in 6.2 and before, the classic dialogs were still needed to make a component editable, but this won't be the case anymore for future versions, where touch dialogs can be provided instead).
Once you're there, here are detailed instructions for setting up your site with the Template Editor UI in AEM 6.2:
Create the template
For now, we'll create the template in the global folder, later however you'll have to make sure that the chosen folder is specific to your site.
Go to the Template Editor (in AEM's global nav, select General > Templates).
Pick the global folder (or your site-specific folder).
Hit the "Create" button and choose "HTML5 Page", hit "Next" and give your template a name, like "Simple Page", then hit "Create" and choose "Open".
Add Client Libraries
Let's configure the page component to load the CSS and JS client libraries that are needed for our site.
In "Structure" mode of the Template Editor, select the second icon from the top-left ("Page Information") and choose "Page Policy". A policy is basically a reusable design configuration that can be shared and reused across multiple templates if desired. What we'll do is duplicate that policy and then edit it to instruct the page to load additional client libraries.
In the "Policy" dialog, duplicate the "Default Page" policy with the double-arrow icon and rename it for instance to " Config". Then click the checkmark at the top-right of the dialog to save.
Again in the top-left ("Page Information") menu, choose this time "Page Design" to edit the actual design configuration.
Edit the list to include all client libraries required by the components that you plan to use. If the template author isn't a developer, this is typically where the developer must instruct the template author what clientlibs must be loaded on the pages of a specific site. In case you have We.Retail installed, you can add a field and paste we-retail.base into it. Save by clicking the top-right checkmark.
Add Structure Components
Structure components are those that were usually hard-coded through static includes on the page components. We typically don't want the structure components to be editable by our page authors later on, unless explicitly defined.
On the page, select the empty parsys and in its toolbar, choose the 1st icon ("Policy") to edit policy.
In the "Policy" dialog, duplicate the "Default Layout Container" policy and rename it for instance to "Template Config". This will be the name of the configuration that tells what components are available in the template for that page-level layout container. Save.
As the page reloads, select the empty parsys again, and this time choose the 2nd icon ("Design") to edit the design configuration.
In the design dialog that opens, select all the components that you want to have available in the template editor (for example, in addition to the few General components already selected, also select the "We.Retail" and the "We.Retail.Structure" component groups at the bottom of the list, or the group name you assigned to your components with the componentGroup property). Make sure to have also the "Layout Container" component selected, as this is the paragraph system (aka parsys) that we'll require later to make the page editable. Save.
You should now see your components showing up in the left "Components" rail, which allows to drag & drop your header and footer components to the page (for We.Retail the header is named "We.Retail Page Header" and is at the very bottom of the component list, and it is similar for the footer).
Also drag a "Layout Container" component between your header and footer components, which is the actual parsys that we'll make editable for our page authors. So on your page, you should now at least have following components: your header (e.g. "We.Retail Page Header"), a "Layout Container", and your footer (e.g. "We.Retail Page Footer").
Make the template editable
We now have to specify which of the components added we want page authors to be able to edit.
Select the parsys placeholder that appears between the header and the footer, and click the last icon of the toolbar ("Unlock structure component").
Once this is done, the placeholder says "No allowed components for Layout Container", the reason is that this parsys has no policy yet assigned to define the list of allowed components for the page authors. Therefore, select this parsys placeholder again and from the toolbar select the second icon ("Policy").
To base our policy on the one previously edited, select the "Template Config", and the hit the duplicate icon and rename it to "Page Config". Save.
The list of allowed components now appear below the parsys placeholder, which looks good, except that we want to remove the components that we want available in for the template structure only. Therefore, let's select the placeholder once more and select the 3rd icon ("Design") from the toolbar.
In the design dialog, uncheck the structure-specific components and groups (for e.g. uncheck the "We.Retail.Structure" group). Save.
Use the template
That's it, we can now enable the template and use it on a site.
On the template admin (which should be still open in a previous browser tab), select your newly created template and hit "Enable" and confirm "Enable".
For pages to be able to be created from templates of the folder we used, one will need to put a cq:allowedTemplates property on a parent page (typically, this property will be set to the root page of the site). However, to create the very first root page, we'll initially just add that property to the /content node by using CRXDE Lite. So go to http://localhost:4502/crx/de/index.jsp#/content and on the root content node set cq:allowedTemplates multi-String property that equals to "/conf/global/settings/wcm/templates/.*" (or whatever folder you created your template in).
Save.
Back in AEM open the global menu and go to Sites and on the root folder, click "Create" and choose "Page".
Choose our "Simple Page" template, hit "Next", give the page a title, like "My Site" and click "Create" and "Open".
You should now see the page with the defined header and footer, but only the parsys in between that is editable. Also the desired components should show up in the left rail under the second "Components" tab.
Create a Template Type
In order to avoid having to repeat all these steps (mainly 1-18) each time one wants to create a new template, we can create a template type out of the template that we created.
In CRXDE Lite, go to the folder where you've created your template, like /conf/global/settings/wcm/templates and copy the template that should become a template type, like the simple-page node in our case.
Move to the template-types folder (e.g. /conf/global/settings/wcm/template-types in our case) and paste there the copied node.
Save.
Now, when creating a template in the global folder, one can choose the "Simple Page" as a starting point.
As you can see, the Template Editor introduces a very big change, not only technically, but also in the process: what required development steps can now be achieved through configuration. I'd therefore recommend to edit the page component only to adapt the technical HTML headers, but not to hard-code any visual items that should be displayed on the page, because surely enough in a few months/years the visual items will change and multiple variations of them will be required, for which you want to lighten the development need to allow faster changes.
Also helpful are following links:
https://docs.adobe.com/docs/en/aem/6-2/develop/templates/page-templates-editable.html
http://fr.slideshare.net/PatrickFauchre/empower-template-authors
https://github.com/Adobe-Marketing-Cloud/aem-sites-example-custom-template-type
If you will check the resources included in template using calls such as <div data-sly-resource="${ # path='footer', resourceType='/apps/<projectname>/components/structure/footer'}" data-sly-unwrap></div> tends to be problematic when it comes to editing, reason so far I have figured out it that if the nodes for the resources don't exist, these resources are not editable. Refer to an article around it here.
What we did was to create a scripts to create nodes on page load (EmbeddedComponent.js) -
"use strict";
/**
* Creates a component node with name, if node does not yet exist.
*/
use([], function () {
var newResourceName = this.name;
var newResourceType = this.type;
var resourceResolver = resource.getResourceResolver();
var newNodePath = resource.path + "/" + newResourceName;
var existingComponentResource = resourceResolver.getResource(newNodePath);
if (existingComponentResource == null) {
var properties = {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType": newResourceType
};
resourceResolver.create(resource, newResourceName, properties);
resourceResolver.commit();
}
});
And in you HTML script you could do something like -
<div data-sly-use="${'Path to script/EmbeddedComponent.js' # name='header', type=resTypHeader}"
data-sly-resource="<header resource type>">
have you tried the data-sly-unwrap="${!wcmmode.edit}" on the header and footer include script?
Related
As per the title really, but to give it more specifics:
My web app has multiple users, each has a different set of permissions and this means that certain parts of the app aren't available to them, in most cases this is simple, whole sections are just blocked out and not displayed at all, but in some cases I would like to be able to wrap a certain section of a page in a tag which if the user hasn't permission to see will either hide this section entirely, or show a "you don't have permission to use this bit" partial view.
I am using .NET Core 3.1 and Razor Pages.
So I am thinking something like this:
<html>
<body>
My web page content....
<permission requires="view_invoices">
<h3>Invoices</h3>
.... invoice content....
BUT - if user has not got permission this section is skipped, so is blank, or shows (/Views/Partial/PermissionNotAvailable)
</permission>
</body>
</html>
Edit - for clarity, I want to be able to write my content assuming the user has permission to view it, but if they don't, the fact that it is wrapped in the permissions tag helper will have it removed or replaced by a server-side helper.
If you are using ASP.NET authorization and razor pages you can do something like the following:
#if (User.IsInRole("ViewInvoices")) {
<h3>Invoices</h3>
.... invoice content....
} else {
(/Views/Partial/PermissionNotAvailable)
}
Where ViewInvoices is a role you added to the database and assigned to certain users. If the user does not have this role that section of the page is not returned to the client.
DNN Platform 9.3.2 /
2sxc 10.25.2
I have a DNN website that uses 2sxc. I created a "Notification Bar" content type and c# razor template that I use to display special notifications to the user. This module is meant to display on every single page of the website. I used the "Add Existing Module" functionality to manually add the module to every page but it's a bit cumbersome and I run the risk that my Content Editors move the module by accident, delete, or forget to add it to new pages.
Is there a special 2sxc skin object that I can use inside of my .ascx DNN skin to load a 2sxc module so that I don't have to add it to every page through DNN? Apparently there is one in DNN OpenContent.
(More than just the notification bar, this would be super useful for the site's header or footer that gets occasionally updated. For example, social media links, contact info like address or phone number, or other links that aren't part of the DNN pages menu.)
There are two ways
create a pane for this specific module (it's the easiest to edit and work with) and just show the module on all pages
create the module on a hidden page and then inject it into the skin, using the Factory to get the CmsBlock - see https://docs.2sxc.org/api/dot-net/ToSic.Sxc.Dnn.Factory.html#ToSic_Sxc_Dnn_Factory_CmsBlock_System_Int32_System_Int32_
Daniel, this is how we did it in the past. I notice your call is similar but simpler (above in the comments). Is that because the API changed somewhere after v10?
<script runat="server">
// get 2sxc to Render() the output from the module on the SITE/Manage Flyout Links page
private IHtmlString RenderFlyoutMenu()
{
return ToSic.SexyContent.Environment.Dnn7.Factory.SxcInstanceForModule(3354, 606).Render();
}
</script>
<%=RenderFlyoutMenu() %>
I have a Chrome extension, and a Chrome app. I need inline install for both of them on the same domain.
As per Googles instructions (for one inline install) I add the header link tag:
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/itemID">
Then add the onclick function in the body:
<button onclick="chrome.webstore.install()" id="install-button">Add to Chrome</button>
<script>
if (chrome.app.isInstalled) {
document.getElementById('install-button').style.display = 'none';
}
</script>
What I need to know is how to add two instances. One for the extension, and one for the app. Do I add two link tags in the header, then edit the onclick function?
This is what Google says to do for multiple instances, but I don't understand where to edit the onclick function to differentiate between the two.
To actually begin inline installation, the
chrome.webstore.install(url, successCallback, failureCallback)
function must be called. This function can only be called in response
to a user gesture, for example within a click event handler; an
exception will be thrown if it is not. The function can have the
following parameters:
url (optional string) If you have more than one tag on your
page with the chrome-webstore-item relation, you can choose which item
you'd like to install by passing in its URL here. If it is omitted,
then the first (or only) link will be used. An exception will be
thrown if the passed in URL does not exist on the page.
successCallback (optional function) This function is invoked when
inline installation successfully completes (after the dialog is shown
and the user agrees to add the item to Chrome). You may wish to use
this to hide the user interface element that prompted the user to
install the app or extension.
failureCallback (optional function) This
function is invoked when inline installation does not successfully
complete. Possible reasons for this include the user canceling the
dialog, the linked item not being found in the store, or the install
being initiated from a non-verified site. The callback is given a
failure detail string as a parameter. You may wish to inspect or log
that string for debugging purposes, but you should not rely on
specific strings being passed back.
I currently have one link tag in my header for the extension. I need to add another inline installation, on a different page, same domain, but this second onclick code needs to be different so it doesn't refer to the existing link tag in my header.
Many thanks.
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/itemID1">
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/itemID2">
<button onclick="chrome.webstore.install('https://chrome.google.com/webstore/detail/itemID1')" id="install-button-1">Add App to Chrome</button>
<button onclick="chrome.webstore.install('https://chrome.google.com/webstore/detail/itemID2')" id="install-button-2">Add Extension to Chrome</button>
The very same docs page shows a method for the extensions.
Basically, your extension can inject a <div id="somethingYouExpect"> into the DOM, and the page's script can detect that.
It's a bit clunky though: I was trying to get it to work for test code and didn't manage to do so in a good way, as content scripts are injected either before DOM is constructed at all or after document ready fires. You can bypass that with mutation observers, but meh and your button will be visible for a split second.
You can save yourself some pain, if you're just hiding an element, by injecting a css file hiding it. Or, you can hide the elements from injected code. Either way is somewhat layout-sensitive though.
If you HAVE to be layout-independent and at the same time want something more complex than element hiding, either go the (div inject + mutation observer) route or you can try window.postMessage approach to signal the page to hide the element.
Step by step guide for the extension / CSS variant.
Suppose your extension install UI is contained in an element with id extension-install.
Add a content script to the manifest file:
"content_scripts": [
{
"matches": ["*://yourdomain/*"],
"css": ["iaminstalled.css"],
"run_at": "document_start"
}
],
The CSS:
#extension-install {
display: none !important;
}
So, to recap:
To allow installs of both the app and the extension, you need two <link> tags in the head
To install either you pass the url parameter to chrome.webstore.install
If the app is installed, it will define chrome.app.isInstalled in the page's context. You can check for it from the page to hide the install button.
If the extension is installed, it can inject CSS/JS into page to hide the install button.
I am developing an HTML 5 mobile angular app with an android style skin. The app will need to be login-aware and I'm looking for advice on best practices. What I need is:
To have a persistent header that will display the current view, change the current view (via a dropdown), and perform login-specific functions (like "view my stuff" or "logout")
To have several different views within the app such as "master view" and "detail view" and "map view"
To have the app display a particular view (login.html) when the user is not logged in.
It seems like 3 is a special case of 1. In any case, the header is persistent throughout the app (except when a user isn't logged in) and the views will change based on user input. What is the best way to tackle this style of application using angular?
I think you want to use ngInclude.
I think you're already using ng-view for your body. Makes things easy :
<body>
<div id="header" ng-include="'header.html'"></div>
<div id="container" ng-view></div>
</body>
My Yii application has a particular section called 'Edit Profile' . It's a pretty data heavy section in the way a lot of data is pulled from db for this one .
However the problem is that I have tab pagination in this section . Because only this section uses tabs on the website I did not include the related CSS/Javascript files in the main layout header .These have been referenced in the view file itself . Because of this the tabs takes time to show up and the tab titles appear as a list first (for a second or two) and then get distributed into tabs with the correct UI . This is of course unacceptable behaviour . Is there any way to selectively include related js/css files into the header tag for this particular view or should I include it in main layhout file even though it won't be used in a lot of other places on the website thus possibly slowing down other pages .
Just specify the position for the file.
In your view where you are including the js or css :
// for js
Yii::app()->clientScript->registerScriptFile('url_of_file',CClientScript::POS_HEAD);
// for css
Yii::app()->clientScript->registerCssFile('url_of_file');
Recommended documentation: registerScriptFile() , and registerCssFile()
You can create your own layout in the layouts folder , where u can include all the required jquery scripts and css. U can then call your layout in the controller.
public function actionDoSomething(){
$this->layout = 'mylayout';
$this->render('myview');
}