AEM 61 - Touch UI Composite Multifield with Rich Text Editor (RTE)

Goal


Create a composite multifield comprised of rich text editors (widgets of type  cq/gui/components/authoring/dialog/richtext)

For AEM 62 check this post

Demo | Package Install




Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/touchui-rte-multifield

2) Create clientlib (type cq:ClientLibraryFolder/apps/touchui-rte-multifield/clientlib and set a property categories of String type to cq.authoring.dialogdependencies of type String[] with value underscore

3) Create file ( type nt:file ) /apps/touchui-rte-multifield/clientlib/js.txt, add the following

                         rte-multifield.js

4) Create file ( type nt:file ) /apps/touchui-rte-multifield/clientlib/rte-multifield.js, add the following code

(function () {
    var DATA_EAEM_NESTED = "data-eaem-nested";
    var CFFW = ".coral-Form-fieldwrapper";
    var RTE_CONTAINER = "richtext-container";

    function setSelect($field, value){
        var select = $field.closest(".coral-Select").data("select");

        if(select){
            select.setValue(value);
        }
    }

    function setHiddenOrRichText($field, value){
        $field.val(value);

        var $parent = $field.parent();

        if(!$parent.hasClass(RTE_CONTAINER)){
            return;
        }

        $field.next(".editable").empty().append(value);
    }

    function setCheckBox($field, value){
        $field.prop( "checked", $field.attr("value") == value);
    }

    //reads multifield data from server, creates the nested composite multifields and fills them
    function addDataInFields() {
        function getMultiFieldNames($multifields){
            var mNames = {}, mName;

            $multifields.each(function (i, multifield) {
                mName = $(multifield).children("[name$='@Delete']").attr("name");

                mName = mName.substring(0, mName.indexOf("@"));

                mName = mName.substring(2);

                mNames[mName] = $(multifield);
            });

            return mNames;
        }

        function buildMultiField(data, $multifield, mName){
            if(_.isEmpty(mName) || _.isEmpty(data)){
                return;
            }

            _.each(data, function(value, key){
                if(key == "jcr:primaryType"){
                    return;
                }

                $multifield.find(".js-coral-Multifield-add").click();

                _.each(value, function(fValue, fKey){
                    if(fKey == "jcr:primaryType"){
                        return;
                    }

                    var $field = $multifield.find("[name='./" + fKey + "']").last(),
                        type = $field.prop("type");

                    if(_.isEmpty($field)){
                        return;
                    }

                    //handle single selection dropdown
                    if(type == "select-one"){
                        setSelect($field, fValue);
                    }else if(type == "checkbox"){
                        setCheckBox($field, fValue);
                    }else if(type == "hidden"){
                        setHiddenOrRichText($field, fValue);
                    }else{
                        $field.val(fValue);
                    }
                });
            });
        }

        $(document).on("dialog-ready", function() {
            var $multifields = $("[" + DATA_EAEM_NESTED + "]");

            if(_.isEmpty($multifields)){
                return;
            }

            var mNames = getMultiFieldNames($multifields),
                $form = $(".cq-dialog"),
                actionUrl = $form.attr("action") + ".infinity.json";

            $.ajax(actionUrl).done(postProcess);

            function postProcess(data){
                _.each(mNames, function($multifield, mName){
                    buildMultiField(data[mName], $multifield, mName);
                });
            }
        });
    }

    //collect data from widgets in multifield and POST them to CRX
    function collectDataFromFields(){
        function fillValue($form, fieldSetName, $field, counter){
            var name = $field.attr("name");

            if (!name) {
                return;
            }

            //strip ./
            if (name.indexOf("./") == 0) {
                name = name.substring(2);
            }

            var value = $field.val();

            if( $field.prop("type") == "checkbox" ){
                value = $field.prop("checked") ? $field.val() : "";
            }

            $('<input />').attr('type', 'hidden')
                .attr('name', fieldSetName + "/" + counter + "/" + name)
                .attr('value', value )
                .appendTo($form);

            //remove the field, so that individual values are not POSTed
            $field.remove();
        }

        $(document).on("click", ".cq-dialog-submit", function () {
            var $multifields = $("[" + DATA_EAEM_NESTED + "]");

            if(_.isEmpty($multifields)){
                return;
            }

            var $form = $(this).closest("form.foundation-form"),
                $fieldSets, $fields;

            $multifields.each(function(i, multifield){
                $fieldSets = $(multifield).find("[class='coral-Form-fieldset']");

                $fieldSets.each(function (counter, fieldSet) {
                    $fields = $(fieldSet).children().children(CFFW);

                    $fields.each(function (j, field) {
                        fillValue($form, $(fieldSet).data("name"), $(field).find("[name]"), (counter + 1));
                    });
                });
            });
        });
    }

    $(document).ready(function () {
        addDataInFields();
        collectDataFromFields();
    });
})();

25 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thanks for the post Sreekanth.
    Could you please let me know if there is a way to add plugins to the RTE. I tried adding paraformat, styles and special char plugins to the component attached here, but could not see them while editing.

    ReplyDelete
    Replies
    1. hi Srikanth, can you upload the dialog xml to google drive or dropbox and post the link here....

      Delete
    2. Hi Sreekanth,
      Here is the dropbox link to touch ui dialog package.
      https://www.dropbox.com/sh/ua5sa6h5rczfpnb/AACUTq9rNfX0-C-GoRMUpVcqa?dl=0

      Delete
    3. you can do something like this for adding plugins to RTE:
      https://paste.ubuntu.com/24236317/

      Delete
  3. Hi Sreekanth,
    I don't see my custom rtePlugin configuration in the dialog
    https://www.dropbox.com/s/9281412i90tk95n/Attachment.zip?dl=0

    ReplyDelete
  4. Hi Sreekant , Is it possible to provide the height to the rich text editor ?? how ??

    ReplyDelete
  5. Do you have a sightly version? When I try to display the result using sightly, it retains the html characters.

    ReplyDelete
    Replies
    1. Hi Jonathan,
      Set the display context to 'html' so that content is free of html tags. For example ${properties.description @ context = 'html'}

      Delete
    2. Thank you Srikanth. That worked.

      Delete
  6. Has anyone been able to get the RTE plugins to appear when the editor is inside of a TouchUI dialog?

    ReplyDelete
  7. i am also not able to see custom RTE plugins

    ReplyDelete
  8. how to add paragraph formats of H1 H2 i tried the same way srikant pogula tried but its not coming

    ReplyDelete
  9. hi, with the cq-6.1.0-featurepack-6563-1.0.0.zip the dialog load dont fill the RTE field. have a fix?

    ReplyDelete
  10. Hi, ive found your post very useful, but there is a way to add rtePlugins to this richtexts textfields? Because i have already tried a million ways and i cannot achieve any results, if there is a way, could you please show me how to do it?

    my email is: rgabrielruiz@gmail.com

    ReplyDelete
  11. Hi, I have a rich text field which is part of multi field in classic UI as well as touch UI. When I enter values in rich text field of classic UI, it doesn't load the very same values in rich text editor of touch UI. It remains blank in touch UI.
    Note: This issue occurs only when the rich text editor is present in multi field.

    Any solution for this ?

    ReplyDelete
  12. This code is not working for RTE in the multifield. This throws script error with longer execution time and breaks the page

    ReplyDelete
  13. Thanks to Sreekanth for this sample. We had a requirement of multifield touch ui but data to be persisted as an array of fields rather than separate child nodes. I have modified the library to suit my requirement and available here.

    https://drive.google.com/file/d/0B6B1_xLyCcy6cElsblhRTjgyT0k/view?usp=sharing

    Sharing if anyone else have similar requirement.

    ReplyDelete
    Replies
    1. Hi, I used ur shared component but after that classic UI breaks, due u have something which works both on classic as well as touch UI

      Delete
  14. HI Sreekanth,

    Is there any method to restrict the items in the multifield??

    Thanks,
    Aswathi

    ReplyDelete
    Replies
    1. Aswathi - http://experience-aem.blogspot.com/2015/11/aem-61-sample-granite-widget-in-touch-ui-extending-multifield-to-limit-items.html

      Delete
  15. Hi Sreekanth,

    Can you please let me know which AEM this plugin supports, its 6.2 or 6.1

    ReplyDelete