layout/accordion.directive.js

/**
 * @module avAccordion
 * @memberof app.layout
 * @restrict A
 * @description handle accordion use
 *
 * The `avAccordion`
 * https://jsfiddle.net/aestheticartist/h72fuxvw/
 */
angular
    .module('app.layout')
    .directive('avAccordion', avAccordion);

/**
 * `avAccordion` directive body.
 *
 * @function avAccordion
 * @param {Object} $compile Angular object
 * @param {Object} $timeout Angular object
 * @param {Object} events Angular object
 * @param {Object} constants the modules whho contains all the constants
 * @return {Object}     directive body
 */
function avAccordion($compile, $timeout, events, constants) {
    const directive = {
        restrict: 'A',
        link
    }

    function link(scope, element) {
        // when model is updated, we need to recreate the accordion
        events.$on(events.avSwitchLanguage, () => { setAccordion(scope, element, constants.delayAccordion); });
        events.$on(events.avSchemaUpdate, () => { setAccordion(scope, element, constants.delayAccordion); });
        events.$on(events.avLoadModel, () => { setAccordion(scope, element, constants.delayAccordion); });

        events.$on(events.avNewItems, () => {
            setAccordion(scope, element, 100);
        });
    }

    /**
     * Set accordion on form if needed
     * @function setAccordion
     * @private
     * @param  {Object} scope Angular scope
     * @param  {Object} element  element to add to
     * @param {Interger} delay timeout to apply
     */
    function setAccordion(scope, element, delay) {
        $timeout(() => {
            element.find('.av-accordion-toggle').not(':has(>md-icon)').each((index, element) => {
                // check if the element need to be collapse by default
                // default behaviour of collapsible element is to be open by default
                let isOpen = true;

                // if element with class av-accordion-toggle also have av-collapse, collapse the group by default
                if (element.classList.contains('av-collapse')) {
                    isOpen = false;
                    $(element.getElementsByClassName('av-accordion-content')).slideToggle();
                }

                addIcon($(element), scope, isOpen);
            });

            // add button for expand and collapse all getElementsByTagName
            // to enable this, add htmml class av-accordion-all at the base level af an array inside the form
            element.find('.av-accordion-all').not(':has(>button)').each((index, element) => {
                addButton($(element), scope);
            });
        }, delay);
    }

    /**
     * Add expand and collapse icon to accordion section
     * @function addIcon
     * @private
     * @param  {Object} element  element to add to
     * @param  {Object} scope Angular scope
     * @param {Boolean} open true if the expand icon is show, false if collapse icon is shown
     */
    function addIcon(element, scope, open) {
        // set the proper icon from the collapsible element state
        const isOpen = (open) ? 'hidden' : '';
        const isClose = (!open) ? 'hidden' : '';

        element.prepend(
            $compile(`<md-icon class='av-accordion-icon av-accordion-expand ${isOpen}' md-svg-src='hardware:keyboard_arrow_right'
                ng-click="self.formService.toggleSection($event, 'slideToggle')"></md-icon>
                    <md-icon class='av-accordion-icon av-accordion-collapse ${isClose}' md-svg-src='hardware:keyboard_arrow_down'
                ng-click="self.formService.toggleSection($event)"></md-icon>`)(scope));
    }

    /**
     * Add expand and collapse button to array section
     * @function addButton
     * @private
     * @param  {Object} element  element to add to
     * @param  {Object} scope Angular scope
     */
    function addButton(element, scope) {
        element.prepend(
            $compile(`<md-button class="av-button-square av-expcol-all md-raised"
                        ng-click="self.formService.toggleAll($event, true)">
                        {{ 'summary.collapse' | translate }}
                        <md-tooltip>{{ 'summary.collapse' | translate }}</md-tooltip>
                    </md-button>
                    <md-button class="av-button-square av-expcol-all md-raised"
                        ng-click="self.formService.toggleAll($event, false)">
                        {{ 'summary.expand' | translate }}
                        <md-tooltip>{{ 'summary.expand' | translate }}</md-tooltip>
                    </md-button>`)(scope));
    }

    return directive;
}