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

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

$
0
0

Goal


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

For a similar extension (Inplace editing) on 61 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/tabs/items/text/items/column/items/text/rtePlugins

Thank you Brett Birschbach for the firefox bug fix

Demo on Chrome | Demo on Firefox | Package Install


Plugin Configuration

 


Add Plugin to RTE Toolbar



Picker with Free Style Palette - Inline Dialog



Picker with Free Style Palette - Full Screen Dialog



Picker with Palette Shades - Classic



Palette Edit Mode



RTE text with Color




Solution


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

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




3) XML representation of /apps/touchui-dialog-mini-rte-color-picker/color-picker-popover/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="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="/apps/touchui-dialog-mini-rte-color-picker/color-picker"
editType="{Boolean}true"
freestylePaletteType="{Boolean}true"
name="./color">
<colors 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"/>
<brown
jcr:primaryType="nt:unstructured"
name="Brown"
value="#996633"/>
<orange
jcr:primaryType="nt:unstructured"
name="Orange"
value="#FF7F00"/>
<purple
jcr:primaryType="nt:unstructured"
name="Purple"
value="#7F007F"/>
<yellow
jcr:primaryType="nt:unstructured"
name="Yellow"
value="#FFFF00"/>
</colors>
</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>

4) Colors shown in picker dialog are added in /apps/touchui-dialog-mini-rte-color-picker/color-picker-popover/cq:dialog/content/items/column/items/picker/colors

5) To workaround the pickerModes bug register a new color picker widget /apps/touchui-dialog-mini-rte-color-picker/color-picker/render.jsp extending ootb color picker widget /libs/granite/ui/components/foundation/form/colorpicker, add the following code

<%@ page import="com.adobe.granite.ui.components.Config" %>
<%@include file="/libs/granite/ui/global.jsp" %>

<%
Config mCfg = cmp.getConfig();

String COLOR_PICKER_WRAPPER_ID = "eaem-color-picker-wrapper-" + mCfg.get("name", String.class).substring(2);
%>

<div id="<%=COLOR_PICKER_WRAPPER_ID%>">
<%--include ootb color picker--%>
<sling:include resourceType="/libs/granite/ui/components/foundation/form/colorpicker"/>
</div>

<script>
(function($){
var wrapper = $("#<%=COLOR_PICKER_WRAPPER_ID%>"),
colorPicker = wrapper.find("[data-init='colorpicker']");

if(_.isEmpty(colorPicker)){
console.log("EAEM - color picker wrapper not found");
return;
}

//extend otb Colorpicker to workaround the pickerModes bug
//in granite/ui/components/foundation/form/colorpicker/render.jsp
//colorpickerJson.put("modes", pickerModes); should have been
//colorpickerJson.put("pickerModes", pickerModes);
var config = colorPicker.data("config");
config.pickerModes = config.modes;

delete config.modes;

colorPicker.attr("data-config", config);
}(jQuery));
</script>

6) Create clientlib (cq:ClientLibraryFolder) /apps/touchui-dialog-mini-rte-color-picker/clientlib set property categories to rte.coralui2 and dependencies to [underscore]

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

                   color-picker.js

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

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

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, true, "Color Picker");
tbGenerator.addElement(GROUP, plg.Plugin.SORT_FORMAT, this.pickerUI, 120);

var groupFeature = GROUP + "#" + COLOR_PICKER_FEATURE;
tbGenerator.registerIcon(groupFeature, "coral-Icon coral-Icon--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"),
content = this.getPickerIFrameContent($(tag).css("color"));

this.addModalDiv();

var modal = new CUI.Modal({
element : '#' + COLOR_PICKER_MODAL_DIV,
heading : "Pick a Color",
content: content
});

registerReceiveDataListener(receiveMessage);

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

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);
}

modal.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);
}
},

getModalHtml: function(){
return "<div class=\"coral-Modal-header\">"
+ "<h2 class=\"coral-Modal-title coral-Heading coral-Heading--2\"></h2>"
+ "<i class=\"coral-Modal-typeIcon coral-Icon coral-Icon--sizeS\"></i>"
+ "<button type=\"button\""
+ "class=\"coral-MinimalButton coral-Modal-closeButton\""
+ "data-dismiss=\"modal\">"
+ "<i class=\"coral-Icon coral-Icon--sizeXS coral-Icon--close "
+ "coral-MinimalButton-icon\"></i>" + "</button>"
+ "</div>"
+ "<div class=\"coral-Modal-body legacy-margins\"></div>";
},

addModalDiv: function(){
var $modalDiv = $("#" + COLOR_PICKER_MODAL_DIV);

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

var tag = {
class: "coral-Modal",
id: COLOR_PICKER_MODAL_DIV
};

var insertModal = $("<div>", tag).hide().html(this.getModalHtml());

$(document.body).append(insertModal);
},

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

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

return "<iframe width='520px' height='405px' frameBorder='0' src='" + url + "'></iframe>";
}
});

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);
}(jQuery, window.CUI));

(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;
}

$document.on("foundation-contentloaded", 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();

var $dialog = $(".cq-dialog").css("background", "white"),
$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]));
}

$dialog.find(".cq-dialog-header").hide();
$dialog.find(".cq-dialog-content").css("top", ".1rem");
$colorPicker.closest(".coral-Form-fieldwrapper").css("margin-bottom", "285px");
$(ADD_COLOR_BUT).css("margin-left", "250px");

$addColor.click(sendDataMessage);
$removeColor.click(sendRemoveMessage);
}

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));

Viewing all articles
Browse latest Browse all 525

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>