Goal
Touch UI Color Picker Plugin for RTE (Rich Text Editor) InPlace and Dialog Edit - /libs/cq/gui/components/authoring/dialog/richtext
For a similar extension on 64 check this post, 62 check this post, 61 check this post; to add General group components on We.Retail pages check this post
For demo purposes, dialog of foundation text component was modified to add the color picker configuration - /libs/foundation/components/text/cq:dialog/content/items/text/items/column/items/text/rtePlugins
Demo | Package Install | Github
Plugin Configuration - InPlace Editing
Plugin Configuration - Dialog
Picker with Free Style Palette - InPlace Editing Maximized
Picker with Free Style Palette - Inline Dialog
Picker with Free Style Palette - Full Screen Dialog
Color Applied
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
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.8)").css("-webkit-transform-origin", "0 0") .css("-moz-transform", "scale(0.8)").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='410px' height='450px' 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); //Coral.templates.RichTextEditor['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"); $dialog[0].open = true; var $addColor = $dialog.find(ADD_COLOR_BUT), $removeColor = $dialog.find(REMOVE_COLOR_BUT), $colorPicker = $document.find(".coral-ColorPicker"), pickerInstance = $colorPicker.data("colorpicker"); if(!_.isEmpty(queryParameters()[COLOR])){ pickerInstance._setColor(decodeURIComponent(queryParams[COLOR])); } adjustHeader($dialog); $dialog.find(".coral-Dialog-wrapper").css("margin","0").find(".coral-Dialog-content").css("padding","0"); $colorPicker.closest(".coral-Form-fieldwrapper").css("margin-bottom", "285px"); $(ADD_COLOR_BUT).css("margin-left", "150px"); $addColor.click(sendDataMessage); $removeColor.click(sendRemoveMessage); } function adjustHeader($dialog){ var $header = $dialog.css("background-color", "#fff").find(".coral-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));
Hi i need to write a plug-in where, once i select some text and click on pug-in : the background color of the text should turn to black.
ReplyDeleteI am new to rte plugins, this looks little complicated to me. can you please help
Hello, from this component I created another that highlights the text. How do I make the two components work together? Now if we call them together they go wrong. Who can help me, thank you
ReplyDeleteIf possible please can you put some comments in the code above so we can better understand how this works?
ReplyDeleteHi Sreekanth,
ReplyDeleteI used this component as it is and was able to get the picker successfully. But I am facing one issue, when the focus is on the pop up box and the "Esc" key is pressed the box gives a 404 not found error and this is what I see in the console: "GET http://localhost:4505/apps/eaem-touchui-dialog-rte-color-picker/color-picker-popover/undefined 404 (Not Found)"
Hi,
ReplyDeletecan you please suggest some links for AEM 6.3 - Touch UI RTE (Rich Text Editor) enabled with image.
i tried to use as it is, not working as expected. color gets applied every alternate time. any one have any suggestions?
ReplyDeleteis it possible to clone only linkplugin and extend WACG functionality.
ReplyDelete@ Sreekanth : Can you please update the AEM 6.5 version of plugin?
ReplyDeleteHi Sreekant, When I tried to apply new color to already applied coplor it removes earlier applied color(actually removes whole span) but do not apply new. So we have to twice apply color. Any fix for it?
ReplyDeleteHi Sreekanth, How to add default color without selecting.
ReplyDeleteHi Dialog is not appearing in aem 6.5 . can you please update the plugin for aem6.5
ReplyDeleteHi All,
ReplyDeleteFixed for 6.5
classes name for AEM 6.5 has been changed. Please below changed for AEM 6.5
line 283 - $dialog = $(".coral-Dialog"); to $dialog = $(".coral3-Dialog");
Line 304 - $dialog.find(".coral-Dialog-wrapper").css("margin","0").find(".coral-Dialog-content").css("padding","0"); TO $dialog.find(".coral3-Dialog-wrapper").css("margin","0").find(".coral3-Dialog-content").css("padding","0");
Line 316 - var $header = $dialog.css("background-color", "#fff").find(".coral-Dialog-header"); TO var $header = $dialog.css("background-color", "#fff").find(".coral3-Dialog-header");
for 65 https://experience-aem.blogspot.com/2019/04/aem-65-touch-ui-rte-rich-text-editor-dialog-color-picker-plugin.html
ReplyDelete65 with core components - https://experience-aem.blogspot.com/2020/01/aem-6530-core-components-280-touch-ui-rte-rich-text-editor-dialog-color-font-plugin.html