Quantcast
Channel: Experiencing Adobe Experience Manager (AEM, CQ)
Viewing all 512 articles
Browse latest View live

AEM 64 - Touch UI Nested Composite Multifield Using Coral 3

$
0
0

Goal


Create a sample component dialog using nested composite coral 3 multifield/libs/granite/ui/components/coral/foundation/form/multifield

Demo | Package Install | Github


Multifield Structure in CRX



Multifield in Dialog



Multifield Storage in CRX



Component Rendering



Solution


1) Login to CRXDE Lite (http://localhost:4502/crx/de), create folder /apps/eaem-coral3-nested-composite-multifield

2) Sample dialog with nested composite multifield /apps/eaem-coral3-nested-composite-multifield/sample-nested-composite-multifield/cq:dialog

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="64 Nested Composite Multi Field"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<products
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
composite="{Boolean}true"
fieldLabel="Products">
<field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container"
name="./products">
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<product
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldDescription="Name of Product"
fieldLabel="Product Name"
name="./product"/>
<components
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
composite="{Boolean}true"
fieldLabel="Components">
<field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container"
name="./components">
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<component
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldDescription="Name of Component"
fieldLabel="Component Name"
name="./component"/>
<compPath
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathbrowser"
fieldDescription="Select Path"
fieldLabel="Path"
name="./compPath"
rootPath="/content"/>
<size
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldDescription="Select Size"
fieldLabel="Size"
name="./size">
<items jcr:primaryType="nt:unstructured">
<def
jcr:primaryType="nt:unstructured"
text="Select Size"
value=""/>
<small
jcr:primaryType="nt:unstructured"
text="Small"
value="small"/>
<medium
jcr:primaryType="nt:unstructured"
text="Medium"
value="medium"/>
<large
jcr:primaryType="nt:unstructured"
text="Large"
value="large"/>
</items>
</size>
</items>
</column>
</items>
</field>
</components>
</items>
</column>
</items>
</field>
</products>
</items>
</column>
</items>
</content>
</jcr:root>


3) #17 composite=true is for outer composite multifield (./products) and #37 composite=true for inner composite multifield (./components)

4) Create file (nt:file) /apps/eaem-coral3-nested-composite-multifield/sample-nested-composite-multifield/helper.js, add the following code for reading stored nodes

"use strict";

use( ["/libs/wcm/foundation/components/utils/ResourceUtils.js","/libs/sightly/js/3rd-party/q.js" ], function(ResourceUtils, Q){
var prodPromise = Q.defer(), company = {},
productsPath = granite.resource.path + "/products";

company.products = undefined;

ResourceUtils.getResource(productsPath)
.then(function (prodParent) {
return prodParent.getChildren();
})
.then(function(products) {
addProduct(products, 0);
});

function addProduct(products, currIndex){
if(!company.products){
company.products = [];
}

if (currIndex >= products.length) {
prodPromise.resolve(company);
return;
}

var productRes = products[currIndex],
properties = productRes.properties;

var product = {
path: productRes.path,
name: properties["product"]
};

ResourceUtils.getResource(productRes.path + "/components")
.then(function (compParent) {
return compParent.getChildren();
})
.then(function(components) {
addComponent(product, components, 0);
});

company.products.push(product);

addProduct(products, (currIndex + 1));
}

function addComponent(product, components, currIndex){
if(!product.components){
product.components = [];
}

if (currIndex >= components.length) {
return;
}

var compRes = components[currIndex],
properties = compRes.properties;

var component = {
path: compRes.path,
name: properties.component,
compPath: properties.compPath,
size: properties.size
};

product.components.push(component);

addComponent(product, components, (currIndex + 1));
}

return prodPromise.promise;
} );


5) Create file (nt:file) /apps/eaem-coral3-nested-composite-multifield/sample-nested-composite-multifield/sample-nested-composite-multifield.html, add the following code for rendering data

<div>
<b>64 Nested Composite Multifield</b>

<div data-sly-use.company="helper.js" data-sly-unwrap>
<div data-sly-test="${!company.products && wcmmode.edit}">
Add products using component dialog
</div>

<div data-sly-test="${company.products}">
<div data-sly-list.product="${company.products}">
<div>
<div>${product.name}</div>

<div data-sly-list.component="${product.components}" style="margin-left:40px">
<div><b>${component.name}</b></div>
<div>${component.compPath}</div>
<div>${component.size}</div>
</div>
</div>
</div>
</div>
</div>
</div>





AEM 64 - Touch UI RTE (Rich Text Editor) Dialog Color Picker Plugin

$
0
0

Goal


Touch UI Color Picker Plugin for RTE (Rich Text Editor) Dialog - /libs/cq/gui/components/authoring/dialog/richtext

For a similar extension on 63 check this post, 62 check this post, 61 check this post

For demo purposes, dialog of core text component v2 was modified to add the color picker configuration - /apps/core/wcm/components/text/v2/text/cq:dialog/content/items/tabs/items/properties/items/columns/items/column/items/text/rtePlugins

Demo | Package Install | Github


Plugin Configuration









Color Picker



Color applied to text







Solution


1) Login to CRXDE Lite, add nt:folder /apps/eaem-touchui-dialog-rte-color-picker

2) To show the color picker in a dialog create /apps/eaem-touchui-dialog-rte-color-picker/color-picker-popover of type sling:Folder and /apps/eaem-touchui-dialog-rte-color-picker/color-picker-popover/cq:dialog of type nt:unstructured

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Color Picker"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
margin="{Boolean}false"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<picker
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/colorfield"
name="./color">
<items jcr:primaryType="nt:unstructured">
<red
jcr:primaryType="nt:unstructured"
name="Red"
value="#FF0000"/>
<green
jcr:primaryType="nt:unstructured"
name="Green"
value="#00FF00"/>
<blue
jcr:primaryType="nt:unstructured"
name="Blue"
value="#0000FF"/>
<black
jcr:primaryType="nt:unstructured"
name="Black"
value="#000000"/>
</items>
</picker>
<add
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/button"
class="coral-Button--primary"
id="EAEM_CP_ADD_COLOR"
text="Add Color"/>
<remove
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/button"
class="coral-Button--warning"
id="EAEM_CP_REMOVE_COLOR"
text="Remove Color"/>
</items>
</column>
</items>
</content>
</jcr:root>


                           
3) Create clientlib (cq:ClientLibraryFolder) /apps/eaem-touchui-dialog-rte-color-picker/clientlib set property categories to cq.authoring.dialog.all and dependencies to [underscore]

4) Create file (nt:file) /apps/eaem-touchui-dialog-rte-color-picker/clientlib/js.txt, add the following content

                   color-picker.js


5) Create file (nt:file) /apps/eaem-touchui-dialog-rte-color-picker/clientlib/color-picker.js, add the following code

(function($, CUI){
var GROUP = "experience-aem",
COLOR_PICKER_FEATURE = "colorPicker",
TCP_DIALOG = "eaemTouchUIColorPickerDialog",
PICKER_NAME_IN_POPOVER = "color",
REQUESTER = "requester",
PICKER_URL = "/apps/eaem-touchui-dialog-rte-color-picker/color-picker-popover/cq:dialog.html";

addPluginToDefaultUISettings();

addDialogTemplate();

var EAEMColorPickerDialog = new Class({
extend: CUI.rte.ui.cui.AbstractDialog,

toString: "EAEMColorPickerDialog",

initialize: function(config) {
this.exec = config.execute;
},

getDataType: function() {
return TCP_DIALOG;
}
});

var TouchUIColorPickerPlugin = new Class({
toString: "TouchUIColorPickerPlugin",

extend: CUI.rte.plugins.Plugin,

pickerUI: null,

getFeatures: function() {
return [ COLOR_PICKER_FEATURE ];
},

initializeUI: function(tbGenerator) {
var plg = CUI.rte.plugins;

if (!this.isFeatureEnabled(COLOR_PICKER_FEATURE)) {
return;
}

this.pickerUI = tbGenerator.createElement(COLOR_PICKER_FEATURE, this, false, { title: "Color Picker" });
tbGenerator.addElement(GROUP, plg.Plugin.SORT_FORMAT, this.pickerUI, 10);

var groupFeature = GROUP + "#" + COLOR_PICKER_FEATURE;
tbGenerator.registerIcon(groupFeature, "textColor");
},

execute: function (id, value, envOptions) {
if(!isValidSelection()){
return;
}

var context = envOptions.editContext,
selection = CUI.rte.Selection.createProcessingSelection(context),
ek = this.editorKernel,
startNode = selection.startNode;

if ( (selection.startOffset === startNode.length) && (startNode != selection.endNode)) {
startNode = startNode.nextSibling;
}

var tag = CUI.rte.Common.getTagInPath(context, startNode, "span"), plugin = this, dialog,
color = $(tag).css("color"),
dm = ek.getDialogManager(),
$container = CUI.rte.UIUtils.getUIContainer($(context.root)),
propConfig = {
'parameters': {
'command': this.pluginId + '#' + COLOR_PICKER_FEATURE
}
};

if(this.eaemColorPickerDialog){
dialog = this.eaemColorPickerDialog;
}else{
dialog = new EAEMColorPickerDialog();

dialog.attach(propConfig, $container, this.editorKernel);

dialog.$dialog.css("-webkit-transform", "scale(0.9)").css("-webkit-transform-origin", "0 0")
.css("-moz-transform", "scale(0.9)").css("-moz-transform-origin", "0px 0px");

dialog.$dialog.find("iframe").attr("src", getPickerIFrameUrl(color));

this.eaemColorPickerDialog = dialog;
}

dm.show(dialog);

registerReceiveDataListener(receiveMessage);

function isValidSelection(){
var winSel = window.getSelection();
return winSel && winSel.rangeCount == 1 && winSel.getRangeAt(0).toString().length > 0;
}

function getPickerIFrameUrl(color){
var url = PICKER_URL + "?" + REQUESTER + "=" + GROUP;

if(!_.isEmpty(color)){
url = url + "&" + PICKER_NAME_IN_POPOVER + "=" + color;
}

return url;
}

function removeReceiveDataListener(handler) {
if (window.removeEventListener) {
window.removeEventListener("message", handler);
} else if (window.detachEvent) {
window.detachEvent("onmessage", handler);
}
}

function registerReceiveDataListener(handler) {
if (window.addEventListener) {
window.addEventListener("message", handler, false);
} else if (window.attachEvent) {
window.attachEvent("onmessage", handler);
}
}

function receiveMessage(event) {
if (_.isEmpty(event.data)) {
return;
}

var message = JSON.parse(event.data),
action;

if (!message || message.sender !== GROUP) {
return;
}

action = message.action;

if (action === "submit") {
if (!_.isEmpty(message.data)) {
ek.relayCmd(id, message.data);
}
}else if(action === "remove"){
ek.relayCmd(id);
}else if(action === "cancel"){
plugin.eaemColorPickerDialog = null;
}

dialog.hide();

removeReceiveDataListener(receiveMessage);
}
},

//to mark the icon selected/deselected
updateState: function(selDef) {
var hasUC = this.editorKernel.queryState(COLOR_PICKER_FEATURE, selDef);

if (this.pickerUI != null) {
this.pickerUI.setSelected(hasUC);
}
}
});

CUI.rte.plugins.PluginRegistry.register(GROUP,TouchUIColorPickerPlugin);

var TouchUIColorPickerCmd = new Class({
toString: "TouchUIColorPickerCmd",

extend: CUI.rte.commands.Command,

isCommand: function(cmdStr) {
return (cmdStr.toLowerCase() == COLOR_PICKER_FEATURE);
},

getProcessingOptions: function() {
var cmd = CUI.rte.commands.Command;
return cmd.PO_SELECTION | cmd.PO_BOOKMARK | cmd.PO_NODELIST;
},

_getTagObject: function(color) {
return {
"tag": "span",
"attributes": {
"style" : "color: " + color
}
};
},

execute: function (execDef) {
var color = execDef.value ? execDef.value[PICKER_NAME_IN_POPOVER] : undefined,
selection = execDef.selection,
nodeList = execDef.nodeList;

if (!selection || !nodeList) {
return;
}

var common = CUI.rte.Common,
context = execDef.editContext,
tagObj = this._getTagObject(color);

//if no color value passed, assume delete and remove color
if(_.isEmpty(color)){
nodeList.removeNodesByTag(execDef.editContext, tagObj.tag, undefined, true);
return;
}

var tags = common.getTagInPath(context, selection.startNode, tagObj.tag);

//remove existing color before adding new color
if (tags != null) {
nodeList.removeNodesByTag(execDef.editContext, tagObj.tag, undefined, true);
}

nodeList.surround(execDef.editContext, tagObj.tag, tagObj.attributes);
}
});

CUI.rte.commands.CommandRegistry.register(COLOR_PICKER_FEATURE, TouchUIColorPickerCmd);

function addPluginToDefaultUISettings(){
var toolbar = CUI.rte.ui.cui.DEFAULT_UI_SETTINGS.inline.toolbar;
toolbar.splice(3, 0, GROUP + "#" + COLOR_PICKER_FEATURE);

toolbar = CUI.rte.ui.cui.DEFAULT_UI_SETTINGS.fullscreen.toolbar;
toolbar.splice(3, 0, GROUP + "#" + COLOR_PICKER_FEATURE);
}

function addDialogTemplate(){
var url = PICKER_URL + "?" + REQUESTER + "=" + GROUP;

var html = "<iframe width='600px' height='500px' frameBorder='0' src='" + url + "'></iframe>";

if(_.isUndefined(CUI.rte.Templates)){
CUI.rte.Templates = {};
}

if(_.isUndefined(CUI.rte.templates)){
CUI.rte.templates = {};
}

CUI.rte.templates['dlg-' + TCP_DIALOG] = CUI.rte.Templates['dlg-' + TCP_DIALOG] = Handlebars.compile(html);
}
}(jQuery, window.CUI,jQuery(document)));

(function($, $document){
var SENDER = "experience-aem",
REQUESTER = "requester",
COLOR = "color",
ADD_COLOR_BUT = "#EAEM_CP_ADD_COLOR",
REMOVE_COLOR_BUT = "#EAEM_CP_REMOVE_COLOR";

if(queryParameters()[REQUESTER] !== SENDER ){
return;
}

$(function(){
_.defer(stylePopoverIframe);
});

function queryParameters() {
var result = {}, param,
params = document.location.search.split(/\?|\&/);

params.forEach( function(it) {
if (_.isEmpty(it)) {
return;
}

param = it.split("=");
result[param[0]] = param[1];
});

return result;
}

function stylePopoverIframe(){
var queryParams = queryParameters(),
$dialog = $("coral-dialog");

if(_.isEmpty($dialog)){
return;
}

$dialog.css("overflow", "hidden").css("background-color", "#fff");

$dialog[0].open = true;

var $addColor = $dialog.find(ADD_COLOR_BUT),
$removeColor = $dialog.find(REMOVE_COLOR_BUT),
color = queryParameters()[COLOR],
$colorPicker = $document.find("coral-colorinput");

if(!_.isEmpty(color)){
color = decodeURIComponent(color);

if(color.indexOf("rgb") == 0){
color = CUI.util.color.RGBAToHex(color);
}

$colorPicker[0].value = color;
}

adjustHeader($dialog);

$colorPicker.css("margin-bottom", "285px");

$(ADD_COLOR_BUT).css("margin-left", "220px");

$addColor.click(sendDataMessage);

$removeColor.click(sendRemoveMessage);
}

function adjustHeader($dialog){
var $header = $dialog.css("background-color", "#fff").find(".coral3-Dialog-header");

$header.find(".cq-dialog-submit").remove();

$header.find(".cq-dialog-cancel").click(function(event){
event.preventDefault();

$dialog.remove();

sendCancelMessage();
});
}

function sendCancelMessage(){
var message = {
sender: SENDER,
action: "cancel"
};

parent.postMessage(JSON.stringify(message), "*");
}

function sendRemoveMessage(){
var message = {
sender: SENDER,
action: "remove"
};

parent.postMessage(JSON.stringify(message), "*");
}

function sendDataMessage(){
var message = {
sender: SENDER,
action: "submit",
data: {}
}, $dialog, color;

$dialog = $(".cq-dialog");

color = $dialog.find("[name='./" + COLOR + "']").val();

if(color && color.indexOf("rgb") >= 0){
color = CUI.util.color.RGBAToHex(color);
}

message.data[COLOR] = color;

parent.postMessage(JSON.stringify(message), "*");
}
})(jQuery, jQuery(document));



AEM 64 - Extend TouchUI Rich Text Editor Table Plugin, Add Summary Field

$
0
0

Goal


Extend Touch UI Rich Text Editor (RTE) to add a field for Table Summary

Classic UI RTE Table extension for Summary is available here

For a similar extension on 61 check this post

Thank you Roger Blanton for the code for 64

Demo | Package Install | GitHub


Table Properties Dialog with Summary




Table Source with Summary




XSS (AntiSamy) Configuration

                                                              /libs/sling/xss/config.xml (please overlay, modified for demo purposes only)

                                                              <attribute name="summary">
                                                                  <regexp-list>
                                                                      <regexp name="anything"/>
                                                                  </regexp-list>
                                                              </attribute>




Solution



1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-rte-table-summary


2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-rte-table-summary/clientlib and set property categories of String type to cq.authoring.dialog and dependencies String[] to underscore


3) Create file ( type nt:file ) /apps/eaem-touchui-rte-table-summary/clientlib/js.txt, add the following


                         summary.js


4) Create file (type nt:file) /apps/eaem-touchui-rte-table-summary/clientlib/summary.js, add the following code


(function ($) {
"use strict";

var _ = window._,
Class = window.Class,
CUI = window.CUI,
EAEM_TABLE = null,
COLUMN_CONTAINER = ".rte-dialog-columnContainer",
SUMMARY_SEL = ".rte-dialog--tableprops input[data-type=\"summary\"]",
SUMMARY_HTML = '<div class="rte-dialog-columnContainer">'
+ '<div class="rte-dialog-column">'
+ 'Summary'
+ '</div>'
+ '<div class="rte-dialog-column">'
+ '<input is="coral-textfield" class="coral3-Textfield rte--large" data-type="summary">'
+ '</div>'
+ '</div>';

if(CUI.rte.ui.cui.TablePropsDialog.eaemExtended){
return;
}

CUI.rte.ui.cui.TablePropsDialog = new Class({

extend: CUI.rte.ui.cui.TablePropsDialog,

toString: "EAEMTablePropsDialog",

initialize: function(config) {
this.superClass.initialize.call(this, config);

this.$summary = this.$container.find(SUMMARY_SEL);

if(!_.isEmpty(this.$summary)){
return;
}

this.$caption = this.$container.find(".rte-dialog--tableprops input[data-type=\"caption\"]");

$(SUMMARY_HTML).insertBefore( this.$caption.closest(COLUMN_CONTAINER) );

this.$summary = this.$container.find(SUMMARY_SEL);

this.propertyItems.push(this.$summary);
}
});

EAEM_TABLE = new Class({
toString: "EAEMTable",

extend: CUI.rte.commands.Table,

transferConfigToTable: function(dom, execDef) {
this.superClass.transferConfigToTable.call(this, dom, execDef);

var com = CUI.rte.Common,
config = execDef.value;

if (config.summary) {
com.setAttribute(dom, "summary", config.summary);
} else {
com.removeAttribute(dom, "summary");
}
}
});

CUI.rte.commands.CommandRegistry.register("_table", EAEM_TABLE);

CUI.rte.ui.cui.TablePropsDialog.eaemExtended = true;
})(jQuery);

AEM 64 - Touch UI RTE (Rich Text Editor) Disable Image Drag and Drop

$
0
0

Goal


Disable drag and drop of JPEGs from the side panel in authoring Touch UI Rich Text Editor

Demo | Package Install | Github

Thank you Hanish Bansal for the code references...




Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-rte-disable-drag-drop

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-rte-disable-drag-drop/clientlib and set property categories of String type to cq.authoring.dialog and dependencies String[] to underscore

3) Create file ( type nt:file ) /apps/eaem-touchui-rte-disable-drag-drop/clientlib/js.txt, add the following

  disable-drag-drop.js

4) Create file (type nt:file) /apps/eaem-touchui-rte-disable-drag-drop/clientlib/disable-drag-drop.js, add the following code

(function () {
"use strict";

var _ = window._,
CUI = window.CUI;

var otbIsMimeTypeAccepted = CUI.RichText.prototype._isMimeTypeAccepted;

function disableJpegDragAndDropInRTE(mimeType) {
if(_.isEmpty(mimeType) || (mimeType != 'image/jpeg') ){
return otbIsMimeTypeAccepted.apply(this, arguments);
}

showAlert("Uh oh! you are restricted from dropping JPEGs", "RTE");

return false;
}

function showAlert(message, title, callback){
var fui = $(window).adaptTo("foundation-ui"),
options = [{
id: "ok",
text: "OK",
primary: true
}];

message = message || "Unknown Error";
title = title || "Error";

fui.prompt(title, message, "warning", options, callback);
}

CUI.RichText.prototype._isMimeTypeAccepted = disableJpegDragAndDropInRTE;
}());

AEM 64 - Touch UI extend Path Browser picker to show asset thumbnail

$
0
0

Goal


Show asset thumbnails in Pathbrowser picker granite/ui/components/coral/foundation/form/pathbrowser

Demo | Package Install | Github


Product




Extension



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-pathbrowser-picker-show-preview

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-pathbrowser-picker-show-preview/clientlib and set property categories of String type to cq.authoring.dialog.all and dependencies String[] to underscore

3) Create file ( type nt:file ) /apps/eaem-touchui-pathbrowser-picker-show-preview/clientlib/js.txt, add the following

  show-preview.js

4) Create file (type nt:file) /apps/eaem-touchui-pathbrowser-picker-show-preview/clientlib/show-preview.js, add the following code

(function ($, $document, gAuthor) {
if(!gAuthor){
return;
}

$document.on('dialog-ready', handlePathBrowser);

function handlePathBrowser(){
var $cuiPathBrowser = $(".coral-PathBrowser");

if(_.isEmpty($cuiPathBrowser)){
return;
}

//handle picker columns
$cuiPathBrowser.each(extendPicker);
}

function extendPicker(index, cuiPathBrowser){
cuiPathBrowser = $(cuiPathBrowser).data("pathBrowser");

var cuiPicker = cuiPathBrowser.$picker.data("picker");

cuiPathBrowser.$button.on("click", function() {
setTimeout(function(){
if(!cuiPicker.columnView){
console.log("EAEM - could not initialize column view");
return;
}

extendColumnView(cuiPicker.columnView);
}, 200);
});
}

function extendColumnView(columnView){
function handler(event, href, data){
if(_.isEmpty(href) || _.isEmpty(data)){
return;
}

var $item, assetPath, thumbHtml,
columnData = columnView._data[href];

if(_.isEmpty(columnData)){
return;
}

var $columnData = $(columnData), $items = $columnData.find(".coral-ColumnView-item");

$items.each(function(index, item){
$item = $(item);

assetPath = $item.data("value");

if(_.isEmpty(assetPath)){
return;
}

thumbHtml = getThumbHtml(assetPath);

if(!thumbHtml){
return;
}

$item.find(".coral-ColumnView-icon").html(thumbHtml);
});

columnView._data[href] = $columnData[0].outerHTML;
}

columnView.$element.on('coral-columnview-load', handler);
}

function getThumbHtml(assetPath){
var assetExt = getStringAfterLastDot(assetPath);

if(!assetExt){
return "";
}

return '<img class="foundation-collection-item-thumbnail" src="'
+ assetPath + '/_jcr_content/renditions/cq5dam.thumbnail.48.48.png" width="40px" height="40px" style="margin-right:10px"'
+ 'alt="' + getStringAfterLastSlash(assetPath) + '">';
}

function getStringAfterLastSlash(str){
if(!str || (str.indexOf("/") == -1)){
return "";
}

return str.substr(str.lastIndexOf("/") + 1);
}

function getStringAfterLastDot(str){
if(!str || (str.indexOf(".") == -1)){
return "";
}

return str.substr(str.lastIndexOf(".") + 1);
}

}(jQuery, jQuery(document), Granite.author));



AEM 64 - Touch UI Show Checked out user in Content Fragment Rich Text Editor

$
0
0

Goal


Show the checked out user info when a user tries to edit content fragments

Demo | Package Install | Github




Solution


1) Login to CRXDE Lite (http://localhost:4502/crx/de) and create folder /apps/eaem-touchui-cfm-show-checkout

2) Create node /apps/eaem-touchui-cfm-show-checkout/clientlib of type cq:ClientLibraryFolder, add a String property categories with value dam.cfm.authoring.contenteditor.v2 and dependencies with String[] value [lodash]

3) Create file (nt:file) /apps/eaem-touchui-cfm-show-checkout/clientlib/js.txt and add

                       show-checkout.js

4) Create file (nt:file) /apps/eaem-touchui-cfm-show-checkout/clientlib/show-checkout.js and add the following code

(function ($, $document) {
var LOCK_ITEM_CSS = "eaem-cf-lock";

$document.on("foundation-contentloaded", checkForDriveLock);

function checkForDriveLock(){
$.ajax(getCFJCRContentPath()).done(handler);

function handler(data){
$("." + LOCK_ITEM_CSS).remove();

var driveLock = data["cq:drivelock"];

if(_.isEmpty(driveLock)){
return;
}

addCheckOutButton(driveLock);

if(getLoggedInUserID() != driveLock){
showAlert("Locked for editing by " + driveLock + ", changes cannot be saved", "Editor");
}
}
}

function showAlert(message, title, callback){
var fui = $(window).adaptTo("foundation-ui"),
options = [{
id: "ok",
text: "OK",
primary: true
}];

message = message || "Unknown Error";
title = title || "Error";

fui.prompt(title, message, "warning", options, callback);
}

function addCheckOutButton(driveLock){
var message = "Locked by " + ( getLoggedInUserID() == driveLock ? "current user - " : "- ") + driveLock;

var html = '<coral-actionbar-item class="coral3-ActionBar-item ' + LOCK_ITEM_CSS + '">'
+ '<coral-icon style="margin:16px 10px 0 0; " class="coral3-Icon coral3-Icon--sizeS coral3-Icon--lockOn" icon="lockOn" size="S"></coral-icon>'
+ '<span>' + message + '</span>'
+ '</coral-actionbar-item>';

$("coral-actionbar-primary").append(html);
}

function getLoggedInUserID(){
return window.sessionStorage.getItem("granite.shell.badge.user");
}

function getCFJCRContentPath(){
return $(".content-fragment-editor").data("fragment") + "/_jcr_content.json";
}
}(jQuery, jQuery(document)));

AEM 64 - Touch UI Extend Rich Text Editor (RTE) to select Anchor for creating Deep Links

$
0
0

Goal


Extend the Link Dialog of Touch UI Rich Text Editor to add a Coral Select widget for showing named anchor links on selected page to create deep links

Demo | Package Install | Github


Drop down with list of Anchors



Anchors on linked page




Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-extend-rte-select-deep-link


2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-extend-rte-select-deep-link/clientlib and set property categories of String type to cq.authoring.dialog.all and dependencies String[] to lodash


3) Create file ( type nt:file ) /apps/eaem-touchui-extend-rte-select-deep-link/clientlib/js.txt, add the following


                         deep-links.js

4) Create file (type nt:file) /apps/eaem-touchui-extend-rte-select-deep-link/clientlib/deep-links.js, add the following code

(function ($) {
"use strict";

var _ = window._,
Class = window.Class,
CUI = window.CUI,
EAEM_ANCHOR_SELECT = "eaem-anchor-select",
RTE_LINK_DIALOG = "rtelinkdialog";

if(CUI.rte.ui.cui.CuiDialogHelper.eaemExtended){
return;
}

var EAEMLinkBaseDialog = new Class({
extend: CUI.rte.ui.cui.CQLinkBaseDialog,

toString: "EAEMLinkBaseDialog",

initialize: function(config) {
this.superClass.initialize.call(this, config);

var baseDialog = this;

this.$rteDialog = this.$container.find("[data-rte-dialog=link]");

var $path = this.$rteDialog.find(".rte-dialog-columnContainer:first");

$(baseDialog.getAnchorsSelect()).insertAfter($path);

$path.find("foundation-autocomplete").on("foundation-field-change", constructSelect);

function constructSelect() {
var pathField = $(this).adaptTo('foundation-field');

$.get(pathField.getValue() + ".html?wcmmode=disabled").done(successFn);

function successFn(respHtml){
var $aTags = $(respHtml).find("a"), options = [];

$aTags.each(function( i, aTag ) {
if(_.isEmpty(aTag.name)){
return;
}

options.push(aTag.name);
});

$(baseDialog.getAnchorsSelect(options)).insertAfter($path);
}
}
},

getAnchorsSelect: function(options, dValue){
$("#" + EAEM_ANCHOR_SELECT).remove();

var html = '<div class="rte-dialog-columnContainer" id="' + EAEM_ANCHOR_SELECT + '">' +
'<div class="rte-dialog-column">' +
'<coral-select class="coral-Form-field" placeholder="Select Link">';

_.each(options, function(option){
html = html + '<coral-select-item value="' + option + '"'
+ ( (dValue == option) ? " selected " : "" ) + '>' + option + '</coral-select-item>';
});

html = html + '</coral-select></div></div>';

return html;
},

dlgFromModel: function() {
if (_.isEmpty(this.objToEdit) || _.isEmpty(this.objToEdit.href)
|| (this.objToEdit.href.indexOf("#") == -1)) {
this.superClass.dlgFromModel.call(this);
return;
}

var href = this.objToEdit.href, anchor,
$path = this.$rteDialog.find(".rte-dialog-columnContainer:first");

this.objToEdit.href = href.substring(0, href.lastIndexOf("#"));

this.superClass.dlgFromModel.call(this);

anchor = href.substring(href.lastIndexOf("#") + 1);

$.get(href + ".html?wcmmode=disabled").done($.proxy(successFn, this));

function successFn(respHtml){
var $aTags = $(respHtml).find("a"), options = [];

$aTags.each(function( i, aTag ) {
if(_.isEmpty(aTag.name)){
return;
}

options.push(aTag.name);
});

$(this.getAnchorsSelect(options, anchor)).insertAfter($path);
}
},

dlgToModel: function() {
this.superClass.dlgToModel.call(this);

var anchorSelect = this.$dialog.find("#" + EAEM_ANCHOR_SELECT + ">* coral-select");

if(_.isEmpty(anchorSelect)){
return;
}

var aVal = anchorSelect.val();

if (_.isEmpty(aVal)) {
return;
}

this.objToEdit.href = this.objToEdit.href + "#" + aVal;
}
});

CUI.rte.ui.cui.CuiDialogHelper = new Class({
extend: CUI.rte.ui.cui.CuiDialogHelper,

toString: "EAEMCuiDialogHelper",

instantiateDialog: function(dialogConfig) {
var type = dialogConfig.type;

if(type !== RTE_LINK_DIALOG){
this.superClass.instantiateDialog.call(this, dialogConfig);
return;
}

var $editable = $(this.editorKernel.getEditContext().root),
$container = CUI.rte.UIUtils.getUIContainer($editable),
dialog = new EAEMLinkBaseDialog();

dialog.attach(dialogConfig, $container, this.editorKernel);

return dialog;
}
});

CUI.rte.ui.cui.CuiDialogHelper.eaemExtended = true;
})(jQuery);

AEM 64 - Touch UI show Project specific Workflow Models in Assets Toolbar Create action

$
0
0

Goal


Show project specific workflow models in the dialog activated by Create -> Workflow action of Assets toolbar. Tee full list of workflows (Product and Project) are still available from Timeline -> Start workflow dropdown

Demo | Package Install | Github


Assets Toolbar Start Workflow



Timeline Start Workflow (Product)



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-show-custom-wfs-in-start-wf

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-show-custom-wfs-in-start-wf/clientlib and set property categories of String type to dam.gui.actions.coral and dependencies String[] to lodash

3) Create file ( type nt:file ) /apps/eaem-touchui-show-custom-wfs-in-start-wf/clientlib/js.txt, add the following

show-custom-wfs.js

4) Create file (type nt:file) /apps/eaem-touchui-show-custom-wfs-in-start-wf/clientlib/show-custom-wfs.js, add the following code. #3 with prefix value set to EAEM, the dropdown shows all models having name starting with EAEM

(function ($, $document) {
var WORKFLOW_DIALOG_CLASS = "cq-common-admin-timeline-toolbar-actions-workflow",
SHOW_MODELS_WITH_PREFIX = "EAEM";

$document.on('foundation-contentloaded', handleWorkflowList);

function handleWorkflowList(event){
var $target = $(event.target);

if(!$target.hasClass(WORKFLOW_DIALOG_CLASS)){
return;
}

var $wfSelect = $target.find("coral-select");

if(_.isEmpty($wfSelect)){
return;
}

_.each($wfSelect[0].items.getAll(), function(item){
if(canShow(item.innerText)){
return;
}

item.remove();
})
}

function canShow(text){
if(_.isEmpty(text)){
return true;
}

return (text.trim().indexOf(SHOW_MODELS_WITH_PREFIX) == 0);
}
}(jQuery, jQuery(document), Granite.author));



AEM 64 - Touch UI Show selected Content Fragment Model (Template) name in New Wizard

$
0
0

Goal


Show the selected content fragment model (template) name in the second step of create new content fragment wizard instead of default New Content Fragment

Demo | Package Install | Github




Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-show-cf-template-name-in-wizard

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-show-cf-template-name-in-wizard/clientlib and set property categories of String type to dam.cfm.adminpage.wizard and dependencies String[] to lodash

3) Create file ( type nt:file ) /apps/eaem-touchui-show-cf-template-name-in-wizard/clientlib/js.txt, add the following

  show-template-name.js

4) Create file (type nt:file) /apps/eaem-touchui-show-cf-template-name-in-wizard/clientlib/show-template-name.js, add the following code

(function ($, $document) {
var NEW_CF_URL = "/mnt/overlay/dam/cfm/admin/content/v2/createfragment.html",
WIZARD_HEADER = '.foundation-layout-wizard2-title',
DEFAULT_HEADER = "New Content Fragment",
FOUNDATION_WIZARD_STEP_CHANGE = "foundation-wizard-stepchange";

if(!isNewCFPage()){
return;
}

$document.on(FOUNDATION_WIZARD_STEP_CHANGE, changeWizardTitle);

function changeWizardTitle(event, prev, current){
var stepNumber = getWizardStepNumber();

if(stepNumber == 1){
$(".foundation-wizard").find(WIZARD_HEADER).html(DEFAULT_HEADER);
return;
}

var $selected = $("coral-masonry-item.is-selected"),
title = DEFAULT_HEADER + " of type '" + $selected.find("coral-card-title").html() + "'";

$(".foundation-wizard").find(WIZARD_HEADER).html(title);
}

function getWizardStepNumber(){
var $wizard = $(".foundation-wizard"),
currentStep = $wizard.find(".foundation-wizard-step-active"),
wizardApi = $wizard.adaptTo("foundation-wizard");

return wizardApi.getPrevSteps(currentStep).length + 1;
}

function isNewCFPage() {
return (window.location.pathname.indexOf(NEW_CF_URL) === 0);
}

}(jQuery, jQuery(document)));

AEM 64 - Touch UI Disable Step Back for specific Workflow Models in Inbox and Page Editor

$
0
0

Goal


Disable the Step Back action in Inbox and on Editor Status Bar for configured workflow models. In this post the Step Back action is disabled for Request for Activation /var/workflow/models/request_for_activation, workflow items

Step Back action can be disabled by just overriding the function CQ.Inbox.UI.commons.stepBackWorkitem, additional code explores the Editor Status Bar api on page authoring

Demo | Package Install | Github


Inbox



Inbox Workitem Detail



Editor



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-disable-wf-step-back

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-disable-wf-step-back/clientlib and set property categories of String[] type to [cq.inbox.gui.commons, cq.authoring.dialog.all] and dependencies String[] to lodash

3) Create file ( type nt:file ) /apps/eaem-touchui-disable-wf-step-back/clientlib/js.txt, add the following

  disable-step-back.js

4) Create file (type nt:file) /apps/eaem-touchui-disable-wf-step-back/clientlib/disable-step-back.js, add the following code

(function ($, $document, gAuthor) {
"use strict";

var _ = window._,
EDITOR_URL = "/editor.html",
REQ_FOR_ACT_MODEL = "/var/workflow/models/request_for_activation",
DISABLE_MESSAGE = "Step back not allowed for 'Request for Activation' workflow",
WF_ACTION_STEP_BACK = "workflow-stepback",
WF_STATUS_TYPE = "workflow";

if(isAuthoring()){
$document.one("cq-editor-statusbar-loaded", disableStepBackOnPage);
}else{
$document.one('foundation-contentloaded', disableStepBackOnInBox);
}

function disableStepBackOnInBox(){
overrideStepBack();
}

function disableStepBackOnPage(){
if(!gAuthor){
return;
}

var wfStatus = getWFStatus();

if(!wfStatus){
return;
}

var stepBackId = wfStatus.actionIds.findIndex(function(ele){
return (ele == WF_ACTION_STEP_BACK);
});

if(stepBackId < 0){
return;
}

var $status = $(gAuthor.ui.statusBarManager.getStatusBar().status),
$stepBack = $status.find("[data-status-action-id='" + WF_ACTION_STEP_BACK + "']");

$stepBack.css("color", "#777777");

overrideStepBack();
}

function overrideStepBack(){
var origFn = window.CQ.Inbox.UI.commons.stepBackWorkitem;

window.CQ.Inbox.UI.commons.stepBackWorkitem = eaemStepBackWorkitem;

function eaemStepBackWorkitem(workitemId, successURL){
$.ajax(getWorkflowId(workitemId) + ".json").done(function(data){
if(data.model != REQ_FOR_ACT_MODEL){
return origFn(workitemId, successURL);
}

showAlert(DISABLE_MESSAGE, "Disabled");
});
}
}

function showAlert(message, title, callback){
var fui = $(window).adaptTo("foundation-ui"),
options = [{
id: "ok",
text: "OK",
primary: true
}];

message = message || "Unknown Error";
title = title || "Error";

fui.prompt(title, message, "warning", options, callback);
}

function getWFStatus(){
var statusBar = gAuthor.ui.statusBarManager.getStatusBar(),
wfStatus;

_.each(statusBar.statuses, function(status){
if(status.statusType == WF_STATUS_TYPE){
wfStatus = status;
}
});

return wfStatus;
}

function getWorkflowId(workitemId){
return workitemId.substring(0, workitemId.indexOf("/workItems"));
}

function isAuthoring() {
return (window.location.pathname.indexOf(EDITOR_URL) === 0);
}
}(jQuery, jQuery(document), Granite.author));

AEM 6410 - Touch UI set Orderable checked by default on New Folder Create Dialog

$
0
0

Goal


Set the Orderable checked on new Folder Create dialog, so any new folders have default type  sling:OrderedFolder

Demo | Package Install | Github



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-assets-folder-create-default-orderable

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-assets-folder-create-default-orderable/clientlib and set property categories of String[] type to dam.gui.coral.fileupload and dependencies String[] to underscore

3) Create file ( type nt:file ) /apps/eaem-touchui-assets-folder-create-default-orderable/clientlib/js.txt, add the following

  default-orderable.js

4) Create file (type nt:file) /apps/eaem-touchui-assets-folder-create-default-orderable/clientlib/default-orderable.js, add the following code

(function ($, $document) {
var DAM_CREATE_FOLDER = "#dam-create-folder",
CREATE_FOLDER_DIALOG = "#createfolder",
ORDERABLE_SEL = "coral-checkbox:last";

$document.on("foundation-contentloaded", onUILoad);

function onUILoad() {
Coral.commons.ready($(DAM_CREATE_FOLDER), function () {
$(DAM_CREATE_FOLDER).click(makeOrderableDefault);
});
}

function makeOrderableDefault(event) {
var $orderable = $(CREATE_FOLDER_DIALOG).find(ORDERABLE_SEL);

if (_.isEmpty($orderable)) {
return;
}

$orderable[0].checked = false;

$orderable.click();
}
})(jQuery, jQuery(document));


AEM 6410 - Touch UI Add View in Publish to Editor Page Info Dropdown

$
0
0

Goal


In the authoring env editor.html, add the View in Publish button to Page Information drop down to open the publish page in new tab or copy the url to clipboard

Demo | Package Install | Github



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-extend-page-info-view-in-publish

2) Create View in Publish button UI node /apps/eaem-touchui-extend-page-info-view-in-publish/ui/view-in-publish add the following code

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
granite:class="eaem-page-info-view-in-publish"
granite:title="View in Publish"
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/button"
text="View in Publish"/>


3) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-extend-page-info-view-in-publish/clientlib and set property categories of String[] type to cq.authoring.dialog.all and dependencies String[] to lodash

4) Create file ( type nt:file ) /apps/eaem-touchui-extend-page-info-view-in-publish/clientlib/js.txt, add the following

  view-in-publish.js

5) Create file (type nt:file) /apps/eaem-touchui-extend-page-info-view-in-publish/clientlib/view-in-publish.js, add the following code

(function ($, $document) {
"use strict";

var EDITOR_LOADED_EVENT = "cq-editor-loaded",
PAGE_INFO_TRIGGER = "#pageinfo-trigger",
VIEW_AS_PUBLISHED_SEL = ".pageinfo-viewaspublished",
EAEM_COPY_ID = "eaem-copy-message",
VIEW_IN_PUBLISH_BUT_URL = "/apps/eaem-touchui-extend-page-info-view-in-publish/ui/view-in-publish.html",
publishServer = null;

$document.on(EDITOR_LOADED_EVENT, addViewInPublish);

function addViewInPublish(){
$(PAGE_INFO_TRIGGER).on('click', addButtonUI);
}

function addButtonUI(){
getPublishServer();

$.ajax(VIEW_IN_PUBLISH_BUT_URL).done(function(html){
$(html).insertAfter($(VIEW_AS_PUBLISHED_SEL)).click(openPublishPage);
});
}

function openPublishPage(){
if(_.isEmpty(publishServer)){
return;
}

var publishPath = publishServer + Granite.author.ContentFrame.currentLocation(),
message = "<div id='" + EAEM_COPY_ID + "'>" + publishPath + "</div>";

showAlert(message, "Open", function(clicked){
if(clicked == "open"){
window.open(publishPath);
return;
}

var range = document.createRange();

range.selectNode(document.getElementById(EAEM_COPY_ID));

window.getSelection().addRange(range);

document.execCommand("copy");
});
}

function getPublishServer(){
$.ajax("/etc/replication/agents.author.2.json").done(successFn);

function successFn(data){
var transportUri = data["publish"]["jcr:content"]["transportUri"];

publishServer = transportUri.substring(0, transportUri.indexOf("/bin/receive"));
}
}

function showAlert(message, title, callback){
var fui = $(window).adaptTo("foundation-ui"),
options = [{
id: "copy",
text: "Copy to Clipboard"
},
{
id: "open",
text: "Open",
primary: true
}];

message = message || "Unknown Error";
title = title || "Error";

fui.prompt(title, message, "info", options, callback);
}
})(jQuery, jQuery(document));

AEM 6410 - Touch UI Add Navigation in Asset Annotate Page

$
0
0

Goal


Asset Navigation is available only in Asset Details page otb. Here we add the same navigation in Annotate page (with keyboard arrow keys support)

Demo | Package Install | Github


Product



Extension



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-asset-navigator-in-annotate

2) Create UI node /apps/eaem-touchui-asset-navigator-in-annotate/ui/asset-navigator add the following code, for fetching navigator html

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
sling:resourceType="/libs/dam/gui/coral/components/admin/assetdetails/assetnavigator"/>


3) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-asset-navigator-in-annotate/clientlib and set property categories of String[] type to dam.gui.annotation.coral and dependencies String[] to [lodash,dam.gui.coral.assetdetails.assetnavigator]

4) Create file ( type nt:file ) /apps/eaem-touchui-asset-navigator-in-annotate/clientlib/js.txt, add the following

  asset-navigator.js

5) Create file (type nt:file) /apps/eaem-touchui-asset-navigator-in-annotate/clientlib/asset-navigator.js, add the following code

(function ($, $document) {
"use strict";

var _ = window._,
eaemNavigatorAdded = false,
TITLE_BAR = ".granite-title",
ANNOTATE_PAGE_URL = "/mnt/overlay/dam/gui/content/assets/annotate.html",
ASSET_DETAILS_PAGE_URL = "/assetdetails.html",
FOUNDATION_CONTENT_REL = ".foundation-content-path",
NAVIGATION_EVENT = "asset-detail-navigation",
NAVIGATOR_UI = "/apps/eaem-touchui-asset-navigator-in-annotate/ui/asset-navigator.html";

$document.on("foundation-contentloaded", addAssetNavigation);

function addAssetNavigation(){
if(!isAnnotatePage() || !!eaemNavigatorAdded){
return;
}

eaemNavigatorAdded = true;

$.ajax(NAVIGATOR_UI + getAssetPath()).done(addNavigationUI);
}

function addNavigationUI(html){
var $titleBar = $(TITLE_BAR);

html = html.substring(html.indexOf("<div"));

html = "<div class='assetdetails-title-container'>" + $titleBar.html() + html + "</div>";

$titleBar.html(html);

$document.trigger("foundation-contentloaded");

$(FOUNDATION_CONTENT_REL).off(NAVIGATION_EVENT).on(NAVIGATION_EVENT, navigateTo);

$document.on('keydown', handleHotKeyNavigation);
}

function handleHotKeyNavigation(event){
var $mainImage = $("#asset-mainimage");

if (event.keyCode == 37){
navigateTo( { asset : getPathInAssetDetailsPage($mainImage.attr("prev"))} )
}else if(event.keyCode == 39){
navigateTo( { asset : getPathInAssetDetailsPage($mainImage.attr("next"))} )
}
}

function getPathInAssetDetailsPage(path){
if(_.isEmpty(path)){
return;
}

return path.substring(path.indexOf(ASSET_DETAILS_PAGE_URL) + ASSET_DETAILS_PAGE_URL.length);
}

function navigateTo(data){
if (_.isEmpty(data.asset)) {
return;
}

window.location.href = Granite.HTTP.externalize(ANNOTATE_PAGE_URL + data.asset);
}

function isAnnotatePage() {
return (window.location.pathname.indexOf(ANNOTATE_PAGE_URL) >= 0);
}

function getAssetPath() {
var path = window.location.pathname;

return (path.substring(path.indexOf(ANNOTATE_PAGE_URL) + ANNOTATE_PAGE_URL.length));
}
})(jQuery, jQuery(document));

AEM 6410 - Touch UI Auto Select Template in Create Page Wizard

$
0
0

Goal


In the Touch UI Create Page Wizard if there is only one template available, auto select it and move to next step. Additionally the extension shows selected template title in second step

Video shows /content/we-retail/jcr:content@cq:allowedTemplates set to single template /conf/we-retail/settings/wcm/templates/hero-page for demonstration

Demo | Package Install | Github




Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-create-page-auto-select-template

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-create-page-auto-select-template/clientlib and set property categories of String[] type to cq.sites.validations and dependencies String[] to lodash

3) Create file ( type nt:file ) /apps/eaem-touchui-create-page-auto-select-template/clientlib/js.txt, add the following

  select-template.js

4) Create file (type nt:file) /apps/eaem-touchui-create-page-auto-select-template/clientlib/select-template.js, add the following code

(function ($, $document) {
var CREATE_PAGE_WIZARD_URL = "/mnt/overlay/wcm/core/content/sites/createpagewizard.html",
DEFAULT_HEADER = "Create Page",
WIZARD_HEADER = '.foundation-layout-wizard2-title';

if(!isCreatePageWizard()){
return;
}

$document.on("foundation-contentloaded", autoSelectTemplate);

function autoSelectTemplate(){
var stepNumber = getWizardStepNumber();

if(stepNumber == 1){
selectTheOneTemplate();
}else if(stepNumber == 2){
setSelectedTemplateInTitle();
}
}

function selectTheOneTemplate(){
var $cards = $("coral-masonry-item");

if($cards.length != 1){
return;
}

selectTemplate($cards[0]);

var wizardApi = $(".foundation-wizard").adaptTo("foundation-wizard");

wizardApi.next();
}

function setSelectedTemplateInTitle(){
var $selected = $("coral-masonry-item.is-selected"),
title = DEFAULT_HEADER + " of type '" + $selected.find("coral-card-title").html() + "'";

$(".foundation-wizard").find(WIZARD_HEADER).html(title);
}

function getWizardStepNumber(){
var $wizard = $(".foundation-wizard"),
currentStep = $wizard.find(".foundation-wizard-step-active"),
wizardApi = $wizard.adaptTo("foundation-wizard");

return wizardApi.getPrevSteps(currentStep).length + 1;
}

function selectTemplate(template){
var $collection = $("coral-masonry");

var selectApi = $collection.adaptTo("foundation-selections");

selectApi.select(template)
}

function isCreatePageWizard() {
return (window.location.pathname.indexOf(CREATE_PAGE_WIZARD_URL) >= 0);
}
}(jQuery, jQuery(document)));

AEM 6410 - Touch UI show Public / Private Label for Collections

$
0
0

Goal


Show Public or Private labels for Collections in Card View

Demo | Package Install | Github


Product



Extension



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-show-public-private-label

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-show-public-private-label/clientlib and set property categories of String[] type to cq.gui.damadmin.collection.coral and dependencies String[] to lodash

3) Create file ( type nt:file ) /apps/eaem-touchui-show-public-private-label/clientlib/js.txt, add the following

  public-private-label.js

4) Create file (type nt:file) /apps/eaem-touchui-show-public-private-label/clientlib/public-private-label.js, add the following code

(function ($, $document) {
"use strict";

var PUBLIC_COLLECTION_ROOT = "/content/dam/collections/public",
PRIVATE_COLLECITON = "Private Collection",
PUBLIC_COLLECITON = "Public Collection";

$document.on("foundation-contentloaded", function(event){
_.defer(function(){
showLabel();
});
});

function showLabel(){
var $items = $("coral-masonry-item"), $item, itemId, text;

$items.each(function(){
$item = $(this);

itemId = $item.data("graniteCollectionItemId");

if(itemId.indexOf(PUBLIC_COLLECTION_ROOT) == 0){
text = PUBLIC_COLLECITON;
}else{
text = PRIVATE_COLLECITON;
}

$item.find("coral-card-context").html(text);
});
}
})(jQuery, jQuery(document));


AEM 6410 - Touch UI Persistent Lightbox for Assets Drag Drop

$
0
0

Goal


Create a persistent lightbox for users to drag assets into it as they traverse folders and make it a named collection

obviously, this is prank on my colleague, but i plan to code it sometime 

Product



Extension






AEM 6420 - Touch UI Add Delete in Assets Review Task

$
0
0

Goal


Add Delete the selected assets functionality in Assets Create Review Task

Demo | Package Install | Github




Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-delete-in-review-task

2) Create Delete button UI node /apps/eaem-touchui-delete-in-review-task/ui/delete-button add the following code

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
granite:rel="eaem-project-admin-actions-delete-asset"
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/collection/action"
icon="delete"
text="Delete"
title="Delete"
variant="actionBar"/>


3) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-delete-in-review-task/clientlib and set property categories of String[] type to cq.inbox.itemdetails and dependencies String[] to lodash

4) Create file ( type nt:file ) /apps/eaem-touchui-delete-in-review-task/clientlib/js.txt, add the following

  review-task-delete.js

5) Create file (type nt:file) /apps/eaem-touchui-delete-in-review-task/clientlib/review-task-delete.js, add the following code

(function ($, $document) {
"use strict";

var REVIEW_TASK_PAYLOAD_PAGE = "/mnt/overlay/cq/core/content/projects/showtasks/reviewtd/payload.html",
DELETE_BUTTON = "/apps/eaem-touchui-delete-in-review-task/ui/delete-button.html",
COMMAND_URL = Granite.HTTP.externalize("/bin/wcmcommand"),
TD_ACTION_BAR = ".review-taskdetail-action-bar",
$deleteButton = null;

if(!isReviewTaskPayloadPage()){
return;
}

$document.on("foundation-selections-change", addDelete);

function addDelete(event){
var $collection = $(event.target),
selectApi = $collection.adaptTo("foundation-selections");

if(!_.isEmpty($deleteButton)){
( (selectApi.count() == 0) ? $deleteButton.hide() : $deleteButton.show());
return;
}

$.ajax(DELETE_BUTTON).done(function(html){
var $titleBar = $(TD_ACTION_BAR).find("betty-titlebar-primary");

$deleteButton = $(html).appendTo($titleBar).click(deleteAction);

$deleteButton.hide();
});
}

function deleteAction(){
var $collection = $(".foundation-collection"),
$items = $collection.find(".foundation-selections-item"),
paths = [];

$items.each(function(index, item) {
paths.push($(item).data("foundation-collection-item-id"));
});

if(_.isEmpty(paths)){
return;
}

var data = {
_charset_: "UTF-8",
cmd: "deletePage",
path: paths,
force: true
};

$.post(COMMAND_URL, data).done(function(){
$(".foundation-content").adaptTo("foundation-content").refresh();

showAlert("Selected assets deleted", "Delete");

$deleteButton = null;
});
}

function showAlert(message, title, callback){
var fui = $(window).adaptTo("foundation-ui"),
options = [{
id: "ok",
text: "OK",
primary: true
}];

message = message || "Unknown Error";
title = title || "Error";

fui.prompt(title, message, "warning", options, callback);
}

function isReviewTaskPayloadPage() {
return (window.location.pathname.indexOf(REVIEW_TASK_PAYLOAD_PAGE) >= 0);
}
})(jQuery, jQuery(document));

AEM 6420 - Touch UI Add Zoom in Assets Annotate page

$
0
0

Goal


In the Assets Annotate page add Zoom In / Zoom Out (available in Assets Detail page). User can zoom in, pan, reset to original for adding annotations

Demo | Package Install | Github


Product



Extension



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-asset-zoom-in-annotate

2) Add content resource /apps/eaem-touchui-asset-zoom-in-annotate/ui/asset-zoom with the following code

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
sling:resourceType="/apps/eaem-touchui-asset-zoom-in-annotate/ui/zoom-viewer"/>

3) Extend otb zoom viewer adding below code in /apps/eaem-touchui-asset-zoom-in-annotate/ui/zoom-viewer/zoom-viewer.jsp

<%@page session="false"%>

<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
<%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %>

<cq:defineObjects />

<%@include file="/libs/dam/gui/coral/components/admin/contentrenderer/base/base.jsp"%>

<%
Resource currentResource = UIHelper.getCurrentSuffixResource(slingRequest);
Asset asset = currentResource.adaptTo(Asset.class);
%>

<sling:include path="<%= asset.getPath() %>" resourceType="dam/gui/components/admin/assetview/zoomviewer" />

4) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-asset-zoom-in-annotate/clientlib and set property categories of String[] type to dam.gui.annotation.coral and dependencies String[] to [lodash, dam.gui.assetview.zoom]

5) Create file ( type nt:file ) /apps/eaem-touchui-asset-zoom-in-annotate/clientlib/js.txt, add the following

  asset-zoom.js

6) Create file (type nt:file) /apps/eaem-touchui-asset-zoom-in-annotate/clientlib/asset-zoom.js, add the following code

(function ($, $document) {
"use strict";

var _ = window._,
eaemZoomAdded = false,
ZOOM_CANVAS_ID = "dam-aasetdetail-zoom-canvas",
ANNOTATION_CONTAINER = "asset-annotation",
ASSET_DETAIL_CONTAINER = "asset-detail",
ASSET_MAIN_IMAGE_ID = "asset-mainimage",
ANNOTATION_CANVAS = ".asset-annotation canvas",
ANNOTATE_PAGE_URL = "/mnt/overlay/dam/gui/content/assets/annotate.html",
ZOOM_UI = "/apps/eaem-touchui-asset-zoom-in-annotate/ui/asset-zoom.html";

function overrideAnnotate(){
var origFn = $.Annotation.prototype._endDraw;

$.Annotation.prototype._endDraw = function(e) {
origFn.call(this, e);

$("#" + ASSET_MAIN_IMAGE_ID).trigger("annotateEnd", [ e.data.self ]);
};
}

function isAnnotatePage() {
return (window.location.pathname.indexOf(ANNOTATE_PAGE_URL) >= 0);
}

function getAssetPath() {
var path = window.location.pathname;

return (path.substring(path.indexOf(ANNOTATE_PAGE_URL) + ANNOTATE_PAGE_URL.length));
}

function showZoomCanvas(){
$("#" + ZOOM_CANVAS_ID).show();
}

function showMainImage(){
$("#" + ASSET_MAIN_IMAGE_ID).css("display", "inline");

$("#" + ZOOM_CANVAS_ID).hide();

$("." + ANNOTATION_CONTAINER).find("canvas").not("#" + ZOOM_CANVAS_ID).show();
}

function reAddImageToCanvas(){
var $mainImage = $("#" + ASSET_MAIN_IMAGE_ID),
imageHtml = $mainImage[0].outerHTML;

$mainImage.css("display", "none");

$("." + ANNOTATION_CONTAINER).find("canvas").not("#" + ZOOM_CANVAS_ID).hide();

$("#" + ZOOM_CANVAS_ID).show();

$document.off(ANNOTATION_CANVAS);

if(!_.isEmpty($(ZOOM_CANVAS_ID))){
return;
}

$document.bind('DOMNodeInserted', function(e) {
var element = e.target;

if(element.id !== ZOOM_CANVAS_ID){
return;
}

$(imageHtml).insertAfter($(element)).css("display", "none");
});
}

function addZoomUI(html){
html = html.substring(html.indexOf("<div"));

var $zoomContainer = $(html).appendTo($("betty-titlebar-primary"));

$zoomContainer.find("coral-actionbar").css("background-color", "#f0f0f0")
.width("200px").css("height" , "2.5rem").css("padding", "0");

$("." + ANNOTATION_CONTAINER).addClass(ASSET_DETAIL_CONTAINER);

$document.on("click", ".dam-asset-zoomIn", reAddImageToCanvas);

$(document).on("click", ".dam-asset-zoomOut", showZoomCanvas);

$document.on("click", ".dam-asset-reset", showMainImage);
}

function addAssetZoom(){
if(!isAnnotatePage() || !!eaemZoomAdded){
return;
}

eaemZoomAdded = true;

$.ajax(ZOOM_UI + getAssetPath()).done(addZoomUI);
}

overrideAnnotate();

$document.on("foundation-contentloaded", addAssetZoom);
}(jQuery, jQuery(document)));



AEM 6420 - Assets Content Fragments Coral 3 Composite Multifield

$
0
0

Goal


Create a Coral 3 Composite Multifield for Content Fragments

The fragment created by this extension stores multifield data in JSON format

Package Install has a sample content fragment model Experience AEM Composite CF Model - /conf/we-retail/settings/dam/cfm/models/experience-aem-composite-cf-model

Demo | Package Install | Github


Master



Sample Variation "Mobile"



Sling Model



Solution


1) Create the Content Fragment Model, drag a Single line text widget, set the Render As to multifield to create a regular multifield



2) In CRXDe Lite, navigate to the created content fragment model and set property composite=true

eg. /conf/we-retail/settings/dam/cfm/models/experience-aem-composite-cf-model/jcr:content/model/cq:dialog/content/items/1539961047566



3) Remove or adjust the field node added by product and create a composite multifield node structure



<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="cq:Template"
allowedPaths="[/content/entities(/.*)?]"
ranking="{Long}100">
<jcr:content
cq:lastModified="{Date}2018-10-19T09:57:39.788-05:00"
cq:lastModifiedBy="admin"
cq:scaffolding="/conf/we-retail/settings/dam/cfm/models/experience-aem-composite-cf-model/jcr:content/model"
cq:templateType="/libs/settings/dam/cfm/model-types/fragment"
jcr:primaryType="cq:PageContent"
jcr:title="Experience AEM Composite CF Model"
sling:resourceSuperType="dam/cfm/models/console/components/data/entity"
sling:resourceType="dam/cfm/models/console/components/data/entity/default">
<model
cq:targetPath="/content/entities"
jcr:primaryType="cq:PageContent"
sling:resourceType="wcm/scaffolding/components/scaffolding"
dataTypesConfig="/mnt/overlay/settings/dam/cfm/models/formbuilderconfig/datatypes"
maxGeneratedOrder="20">
<cq:dialog
jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:lastModified="{Date}2018-10-19T09:57:39.788-05:00"
jcr:lastModifiedBy="admin"
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
<items
jcr:primaryType="nt:unstructured"
maxGeneratedOrder="22">
<_x0031_539961036041
jcr:primaryType="nt:unstructured"
sling:resourceType="dam/cfm/admin/components/authoring/contenteditor/multieditor"
cfm-element="Company"
listOrder="21"
metaType="text-multi"
name="company"
renderReadOnly="false"
showEmptyInReadOnly="true"
valueType="string"/>
<_x0031_539961047566
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
composite="{Boolean}true"
fieldLabel="Products"
listOrder="22"
maxlength="255"
metaType="text-single"
name="products"
renderReadOnly="false"
showEmptyInReadOnly="true"
valueType="string[]">
<field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container"
name="./products">
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<product
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldDescription="Name of Product"
fieldLabel="Product Name"
name="./product"/>
<path
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathbrowser"
fieldDescription="Select Path"
fieldLabel="Path"
name="./path"
rootPath="/content"/>
<show
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
name="./show"
text="Show?"
value="yes"/>
<type
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldDescription="Select Size"
fieldLabel="Size"
name="./size">
<items jcr:primaryType="nt:unstructured">
<def
jcr:primaryType="nt:unstructured"
text="Select Size"
value=""/>
<small
jcr:primaryType="nt:unstructured"
text="Small"
value="small"/>
<medium
jcr:primaryType="nt:unstructured"
text="Medium"
value="medium"/>
<large
jcr:primaryType="nt:unstructured"
text="Large"
value="large"/>
</items>
</type>
</items>
</column>
</items>
</field>
</_x0031_539961047566>
</items>
</content>
</cq:dialog>
</model>
</jcr:content>
</jcr:root>

4) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-cfm-composite-multifield

5) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-cfm-composite-multifield/clientlib and set property categories of String[] type to dam.cfm.authoring.contenteditor.v2 and dependencies String[] to [lodash]

6) Create file ( type nt:file ) /apps/eaem-touchui-cfm-composite-multifield/clientlib/js.txt, add the following

  cfm-composite-multifield.js

7) Create file (type nt:file) /apps/eaem-touchui-cfm-composite-multifield/clientlib/cfm-composite-multifield.js, add the following code

(function ($) {
var CFM = window.Dam.CFM,
MASTER = "master",
CFM_EDITOR_SEL = ".content-fragment-editor",
CORAL_MF_ITEM = "coral-multifield-item",
EAEM_COMPOSITE_ITEM_VALUE = "data-eaem-composite-item-value",
MF_NAME_ATTR = "data-granite-coral-multifield-name",
COMPOSITE_MF_SEL = "[data-granite-coral-multifield-composite]";

CFM.Core.registerReadyHandler(getMultifieldsContent);

extendRequestSave();

function getMultifieldsContent(){
if(!compositeMutifieldsExist()){
return;
}

var url = CFM.EditSession.fragment.urlBase + "/jcr:content/data.2.json";

$.ajax(url).done(loadContentIntoMultiFields);
}

function loadContentIntoMultiFields(data){
var $composites = $(COMPOSITE_MF_SEL), mfValArr, mfAddEle,
vData = data[getVariation()], $lastItem;

if(_.isEmpty(vData)){
return;
}

_.each($composites, function(mField){
mfValArr = vData[getNameDotSlashRemoved(($(mField)).attr(MF_NAME_ATTR))];

if(_.isEmpty(mfValArr)){
return;
}

mfAddEle = mField.querySelector("[coral-multifield-add]");

_.each(mfValArr, function(mfMap){
mfAddEle.click();

$lastItem = $(mField).find(CORAL_MF_ITEM).last();

$lastItem.attr(EAEM_COMPOSITE_ITEM_VALUE, mfMap);

Coral.commons.ready($lastItem[0], function (lastItem) {
fillMultifieldItems(lastItem);
});
});
});
}

function fillMultifieldItems(mfItem){
if(mfItem == null){
return;
}

var mfMap = mfItem.getAttribute(EAEM_COMPOSITE_ITEM_VALUE);

if(_.isEmpty(mfMap)){
return;
}

mfMap = JSON.parse(mfMap);

_.each(mfMap, function(fValue, fKey){
var field = mfItem.querySelector("[name='./" + fKey + "']");

if(_.isEmpty(field)){
field = mfItem.querySelector("[name='" + fKey + "']");
}

if(field == null){
return;
}

setFieldValue(field, fValue);
});
}

function setFieldValue(field, value){
if( field.tagName == "CORAL-CHECKBOX"){
field.checked = (field.getAttribute("value") == value);
}else{
field.value = value;
}
}

function getVariation(){
var variation = $(CFM_EDITOR_SEL).data('variation');

variation = variation || "master";

return variation;
}

function compositeMutifieldsExist(){
return !_.isEmpty($(COMPOSITE_MF_SEL));
}

function extendRequestSave(){
var orignFn = CFM.editor.Page.requestSave;

CFM.editor.Page.requestSave = requestSave;

function requestSave(callback, options) {
orignFn.call(this, callback, options);

if(!compositeMutifieldsExist()){
return;
}

var mfsData = getMultifieldData();

if(_.isEmpty(mfsData)){
return;
}

var url = CFM.EditSession.fragment.urlBase + ".cfm.content.json",
variation = getVariation(),
createNewVersion = (options && !!options.newVersion) || false;

var data = {
":type": "multiple",
":newVersion": createNewVersion,
"_charset_": "utf-8"
};

if(variation !== MASTER){
data[":variation"] = variation;
}

var request = {
url: url,
method: "post",
dataType: "json",
data: _.merge(data, mfsData),
cache: false
};

CFM.RequestManager.schedule({
request: request,
type: CFM.RequestManager.REQ_BLOCKING,
condition: CFM.RequestManager.COND_EDITSESSION,
ui: (options && options.ui)
})
}
}

function getMultifieldData(){
var $composites = $(COMPOSITE_MF_SEL), value,
mfData = {}, values, $fields;

_.each($composites, function(mField){
values = [];

_.each(mField.items.getAll(), function(item) {
$fields = $(item.content).find("[name]");

value = {};

_.each($fields, function(field){
if(canbeSkipped(field)){
return;
}

value[getNameDotSlashRemoved(field.getAttribute("name"))] = getFieldValue(field);
});

values.push(JSON.stringify(value));
});

mfData[ getNameDotSlashRemoved(($(mField)).attr(MF_NAME_ATTR))] = values;
});

return mfData;
}

function getFieldValue(field){
var value;

if( field.tagName == "CORAL-CHECKBOX"){
value = field.checked ? field.getAttribute("value") : "";
}else{
value = field.value;
}

return value;
}

function canbeSkipped(field){
return (($(field).attr("type") == "hidden") || (field.type == "checkbox"));
}

function getNameDotSlashRemoved(name){
if(_.isEmpty(name)){
return name;
}

return ((name.indexOf("./") == 0) ? name.substr(2) : name);
}
}(jQuery));

AEM 6420 - Touch UI Extend Inbox View Payload and change target to Review Task Payload page

$
0
0

Goal


AEM's View Payload action bar button in Inbox opens Review Task page, clicking Review button in the Review Task page then opens payload page. This extension cuts one step and opens the Review task payload page directly from Inbox clicking View Payload button

Demo | Package Install | Github




Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-inbox-view-payload

2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-inbox-view-payload/clientlib and set property categories of String[] type to cq.inbox.gui and dependencies String[] to lodash

3) Create file ( type nt:file ) /apps/eaem-touchui-inbox-view-payload/clientlib/js.txt, add the following

  view-payload.js

4) Create file (type nt:file) /apps/eaem-touchui-inbox-view-payload/clientlib/view-payload.js, add the following code

(function ($, $document) {
var _ = window._,
INBOX_UI_PAGE_VANITY = "/aem/inbox",
INBOX_UI_PAGE = "/mnt/overlay/cq/inbox/content/inbox.html",
PAYLOAD_URL = "/mnt/overlay/cq/core/content/projects/showtasks/reviewtd/payload.html",
REVIEW_TASK_PAGE = "reviewtd.html";

function isInboxPage() {
var pathName = window.location.pathname;
return ((pathName.indexOf(INBOX_UI_PAGE) >= 0) || (pathName.indexOf(INBOX_UI_PAGE_VANITY) >= 0));
}

function getContentUrl(url){
return url.substring(url.indexOf(REVIEW_TASK_PAGE) + REVIEW_TASK_PAGE.length, url.indexOf("?") );
}

function linkHandler(name, el, config, collection, selections){
var linkAttrName = config.data.linkAttributeName,
itemId, reviewTDUrl, content, url;

if(_.isEmpty(linkAttrName)){
return;
}

itemId = $(selections).data("foundationCollectionItemId");
reviewTDUrl = $(selections).data(linkAttrName);
content = getContentUrl(reviewTDUrl);
url = PAYLOAD_URL + content + "?item=" + itemId + "&content=" + content + "&_charset_=utf-8";

if (config.data.target) {
window.open(url, config.data.target);
} else {
window.location = url;
}
}

function changeViewPayloadTarget(){
if(!isInboxPage()){
return;
}

$(window).adaptTo("foundation-registry").register("foundation.collection.action.action", {
name: "cq.inbox.openlink",
handler: linkHandler
});
}

$document.on("foundation-contentloaded", changeViewPayloadTarget);
}(jQuery, jQuery(document)));


Viewing all 512 articles
Browse latest View live




Latest Images