Goal
Add an RTE plugin eaemTextFont to apply size, color, background color to the text in content fragment editor
Package validated on AEM 6.5.3.0
Demo | Package Install | Github
Minimized
Toolbar Plugin
Maximized
Saved in CRX
Solution
1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-cfm-font-size-plugin
2) Create a Font selector cq:Page /apps/eaem-touchui-cfm-font-size-plugin/font-selector with 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: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:Page"> <jcr:content jcr:mixinTypes="[sling:VanityPath]" jcr:primaryType="nt:unstructured" jcr:title="EAEM Font Selector" sling:resourceType="granite/ui/components/coral/foundation/page"> <head jcr:primaryType="nt:unstructured"> <favicon jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/page/favicon"/> <viewport jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/admin/page/viewport"/> <clientlibs jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/includeclientlibs" categories="[coralui3,granite.ui.coral.foundation,granite.ui.shell,dam.gui.admin.coral, eaem-cfm.rte.plugin]"/> </head> <body jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/page/body"> <items jcr:primaryType="nt:unstructured"> <form jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form" class="foundation-form content-container" maximized="{Boolean}true" style="vertical"> <items jcr:primaryType="nt:unstructured"> <wizard jcr:primaryType="nt:unstructured" jcr:title="Select Text Font Color..." sling:resourceType="granite/ui/components/coral/foundation/wizard"> <items jcr:primaryType="nt:unstructured"> <text jcr:primaryType="nt:unstructured" jcr:title="Select Text Font Color..." sling:resourceType="granite/ui/components/coral/foundation/container"> <items jcr:primaryType="nt:unstructured"> <fixedColumns jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container"> <items jcr:primaryType="nt:unstructured"> <fontSize jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldDescription="Select text 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 (15px)" value="15px"/> <medium jcr:primaryType="nt:unstructured" text="Medium (30px)" value="30px"/> <large jcr:primaryType="nt:unstructured" text="Large (40px)" value="40px"/> </items> </fontSize> <color jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/colorfield" fieldDescription="Select text color" fieldLabel="Text Color" name="./color" showProperties="{Boolean}true"/> <bgColor jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/colorfield" fieldDescription="Select background color" fieldLabel="Background Color" name="./bgColor" showProperties="{Boolean}true"/> </items> </column> </items> </fixedColumns> </items> <parentConfig jcr:primaryType="nt:unstructured"> <prev granite:class="foundation-wizard-control" jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/anchorbutton" text="Cancel"> <granite:data jcr:primaryType="nt:unstructured" foundation-wizard-control-action="cancel"/> </prev> <next granite:class="foundation-wizard-control" jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/button" disabled="{Boolean}true" text="Apply" type="submit" variant="primary"> <granite:data jcr:primaryType="nt:unstructured" foundation-wizard-control-action="next"/> </next> </parentConfig> </text> </items> </wizard> </items> </form> </items> </body> </jcr:content> </jcr:root>
3) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-cfm-font-size-plugin/clientlib and set property categories of String[] type to [dam.cfm.authoring.contenteditor.v2, eaem-cfm.rte.plugin] and dependencies String[] to [lodash]
4) Create file ( type nt:file ) /apps/eaem-touchui-cfm-font-size-plugin/clientlib/css.txt, add the following
cfm-rte-font-size-plugin.css
5) Create file (type nt:file) /apps/eaem-touchui-cfm-font-size-plugin/clientlib/cfm-rte-font-size-plugin.css, add the following code
.eaem-cfm-font-size { width: 50%; margin-left: -50%; height: 53%; margin-top: -50%; box-sizing: content-box; z-index: 10100; } .eaem-cfm-font-size > iframe { width: 100%; height: 100%; border: 1px solid #888; }
6) Create file ( type nt:file ) /apps/eaem-touchui-cfm-font-size-plugin/clientlib/js.txt, add the following
cfm-rte-font-size-plugin.js
7) Create file (type nt:file) /apps/eaem-touchui-cfm-font-size-plugin/clientlib/cfm-rte-font-size-plugin.js, add the following code
(function ($, $document) { var EAEM_PLUGIN_ID = "eaemfont", EAEM_TEXT_FONT_FEATURE = "eaemTextFont", EAEM_TEXT_FONT_ICON = EAEM_PLUGIN_ID + "#" + EAEM_TEXT_FONT_FEATURE, CANCEL_CSS = "[data-foundation-wizard-control-action='cancel']", FONT_SELECTOR_URL = "/apps/eaem-touchui-cfm-font-size-plugin/font-selector.html", SENDER = "experience-aem", REQUESTER = "requester", $eaemFontPicker, url = document.location.pathname; if( url.indexOf("/editor.html") == 0 ){ extendStyledTextEditor(); registerPlugin(); }else if(url.indexOf(FONT_SELECTOR_URL) == 0){ handlePicker(); } function handlePicker(){ $document.on("foundation-contentloaded", fillDefaultValues); $document.on("click", CANCEL_CSS, sendCancelMessage); $document.submit(sentTextAttributes); } function setWidgetValue(form, selector, value){ Coral.commons.ready(form.querySelector(selector), function (field) { field.value = _.isEmpty(value) ? "" : decodeURIComponent(value); }); } function rgbToHex(color){ if(_.isEmpty(color)){ return color; } if(color.indexOf("rgb") == 0){ color = CUI.util.color.RGBAToHex(color); } return color; } function fillDefaultValues(){ var queryParams = queryParameters(), form = $("form")[0]; setWidgetValue(form, "[name='./color']", queryParams.color); setWidgetValue(form, "[name='./size']", queryParams.size); setWidgetValue(form, "[name='./bgColor']", queryParams.bgColor); } function sentTextAttributes(){ var message = { sender: SENDER, action: "submit", data: {} }, $form = $("form"), $field; _.each($form.find("[name^='./']"), function(field){ $field = $(field); message.data[$field.attr("name").substr(2)] = $field.val(); }); parent.postMessage(JSON.stringify(message), "*"); } 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 sendCancelMessage(){ var message = { sender: SENDER, action: "cancel" }; getParent().postMessage(JSON.stringify(message), "*"); } function getParent() { if (window.opener) { return window.opener; } return parent; } function closePicker(event){ event = event.originalEvent || {}; if (_.isEmpty(event.data)) { return; } var message, action; try{ message = JSON.parse(event.data); }catch(err){ return; } if (!message || message.sender !== SENDER) { return; } action = message.action; if(action === "submit"){ $eaemFontPicker.eaemFontPlugin.editorKernel.execCmd(EAEM_TEXT_FONT_FEATURE, message.data); } var modal = $eaemFontPicker.data('modal'); modal.hide(); modal.$element.remove(); } function extendStyledTextEditor(){ var origFn = Dam.CFM.StyledTextEditor.prototype._start; Dam.CFM.StyledTextEditor.prototype._start = function(){ addTextFontPluginSettings(this); origFn.call(this); } } function addTextFontPluginSettings(editor){ var config = editor.$editable.data("config"); config.rtePlugins[EAEM_PLUGIN_ID] = { features: "*" }; config.uiSettings.cui.multieditorFullscreen.toolbar.push(EAEM_TEXT_FONT_ICON); } function registerPlugin(){ var EAEM_CFM_TEXT_FONT_PLUGIN = new Class({ toString: "eaemCFMTextFontPlugin", extend: CUI.rte.plugins.Plugin, textFontUI: null, getFeatures: function () { return [ EAEM_TEXT_FONT_FEATURE ]; }, notifyPluginConfig: function (pluginConfig) { var defaults = { tooltips: {} }; defaults.tooltips[EAEM_TEXT_FONT_FEATURE] = { title: "Set text font size, color, background color..." }; CUI.rte.Utils.applyDefaults(pluginConfig, defaults); this.config = pluginConfig; }, initializeUI: function (tbGenerator) { if (!this.isFeatureEnabled(EAEM_TEXT_FONT_FEATURE)) { return; } this.textFontUI = new tbGenerator.createElement(EAEM_TEXT_FONT_FEATURE, this, false, this.config.tooltips[EAEM_TEXT_FONT_FEATURE]); tbGenerator.addElement(EAEM_TEXT_FONT_FEATURE, 999, this.textFontUI, 999); if (tbGenerator.registerIcon) { tbGenerator.registerIcon(EAEM_TEXT_FONT_ICON, "textColor"); } $(window).off('message', closePicker).on('message', closePicker); }, isValidSelection: function(){ var winSel = window.getSelection(); return winSel && winSel.rangeCount == 1 && winSel.getRangeAt(0).toString().length > 0; }, execute: function (pluginCommand, value, envOptions) { var context = envOptions.editContext; if (pluginCommand != EAEM_TEXT_FONT_FEATURE) { return; } if(!this.isValidSelection()){ return; } var 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")), color, size = $tag.css("font-size"); color = this.getColorAttributes($tag); this.showFontModal(this.getPickerIFrameUrl(size, color.color, color.bgColor)); }, getColorAttributes: function($tag){ var key, color = { color: "", bgColor : ""}; if(!$tag.attr("style")){ return color; } //donot use .css("color"), it returns default font color, if color is not set var parts = $tag.attr("style").split(";"); _.each(parts, function(value){ value = value.split(":"); key = value[0] ? value[0].trim() : ""; value = value[1] ? value[1].trim() : ""; if(key == "color"){ color.color = rgbToHex(value); }else if(key == "background-color"){ color.bgColor = rgbToHex(value); } }); return color; }, showFontModal: function(url){ var self = this, $iframe = $('<iframe>'), $modal = $('<div>').addClass('eaem-cfm-font-size coral-Modal'); $iframe.attr('src', url).appendTo($modal); $modal.appendTo('body').modal({ type: 'default', buttons: [], visible: true }); $eaemFontPicker = $modal; $eaemFontPicker.eaemFontPlugin = self; $modal.nextAll(".coral-Modal-backdrop").addClass("cfm-coral2-backdrop"); }, getPickerIFrameUrl: function(size, color, bgColor){ var url = Granite.HTTP.externalize(FONT_SELECTOR_URL) + "?" + REQUESTER + "=" + SENDER; if(!_.isEmpty(color)){ url = url + "&color=" + encodeURIComponent(color); } if(!_.isEmpty(bgColor)){ url = url + "&bgColor=" + encodeURIComponent(bgColor); } if(!_.isEmpty(size)){ url = url + "&size=" + size; } return url; } }); var EAEM_CFM_TEXT_FONT_CMD = new Class({ toString: "eaemCFMTextFontCmd", extend: CUI.rte.commands.Command, isCommand: function (cmdStr) { return (cmdStr.toLowerCase() == EAEM_TEXT_FONT_FEATURE); }, getProcessingOptions: function () { var cmd = CUI.rte.commands.Command; return cmd.PO_SELECTION | cmd.PO_BOOKMARK | cmd.PO_NODELIST; }, getTagObject: function(textData) { var style = ""; if(!_.isEmpty(textData.color)){ style = "color: " + textData.color + ";"; } if(!_.isEmpty(textData.size)){ style = style + "font-size: " + textData.size + ";"; } if(!_.isEmpty(textData.bgColor)){ style = style + "background-color: " + textData.bgColor; } return { "tag": "span", "attributes": { "style" : style } }; }, execute: function (execDef) { var textData = execDef.value, selection = execDef.selection, nodeList = execDef.nodeList; if (!selection || !nodeList) { return; } var common = CUI.rte.Common, context = execDef.editContext, tagObj = this.getTagObject(textData); if(_.isEmpty(textData.size) && _.isEmpty(textData.color) && _.isEmpty(textData.bgColor)){ 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, tags.attributes ? tags.attributes : undefined, true); } nodeList.surround(execDef.editContext, tagObj.tag, tagObj.attributes); }, queryState: function(selectionDef, cmd) { return false; } }); CUI.rte.plugins.PluginRegistry.register(EAEM_PLUGIN_ID, EAEM_CFM_TEXT_FONT_PLUGIN); CUI.rte.commands.CommandRegistry.register(EAEM_TEXT_FONT_FEATURE, EAEM_CFM_TEXT_FONT_CMD); } }(jQuery, jQuery(document)));
How to add this plug to a component? same as experience-aem?
ReplyDeleteyou mean this? http://experience-aem.blogspot.com/2018/05/aem-64-touch-ui-rte-rich-text-editor-color-picker-plugin.html
Delete@sreekanth choudry can you share same plugin with same options for RTE?
DeleteHi,
ReplyDeleteI am trying to add h4 to the paraformat drop down for the same content fragment rte, right now it shows p,h1,h2,h3 only. Any suggestions in how to do this?
Hi Bhaskar, did you achieve it ?
DeleteHi,
ReplyDeletehow can I add this plugin in text component.
Hi,
ReplyDeletein AEM 6.5 it is not working, I have this console error:
Uncaught ReferenceError: Dam is not defined
Any idea regarding this error?
Regards.
Were you able to resolve this issue ? Facing similar DAM issue now in aem 6.5
DeleteHi,
ReplyDeletei have to create a content fragment model with a multifield. Multifield will consist of three fields 1.Text 2.pathbrowser 3.Summary.
the 3rd field summary under multifield should be a rte.
Any idea on how to proceed with this scenario?
Regards,
Komal
Hi,
ReplyDeleteCan you please suggest how to enable font size selection in RTE field ?
Getting following error while adding : Uncaught ReferenceError: Dam is not defined
ReplyDeleteHow to resolve this issue