Goal
Touch UI Color Picker Plugin for RTE (Rich Text Editor) Dialog -
/libs/cq/gui/components/authoring/dialog/richtextIn
Core Components 2.8.0 uiSettings/cui/dialogFullScreen was removed and the plugin settings were moved to
Template Policies, this post is for making the
Font & Color plugin work with Core Components 2.8.0For a similar extension on 65 and older Core Components
check this post 64
check this post 63
check this postFor demo purposes, design dialog of
core text component v2 was modified to add the font picker configuration -
/apps/core/wcm/components/text/v2/text/cq:design_dialog/content/items/tabs/items/plugins/items/experience-aem-fontsDemo |
Package Install |
GithubPlugin Configuration in Design Dialog
Plugin Config in Template PolicyPlugin PickerFont and ColorSolution
1) Login to
CRXDE Lite, add nt:folder
/apps/eaem-fonts-plugin2) To show the
color picker in a dialog create cq:Page
/apps/eaem-fonts-plugin/font-selector and add
eaem.rte.font.plugincategories in
/apps/eaem-fonts-plugin/font-selector/jcr:content/head/clientlibs<?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.rte.font.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 (cq:ClientLibraryFolder)
/apps/eaem-fonts-plugin/clientlib set property
categories to
[cq.authoring.dialog.all, eaem.rte.font.plugin] and
dependencies to
[lodash]4) Create file (nt:file)
/apps/eaem-fonts-plugin/clientlib/js.txt, add the following content
eaem-fonts.js5) Create file (nt:file)
/apps/eaem-fonts-plugin/clientlib/eaem-fonts.js, add the following code
(function($, CUI, $document){
var GROUP = "experience-aem-fonts",
FONT_FEATURE = "applyFont",
FONT_SIZE_FEATURE = "fontSize",
TEXT_COLOR_FEATURE = "textColor",
TEXT_BG_COLOR_FEATURE = "textBackgroundColor",
EAEM_APPLY_FONT_DIALOG = "eaemTouchUIApplyFontDialog",
SENDER = "experience-aem", REQUESTER = "requester", $eaemFontPicker,
CANCEL_CSS = "[data-foundation-wizard-control-action='cancel']",
FONT_SELECTOR_URL = "/apps/eaem-fonts-plugin/font-selector.html",
url = document.location.pathname;
if( url.indexOf(FONT_SELECTOR_URL) == 0 ){
handlePicker();
return;
}
function handlePicker(){
$document.on("foundation-contentloaded", fillDefaultValues);
$document.on("click", CANCEL_CSS, sendCancelMessage);
$document.submit(sentTextAttributes);
}
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 setWidgetValue(form, selector, value, enable){
Coral.commons.ready(form.querySelector(selector), function (field) {
field.value = _.isEmpty(value) ? "" : decodeURIComponent(value);
if(enable){
delete field.disabled;
}else{
field.disabled = "disabled";
}
});
}
function fillDefaultValues(){
var queryParams = queryParameters(),
$form = $("form");
if(_.isEmpty(queryParams.features)){
return;
}
var features = queryParams.features.split(",");
setWidgetValue($form[0], "[name='./color']", queryParams.color, features.includes(TEXT_COLOR_FEATURE));
setWidgetValue($form[0], "[name='./size']", queryParams.size, features.includes(FONT_SIZE_FEATURE));
setWidgetValue($form[0], "[name='./bgColor']", queryParams.bgColor, features.includes(TEXT_BG_COLOR_FEATURE));
$form.css("background-color", "#fff");
}
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();
});
getParent().postMessage(JSON.stringify(message), "*");
}
function sendCancelMessage(){
var message = {
sender: SENDER,
action: "cancel"
};
getParent().postMessage(JSON.stringify(message), "*");
}
function getParent() {
if (window.opener) {
return window.opener;
}
return parent;
}
addPlugin();
addPluginToDefaultUISettings();
addDialogTemplate();
function addDialogTemplate(){
var url = Granite.HTTP.externalize(FONT_SELECTOR_URL) + "?" + REQUESTER + "=" + SENDER;
var html = "<iframe width='700px' 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-' + EAEM_APPLY_FONT_DIALOG] = CUI.rte.Templates['dlg-' + EAEM_APPLY_FONT_DIALOG] = Handlebars.compile(html);
}
function rgbToHex(color){
if(_.isEmpty(color)){
return color;
}
if(color.indexOf("rgb") == 0){
color = CUI.util.color.RGBAToHex(color);
}
return color;
}
function addPluginToDefaultUISettings(){
var groupFeature = GROUP + "#" + FONT_FEATURE,
toolbar = CUI.rte.ui.cui.DEFAULT_UI_SETTINGS.dialogFullScreen.toolbar;
if(toolbar.includes(groupFeature)){
return;
}
toolbar.splice(3, 0, groupFeature);
}
var EAEMApplyFontDialog = new Class({
extend: CUI.rte.ui.cui.AbstractDialog,
toString: "EAEMApplyFontDialog",
initialize: function(config) {
this.exec = config.execute;
},
getDataType: function() {
return EAEM_APPLY_FONT_DIALOG;
}
});
function addPlugin(){
var EAEMTouchUIFontPlugin = new Class({
toString: "EAEMTouchUIFontPlugin",
extend: CUI.rte.plugins.Plugin,
pickerUI: null,
getFeatures: function() {
return [ FONT_FEATURE ];
},
initializeUI: function(tbGenerator) {
var plg = CUI.rte.plugins;
addPluginToDefaultUISettings();
if (!this.isFeatureEnabled(FONT_FEATURE)) {
return;
}
this.pickerUI = tbGenerator.createElement(FONT_FEATURE, this, false, { title: "Select Font..." });
tbGenerator.addElement(GROUP, plg.Plugin.SORT_FORMAT, this.pickerUI, 10);
var groupFeature = GROUP + "#" + FONT_FEATURE;
tbGenerator.registerIcon(groupFeature, "abc");
},
execute: function (pluginCommand, value, envOptions) {
var context = envOptions.editContext,
ek = this.editorKernel;
if (pluginCommand != FONT_FEATURE) {
return;
}
if(!isValidSelection()){
return;
}
var selection = CUI.rte.Selection.createProcessingSelection(context),
startNode = selection.startNode;
if ( (selection.startOffset === startNode.length) && (startNode != selection.endNode)) {
startNode = startNode.nextSibling;
}
var $tag = $(CUI.rte.Common.getTagInPath(context, startNode, "span")),
size = $tag.css("font-size"),dialog,dm = ek.getDialogManager(),
$container = CUI.rte.UIUtils.getUIContainer($(context.root)),
propConfig = {
'parameters': {
'command': this.pluginId + '#' + FONT_FEATURE
}
};
var color = this.getColorAttributes($tag);
if(this.eaemApplyFontDialog){
dialog = this.eaemApplyFontDialog;
dialog.$dialog.find("iframe").attr("src", this.getPickerIFrameUrl(this.config.features, size, color.color, color.bgColor));
}else{
dialog = new EAEMApplyFontDialog();
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", this.getPickerIFrameUrl(this.config.features, size, color.color, color.bgColor));
this.eaemApplyFontDialog = dialog;
}
dm.show(dialog);
$(window).off('message', receiveMessage).on('message', receiveMessage);
function isValidSelection(){
var winSel = window.getSelection();
return winSel && winSel.rangeCount == 1 && winSel.getRangeAt(0).toString().length > 0;
}
function receiveMessage(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"){
ek.relayCmd(pluginCommand, message.data);
}
dialog.hide();
}
},
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(features, size, color, bgColor){
var url = Granite.HTTP.externalize(FONT_SELECTOR_URL) + "?" + REQUESTER + "=" + SENDER;
url = url + "&features=" + features.join(",");
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;
},
updateState: function(selDef) {
var hasUC = this.editorKernel.queryState(FONT_FEATURE, selDef);
if (this.pickerUI != null) {
this.pickerUI.setSelected(hasUC);
}
}
});
var EAEMTouchUIFontCmd = new Class({
toString: "EAEMTouchUIFontCmd",
extend: CUI.rte.commands.Command,
isCommand: function (cmdStr) {
return (cmdStr.toLowerCase() == 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.commands.CommandRegistry.register(FONT_FEATURE, EAEMTouchUIFontCmd);
CUI.rte.plugins.PluginRegistry.register(GROUP,EAEMTouchUIFontPlugin);
}
}(jQuery, window.CUI,jQuery(document)));