Touch UI Emoji Picker Plugin for RTE (Rich Text Editor) Dialog - /libs/cq/gui/components/authoring/dialog/richtext
In Core Components 2.8.0 uiSettings/cui/dialogFullScreen was removed and the plugin settings were moved to Template (Component) Policies, this post is for core components >= 2.8.0
Uses Open Emoji API https://emoji-api.com/
For demo purposes, design dialog of core text component v2 was modified to add the emoji picker configuration - /apps/core/wcm/components/text/v2/text/cq:design_dialog/content/items/tabs/items/plugins/items/experience-aem-emojis
Emoji Plugin
Plugin Configuration in Design
Enable Plugin in Component Policy
Let's Do It
1) Login to CRXDE Lite, add nt:folder /apps/eaem-emojis-rte-plugin
2) To show the Emoji Picker in a dialog create cq:Page /apps/eaem-emojis-rte-plugin/emoji-selector and add eaem.rte.emojis.plugin categories in /apps/eaem-emojis-rte-plugin/emoji-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: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 Emoji 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.emojis.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"> <emoji jcr:primaryType="nt:unstructured" jcr:title="Click on the Emoji select.." 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"> <emojiPicker jcr:primaryType="nt:unstructured" sling:resourceType="/apps/eaem-emojis-rte-plugin/emoji-widget" fieldDescription="Select Emoji..." fieldLabel="Select Emoji..." name="./eaemEmoji"/> </items> </column> </items> </fixedColumns> </items> </emoji> </items> </form> </items> </body> </jcr:content> </jcr:root>
3) Create widget /apps/eaem-emojis-rte-plugin/emoji-widget/emoji-widget.jsp to add a div container, search code for the emojis...
<%@ include file="/libs/granite/ui/global.jsp" %> <ui:includeClientLib categories="lodash" /> <% String defaultKeyword = "face"; %> <div class="coral-Form-fieldwrapper"> <label class="coral-Form-fieldlabel">Search</label> <input is="coral-textfield" class="coral-Form-field" placeholder="<%= defaultKeyword %>" id="eaem-emoji-input" value="<%= defaultKeyword %>"> </div> <div class="coral-Form-fieldwrapper" id="eaem-emojis"> </div> <script> (function($){ var URL = "https://emoji-api.com/emojis?access_key=bcbd6980f7392ceda8914932404927e9b198486e&search="; function showEmojis(keyword) { $.ajax(URL + keyword).done(handler); function handler(data) { var $emojis = $("#eaem-emojis"), html = ""; _.each(data, function (emoji) { html = html + getEmojiHtml(emoji["character"]); }); $emojis.html(html); } function getEmojiHtml(character) { return "<span style='cursor:pointer'>" + character + "</span>"; } } function addListener(){ $("form").on("submit", function(){ showEmojis($("#eaem-emoji-input").val()); return false; }); } showEmojis("<%=defaultKeyword%>"); addListener(); }(jQuery)); </script>
4) Create clientlib (cq:ClientLibraryFolder) /apps/eaem-emojis-rte-plugin/clientlib set property categories to [cq.authoring.dialog.all, eaem.rte.emojis.plugin] and dependencies to [lodash]
5) Create file (nt:file) /apps/eaem-emojis-rte-plugin/clientlib/js.txt, add the following content
eaem-emojis.js
6) Create file (nt:file) /apps/eaem-emojis-rte-plugin/clientlib/eaem-emojis.js, add the following code
(function($, CUI, $document){ var GROUP = "experience-aem-emojis", INSERT_EMOJI_FEATURE = "insertEmoji", EAEM_INSERT_EMOJI_DIALOG = "eaemTouchUIInsertEmojiDialog", SENDER = "experience-aem", REQUESTER = "requester", FONT_SELECTOR_URL = "/apps/eaem-emojis-rte-plugin/emoji-selector.html", url = document.location.pathname; if( url.indexOf(FONT_SELECTOR_URL) == 0 ){ handlePicker(); return; } function handlePicker(){ $document.on("click", "#eaem-emojis span", addEmojiSelectListener); } function addEmojiSelectListener(){ var message = { sender: SENDER, action: "submit", data: { emoji: $(this).html() } }; 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='300px' 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_INSERT_EMOJI_DIALOG] = CUI.rte.Templates['dlg-' + EAEM_INSERT_EMOJI_DIALOG] = Handlebars.compile(html); } function addPluginToDefaultUISettings(){ var groupFeature = GROUP + "#" + INSERT_EMOJI_FEATURE, toolbar = CUI.rte.ui.cui.DEFAULT_UI_SETTINGS.dialogFullScreen.toolbar; if(toolbar.includes(groupFeature)){ return; } toolbar.splice(3, 0, groupFeature); } var EAEMInsertEmojiDialog = new Class({ extend: CUI.rte.ui.cui.AbstractDialog, toString: "EAEMInsertEmojiDialog", initialize: function(config) { this.exec = config.execute; }, getDataType: function() { return EAEM_INSERT_EMOJI_DIALOG; } }); function addPlugin(){ var EAEMTouchUIInsertEmojiPlugin = new Class({ toString: "EAEMTouchUIInsertEmojiPlugin", extend: CUI.rte.plugins.Plugin, pickerUI: null, getFeatures: function() { return [ INSERT_EMOJI_FEATURE ]; }, initializeUI: function(tbGenerator) { var plg = CUI.rte.plugins; addPluginToDefaultUISettings(); if (!this.isFeatureEnabled(INSERT_EMOJI_FEATURE)) { return; } this.pickerUI = tbGenerator.createElement(INSERT_EMOJI_FEATURE, this, false, { title: "Select Emoji..." }); tbGenerator.addElement(GROUP, plg.Plugin.SORT_FORMAT, this.pickerUI, 10); var groupFeature = GROUP + "#" + INSERT_EMOJI_FEATURE; tbGenerator.registerIcon(groupFeature, "heart"); }, execute: function (pluginCommand, value, envOptions) { var context = envOptions.editContext, ek = this.editorKernel; if (pluginCommand != INSERT_EMOJI_FEATURE) { return; } var dialog,dm = ek.getDialogManager(), $container = CUI.rte.UIUtils.getUIContainer($(context.root)), propConfig = { 'parameters': { 'command': this.pluginId + '#' + INSERT_EMOJI_FEATURE } }; if(this.eaemInsertEmojiDialog){ dialog = this.eaemInsertEmojiDialog; dialog.$dialog.find("iframe").attr("src", this.getPickerIFrameUrl()); }else{ dialog = new EAEMInsertEmojiDialog(); dialog.attach(propConfig, $container, this.editorKernel); dialog.$dialog.find("iframe").attr("src", this.getPickerIFrameUrl()); this.eaemInsertEmojiDialog = dialog; $(window).off('message', receiveMessage).on('message', receiveMessage); } dm.show(dialog); 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(); } }, getPickerIFrameUrl: function(){ return Granite.HTTP.externalize(FONT_SELECTOR_URL) + "?" + REQUESTER + "=" + SENDER; }, updateState: function(selDef) { var hasUC = this.editorKernel.queryState(INSERT_EMOJI_FEATURE, selDef); if (this.pickerUI != null) { this.pickerUI.setSelected(hasUC); } } }); var EAEMTouchUIEmojiCmd = new Class({ toString: "EAEMTouchUIEmojiCmd", extend: CUI.rte.commands.Command, isCommand: function (cmdStr) { return (cmdStr.toLowerCase() == INSERT_EMOJI_FEATURE); }, getProcessingOptions: function () { var cmd = CUI.rte.commands.Command; return cmd.PO_SELECTION | cmd.PO_BOOKMARK | cmd.PO_NODELIST; }, execute: function (execDef) { var emoji = execDef.value.emoji, context = execDef.editContext, emojiSpan = context.doc.createElement("span"); emojiSpan.innerHTML = emoji; var range = CUI.rte.Common.ua.isIE ? CUI.rte.Selection.saveNativeSelection(context) : CUI.rte.Selection.getLeadRange(context); range.insertNode(emojiSpan); }, queryState: function(selectionDef, cmd) { return false; } }); CUI.rte.commands.CommandRegistry.register(INSERT_EMOJI_FEATURE, EAEMTouchUIEmojiCmd); CUI.rte.plugins.PluginRegistry.register(GROUP,EAEMTouchUIInsertEmojiPlugin); } }(jQuery, window.CUI,jQuery(document)));
it doesnt work !!
ReplyDelete