Dialog for the plugin can be configured with any standard Touch UI Widgets. In this post, we configure a textfield - /libs/granite/ui/components/foundation/form/textfield for entering alt text and path browser - /libs/granite/ui/components/foundation/form/pathbrowser for selecting image
Demo | Package Install
Component Dialog RTE Config
Add the image insert plugin - touchuiinsertimage, available in group experience-aem in component dialog eg. /libs/foundation/components/text/dialog/items/tab1/items/text/rtePlugins (for demonstration only; never modify foundation components)

Plugin Dialog with Path Browser Config

Plugin Dialog

Plugin Dialog with Picker

Plugin Dialog with Image Selected

Image Shown in RTE

Image Source in RTE

Solution
1) Login to CRXDE Lite, create folder (nt:folder) /apps/touchui-rte-browse-insert-image
2) Add the dialog configuration for RTE Plugin, shown in popover window when the user clicks on image plugin icon; create a node of type sling:Folder - /apps/touchui-rte-browse-insert-image/popover with the following configuration
<?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"
jcr:primaryType="sling:Folder"
jcr:title="Pick an Image"
sling:resourceType="cq/gui/components/authoring/dialog"/>
3) Add dialog content /apps/touchui-rte-browse-insert-image/popover/content; #5 attribute eaem-rte-iframe-content marks this dialog RTE specific
<?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="granite/ui/components/foundation/container"
eaem-rte-iframe-content="">
<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">
<alt
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldLabel="Alt Text"
name="./alt"/>
<image
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/pathbrowser"
fieldLabel="Image"
name="./image"
rootPath="/content/dam"/>
</items>
</column>
</items>
</jcr:root>
4) Dialog in CRXDE Lite

5) Create clientlib (type cq:ClientLibraryFolder) /apps/touchui-rte-browse-insert-image/clientlib, set property categories of String type to rte.coralui2
6) Create file ( type nt:file ) /apps/touchui-rte-browse-insert-image/clientlib/js.txt, add the following
image-insert.js
popover.js
popover.js
7) Create file ( type nt:file ) /apps/touchui-rte-browse-insert-image/clientlib/image-insert.js, add the following code. This file contains logic for image plugin; receiving a selected image from popover iframe showing the dialog and adding it in RTE
(function ($, $document, Handlebars) {
var ExperienceAEM = {
GROUP: "experience-aem",
TIM_FEATURE: "touchuiinsertimage",
TIM_DIALOG: "touchuiinsertimagedialog",
CONTENT_URL: "/apps/touchui-rte-browse-insert-image/popover.html",
EAEM_RTE_IFRAME_CONTENT: "eaem-rte-iframe-content"
};
ExperienceAEM.TIM_UI_SETTING = ExperienceAEM.GROUP + "#" + ExperienceAEM.TIM_FEATURE;
//extend toolbar builder to register insert image
ExperienceAEM.CuiToolbarBuilder = new Class({
toString: "EAEMCuiToolbarBuilder",
extend: CUI.rte.ui.cui.CuiToolbarBuilder,
_getUISettings: function (options) {
var uiSettings = this.superClass._getUISettings(options);
//inline toolbar
var toolbar = uiSettings["inline"]["toolbar"],
feature = ExperienceAEM.TIM_UI_SETTING;
//uncomment this to make image insert available for inline toolbar
/*if (toolbar.indexOf(feature) == -1) {
var index = toolbar.indexOf("fullscreen#start");
toolbar.splice(index, 0, feature);
toolbar.splice(index + 1, 0, "-");
}*/
//add image insert to fullscreen toolbar
toolbar = uiSettings["fullscreen"]["toolbar"];
if (toolbar.indexOf(feature) == -1) {
toolbar.splice(3, 0, feature);
}
if (!this._getClassesForCommand(feature)) {
this.registerAdditionalClasses(feature, "coral-Icon coral-Icon--image");
}
return uiSettings;
}
});
//popover dialog thats hosts iframe
ExperienceAEM.InsertImageDialog = new Class({
extend: CUI.rte.ui.cui.AbstractBaseDialog,
toString: "EAEMInsertImageDialog",
getDataType: function () {
return ExperienceAEM.TIM_DIALOG;
}
});
//extend the CUI dialog manager to register popover dialog
ExperienceAEM.DialogManager = new Class({
toString: "EAEMDialogManager",
extend: CUI.rte.ui.cui.CuiDialogManager,
create: function (dialogId, config) {
if (dialogId !== ExperienceAEM.TIM_DIALOG) {
return this.superClass.create.call(this, dialogId, config);
}
var context = this.editorKernel.getEditContext();
var $container = CUI.rte.UIUtils.getUIContainer($(context.root));
var dialog = new ExperienceAEM.InsertImageDialog();
dialog.attach(config, $container, this.editorKernel, true);
return dialog;
}
});
//extend the toolkit implementation for returning custom toolbar builder and dialog manager
ExperienceAEM.ToolkitImpl = new Class({
toString: "EAEMToolkitImpl",
extend: CUI.rte.ui.cui.ToolkitImpl,
createToolbarBuilder: function () {
return new ExperienceAEM.CuiToolbarBuilder();
},
createDialogManager: function (editorKernel) {
return new ExperienceAEM.DialogManager(editorKernel);
}
});
CUI.rte.ui.ToolkitRegistry.register("cui", ExperienceAEM.ToolkitImpl);
ExperienceAEM.TouchUIInsertImagePlugin = new Class({
toString: "TouchUIInsertImagePlugin",
extend: CUI.rte.plugins.Plugin,
pickerUI: null,
getFeatures: function () {
return [ ExperienceAEM.TIM_FEATURE ];
},
initializeUI: function (tbGenerator) {
var plg = CUI.rte.plugins;
if (this.isFeatureEnabled(ExperienceAEM.TIM_FEATURE)) {
this.pickerUI = tbGenerator.createElement(ExperienceAEM.TIM_FEATURE, this, true, "Insert Image");
tbGenerator.addElement(ExperienceAEM.GROUP, plg.Plugin.SORT_FORMAT, this.pickerUI, 120);
}
},
execute: function (id) {
var ek = this.editorKernel,
dm = ek.getDialogManager();
var dialogConfig = {
parameters: {
"command": ExperienceAEM.TIM_UI_SETTING
}
};
var dialog = this.dialog = dm.create(ExperienceAEM.TIM_DIALOG, dialogConfig);
dm.prepareShow(this.dialog);
dm.show(this.dialog);
var $popover = this.dialog.$dialog.find(".coral-Popover-content");
loadPopoverUI($popover);
function loadPopoverUI($popover) {
$popover.parent().css("width", ".1px").height(".1px").css("border", "none");
$popover.css("width", ".1px").height(".1px");
$popover.find("iframe").attr("src", ExperienceAEM.CONTENT_URL);
//receive the dialog values from child window
registerReceiveDataListener(receiveMessage);
}
function receiveMessage(event) {
if (_.isEmpty(event.data)) {
return;
}
var message = JSON.parse(event.data);
if(!message || message.sender != ExperienceAEM.EAEM_RTE_IFRAME_CONTENT){
return;
}
var action = message.action;
if(action == "submit"){
var data = message.data;
if(!_.isEmpty(data) && !_.isEmpty(data.imagePath)){
ek.relayCmd(id, message.data);
}
}
dialog.hide();
removeReceiveDataListener(receiveMessage);
}
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);
}
}
},
//to mark the icon selected/deselected
updateState: function (selDef) {
var hasUC = this.editorKernel.queryState(ExperienceAEM.TIM_FEATURE, selDef);
if (this.pickerUI != null) {
this.pickerUI.setSelected(hasUC);
}
}
});
CUI.rte.plugins.PluginRegistry.register(ExperienceAEM.GROUP, ExperienceAEM.TouchUIInsertImagePlugin);
ExperienceAEM.InsertImageCmd = new Class({
toString: "InsertImageCmd",
extend: CUI.rte.commands.Command,
isCommand: function (cmdStr) {
return (cmdStr.toLowerCase() == ExperienceAEM.TIM_FEATURE);
},
getProcessingOptions: function () {
var cmd = CUI.rte.commands.Command;
return cmd.PO_BOOKMARK | cmd.PO_SELECTION;
},
execute: function (execDef) {
var data = execDef.value, path = data.imagePath, alt = data.altText || "",
width = 100, height = 100,
imageUrl = CUI.rte.Utils.processUrl(path, CUI.rte.Utils.URL_IMAGE),
imgHtml = "";
imgHtml += "<img src=\"" + imageUrl + "\" alt=\"" + alt + "\"";
imgHtml += " " + CUI.rte.Common.SRC_ATTRIB + "=\"" + path + "\"";
imgHtml += " width=\"" + width + "\"";
imgHtml += " height=\"" + height + "\"";
imgHtml += ">";
execDef.editContext.doc.execCommand("insertHTML", false, imgHtml);
}
});
CUI.rte.commands.CommandRegistry.register(ExperienceAEM.GROUP, ExperienceAEM.InsertImageCmd);
//returns the picker dialog html
//Handlebars doesn't do anything useful here, but the framework expects a template
function cpTemplate() {
CUI.rte.Templates["dlg-" + ExperienceAEM.TIM_DIALOG] =
Handlebars.compile('<div data-rte-dialog="' + ExperienceAEM.TIM_DIALOG
+ '" class="coral--dark coral-Popover coral-RichText-dialog">'
+ '<iframe width="1100px" height="700px"></iframe>'
+ '</div>');
}
cpTemplate();
})(jQuery, jQuery(document), Handlebars);
8) Create file ( type nt:file ) /apps/touchui-rte-browse-insert-image/clientlib/popover.js, add the following code. This file contains logic for sending the dialog values like image selected to parent window RTE
(function($, $document){
//dialogs marked with eaem-rte-iframe-content data attribute execute the below logic
//to send dialog values to parent window RTE
var EAEM_RTE_IFRAME_CONTENT = "eaem-rte-iframe-content",
HELP_BUTTON_SEL = ".cq-dialog-help",
CANCEL_BUTTON_SEL = ".cq-dialog-cancel",
SUBMIT_BUTTON_SEL = ".cq-dialog-submit",
ALT_TEXT_NAME = "./alt",
IMAGE_NAME = "./image";
$document.on("foundation-contentloaded", stylePopoverIframe);
function stylePopoverIframe(){
var $iframeContent = $("[" + 'data-' + EAEM_RTE_IFRAME_CONTENT + "]");
if(_.isEmpty($iframeContent)){
return
}
var $form = $iframeContent.closest("form"),
$cancel = $form.find(CANCEL_BUTTON_SEL),
$submit = $form.find(SUBMIT_BUTTON_SEL);
$form.css("border", "solid 2px");
$form.find(HELP_BUTTON_SEL).hide();
$document.off("click", CANCEL_BUTTON_SEL);
$document.off("click", SUBMIT_BUTTON_SEL);
$document.off("submit");
$cancel.click(sendCloseMessage);
$submit.click(sendDataMessage);
}
function sendCloseMessage(){
var message = {
sender: EAEM_RTE_IFRAME_CONTENT,
action: "close"
};
parent.postMessage(JSON.stringify(message), "*");
}
function sendDataMessage(){
var message = {
sender: EAEM_RTE_IFRAME_CONTENT,
action: "submit",
data:{
altText: $("[name='" + ALT_TEXT_NAME + "']").val(),
imagePath: $("[name='" + IMAGE_NAME + "']").val()
}
};
parent.postMessage(JSON.stringify(message), "*");
}
})(jQuery, jQuery(document));
Source:
http://experience-aem.blogspot.com/2015/09/aem-61-touch-ui-rich-text-editor-rte-browse-insert-image.html
No comments:
Post a Comment
If you have any doubts or questions, please let us know.