Goal
Extend the Link Dialog of Touch UI Rich Text Editor to add Coral Select widget for selecting rel attribute of anchor tag
For AEM 62 check this post
Demo | Package Install | Github
rel Attribute select in Link Dialog
rel Applied to Anchor Tag
AntiSamy considerations
Adding new attributes in anchor tag may result in the attributes skipped during page rendering or link dialog load; the following warning can be seen in error.log...
26.09.2017 12:40:42.804 *INFO* [0:0:0:0:0:0:0:1 [1506447642680] GET /content/we-retail/language-masters/en.html HTTP/1.1] org.apache.sling.xss.impl.HtmlToHtmlContentContext AntiSamy warning: The a tag contained an attribute that we could not process. The rel attribute had a value of "bookmark". This value could not be accepted for security reasons. We have chosen to remove this attribute from the tag and leave everything else in place so that we could process the input.
To make rel accepted, make the following changes in /apps/cq/xssprotection/config.xml (overlaying /libs/cq/xssprotection/config.xml), for Sightly/HTL its /libs/sling/xss/config.xml
Solution
1) Login to CRXDE Lite, create folder (nt:folder) /apps/eaem-touchui-extend-rte-link-options
2) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-touchui-extend-rte-link-options/clientlib and set property categories of String type to cq.authoring.dialog.all and dependencies String[] to lodash
3) Create file ( type nt:file ) /apps/eaem-touchui-extend-rte-link-options/clientlib/js.txt, add the following
link-options.js
4) Create file (type nt:file) /apps/eaem-touchui-extend-rte-link-options/clientlib/link-options.js, add the following code
(function ($) {
"use strict";
var _ = window._,
Class = window.Class,
CUI = window.CUI,
REL_FIELD = "rel",
RTE_LINK_DIALOG = "rtelinkdialog";
if(CUI.rte.ui.cui.CuiDialogHelper.eaemExtended){
return;
}
var EAEMLinkBaseDialog = new Class({
extend: CUI.rte.ui.cui.CQLinkBaseDialog,
toString: "EAEMLinkBaseDialog",
initialize: function(config) {
this.superClass.initialize.call(this, config);
this.$rteDialog = this.$container.find("[data-rte-dialog=link]");
this.$rteDialog.find(".rte-dialog-columnContainer:last").before(getLinkRelOptionsHtml());
},
dlgToModel: function() {
this.superClass.dlgToModel.call(this);
var relField = this.getFieldByType(REL_FIELD);
if(_.isEmpty(relField)){
return;
}
var relVal = relField.val();
if (_.isEmpty(relVal)) {
return;
}
this.objToEdit.attributes["rel"] = relVal;
},
dlgFromModel: function() {
this.superClass.dlgFromModel.call(this);
if(_.isEmpty(this.objToEdit.attributes)){
return;
}
var relValue = this.objToEdit.attributes['rel'];
if(_.isEmpty(relValue)){
return;
}
var relSelect = this.$rteDialog.find("[data-type='rel']")[0];
relSelect.items.getAll().forEach(function(elem) {
elem.selected = (elem.value === relValue);
});
}
});
CUI.rte.ui.cui.CuiDialogHelper = new Class({
extend: CUI.rte.ui.cui.CuiDialogHelper,
toString: "EAEMCuiDialogHelper",
instantiateDialog: function(dialogConfig) {
var type = dialogConfig.type;
if(type !== RTE_LINK_DIALOG){
this.superClass.instantiateDialog.call(this, dialogConfig);
return;
}
var $editable = $(this.editorKernel.getEditContext().root),
$container = CUI.rte.UIUtils.getUIContainer($editable),
dialog = new EAEMLinkBaseDialog();
dialog.attach(dialogConfig, $container, this.editorKernel);
return dialog;
}
});
function getLinkRelOptionsHtml(){
var html = "<div class='rte-dialog-columnContainer'>" +
"<div class='rte-dialog-column'>" +
"<coral-select data-type='rel' placeholder='Choose \"rel\" attribute'>";
var options = ["alternate", "author", "bookmark", "external", "help",
"license", "next", "nofollow", "noreferrer", "noopener", "prev", "search", "tag" ];
_.each(options, function(option){
html = html + getOptionHtml(option);
});
html = html + "</coral-select></div></div>";
return html;
function getOptionHtml(option){
return "<coral-select-item>" + option + "</coral-select-item>"
}
}
CUI.rte.ui.cui.CuiDialogHelper.eaemExtended = true;
})(jQuery);