Expand my Community achievements bar.

SOLVED

Customising RTE Plugin for uploadasset

Avatar

Level 3

Dear All,

 

I am customizing RTE plugin  by following blog https://aemlab.blogspot.com/2019/07/aem-rte-custom-plugins-1.html for upload asset and facing below two issues.

 

1) My upload ICON should come as below highlighted in yellow but it is not coming.

 

subnaik_0-1681313498793.png

 

I have written below JavaScript and added below node in RTE plugins as below.

 

************ BELOW JAVASCRIPT *************

 

(function ($, $document) {
    console.log("inside asset upload");
    var EAEM_PLUGIN_ID = "assetuploadButton",
        EAEM_ASSETUPLOAD_FEATURE = "assetUploadButton",
        EAEM_ASSETUPLOAD_ICON = EAEM_PLUGIN_ID + "#" + EAEM_ASSETUPLOAD_FEATURE,
        BUTTON_FORM_URL = "/apps/cfm-rte-plugins/rte-assetUpload-form.html",
        SENDER = "experience-aem-button", REQUESTER = "requester", $eaemButtonFormModal;
    var url = document.location.pathname;

    console.log("EAEM_ASSETUPLOAD_ICON ==== " + EAEM_ASSETUPLOAD_ICON);
    var assetUploadPath;

    var SUPPORTED_TYPES = [
        {
            "type": "image",
            "mimeTypeDetector": function (mimeType) {
                if (CUI.rte.Common.strStartsWith(mimeType, "image/")) {
                    return true;
                }
                return false;
            },
            createHTML: function (path) {
                return "<img src=\"" + encodeURI(path) + "\">";
            }
        }, {
            "type": "video",
            "mimeTypeDetector": function (mimeType) {
                if (CUI.rte.Common.strStartsWith(mimeType, "video/")) {
                    return true;
                }
                return false;
            },
            createHTML: function (path) {
                return "<video src=\"" + path + "\" controls=\"controls\"></video>";
            }
        }
    ];

    if (url.indexOf("/editor.html") == 0) {
        extendButtonPlugin();
        registerPlugin();
    } else if (url.indexOf(BUTTON_FORM_URL) == 0) {
        handleForm();
    }

    function handleForm() {
        $document.on("foundation-contentloaded", fillDefaultValues);

        setTimeout(function () {
            $('a[data-foundation-wizard-control-action="cancel"]').click(sendCancelMessage);
            $('button[data-foundation-wizard-control-action="next"]').hide();
            validateForm();
        }, 100);
    }
    function replaceLastString(str) {
        var myArr = str.split("/");
        var lastIndex = str.lastIndexOf("/");
        str = str.slice(0, lastIndex);
        return str;
    }

    function initSelectBehavior($form) {
        $(window.document).unbind("foundation-validation-valid");
        $(window.document).unbind("foundation-validation");

        var $form = $("coral-panel");
        $form.addClass("coral-Form coral-Form--vertical foundation-layout-util-maximized-container");

        $form.find('button[data-foundation-wizard-control-action="next"]').prop('disabled', true);

        var $buttonSelect = $form.find('coral-select[name="button_select"]');
        $buttonSelect[0].addEventListener('change', function (event) {
            validateForm();
        });

        assetUploadPath = getParent().location.pathname.replace("/editor.html", "").replace(getcontentFragmentType(), "assets/images");
        assetUploadPath = replaceLastString(assetUploadPath);

        var $altTextInput = $form.find('input[name="altText"]');
        $altTextInput.on('change', validateForm);

        var $assetNameInput = $form.find('input[name="assetName"]');
        $assetNameInput.on("change", function (event) {
            if (validateAssetName(this.value)) {
                addOrReplaceInCustomPatameter(document.querySelector('coral-fileupload[name="file"]')._uploadQueue[0], "fileName", this.value);
            }
            validateForm();
        });

        var $rteAssetUpload = $('coral-fileupload[name="file"]');
        $rteAssetUpload.attr('action', assetUploadPath + '.createasset.html');


        $assetNameInput.parent().appendTo($rteAssetUpload);
        $altTextInput.parent().appendTo($rteAssetUpload);

        var uploadButton = new Coral.Button().set({
            label: {
                innerHTML: "Upload Asset"
            },
            icon: "upload",
            iconSize: "S",
            id: 'uploadButton',
            class: 'coral3-Button coral3-Button--secondary',
            size: 'S',
            variant: 'secondary',
            title: 'Upload Asset',
            type: 'button'
        });
        $(uploadButton).attr('coral-fileupload-submit', '');
        $(uploadButton).appendTo($rteAssetUpload);
		uploadButton.on('click', function (event){
				var loadingDialog = FORM.createLoadingModal();
				loadingDialog.show();
        		});
        $rteAssetUpload.width('100%');
        $rteAssetUpload.on('coral-fileupload:fileadded', function (event) {
            //validate/change filename                  
            var item = event.detail.item;
            var isAssetNameValid = validateAssetName(item.file.name);

            var $assetName = $('input[name="assetName"]');
            if (!isAssetNameValid) {
                $assetName.addClass('is-invalid');
                $(uploadButton).prop('disabled', true);
            } else {
                $assetName.removeClass('is-invalid');
                $(uploadButton).prop('disabled', false);
                addOrReplaceInCustomPatameter(item, "fileName", item.file.name);
            }

            $assetName.val(item.file.name);
        });
        $rteAssetUpload.on('coral-fileupload:load', function (event) {

            var item = event.detail.item;
            var altText = $('input[name="altText"]').val();
            //alert("altText is : " + altText);
            if (item.status === 200) {

                var assetPath = assetUploadPath + '/' + item.name;

                $.ajax({
                    type: 'GET',
                    url: '/bin/updateproperty',
                    data: {
                        assetpath: assetPath,
                        AltText: altText
                    },
                    dataType: 'json',
                    success: function (data) {
                        console.log("success");
                    }
                });


                var message = {
                    sender: SENDER,
                    action: "submit",
                    data: {}
                };
                message.assetPath = assetPath;
                parent.postMessage(JSON.stringify(message), "*");

            }
            if (item._xhr.statusText !== "OK") {
                var errorDialog = document.querySelector('#uploadErrorDialog');
				loadingDialog.hide();
                errorDialog.show();
            }
        });
        $rteAssetUpload.parent().hide();
        function addOrReplaceInCustomPatameter(item, name, value) {
            item.parameters = item.parameters ? item.parameters : [];
            var isPresent = false;
            item.parameters.forEach(function (itm) {
                isPresent = true;
                if (itm.name === name) {
                    itm.value = value;
                }
            });
            if (!isPresent) {
                item.parameters.push({
                    name: name,
                    value: value
                });
            }

            // Specific handling for file name. As file object also contains name
            if (name === "fileName") {
                item.name = value;
            }
        };
    }

    function getcontentFragmentType() {
        return getParent().location.pathname.split("/")[6];
    }
    function validateForm() {

        $assetName = $('input[name="assetName"]');
        var isAssetNameValid = validateAssetName($assetName.val());
        $rteAssetUpload = $('coral-fileupload[name="file"]');
        if (!isAssetNameValid) {
            $assetName.addClass('is-invalid');
            $('#uploadButton').prop('disabled', true);
        } else {
            $assetName.removeClass('is-invalid');
            $('#uploadButton').prop('disabled', false);
            addOrReplaceInCustomPatameter($rteAssetUpload, "fileName", $assetName.val());
        }


        $buttonSelect = $('coral-select[name="button_select"]');
        if ($buttonSelect[0].selectedItem.value !== '') {
            $buttonSelect.prop('invalid', false);
            $rteAssetUpload.parent().show();
            setTimeout(function () { $buttonSelect.prop('invalid', false); });
            if ($buttonSelect[0].selectedItem.value === 'Image') {
                $('input[name="altText"]').parent().show();
                $rteAssetUpload.attr('accept', 'image/*');

                assetUploadPath = getParent().location.pathname.replace("/editor.html", "").replace(getcontentFragmentType(), "assets/images");
                assetUploadPath = replaceLastString(assetUploadPath);
                $rteAssetUpload.attr('action', assetUploadPath + '.createasset.html');
            }
            else {
                $rteAssetUpload.attr('accept', 'video/*');
                $('input[name="altText"]').val('');
                $('input[name="altText"]').parent().hide();               
                assetUploadPath = getParent().location.pathname.replace("/editor.html", "").replace(getcontentFragmentType(), "assets/videos");
                assetUploadPath = replaceLastString(assetUploadPath);
                $rteAssetUpload.attr('action', assetUploadPath + '.createasset.html');
            }
        } else {

            setTimeout(function () { $buttonSelect.prop('invalid', true); });
            $rteAssetUpload.parent().hide();
            $buttonSelect.prop('invalid', true);
            $('#uploadButton').prop('disabled', true);
        }

    }
    function addOrReplaceInCustomPatameter(item, name, value) {
        item.parameters = item.parameters ? item.parameters : [];
        var isPresent = false;
        item.parameters.forEach(function (itm) {
            isPresent = true;
            if (itm.name === name) {
                itm.value = value;
            }
        });
        if (!isPresent) {
            item.parameters.push({
                name: name,
                value: value
            });
        }

        // Specific handling for file name. As file object also contains name
        if (name === "fileName") {
            item.name = value;
        }
    }
    function validateAssetName(assetName) {
        var illegalCharacters = ["*", "/", ":", "[", "\\", "]", "|", "#", "%", "{", "}", "?", "`", "‘", "’", "'", "!", "$", "<", ">", "~", "@", "&", "^", "+", "=", ",", "é", "à", "è", "ù", "â", "ê", "î", "ô", "û", "ä", "ë", "ü", "ç", "ó", "ï", "Ç", "œ", "«", "»", ";", "æ", "€", "—", "–", "À", "Â",
            "Ä", "Æ", "Ç", "È", "É", "Ê", "Ë", "Î", "Ï", "Ô", "Œ", "Ù", "Û", "Ü", " "];
        var pattern = /\.[0-9a-z]{3,4}$/i;
        if (typeof assetName === "string") {
            if (contains(assetName, illegalCharacters) || !assetName.match(pattern)) {
                return false;
            } else {
                return true;
            }
        }
    }
    function contains(str, chars) {
        for (var i = 0; i < chars.length; i++) {
            if (str.indexOf(chars[i]) > -1) {
                return true;
            }
        }
        return false;
    }
    function fillDefaultValues() {
        var $form = $("coral-panel"),
            form = $("form")[0];

        initSelectBehavior($form);
    }

    function sendCancelMessage() {
        var message = {
            sender: SENDER,
            action: "cancel"
        };

        getParent().postMessage(JSON.stringify(message), "*");
    }

    function getParent() {
        if (window.opener) {
            return window.opener;
        }

        return parent;
    }

    function closePicker(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") {
            if (message.assetPath !== undefined) {


                getData(message.assetPath, function (assetToInsert) {
                    // create HTML and insert it
                    if (assetToInsert) {
                        var assetPath = assetToInsert.path;
                        var type = assetToInsert.type;
                        var html = type.createHTML(assetPath);
                        $eaemButtonFormModal.eaemButtonPlugin.editorKernel.execCmd("insertprocessed", html);

                    } else {
                        // TODO error handling?
                    }
                    if ($eaemButtonFormModal) {
                        var modal = $eaemButtonFormModal.data('modal');
                        modal.hide();
                        modal.$element.remove();
                    }
                    var uploadAssetSuccessDialog = new Coral.Dialog().set({
                        id: "uploadAssetSuccessDialog",
                        header: {
                            innerHTML: Granite.I18n.get('Asset Uploaded')
                        },
                        backdrop: Coral.Dialog.backdrop.STATIC,
                        content: {
                            innerHTML:
                                `Your asset is saved at ${assetPath || message.assetPath}`
                        },
                        footer: {
                            innerHTML: "<button is=\"coral-button\" variant=\"primary\" coral-close=\"\" class=\"coral3-Button coral3-Button--primary\" size=\"M\"><coral-button-label>Ok</coral-button-label></button>"
                        },
                        variant: "success"
                    });
					var loadingDialog = FORM.createLoadingModal();
					loadingDialog.hide();
                    uploadAssetSuccessDialog.show();
                });
            }
        }

        if (action === "cancel") {
            if ($eaemButtonFormModal) {
                var modal = $eaemButtonFormModal.data('modal');
                modal.hide();
                modal.$element.remove();
            }
        }
    }

    function getMetaData(data) {
        var metaData = undefined;
        if (data.hasOwnProperty("jcr:content")) {
            metaData = data["jcr:content"]["metadata"];
        }
        return metaData;
    }

    function getAssetTypeFromMimeType(mimeType) {
        if (!mimeType) {
            return undefined;
        }
        for (var t = 0; t < SUPPORTED_TYPES.length; t++) {
            var type = SUPPORTED_TYPES[t];
            if (type.mimeTypeDetector(mimeType)) {
                return type;
            }
        }
        return undefined;
    }
    function getData(path, callback) {
        $.ajax(path + ".2.json", {
            success: function (data) {
                var assetData = undefined;
                if (data) {
                    if (data["jcr:primaryType"] === "dam:Asset") {
                        var metaData = getMetaData(data);
                        if (metaData) {
                            var mimeType = metaData["dam:MIMEtype"]
                                || metaData["dc:format"];
                            var assetType = getAssetTypeFromMimeType(mimeType);
                            if (assetType) {
                                assetData = {
                                    "type": assetType,
                                    "path": path,
                                    "metaData": metaData
                                };
                            }
                        }
                    }
                }
                if (callback) {
                    callback(assetData);
                }
            },
            error: function () {
                if (callback) {
                    callback(undefined);
                }
            }
        });
    }

    function extendButtonPlugin() {
        var origFn = Dam.CFM.StyledTextEditor.prototype._start;

        Dam.CFM.StyledTextEditor.prototype._start = function () {
            addRTEPluginSettings(this);
            origFn.call(this);
        }
    }

    function addRTEPluginSettings(editor) {
        var config = editor.$editable.data("config");

        config.rtePlugins[EAEM_PLUGIN_ID] = {
            features: "*"
        };

        config.uiSettings.cui.multieditorFullscreen.toolbar.push(EAEM_ASSETUPLOAD_ICON);
    }

    function registerPlugin() {
        var EAEM_CFM_ASSETUPLOAD_PLUGIN = new Class({
            toString: "eaemCFMUploadPlugin",

            extend: CUI.rte.plugins.Plugin,

            buttonFormUI: null,

            getFeatures: function () {
                return [EAEM_ASSETUPLOAD_FEATURE];
            },

            notifyPluginConfig: function (pluginConfig) {
                var defaults = {
                    tooltips: {}
                };

                defaults.tooltips[EAEM_ASSETUPLOAD_FEATURE] = {
                    title: "Upload Asset from your desktop..."
                };

                CUI.rte.Utils.applyDefaults(pluginConfig, defaults);

                this.config = pluginConfig;
            },

            initializeUI: function (tbGenerator) {
                if (!this.isFeatureEnabled(EAEM_ASSETUPLOAD_FEATURE)) {
                    return;
                }

                this.buttonFormUI = new tbGenerator.createElement(EAEM_ASSETUPLOAD_FEATURE, this, false,
                    this.config.tooltips[EAEM_ASSETUPLOAD_FEATURE]);

                tbGenerator.addElement(EAEM_ASSETUPLOAD_FEATURE, 999, this.buttonFormUI, 999);

                if (tbGenerator.registerIcon) {
                    tbGenerator.registerIcon(EAEM_ASSETUPLOAD_ICON, "upload");
                }

                $(window).off('message', closePicker).on('message', closePicker);
            },

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

            execute: function (pluginCommand, value, envOptions) {
                var context = envOptions.editContext;

                if (pluginCommand != EAEM_ASSETUPLOAD_FEATURE) {
                    return;
                }

                var selection = CUI.rte.Selection.createProcessingSelection(context),
                    ek = this.editorKernel, startNode = selection.startNode;

                var winSel = window.getSelection();

                if (winSel && winSel.rangeCount == 1 && winSel.getRangeAt(0).toString().length == 0 && ($(window.getSelection().baseNode).prop('tagName') !== 'A' && $(window.getSelection().baseNode).parent().prop("tagName") !== 'A')) {
                    if ((selection.startOffset === startNode.length) && (startNode != selection.endNode)) {
                        startNode = startNode.nextSibling;
                    }

                    this.showModal(this.getButtonFormFrameUrl());
                }
            },

            showModal: function (url) {
                var self = this, $iframe = $('<iframe id="rteAssetUploadFrame">'),
                    $modal = $('<div>').addClass('eaem-cfm-font-size-rte coral-Modal');

                $iframe.attr('src', url).appendTo($modal);

                $modal.appendTo('body').modal({
                    type: 'default',
                    buttons: [],
                    visible: true
                });

                $eaemButtonFormModal = $modal;

                $eaemButtonFormModal.eaemButtonPlugin = self;

                $modal.nextAll(".coral-Modal-backdrop").addClass("cfm-coral2-backdrop-rte");
            },

            getButtonFormFrameUrl: function () {
                return Granite.HTTP.externalize(BUTTON_FORM_URL) + "?" + REQUESTER + "=" + SENDER;
            },

            updateState: function (selDef) {
                var hasUC = this.editorKernel.queryState(EAEM_ASSETUPLOAD_FEATURE, selDef);

                if (this.buttonFormUI != null && this.buttonFormUI.$ui != null) {
                    var winSel = window.getSelection(),
                        isTextSelected = winSel && winSel.rangeCount == 1 && winSel.getRangeAt(0).toString().length == 0 && ($(window.getSelection().baseNode).prop('tagName') !== 'A' && $(window.getSelection().baseNode).parent().prop("tagName") !== 'A');
                    isTextSelected ? this.buttonFormUI.$ui.removeClass('is-disabled') : this.buttonFormUI.$ui.addClass('is-disabled');
                    this.buttonFormUI.setSelected(isTextSelected);
                }
            }
        });

        CUI.rte.plugins.PluginRegistry.register(EAEM_PLUGIN_ID, EAEM_CFM_ASSETUPLOAD_PLUGIN);
    }
}(jQuery, jQuery(document)));

 

and I have added below highlighted in yellow in RTE Plugins

 

subnaik_1-1681313780400.png

 

and then I have added assetupload#assetUploadButton  in both inline and dialogFullscreen under UIsettings , as shown below.

 

subnaik_2-1681313860768.png

 

But after adding all upload asset ICON is coming blank , as shown below

 

subnaik_3-1681314012747.png

 

2) The second issue is that I am getting below error in my console for dam is not defined for button plugin as shown below.

 

subnaik_4-1681314176516.png

 

 

function extendButtonPlugin() {
var origFn = Dam.CFM.StyledTextEditor.prototype._start;

 

Can anybody please help me here.

 

 

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

It seems the problem is in your code. Maybe the "selection" is getting null so that "startNode" is not going to be read as a property. Please do some debugging in your code. I hope you will find the problem asap.

 

Thanks.

View solution in original post

3 Replies

Avatar

Community Advisor

Hello @subnaik

If everything is ok that means you have registered the icon properly and added "assetupload#assetUploadButton" properly you can check this thing for you "icon" not showing issue

You may have a category for your custom RTE plugin

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
          jcr:primaryType="cq:ClientLibraryFolder"
          allowProxy="{Boolean}true"
          categories="[your.custom.rte-upload-plugin]"/>

You need to add this category into your "Text" component's dialog by extraClientlib

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/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"
    extraClientlibs="[your.custom.rte-upload-plugin]">

 

Avatar

Level 3

@AsifChowdhury  Thanks for your reply.

 

Now my icon is coming fine after I add below in category but my function is not working properly and upload asset is going to back , as shown below

 

subnaik_0-1681379912849.png

 

 

Upload Asset is coming as below.

 

subnaik_1-1681380189892.png

 

and getting below error in console for js.

 

subnaik_2-1681380250470.png

 

var selection = CUI.rte.Selection.createProcessingSelection(context),
ek = this.editorKernel, startNode = selection.startNode;

 

Also can we call upload asset (dam library) under RTE Plugin in AEM 6.5 ?

Avatar

Correct answer by
Community Advisor

It seems the problem is in your code. Maybe the "selection" is getting null so that "startNode" is not going to be read as a property. Please do some debugging in your code. I hope you will find the problem asap.

 

Thanks.