Source: pickers/Picker.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/>.
 */

/**
 * <p>The default picker widget for use in [picker form controls]{@link module:alfresco/forms/controls/Picker} and can be
 * extended as necessary to customize the initial set of "root pickers" by overriding the [widgetsForRootPicker attribute]
 * {@link module:alfresco/pickers/Picker#widgetsForRootPicker}. The picked items display can also be customized by
 * overriding the [widgetsForPickedItems attribute]{@link module:alfresco/pickers/Picker#widgetsForPickedItems}.</p>
 *
 * @module alfresco/pickers/Picker
 * @extends external:dijit/_WidgetBase
 * @mixes external:dojo/_TemplatedMixin
 * @mixes module:alfresco/core/Core
 * @mixes module:alfresco/core/CoreWidgetProcessing
 * @author Dave Draper
 * @author David Webster
 */
define(["dojo/_base/declare",
        "dijit/_WidgetBase",
        "dijit/_TemplatedMixin",
        "dojo/text!./templates/Picker.html",
        "alfresco/core/Core",
        "alfresco/core/CoreWidgetProcessing",
        "alfresco/core/topics",
        "dojo/_base/array",
        "dojo/_base/lang"],
        function(declare, _WidgetBase, _TemplatedMixin, template, AlfCore, CoreWidgetProcessing, topics, array, lang) {

   return declare([_WidgetBase, _TemplatedMixin, AlfCore, CoreWidgetProcessing], {

      /**
       * An array of the i18n files to use with this widget.
       *
       * @instance
       * @type {Array}
       */
      i18nRequirements: [{i18nFile: "./i18n/Picker.properties"}],

      /**
       * An array of the CSS files to use with this widget.
       *
       * @instance
       * @type {object[]}
       * @default [{cssFile:"./css/Picker.css"}]
       */
      cssRequirements: [{cssFile:"./css/Picker.css"}],

      /**
       * The HTML template to use for the widget.
       * @instance
       * @type {String}
       */
      templateString: template,

      /**
       * Keeps track of the current picker depth. When a new picker is added it will be given the current depth
       * which will then be incremented. When a picker requests a another picker be added it should include the depth
       * within the request so that deeper pickers (that are no longer relevant) are removed.
       *
       * @instance
       * @type {number}
       * @default
       */
      currentPickerDepth: 0,

      /**
       * Used to keep track of the current pickers that are displayed. When a new picker is added it will be added at
       * a depth that is greater than the requesting picker. This means that "deeper" pickers must be destroyed and
       * this is the object that will be referenced to determine which pickers are destroyed
       *
       * @instance
       * @type {object[]}
       * @default
       */
      currentPickers: null,

      /**
       * This boolean variable should be set to true when the picked items model should be shown and
       * set to false when it shouldn't. Showing picked items is useful for documents but not necessarily
       * for selecting a single folder. It will ensure that the [widgetsForPickedItems]{@link module:alfresco/pickers/Picker#widgetsForPickedItems}
       * model is rendered.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      showPickedItems: true,

      /**
       * This boolean variable is set to true when the picked items model is being rendered and is set
       * back to false once the rendering is complete. This is done so that the pickedItems is only
       * processed once and the root picked item widget is not added to the list of sub-pickers.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      _processsingPickedItems: false,

      /**
       * Override the default widget behaviour to generate a pubSubScope.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      generatePubSubScope: true,

      /**
       * This should be set to the NodeRef to be used to represent the root of the Repository. By default
       * this is "alfresco://company/home" but can be configured to be any other value. This value is used
       * as the root location for the Repository root picker.
       *
       * @instance
       * @type {string}
       * @default
       */
      repoNodeRef: "alfresco://company/home",

      /**
       * An array of publications that will be published when the picker is ready. By default there
       * are none specified.
       * 
       * @instance
       * @type {object}
       * @default
       * @since 1.0.85
       */
      publishOnReady: null,

      /**
       *
       *
       * @instance
       */
      postCreate: function alfresco_pickers_Picker__postCreate() {
         this.currentPickers = [];
         this.alfSubscribe("ALF_ADD_PICKER", lang.hitch(this, this.addPicker));

         // If requested, show picked items...
         if (this.showPickedItems === true)
         {
            this._processsingPickedItems = true;
            this.processWidgets(lang.clone(this.widgetsForPickedItems), this.pickedItemsNode);
            if (this.pickedItemsLabel) {
               this.pickedItemsLabelNode.innerHTML = this.message(this.pickedItemsLabel);
            }
         }

         if (this.widgetsForRootPicker !== null)
         {
            var clonedWidgetsForRootPicker = lang.clone(this.widgetsForRootPicker);
            this.processObject(["processInstanceTokens"], clonedWidgetsForRootPicker);
            this.processWidgets(clonedWidgetsForRootPicker, this.subPickersNode);
            if (this.subPickersLabel) {
               this.subPickersLabelNode.innerHTML = this.message(this.subPickersLabel);
            }
         }

         if (this.publishOnReady)
         {
            var clonedPublishOnReady = lang.clone(this.publishOnReady);
            array.forEach(clonedPublishOnReady, function(publication) {
               if (publication.publishTopic)
               {
                  this.alfPublish(publication.publishTopic,
                                  publication.publishPayload, 
                                  publication.publishGlobal,
                                  publication.publishToParent,
                                  publication.publishScope);
               }
            }, this);
         }
      },

      /**
       * Handles a request to add another picker.
       *
       * @instance
       * @param {object} payload
       */
      addPicker: function alfresco_pickers_Picker__addPicker(payload) {

         // Remove any pickers that are "deeper" than the picker requesting the new picker...
         if (payload.currentPickerDepth === undefined)
         {
            this.alfLog("warn", "No 'currentPickerDepth' was provided in a request to add a new picker, so the picker will be appended", payload, this);
         }
         else
         {
            var pickerDepth = payload.currentPickerDepth + 1;
            for (var i=pickerDepth; i < this.currentPickers.length; i++)
            {
               var picker = this.currentPickers[i];
               if (picker !== null && typeof picker.destroyRecursive === "function")
               {
                  picker.destroyRecursive();
               }
            }
            // Remove the elements from the array that have now been destroyed...
            this.currentPickers.splice(pickerDepth, this.currentPickers.length - pickerDepth);
            this.currentPickerDepth = payload.currentPickerDepth;
         }

         // Add the new picker...
         if (payload.picker !== null && payload.picker !== undefined)
         {
            if (payload.picker.config === null || payload.picker.config === undefined)
            {
               payload.picker.config = {};
            }
            payload.picker.config.pickerDepth = this.currentPickerDepth;
            this.processWidgets(payload.picker, this.subPickersNode);
            this.currentPickerDepth++;
         }
         else
         {
            this.alfLog("error", "Error creating a picker: the payload picker is missing a picker object: ", payload);
         }
      },

      /**
       * Publish a request to resize dialogs after new widgets are processed. There is no guarantee that this instance
       * will be in a dialog but if it is then this will ensure that the dialog is resized to contain the new pickers.
       * TODO: Should this be a more abstract "resize" topic?
       *
       * @instance
       * @param {object[]} widgets The instantiated widgets.
       */
      allWidgetsProcessed: function alfresco_pickers_Picker__allWidgetsProcessed(widgets) {

         if (this._processsingPickedItems === true)
         {
            // Reset the _processsingPickedItems flag now that the picked items model has
            // been rendered...
            this._processsingPickedItems = false;
            this.pickedItemsWidget.setPickedItems(this.value);
         }
         else if (widgets === null || widgets.length !== 1)
         {
            this.alfLog("warn", "A single picker widget was expected but " + widgets.length + " were created", widgets, this);
         }
         else
         {
            // Add the picker to the list
            this.currentPickers.push(widgets[0]);
         }

         this.alfPublish("ALF_RESIZE_DIALOG", {});
      },

      /**
       * It is necessary to provide a name attribute so that the data returned from [getValue]{@link module:alfresco/pickers/Picker#getValue}
       * will be mapped to an attribute when used in a [form]{@link module:alfresco/forms/Form}.
       *
       * @instance
       * @type {string}
       * @default
       */
      name: "pickedItems",

      /**
       * Returns an array of the selected item objects.
       *
       * @instance
       * @returns {object[]} The picked items
       */
      getValue: function alfresco_pickers_Picker__getValue() {
         var value = [];
         if (this.showPickedItems === true)
         {
            if (this.pickedItemsWidget !== null)
            {
               value = this.pickedItemsWidget.currentData.items;
            }
         }
         return value;
      },

      /**
       * The default widgets for the picker. This can be overridden at instantiation based on what is required to be
       * displayed in the picker.
       *
       * @instance
       * @type {object}
       */
      widgetsForRootPicker: [
         {
            name: "alfresco/menus/AlfVerticalMenuBar",
            config: {
               widgets: [
                  {
                     name: "alfresco/menus/AlfMenuBarItem",
                     config: {
                        label: "picker.recentSites.label",
                        publishTopic: "ALF_ADD_PICKER",
                        publishPayload: {
                           currentPickerDepth: 0,
                           picker: [
                              {
                                 name: "alfresco/pickers/SingleItemPicker",
                                 config: {
                                    currentPickerDepth: 1,
                                    requestItemsTopic: topics.GET_RECENT_SITES
                                 }
                              }
                           ]
                        }
                     }
                  },
                  {
                     name: "alfresco/menus/AlfMenuBarItem",
                     config: {
                        label: "picker.favouriteSites.label",
                        publishTopic: "ALF_ADD_PICKER",
                        publishPayload: {
                           currentPickerDepth: 0,
                           picker: [
                              {
                                 name: "alfresco/pickers/SingleItemPicker",
                                 config: {
                                    currentPickerDepth: 1,
                                    requestItemsTopic: topics.GET_FAVOURITE_SITES
                                 }
                              }
                           ]
                        }
                     }
                  },
                  {
                     name: "alfresco/menus/AlfMenuBarItem",
                     config: {
                        label: "picker.allSites.label",
                        publishTopic: "ALF_ADD_PICKER",
                        publishPayload: {
                           currentPickerDepth: 0,
                           picker: [
                              {
                                 name: "alfresco/pickers/SingleItemPicker",
                                 config: {
                                    currentPickerDepth: 1,
                                    requestItemsTopic: "ALF_GET_SITES"
                                 }
                              }
                           ]
                        }
                     }
                  },
                  {
                     name: "alfresco/menus/AlfMenuBarItem",
                     config: {
                        label: "picker.repository.label",
                        publishTopic: "ALF_ADD_PICKER",
                        publishPayload: {
                           currentPickerDepth: 0,
                           picker: [
                              {
                                 name: "alfresco/pickers/DocumentListPicker",
                                 config: {
                                    nodeRef: "{repoNodeRef}",
                                    path: "/"
                                 }
                              }
                           ]
                        }
                     }
                  },
                  {
                     name: "alfresco/menus/AlfMenuBarItem",
                     config: {
                        label: "picker.sharedFiles.label",
                        publishTopic: "ALF_ADD_PICKER",
                        publishPayload: {
                           currentPickerDepth: 0,
                           picker: [
                              {
                                 name: "alfresco/pickers/DocumentListPicker",
                                 config: {
                                    nodeRef: "alfresco://company/shared",
                                    filter: {
                                       path: "/"
                                    }
                                 }
                              }
                           ]
                        }
                     }
                  },
                  {
                     name: "alfresco/menus/AlfMenuBarItem",
                     config: {
                        label: "picker.myFiles.label",
                        publishOnRender: true, // Topic will be published when the item is rendered.
                        publishPayload: {
                           currentPickerDepth: 0,
                           picker: [
                              {
                                 name: "alfresco/pickers/DocumentListPicker",
                                 config: {
                                    nodeRef: "alfresco://user/home",
                                    path: "/"
                                 }
                              }
                           ]
                        }
                     }
                  }
               ]
            }
         }
      ],

      /**
       * This is the widget model for displaying picked items. It will only be displayed when
       * requested.
       *
       * @instance
       * @type {object}
       * @default
       */
      widgetsForPickedItems: [
         {
            name: "alfresco/pickers/PickedItems",
            assignTo: "pickedItemsWidget"
         }
      ],

      /**
       * This is the label to display above the picker.
       *
       * @instance
       * @type {string}
       * @default
       */
      subPickersLabel: "picker.subPickers.label",

      /**
       * This is the label to display above the picked items.
       *
       * @instance
       * @type {string}
       * @default
       */
      pickedItemsLabel: "picker.pickedItems.label"
   });
});