Adobe-Consulting-Services/acs-aem-commons

View on GitHub
ui.apps/src/main/content/jcr_root/apps/acs-commons/rte-plugins/accordion/source/rte-accordion.js

Summary

Maintainability
A
0 mins
Test Coverage
/*
 * #%L
 * ACS AEM Commons Package
 * %%
 * Copyright (C) 2016 Adobe
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 * 
 * Accordion TouchUI RTE plugin
 *
 * Steps:
 *
 * 1) Create ACS Commons plugin nt:unstructured node "acs-commons"
 *      eg. /apps/<project>/components/text/dialog/items/tab1/items/text/rtePlugins/acs-commons
 * 2) Add property "features" of type String[] and single value "rte-accordion"
 * 3) Add to the fullscreen uiSettings "toolbar" property. Include "acs-commons#rte-accordion" in the desired location
 *      e.g. /apps/<project>/components/text/dialog/items/tab1/items/text/uiSettings/cui/fullscreen
 * 4) To use the provided minimal generic styling, add "acs-commons.rte-accordion" to the embed property of your Client Library Folder
 *
 */
(function($, CUI){
    var RTEAccordion = {
        GROUP: "acs-commons",
        FEATURE: "rte-accordion",
        CLASS: "acs-commons-rte-accordion"
    };
  
    // Initialize the Accordion RTE Plugin
    RTEAccordion.TouchUIAccordionPlugin = new Class({
        extend: CUI.rte.plugins.Plugin,
        accordionUI: null,
  
        getFeatures: function() {
            return [ RTEAccordion.FEATURE ];
        },

        initializeUI: function(tbGenerator) {
            var plg = CUI.rte.plugins;
  
            this.accordionUI = tbGenerator.createElement(RTEAccordion.FEATURE, this, true, "Accordion");
            tbGenerator.addElement(RTEAccordion.GROUP, plg.Plugin.SORT_FORMAT, this.accordionUI, 120);
            tbGenerator.registerIcon(RTEAccordion.GROUP + "#" + RTEAccordion.FEATURE, "coral-Icon coral-Icon--feed");
        },
  
        // Triggers on click of the RTE button
        execute: function(id) {
            // Relays this click event to the Command registered with this ID (in this case, set below in AccordionCmd)
            this.editorKernel.relayCmd(id);
        },
  
        // This marks the accordion icon as active or not based on the selected DOM element in selDef
        updateState: function(selDef) {
            // Returns true or false whether this plugin is active in the selected DOM element in selDef
            var hasUC = this.editorKernel.queryState(RTEAccordion.FEATURE, selDef);

            if ( this.accordionUI !== null ) {
                // Set as selected (Adds a darker background color to the icon)
                this.accordionUI.setSelected(hasUC);
            }

            if (hasUC === true) {
                // Change the accordion icon to use the one with a plus to indicate that this adds another accordion item to the existing accordion
                $("[data-action='" + RTEAccordion.GROUP + "#" + RTEAccordion.FEATURE + "']").removeClass("coral-Icon--feed").addClass("coral-Icon--feedAdd");
            } else {
                // Restore the original icon in case it was changed above
                $("[data-action='" + RTEAccordion.GROUP + "#" + RTEAccordion.FEATURE + "']").removeClass("coral-Icon--feedAdd").addClass("coral-Icon--feed");
            }
        }
    });

    // Accordion Plugin Commands
    RTEAccordion.AccordionCmd = new Class({
        extend: CUI.rte.commands.Command,
  
        isCommand: function(cmdStr) {
            return (cmdStr.toLowerCase() == RTEAccordion.FEATURE);
        },
  
        getProcessingOptions: function() {
            var cmd = CUI.rte.commands.Command;
            return cmd.PO_SELECTION | cmd.PO_BOOKMARK | cmd.PO_NODELIST;
        },
  
        // The base node for this plugin is a div with an accordion class, used in multiple places to check and add this element
        _getTagObject: function() {
            return {
                "tag": "div",
                "attributes": {
                    "class" : RTEAccordion.CLASS
                }
            };
        },

        // We don't want to add this plugin inside another element, this code will find the highest parent for the current context
        _getHighestParent: function ( context, node ){
            var common = CUI.rte.Common;
            // Get the nearest parent of the passed node
            var parent = common.getParentNode(context, node);

            // If the returned parent has an accordion class, this is the higest parent for this accordion so return it
            if ( parent.className == RTEAccordion.CLASS ) {
                return parent;
            } 
            // We don't want to go too far up the dom, if the next parent after this is null return this node
            else if ( common.getParentNode(context, parent) === null ) {
                return node;
            } 
            // No appropriate results were found yet, recursively call this method again to go up another level
            else {
                return this._getHighestParent(context, parent);
            }
        },

        execute: function(execDef) {
            var common = CUI.rte.Common;
            var dpr = CUI.rte.DomProcessor;

            // Get the current context that this execute method was triggered in
            var context = execDef.editContext;
            var selection = execDef.selection;
            var startNode = selection.startNode;
            var tagObj = this._getTagObject();

            if (!selection) {
                return;
            }

            // Set up our DOM elements for the Accordion, defaults to an unordered list with a single item
            var accordionItem = context.createElement('li');
            accordionItem.className = 'accordion-item';
            var accordionHTML = '';
            accordionHTML += '<h3 class="accordion-header">Accordion Header</h3>';
            accordionHTML += '<div class="accordion-content">';
            accordionHTML += '    <p>Accordion Content.</p>';
            accordionHTML += '</div>';
            accordionItem.innerHTML = accordionHTML;
            
            // Find the nearest parent
            var parent = this._getHighestParent(context, startNode);

            // If the nearest parent is the .accordion container div, we want to only add an accordionItem to the end
            if ( parent.className == RTEAccordion.CLASS ) {
                parent.firstChild.appendChild(accordionItem);
            } 
            // Otherwise we want to add a new .accordion container with a new list and item inside
            else {
                var accordionDom = dpr.createNode(context, tagObj.tag, tagObj.attributes);
                var accordionlist = context.createElement('ul');
                accordionlist.appendChild(accordionItem);
                accordionDom.appendChild(accordionlist);
                parent.parentNode.insertBefore(accordionDom, parent.nextSibling);
            }
        },
  
        queryState: function(selectionDef) {
            var common = CUI.rte.Common;
            var context = selectionDef.editContext;
  
            var selection = selectionDef.selection;
            var startNode = selection.startNode;
            var tagObj = this._getTagObject();
  
            return (common.getTagInPath(context, startNode, tagObj.tag, tagObj.attributes) !== null);
        }
    });
  
    CUI.rte.plugins.PluginRegistry.register(RTEAccordion.GROUP, RTEAccordion.TouchUIAccordionPlugin);
    CUI.rte.commands.CommandRegistry.register(RTEAccordion.FEATURE, RTEAccordion.AccordionCmd);
})($, window.CUI);