AEM 62 - Touch UI Rich Text Editor InPlace Editing perform Spell Check before Save

Goal


Touch UI Rich Text Editor In Place Editing - perform Spell Check on the edited content before saving it to CRX.

Out of the box spell check plugin is available in InPlace editing full screen mode (enable the plugin in rtePlugins eg. /libs/foundation/components/text/dialog/items/tab1/items/text/rtePlugins/spellcheck); With the plugin enabled, user has to explicitly click on the following plugin button before saving, to do the spell check on content...



This extension listens to the beforeFinish event of InPlace Editing to do the spellcheck, relieving user from the manual task of clicking spellcheck button each time; provides spell check functionality in inline mode as well

Spellcheck DOESN'T need to be enabled (in rtePlugins) for this extension to work

Demo | Package Install




Solution


1) Login to CRXDE Lite (http://localhost:4502/crx/de) and create folder /apps/eaem-touchui-rte-spellcheck-before-save

2) Create node /apps/eaem-touchui-rte-spellcheck-before-save/clientlib of type cq:ClientLibraryFolder and add a String property categories with value cq.authoring.dialog and dependencies to underscore

3) Create file (nt:file) /apps/eaem-touchui-rte-spellcheck-before-save/clientlib/js.txt and add

                       inline-edit-spellcheck-before-save.js

4) Create file (nt:file) /apps/eaem-touchui-rte-spellcheck-before-save/clientlib/inline-edit-spellcheck-before-save.js and add the following code

(function ($, $document, gAuthor) {
    if(!gAuthor){
        return;
    }

    var SPELL_CHECK_URL = "/libs/cq/ui/rte/spellcheck",
        currentEditable = null, doSpellCheck = true;

    $document.on("cq-editables-loaded", function(event){
        $.each(event.editables, function(index, editable){
            if(!editable.dom || !isInPlaceEditingEnabled(editable)){
                return;
            }

            editable.dom.on("editing-start", getEditStartedListener(editable));
        });
    });

    $document.on("inline-edit-finish", function (event) {
        event.editable.dom.on("editing-start", getEditStartedListener(event.editable));
    });

    function isInPlaceEditingEnabled(editable){
        try{
            var editConfig = editable.config.editConfig;
            return editConfig && editConfig.inplaceEditingConfig && editConfig.inplaceEditingConfig.active;
        }catch(err){
            return false;
        }
    }

    function getEditStartedListener(editable){
        var gRegistry = Granite.author.editor.registry,
            emptyFn = function(){};

        if(_.isEmpty(gRegistry)){
            console.log("EAEM - Granite author registry not available");
            return emptyFn;
        }

        var inlineTextEditor = gRegistry["text"];

        if(!inlineTextEditor){
            console.log("EAEM - Granite author rte not available");
            return emptyFn;
        }

        return function eaemEditStartedListener(){
            if(!inlineTextEditor.rte){
                return;
            }

            currentEditable = editable;

            doSpellCheck = true;

            var listeners = inlineTextEditor.rte.options.listeners,
                beforeFinishFn = listeners["beforeFinish"],
                onStartedFn = listeners["onStarted"];

            if(!beforeFinishFn){
                listeners["beforeFinish"] = eaemBeforeFinishListener;
            }else{
                listeners["beforeFinish"] = function(){
                    eaemBeforeFinishListener();
                    beforeFinishFn();
                }
            }

            if(!onStartedFn){
                listeners["onStarted"] = eaemEditStartedListener;
            }else{
                listeners["onStarted"] = function(){
                    eaemEditStartedListener();
                    onStartedFn();
                }
            }
        }
    }

    function eaemBeforeFinishListener(){
        return performSpellCheck(this.getContent());
    }

    function performSpellCheck(content){
        if(!doSpellCheck){
            return false;
        }

        var doNotSave = false;

        $.ajax({
            async: false,
            url: SPELL_CHECK_URL,
            data: {
                "_charset_": "utf-8",
                "mode": "text",
                "html": "true",
                "text": content
            }
        }).done(handler);

        function handler(spellCheckResults){
            if(_.isEmpty(spellCheckResults.words)){
                return;
            }

            var spellCheckPlugin = getMockSpellCheckPlugin();
            spellCheckPlugin.checkSuccess(spellCheckResults);

            showMessageBox("Spell check found mistakes...", "Spellcheck");

            doNotSave = true;
        }

        return doNotSave;
    }

    function getMockSpellCheckPlugin(){
        var inlineTextEditor = Granite.author.editor.registry["text"],
            spellCheckPlugin = new CUI.rte.plugins.SpellCheckerPlugin(inlineTextEditor.rte.editorKernel, "spellcheck");

        spellCheckPlugin.config = {
            "invalidStyle": "border-bottom: dotted red;"
        };

        spellCheckPlugin.checkTextUI = {
            setHighlighted: function(){}
        };

        return spellCheckPlugin;
    }

    function showMessageBox(message, title){
        var fui = $(window).adaptTo("foundation-ui"),
            options = [{
                id: "RE-EDIT",
                text: "RE-EDIT",
                primary: true
            },{
                id: "SAVE",
                text: "SAVE",
                warning: true
            }];

        message = message || "Message";
        title = title || "Title";

        fui.prompt(title, message, "error", options, handler);

        function handler(btnId){
            var inlineTextEditor = Granite.author.editor.registry["text"];

            doSpellCheck = false;

            if (btnId === "SAVE") {
                inlineTextEditor.rte.editorKernel.execCmd("save");
            }else{
                _.debounce(startInlineEdit, 500)();
            }
        }
    }

    function startInlineEdit(){
        var inlineTextEditor = Granite.author.editor.registry["text"];
        inlineTextEditor.startInlineEdit(currentEditable);
    }
}(jQuery, jQuery(document), Granite.author));

2 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. Hi Sreekanth,

    thank you for the great post. one follow up question, I have. we are using the inline-edit-finish event, if there is an error on spell check.. I have 2 options reedit and save.. By that point of time, already the text is saved in the jcr... now we are prompting the dialog to modify the spelling accordingly with reedit. At this point of time, If I reload the browser, since the text is already present in jcr, now the text with incorrect spelling loads up.. it only corrects next time when I edit the rte component.

    Rather than inline-edit-finish, can we rely on any other event, before storing the actual content in the jcr. Please suggest.

    ReplyDelete