Source: core/WidgetsOverrideMixin.js

/**
 * Copyright (C) 2005-2016 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * This mixin module provides a [function]{@link module:alfresco/core/WidgetsOverrideMixin#applyWidgetOverrides}
 * for overriding the default widget model to be generated. This function provides a consistent way in which 
 * new widgets can be added, removed, replaced and updated.
 * 
 * @module alfresco/core/WidgetsOverrideMixin
 * @author Dave Draper
 * @since 1.0.97
 */
define(["dojo/_base/declare",
        "alfresco/core/ObjectTypeUtils",
        "jquery"], 
        function(declare, ObjectTypeUtils, $) {
   
   return declare(null, {
      
      /**
       * Iterates over the supplied array of widgets until one with the supplied target id is found. The index
       * of the widget within the supplied array is then returned.
       *
       * @instance
       * @param  {object[]} widgets  An array of widgets to iterate over
       * @param  {string}   targetId The target ID to match
       * @return {number} The index of the widget in the array or -1 if it could not be found.
       */
      findWidgetToOverride: function alfresco_core_WidgetsOverrideMixin__findWidgetToOverride(widgets, targetId) {
         var existingWidgetIndex = -1;
         if (ObjectTypeUtils.isArray(widgets))
         {
            widgets.some(function(currentWidget, index) {
               if (currentWidget.id === targetId)
               {
                  existingWidgetIndex = index;
               }
               return existingWidgetIndex !== -1;
            }, this);
         }
         return existingWidgetIndex;
      },

      /**
       * Applies the supplied overrides to the supplied widgets model. Each element in the overrides array should
       * define how it should be applied to the widgets array. Given the starting widgets array:
       *
       * @example <caption>This is the default widgets model to be updated in the following examples</caption>
       * [
       *   {
       *     id: "WIDGET_1",
       *     name: "alfresco/forms/controls/TextBox",
       *     config: {
       *       fieldId: "NAME",
       *       label: "Name",
       *       description: "Enter your name",
       *       name: "name"
       *     }
       *   },
       *   {
       *     id: "WIDGET_2",
       *     name: "alfresco/forms/controls/NumberSpinner",
       *     config: {
       *       fieldId: "AGE",
       *       label: "Age",
       *       description: "How old are you?",
       *       name: "age"
       *     }
       *   }
       * ]
       *
       * @example <caption>Insert a widget at the start of the model using a <b>targetPosition</b> of <b>"START"</b></caption>
       * [
       *   {
       *     id: "ADDRESS",
       *     targetPosition: "START",
       *     name: "alfresco/forms/controls/TextBox",
       *     config: {
       *       fieldId: "ADDRESS",
       *       label: "Address",
       *       description: "Where do you live?",
       *       name: "address"
       *     }
       *   }
       * ]
       * 
       * @example <caption>Insert a widget at the end of the model using a <b>targetPosition</b> of <b>"END"</b></caption>
       * [
       *   {
       *     id: "ADDRESS",
       *     targetPosition: "END",
       *     name: "alfresco/forms/controls/TextBox",
       *     config: {
       *       fieldId: "ADDRESS",
       *       label: "Address",
       *       description: "Where do you live?",
       *       name: "address"
       *     }
       *   }
       * ]
       *
       * @example <caption>Insert a widget before another widget using by using a <b>targetPosition</b> of <b>"BEFORE"</b> and providing a <b>targetId</b></caption>
       * [
       *   {
       *     id: "ADDRESS",
       *     targetId: "WIDGET_2"
       *     targetPosition: "BEFORE",
       *     name: "alfresco/forms/controls/TextBox",
       *     config: {
       *       fieldId: "ADDRESS",
       *       label: "Address",
       *       description: "Where do you live?",
       *       name: "address"
       *     }
       *   }
       * ]
       *
       * @example <caption>Insert a widget after another widget using by using a <b>targetPosition</b> of <b>"AFTER"</b> and providing a <b>targetId</b></caption>
       * [
       *   {
       *     id: "ADDRESS",
       *     targetId: "WIDGET_1"
       *     targetPosition: "AFTER",
       *     name: "alfresco/forms/controls/TextBox",
       *     config: {
       *       fieldId: "ADDRESS",
       *       label: "Address",
       *       description: "Where do you live?",
       *       name: "address"
       *     }
       *   }
       * ]
       *
       * @example <caption>Remove a widget using using the <b>remove</b> attribute with the <b>id</b> of the widget to remove.</caption>
       * [
       *   {
       *     id: "WIDGET_2",
       *     remove: true
       *   }
       * ]
       *
       * @example <caption>Replace a widget using the <b>replace</b> attribute with the <b>id</b> of the widget to replace.</caption>
       * [
       *   {
       *     id: "WIDGET_2",
       *     replace: true,
       *     name: "alfresco/forms/controls/TextArea",
       *     config: {
       *       fieldId: "ADDRESS",
       *       label: "Location",
       *       name: "address"
       *     }
       *   }
       * ]
       *
       * @example <caption>Merge new configuration into an existing widget <b>id</b></caption>
       * [
       *   {
       *     id: "WIDGET_1",
       *     name: "alfresco/forms/controls/TextArea",
       *     config: {
       *       name: "Who are you?"
       *     }
       *   }
       * ]
       *
       * @instance
       * @param {object[]} widgets The default widgets
       * @param {object[]} overrides The overrides to apply
       */
      applyWidgetOverrides: function alfresco_core_WidgetsOverrideMixin__applyWidgetOverrides(widgets, overrides) {
         var existingWidgetIndex;

         if (ObjectTypeUtils.isArray(widgets) && ObjectTypeUtils.isArray(overrides))
         {
            overrides.forEach(function(override) {
               // jshint maxcomplexity:false
               if (override.targetPosition === "START")
               {
                  // Place the override widget as the first entry...
                  widgets.unshift(override);
               }
               else if (override.targetPosition === "END")
               {
                  // Place the override widget as the last entry...
                  widgets.push(override);
               }
               else if (override.targetId)
               {
                  // Find the target widget...
                  existingWidgetIndex = this.findWidgetToOverride(widgets, override.targetId);
                  if (existingWidgetIndex !== -1)
                  {
                     if (typeof override.targetPosition === "undefined" || override.targetPosition === "BEFORE")
                     {
                        // Place the override widget before the target
                        widgets.splice(existingWidgetIndex, 0, override);
                     }
                     else if (override.targetPosition === "AFTER")
                     {
                        // Place the override widget after the target
                        widgets.splice(existingWidgetIndex + 1, 0, override);
                     }
                     else
                     {
                        this.alfLog("warn", "An override widget has a target, but an unknown position", override, this);
                     }
                  }
                  else
                  {
                     this.alfLog("warn", "Could not find widget with requested targetId", override.targetId, this);
                  }
               }
               else if (override.id)
               {
                  // Find the target widget...
                  existingWidgetIndex = this.findWidgetToOverride(widgets, override.id);
                  if (existingWidgetIndex !== -1)
                  {
                     if (override.remove)
                     {
                        // Remove the widget (if it exists)
                        widgets.splice(existingWidgetIndex, 1);
                     }
                     else if (override.replace)
                     {
                        // Replace the widget (if it exists)
                        widgets[existingWidgetIndex] = override;
                     }
                     else
                     {
                        // Merge into the widget (if it exists)
                        $.extend(true, widgets[existingWidgetIndex], override);
                     }
                  }
                  else
                  {
                     this.alfLog("warn", "Could not find widget with requested id", override.targetId, this);
                  }
               }
            }, this);
         }
         else
         {
            this.alfLog("warn", "Invalid arguments provided for overriding widgets, two arrays were expected", widgets, overrides, this);
         }
      }
   });
});