This plugin works just like a status plugin reflecting the count of words entered by the editor while entering content in the rich text editor.
How to create ?
Create clientlibs for our text component with categories[] | String | core.aeexplorers.text
Now, add word-count.js in the above created clientlib and update the file name in js.txt as well.
word-count.js
(function ($, $document) {
"use strict";
function word_count(htmlContent){
htmlContent = htmlContent.replace(/<[^>]*>/g," ");
htmlContent = htmlContent.replace(/ /g, ' ');
htmlContent = htmlContent.replace(/\s+/g, ' ');
htmlContent = htmlContent.trim();
var count = htmlContent.split(" ").length;
var displayCount=count;
if(count===1 && htmlContent.split(" ")[0]==='') {
displayCount=0;
}
var htmlStringToShow="<p class=\"word-count\" style=\"color:blue\">Word Count : "+displayCount+"</p>"
return htmlStringToShow;
}
$document.on("dialog-ready", function() {
var textarea=$(".cq-RichText-editable");
var htmlContent = textarea.html();
var htmlStringToShow=word_count(htmlContent);
$(htmlStringToShow).insertAfter(textarea);
$(".cq-RichText-editable").keyup(function(){
var htmlContent = $(this).html();
var htmlStringToShow=word_count(htmlContent);
$(".word-count").html(htmlStringToShow);
});
});
})($, $(document));
Now, include the above created clientlibs to cq:dialog of text component by adding the property extraClientlibs[] | String | core.aeexplorers.text
The plugin is now created and ready to use.
How to use ?
Place a text component on the content page and start typing. Just below the text area, a word count status would be displayed which will be updated in real time, as an when you enter a character.
To download the installable jcr package, click on the below button.
The out of the box anchor plugin present in text component is buggy and doesn’t work as expected. The issues identified on the Anchor Plugin are : 1. The “href “attribute is being removed on submit of dialog i.e. the href property is not stored on the text node 2. Modification of the anchor id/href attribute is not possible as the plugin doesn’t load the saved property.
To meet the above requirement, we have developed a custom anchor plugin.
How to create ?
Create a text component and go to rtePlugins node present under cq:dialog of the component.
Add a property to the node > adobe-explorers features | <String> | *
Enable the plugin feature in dialog inline and full screen mode by adding the feature on below nodes :
inline > on this node go to the multi value property named – “toolbar“. Add the feature in this property > adobe-explorers#anchor
dialogFullScreen > similar to above – > on this node go to the multi value property named – “toolbar“. Add the feature in this property > adobe-explorers#anchor
Now, let’s create a dialog which will be displayed on click of plugin. Here, in our case, we would need to have a textfield and two buttons, one to add anchor tag and another to remove anchor tag.
Now, let’s create clientlibs for our text component with categories[] | String | core.aeexplorers.text, cq.authoring.dialog.all and dependencies | String | underscore
To create the Anchor Plugin feature, we would need to add following three js files to above created clientlibs – anchor-plugin.js ( this contains the dialog and the complete code on how to wrap the text with anchot tag) ,dialog-before-submit.js and richtext.js ( The changes in these two js is needed to preserve the href tag on the text node ).
1. anchor-plugin.js
(function($, CUI) {
var GROUP = "adobe-explorers",
ANCHOR_PICKER_FEATURE = "anchor",
TCP_DIALOG = "aeTouchUIAnchorPickerDialog",
PICKER_NAME_IN_POPOVER = "anchorvalue",
REQUESTER = "requester",
PICKER_URL = "/apps/adobeexplorers/components/content/text/anchor-popover/cq:dialog.html",
url = document.location.pathname;
if (url.indexOf(PICKER_URL) !== 0) {
addPluginToDefaultUISettings();
addDialogTemplate();
}
var AEAnchorPickerDialog = new Class({
extend : CUI.rte.ui.cui.AbstractDialog,
toString : "AEAnchorPickerDialog",
initialize : function(config) {
this.exec = config.execute;
},
getDataType : function() {
return TCP_DIALOG;
}
});
var TouchUIAnchorPickerPlugin = new Class(
{
toString : "TouchUIAnchorPickerPlugin",
extend : CUI.rte.plugins.Plugin,
pickerUI : null,
getFeatures : function() {
return [ ANCHOR_PICKER_FEATURE ];
},
initializeUI : function(tbGenerator) {
var plg = CUI.rte.plugins;
if (!this.isFeatureEnabled(ANCHOR_PICKER_FEATURE)) {
return;
}
this.pickerUI = tbGenerator.createElement(
ANCHOR_PICKER_FEATURE, this, false, {
title : "Anchor Plugin"
});
tbGenerator.addElement(GROUP, plg.Plugin.SORT_FORMAT,
this.pickerUI, 10);
var groupFeature = GROUP + "#" + ANCHOR_PICKER_FEATURE;
tbGenerator.registerIcon(groupFeature, "anchor");
},
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,
"a"), plugin = this, dialog, anchorval = $(tag)
.attr("href"), dm = ek.getDialogManager(), $container = CUI.rte.UIUtils
.getUIContainer($(context.root)), propConfig = {
'parameters' : {
'command' : this.pluginId + '#'
+ ANCHOR_PICKER_FEATURE
}
};
var cond1 = (anchorval != undefined);
var cond2 = (anchorval != null);
if (cond1 || cond2) {
anchorval = anchorval.substring(1);
}
if (this.aeAnchorPickerDialog) {
dialog = this.aeAnchorPickerDialog;
} else {
dialog = new AEAnchorPickerDialog();
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",
getPickerIFrameUrl(anchorval));
this.aeAnchorPickerDialog = 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(anchorval) {
var url = PICKER_URL + "?" + REQUESTER + "=" + GROUP;
if (!_.isEmpty(anchorval)) {
url = url + "&" + PICKER_NAME_IN_POPOVER + "="
+ anchorval;
}
console.log(url);
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);
plugin.aeAnchorPickerDialog = null;
} else if (action === "cancel") {
plugin.aeAnchorPickerDialog = null;
}
dialog.hide();
removeReceiveDataListener(receiveMessage);
}
},
// to mark the icon selected/deselected
updateState : function(selDef) {
var hasUC = this.editorKernel.queryState(
ANCHOR_PICKER_FEATURE, selDef);
if (this.pickerUI != null) {
this.pickerUI.setSelected(hasUC);
}
}
});
CUI.rte.plugins.PluginRegistry.register(GROUP, TouchUIAnchorPickerPlugin);
var TouchUIAnchorPickerCmd = new Class(
{
toString : "TouchUIAnchorPickerCmd",
extend : CUI.rte.commands.Command,
isCommand : function(cmdStr) {
return (cmdStr.toLowerCase() == ANCHOR_PICKER_FEATURE);
},
getProcessingOptions : function() {
var cmd = CUI.rte.commands.Command;
return cmd.PO_SELECTION | cmd.PO_BOOKMARK | cmd.PO_NODELIST;
},
_getTagObject : function(anchorval) {
return {
"tag" : "a",
"attributes" : {
"href" : "#" + anchorval
}
};
},
execute : function(execDef) {
var anchorval = 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(anchorval);
// if no anchorval value passed, assume delete and remove
// anchorval
if (_.isEmpty(anchorval)) {
nodeList.removeNodesByTag(execDef.editContext,
tagObj.tag, undefined, true);
return;
}
// remove existing anchorval before adding new anchorval
if (tags != null) {
nodeList.removeNodesByTag(execDef.editContext,
tagObj.tag, undefined, true);
nodeList.commonAncestor = nodeList.nodes[0].dom.parentNode;
}
var tags = common.getTagInPath(context,
selection.startNode, tagObj.tag, tagObj.attributes);
if (tags == null) {
nodeList.surround(execDef.editContext, tagObj.tag,
tagObj.attributes);
} else {
nodeList.removeNodesByTag(execDef.editContext,
tagObj.tag, tagObj.attributes, true);
}
}
});
CUI.rte.commands.CommandRegistry.register(ANCHOR_PICKER_FEATURE,
TouchUIAnchorPickerCmd);
function addPluginToDefaultUISettings() {
var toolbar = CUI.rte.ui.cui.DEFAULT_UI_SETTINGS.inline.toolbar;
toolbar.splice(3, 0, GROUP + "#" + ANCHOR_PICKER_FEATURE);
toolbar = CUI.rte.ui.cui.DEFAULT_UI_SETTINGS.fullscreen.toolbar;
toolbar.splice(3, 0, GROUP + "#" + ANCHOR_PICKER_FEATURE);
}
function addDialogTemplate() {
var url = PICKER_URL + "?" + REQUESTER + "=" + GROUP;
var html = "<iframe width='600px' 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-' + TCP_DIALOG] = CUI.rte.Templates['dlg-'
+ TCP_DIALOG] = Handlebars.compile(html);
}
}(jQuery, window.CUI, jQuery(document)));
(function($, $document) {
var SENDER = "adobe-explorers", REQUESTER = "requester", ANCHORVAL = "anchorvalue", ADD_ANCHOR_BUTTON = "#AELINK_ANCHOR_ADD", REMOVE_ANCHOR_BUTTON = "#AELINK_ANCHOR_REMOVE";
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").css("background-color", "#fff");
$dialog[0].open = true;
var $addAnchor = $dialog.find(ADD_ANCHOR_BUTTON), $removeAnchor = $dialog
.find(REMOVE_ANCHOR_BUTTON), anchorval = queryParameters()[ANCHORVAL];
if (!_.isEmpty(anchorval)) {
$("input[name='./anchorvalue']").val(anchorval);
}
adjustHeader($dialog);
$(ADD_ANCHOR_BUTTON).css("margin-left", "220px");
$addAnchor.click(sendDataMessage);
$removeAnchor.click(sendRemoveMessage);
}
function adjustHeader($dialog) {
var $header = $dialog.css("background-color", "#fff").find(
".coral3-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"
}, $dialog, anchorval;
$dialog = $(".cq-dialog");
anchorval = $dialog.find("[name='./" + ANCHORVAL + "']").val();
parent.postMessage(JSON.stringify(message), "*");
}
function sendDataMessage() {
var message = {
sender : SENDER,
action : "submit",
data : {}
}, $dialog, anchorval;
$dialog = $(".cq-dialog");
anchorval = $dialog.find("[name='./" + ANCHORVAL + "']").val();
message.data[ANCHORVAL] = anchorval;
parent.postMessage(JSON.stringify(message), "*");
}
})(jQuery, jQuery(document));
2. dialog-before-submit.js
(function(window, document, $, ns) {
"use strict";
var ui = $(window).adaptTo("foundation-ui");
var $document = $(document);
function gotoPageEditor(dialog) {
if (dialog.data("cqDialogReturntoreferral")){
window.location = document.referrer;
} else {
if (dialog.closest(".cq-dialog-page").length) {
window.location = dialog.data("cqDialogPageeditor");
} else {
dialog.remove();
}
}
$document.trigger("dialog-closed");
}
function _cancel($dialog) {
$dialog.trigger("dialog-beforeclose");
/**
* @deprecated Since 6.3
*/
// Still requested by external listeners
var $dialogForm = $dialog.find("form").eq(0);
$dialogForm.trigger("dialog-beforeclose");
gotoPageEditor($dialogForm);
}
$document.on("click", ".cq-dialog-cancel", function(e) {
e.preventDefault();
var $dialog = $(this).closest(".cq-Dialog");
_cancel($dialog);
});
$document.on("coral-overlay:beforeclose", ".cq-Dialog", function(e) {
// only triggered when the dialog is closed by the escape key
if ($(e.target).hasClass("cq-Dialog")) {
// components in the the dialog like select trigger this event as well
_cancel($(this));
}
});
$document.on("click", ".cq-dialog-layouttoggle", function(e) {
var dialog = this.closest("coral-dialog");
Granite.DialogUtils.unifySpacing(dialog);
e.preventDefault();
});
$document.on("click", ".cq-dialog-help", function(e) {
e.preventDefault();
var el = $(this);
window.open(el.data("href"), "_blank");
});
$document.on("foundation-form-submitted", ".cq-Dialog", function(e, status, xhr) {
if (status === true) {
var $dialog = $(this);
$document.trigger("dialog-success");
// Trigger an event 'dialog-beforeclose' which can be used by the contained
// fields to finish editing before the dialog closes. (CQ-63409)
// This event is triggered just before the dialog is surely being closed
$dialog.trigger("dialog-beforeclose");
/**
* @deprecated Since 6.3
*/
// Still requested by external listeners
var $dialogForm = $dialog.find("form").eq(0);
$dialogForm.trigger("dialog-beforeclose");
gotoPageEditor($dialog.find("form").eq(0));
} else {
$document.trigger("dialog-fail", xhr);
}
});
$document.on("foundation-contentloaded", function (event) {
// dialog may be the page properties form launched from the sites console
// or the .cq-dialog launched from authoring
var $dialog = $(event.target).find("#cq-sites-properties-form, .cq-dialog");
if ($dialog.length) {
var resourceType = $dialog.find("input[name='./sling:resourceType']").val();
Granite.DialogUtils.unifySpacing($dialog.parents("coral-dialog").get(0));
$document.trigger($.Event("dialog-loaded", {
dialog: $dialog,
resourceType: resourceType
}));
}
});
// Force blur on fields before submitting (CQ-55684)
// Listen on body because form submit is already intercepted to handle tags (see properties.js)
$("body").on("submit", ".cq-Dialog", function (event) {
var $dialog = $(this);
//changes by hemant start
$("input[name$='text']").val($dialog.find(".cq-RichText>.cq-RichText-editable").html());
//changes by hemant end
$dialog.find("input, textarea").blur();
});
})(window, document, Granite.$, Granite.author);
3. richtext.js
(function(window, document, $) {
"use strict";
var rteFixedColumnCss = "cq-RichText-FixedColumn-column";
var rteFixedColumnCssCompat = "coral-RichText-FixedColumn-column";
var DATA_RTE_INSTANCE = "rteinstance";
var startRTE = function($editable, options) {
var editorType = $editable.data("editorType"), rtePluginsDefaults, configCallBack;
var externalStyleSheets = $editable.data("externalStyleSheets"), index, $styleSheet, styleElements;
if (editorType === "table") {
rtePluginsDefaults = {
"useColPercentage": false,
"rtePlugins": {
"table": {
"features": "*",
"defaultValues": {
"width": "100%"
},
"editMode": CUI.rte.plugins.TablePlugin.EDITMODE_TABLE
}
}
};
configCallBack = function(config) {
return Granite.Util.applyDefaults({}, rtePluginsDefaults, config);
};
}
var rte = new CUI.RichText({
"element": $editable,
"componentType": editorType,
"preventCaretInitialize": true
});
if (externalStyleSheets && externalStyleSheets.length > 0) {
externalStyleSheets = externalStyleSheets.split(",");
for (index = 0; index < externalStyleSheets.length; index++) {
$styleSheet = $("head link[href='" + externalStyleSheets[index] +"']");
if ($styleSheet.length <= 0) {
$styleSheet = $("<link rel=\"stylesheet\" href=\"" + externalStyleSheets[index] + "\" type=\"text/css\">");
$("head").append($styleSheet);
styleElements = $editable.data("externalStyleElements");
if (!styleElements) {
styleElements = [$styleSheet];
} else {
styleElements.push($styleSheet);
}
$editable.data("externalStyleElements", styleElements);
}
}
}
CUI.rte.ConfigUtils.loadConfigAndStartEditing(rte, $editable, configCallBack);
};
$(document).on("foundation-contentloaded", function(e) {
var $container = $(e.target).hasClass(".cq-RichText") ? $(e.target) : $(e.target).find(".cq-RichText");
// Added in 6.4 to ensure Full BC (CQ-4231708)
// Should ideally be removed in 6.6
$container.each(function () {
var $this = $(this);
$this.closest("." + rteFixedColumnCss).addClass(rteFixedColumnCssCompat);
$this.closest("." + rteFixedColumnCssCompat + ":not(." + rteFixedColumnCss + ")").addClass(rteFixedColumnCss);
});
// Copy hidden text field value to RTE and stop implicit submission of form, when enter key is pressed in RTE UI.
// We don't put html value into RTE while rendering, otherwise, the linkchecker
// converts invalid links to image tags. (See CQ-4219770). So, we add it in the
// value attribute of hidden input field when rendering and copy it from there now
$container.each(function() {
var $this = $(this);
var $richTextDiv = $this.find(".cq-RichText-editable");
if (!$richTextDiv.data(DATA_RTE_INSTANCE)) {
var html = $this.find("input[type='hidden'][data-cq-richtext-input='true']").val();
$richTextDiv.empty().append(html);
}
$this.on("keypress", "input", function (e) {
if (e.keyCode === 13) {
e.preventDefault();
}
});
});
// Copy RTE text to hidden field
$container.on("change", "[data-cq-richtext-editable='true']", function() {
var el = $(this).closest(".cq-RichText");
var rteInstance = el.find(".cq-RichText-editable").data(DATA_RTE_INSTANCE);
el.find("input[type=hidden][data-cq-richtext-input='true']").val(rteInstance.getContent());
});
var $richTextDiv = $(e.target).find(".cq-RichText>.cq-RichText-editable");
$richTextDiv.each(function() {
var $this = $(this);
if ($this.data("customStart")) {
$this.on("rte-start", function() {
var $this = $(this);
if ($this.data("useFixedInlineToolbar") && !$this.data(DATA_RTE_INSTANCE)) {
var html = $(this).parent().find("input[type=hidden][data-cq-richtext-input='true']").val();
$this.empty().append(html);
startRTE($this);
}
});
} else {
if ($this.data("useFixedInlineToolbar") && !$this.data(DATA_RTE_INSTANCE)) {
startRTE($this);
}
}
$this.on("editing-start", function() {
var rte = $(this).data(DATA_RTE_INSTANCE);
var $this = $(this);
var $coralDialog = $this.closest("coral-dialog");
rte.editorKernel.getToolbar().hide();
if ($coralDialog.length && $coralDialog[0].fullscreen === true) {
switchToolbar("dialogFullScreen", rte);
}
$this.closest("coral-dialog-content").on("click", function(e) {
var $target = $(e.target);
if (!$target.closest(".cq-RichText").length) {
//[Workaround] CQ-4249635 : Safari doesn't blur selection from contenteditable when clicking on radio/checkbox
if (CUI.rte.Common.ua.isSafari && $target.is("input[type='radio'], input[type='checkbox']")) {
var context = rte.editorKernel.getEditContext();
var selection = CUI.rte.Selection.getSelection(context);
selection.removeAllRanges();
}
if (rte.useFixedInlineToolbar && !rte.sourceEditMode) {
rte.editorKernel.toolbar.hide();
}
}
});
});
$(this).on("click", function() {
var self = this;
$richTextDiv.each(function() {
var rte = $(this).data(DATA_RTE_INSTANCE);
if (this !== self && rte && !rte.sourceEditMode) {
rte.editorKernel.getToolbar().hide();
}
});
});
});
});
var rteFinish = function() {
var $this = $(this), index;
var rteInstance = $this.data(DATA_RTE_INSTANCE), styleElements = $this.data("externalStyleElements");
if (rteInstance) {
rteInstance.finish(false);
if (styleElements) {
for (index = 0; index < styleElements.length; index++) {
styleElements[index].remove();
}
}
$this.removeData(DATA_RTE_INSTANCE);
}
};
//changes by hemant start
var htmlContent='';
//changes by hemant end
$(document).on("dialog-beforeclose", ".cq-Dialog", function(e) {
//changes by hemant start
if(htmlContent===''){
htmlContent=$(this).closest(".cq-Dialog").find(".cq-RichText>.cq-RichText-editable").html();
}
$(this).find(".cq-RichText>.cq-RichText-editable").html(htmlContent);
//changes by hemant end
if (!$(e.target).hasClass("cq-Dialog")) {
// dialog currently throws dialog-beforeclose twice - once on form and once on coral-dialog element
// we need to only listen to event on coral-dialog
return;
}
$(this).find(".cq-RichText>.cq-RichText-editable").each(rteFinish);
});
$(document).on("dialog-layouttoggle-fullscreen", ".cq-Dialog", function(e) {
var $richTextDiv = $(e.target).find(".cq-RichText>.cq-RichText-editable");
$richTextDiv.each(function() {
var rte = $(this).data(DATA_RTE_INSTANCE);
if (rte) {
switchToolbar("dialogFullScreen", rte)
}
});
});
$(document).on("dialog-layouttoggle-floating", ".cq-Dialog", function(e) {
var $richTextDiv = $(e.target).find(".cq-RichText>.cq-RichText-editable");
$richTextDiv.each(function() {
var rte = $(this).data(DATA_RTE_INSTANCE);
if (rte) {
switchToolbar("inline", rte)
}
});
});
$(document).on("click", ".coral-Wizard-nextButton", function(e) {
$(this).closest(".foundation-form").find(".cq-RichText>.cq-RichText-editable").each(rteFinish);
});
function switchToolbar(toolbarType, rte) {
var ek = rte.editorKernel;
if (rte.sourceEditMode) {
ek.fireUIEvent('disablesourceedit');
}
if (!ek.hasBackgroundToolbar(toolbarType)) {
ek.addBackgroundToolbar({
"tbType": toolbarType,
"isFullScreen": ek.getEditContext().getState("fullscreenadapter").isFullScreen(),
"useFixedInlineToolbar": true
});
}
ek.setActiveToolbar(toolbarType);
}
CUI.rte.Theme.BLANK_IMAGE = Granite.HTTP.externalize("/libs/clientlibs/granite/richtext/resources/images/blank.png");
})(window, document, Granite.$);
Now, include the above created clientlibs to cq:dialog of text component by adding the property extraClientlibs[] | String | cq.authoring.dialog.all, core.aeexplorers.text
The plugin is now created and ready to use.
How to use ?
To create an anchor tag, select the text and click on Anchor Plugin
Fill in the data and click on Create button. The text will now behave as an anchor tag having href set to the tag.
To remove the anchor tag from a text, select the text and click on Anchor Plugin. In the anchor popover dialog, click on Remove button. The anchor tag will be removed from targeted text.
Note : To modify an existing anchor value, remove the existing anchor value by clicking on remove button and then add anchor to it.
To download the installable jcr package, click on the below button.
AEM provides OOTB OSGI configuration to enable the mailing service.This service is named as DAY CQ Mailing service. Here the configuration of the SMTP server to be used needs to be added. In this blog, we are going to see how can we use gmail SMTP server to enable the mailing service in AEM.
Click on Edit, to setup the configuration. Configure it as shown below –
SMTP Server Host Name
smtp.gmail.com
SMTP Server Port
465
SMTP User
<gmail address>
SMTP Password
<gmail password>
“From” address
<gmail address>
SMTP use SSL
Check this
SMTP use StartTLS
Don’t check
Debug email
Don’t check
Search for the config file using PID. Check in this config file into configuration code base to persist the configuration even after deployment. [com.day.cq.mailer.DefaultMailService.config]
# Configuration created by Apache Sling JCR Installer
smtp.password="secretPassword"
debug.email=B"false"
smtp.port=I"465"
smtp.user="adobeexplorers@gmail.com"
smtp.ssl=B"true"
smtp.starttls=B"false"
from.address="adobe-explorers@gmail.com"
smtp.host="smtp.gmail.com"