AEM 63 - Touch UI Extend Rich Text Link Dialog, Add Rel Attribute Select

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




7 comments:

  1. Hi Sreekanth,
    It's awesome concept, it's works fine in my local server. But same is not working my production server in author instance, it's working in my production server in publish server. I think xssprotection have some restriction for security reasons. could you please give me proper solution for production author server.

    ReplyDelete
    Replies
    1. if its being saved properly in jcr and attributes are not showing in RTE editor, then you might need to disable XSS filtering in your edit dialog. You can do this for RTE by adding the proeprty disableXSSfiltering={Boolean}true to your text node (where the sling resource type for RTE is). Also recommend to do this in you cq:inplaceEditing config node.

      Delete
  2. Hi Sreekanth,

    I need to add custom 'overlay' option in Target dropdown in link dialog. Can you please suggest how to do that.

    ReplyDelete
  3. hi i want to remove p tags which are crated by rte i'm using removeSingleParagraphContainer property but there in no use with that can u help out how to remove p tags

    ReplyDelete
  4. Hi Sreekanth,
    This is perfect, can you share the similar customization for RTE Image plugin as well?

    ReplyDelete
  5. Hi Sreekanth,
    I want to remove the .html extension from RTE at content fragment level

    ReplyDelete
  6. On dialog edit mode, is enough to add disableXSSfiltering={Boolean}true BUT if you want to publish the content, another XSS saniziation will occur and the rel attribute from content page will be removed. In order to fix this, I was able to edit the XSS config into CRX /libs/cq/xssprotection/config.xm. You have to search for and under this object config you will find the rules for rel attribute . By default only nofollow value is allowed but you can add all possible values or

    ReplyDelete