Source: forms/controls/FilePicker.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>This widget is intended to ultimately to replace the 
 * [DocumentPicker]{@link module:alfresco/forms/controls/DocumentPicker} but at the moment it is still
 * in development and not ready for production use. However it is currently included in Aikau releases 
 * for feedback and community collaboration. See https://issues.alfresco.com/jira/browse/AKU-1033 for the
 * complete of tasks remaining to complete the first cut of the widget. It is however currently functional
 * in that it can be used to select files.</p>
 *
 * <p>A number of services (or customized equivalents) need to be included on a page for this picker to be 
 * functional, these are:
 * <ul><li>alfresco/services/SearchService</li>
 * <li>alfresco/services/SiteService</li>
 * <li>alfresco/services/DialogService</li>
 * <li>alfresco/services/DocumentService</li></ul></p>
 * 
 * @module alfresco/forms/controls/FilePicker
 * @extends module:alfresco/forms/controls/BaseFormControl
 * @mixes module:alfresco/core/CoreWidgetProcessing
 * @author Dave Draper
 * @since 1.0.81
 */
define(["dojo/_base/declare",
        "alfresco/forms/controls/BaseFormControl",
        "alfresco/core/CoreWidgetProcessing",
        "alfresco/core/ObjectTypeUtils",
        "alfresco/core/topics",
        "dijit/registry",
        "dojo/_base/array",
        "dojo/_base/lang"],
        function(declare, BaseFormControl, CoreWidgetProcessing, ObjectTypeUtils, topics, registry, array, lang) {

   return declare([BaseFormControl, CoreWidgetProcessing], {

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

      /**
       * An array of sites available the current user. This will be generated the first time that 
       * [onRecentSitesOptionsRequest]{@link module:alfresco/forms/controls/FilePicker#onAllSitesOptionsRequest}
       * is called.
       * 
       * @instance
       * @type {object[]}
       * @default
       */
      allSites: null,

      /**
       * This is the property that is used to uniquely identify each 
       * [item]{@link module:alfresco/core/CoreWidgetProcessing#currentItem} that is picked. Ultimately this
       * will be the data that is used as the value of the form control.
       * 
       * @instance
       * @type {string}
       * @default
       */
      itemKeyProperty: "nodeRef",

      /**
       * Indicates whether or not more than one can be picked.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      multipleItemSelection: false,

      /**
       * An array of the favourite sites. This will be generated the first time that 
       * [onFavouriteSitesOptionsRequest]{@link module:alfresco/forms/controls/FilePicker#onFavouriteSitesOptionsRequest}
       * is called.
       * 
       * @instance
       * @type {object[]}
       * @default
       */
      favouriteSites: null,

      /**
       * An array of the recent sites. This will be generated the first time that 
       * [onRecentSitesOptionsRequest]{@link module:alfresco/forms/controls/FilePicker#onRecentSitesOptionsRequest}
       * is called.
       * 
       * @instance
       * @type {object[]}
       * @default
       */
      recentSites: null,

      /**
       * The root node at which to start repository browsing.
       * 
       * @instance
       * @type {string}
       * @default
       */
      repositoryRootNode: "alfresco://company/home",

      /**
       * Used to track the files that have been selected.
       * 
       * @instance
       * @type {object[]}
       * @default
       */
      selectedFiles: null,

      /**
       * Indicates whether or not the "All Sites" tab in the picker dialog should be displayed.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      showAllSites: true,

      /**
       * Indicates whether or not the "Favourite Sites" tab in the picker dialog should be displayed.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      showFavouriteSites: true,

      /**
       * Indicates whether or not the "Recent Sites" tab in the picker dialog should be displayed.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      showRecentSites: true,

      /**
       * Indicates whether or not the "Search" tab in the picker dialog should be displayed.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      showSearch: true,

      /**
       * Indicates whether or not the "Repository" tab in the picker dialog should be displayed.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      showRepository: true,

      /**
       * 
       * 
       * @instance
       */
      createFormControl: function alfresco_forms_controls_FilePicker__createFormControl() {
         
         this.setupPubSubData();

         // We need to process the widgets for the search view to ensure the generated topics are available...
         // We need to clone the model to prevent the first topic generated being reused between all picker instances...
         var widgetsForSearchView = lang.clone(this.widgetsForSearchView);
         this.processObject(["processInstanceTokens"], widgetsForSearchView);
         this.widgetsForSearchView = widgetsForSearchView;

         var widgetsForBrowseView = lang.clone(this.widgetsForBrowseView);
         this.processObject(["processInstanceTokens"], widgetsForBrowseView);
         this.widgetsForBrowseView = widgetsForBrowseView;

         var widgets = lang.clone(this.widgetsForDialog);
         this.processObject(["processInstanceTokens"], widgets);

         this._dialogId = this.id + "_FILE_PICKER_DIALOG";

         var button = this.createWidget({
            name: "alfresco/layout/VerticalWidgets",
            config: {
               widgets: [
                  {
                     id: this.id + "_SELECTED_FILES",
                     name: "alfresco/layout/DynamicWidgets",
                     config: {
                        subscriptionTopic: this.showSelectedFilesTopic,
                        subscribeGlobal: true
                     }
                  },
                  {
                     id: this.id + "_SHOW_FILE_PICKER_DIALOG",
                     name: "alfresco/buttons/AlfButton",
                     config: {
                        label: "filepicker.dialog.title",
                        publishTopic: topics.CREATE_DIALOG,
                        publishPayload: {
                           dialogId: this._dialogId,
                           dialogTitle: "filepicker.dialog.title", 
                           widgetsContent: widgets,
                           contentWidth: "800px",
                           contentHeight: "700px",
                           handleOverflow : false,
                           widgetsButtons: [
                              {
                                 id: this.id + "_CONFIRMATION_BUTTON",
                                 name: "alfresco/buttons/AlfButton",
                                 config: {
                                    label: "filepicker.dialog.confirmation.label",
                                    publishTopic: this.confirmFileSelectionTopic,
                                    additionalCssClasses: "call-to-action"
                                 }
                              },
                              {
                                 id: this.id + "_CANCELLATION_BUTTON",
                                 name: "alfresco/buttons/AlfButton",
                                 config: {
                                    label: "filepicker.dialog.cancellation.label",
                                    publishTopic: this.cancelFileSelectionTopic
                                 }
                              }
                           ],
                           publishOnShow: [
                              {
                                 publishTopic: this.addPreviouslySelectedFilesTopic,
                                 publishGlobal: true
                              }
                           ]
                        },
                        publishGlobal: true
                     }
                  }
               ]
            }
         });
         return button;
      },

      /**
       * This function generates the scopes, topics and subscriptions required to prevent this 
       * picker instance (or any of its nested widgets) from inadvertently communicating with
       * other instances or widgets.
       * 
       * @instance
       */
      setupPubSubData: function alfresco_forms_controls_FilePicker__setupPubSubData() {
         // This topic is used for publishing to the DynamicWidgets that will show the selected
         // files in the main form control (i.e. NOT in the dialog)...
         this.showSelectedFilesTopic = "SSF_" + this.generateUuid();

         // Scoping of tabs is required...
         this.searchTabScope = "STS_" + this.generateUuid();
         this.recentSitesTabScope = "RSTB_" + this.generateUuid();
         this.favouriteSitesTabScope = "FSTS_" + this.generateUuid();
         this.allSitesTabScope = "ASTS_" + this.generateUuid();
         this.repositoryTabScope = "RTS_" + this.generateUuid();

         // Generate some unique topics for this form control to avoid any cross-contamination
         // of other instances of the widget within the same scope...
         this.recentSitesRequestTopic = "RSRT_" + this.generateUuid();
         this.favouriteSitesRequestTopic = "FSRT_" + this.generateUuid();
         this.showRecentSiteBrowserTopic = "SRSBT_" + this.generateUuid();
         this.showFavouriteSiteBrowserTopic = "SFSBT_" + this.generateUuid();
         this.allSitesRequestTopic = "ASRT_" + this.generateUuid();
         this.showSiteBrowserTopic = "SASBT_" + this.generateUuid();

         // Generate topics for selecting and removing items...
         this.addFileTopic = "AFT_" + this.generateUuid();
         this.alfSubscribe(this.addFileTopic, lang.hitch(this, this.onFileSelected), true);
         this.removeFileTopic = "RFT_" + this.generateUuid();
         this.alfSubscribe(this.removeFileTopic, lang.hitch(this, this.onFileRemoved), true);

         this.updateSelectedFilesTopic = "USFT_" + this.generateUuid();

         // Generate and subscribe to a topic for populating the dialog with the previously selected
         // files when it is first displayed...
         this.addPreviouslySelectedFilesTopic = "APSFT_" + this.generateUuid();
         this.alfSubscribe(this.addPreviouslySelectedFilesTopic, lang.hitch(this, this.addPreviouslySelectedFiles), true);

         // Generate a topic for confirming the file selection...
         this.confirmFileSelectionTopic = "ConFST_" + this.generateUuid();
         this.alfSubscribe(this.confirmFileSelectionTopic, lang.hitch(this, this.onFileSelectionConfirmed), true);
         this.cancelFileSelectionTopic = "CanFST_" + this.generateUuid();

         // Set up the subscriptions to handle publication of the generated topics...
         this.alfSubscribe(this.recentSitesRequestTopic, lang.hitch(this, this.onRecentSitesOptionsRequest), true);
         this.alfSubscribe(this.favouriteSitesRequestTopic, lang.hitch(this, this.onFavouriteSitesOptionsRequest), true);
         this.alfSubscribe(this.allSitesRequestTopic, lang.hitch(this, this.onAllSitesOptionsRequest), true);
         
         // Set up subscription to valueChangeOf generated Select control fieldIds for recent and favourite sites
         this.alfSubscribe(this.recentSitesTabScope + "_valueChangeOf_RECENT_SITE_SELECTION", lang.hitch(this, this.onShowSiteBrowser, this.showRecentSiteBrowserTopic), true);
         this.alfSubscribe(this.favouriteSitesTabScope + "_valueChangeOf_FAVOURITE_SITE_SELECTION", lang.hitch(this, this.onShowSiteBrowser, this.showFavouriteSiteBrowserTopic), true);
         this.alfSubscribe(this.allSitesTabScope + "_valueChangeOf_SITE_SELECTION", lang.hitch(this, this.onShowSiteBrowser, this.showSiteBrowserTopic), true);
      },

      /**
       * Overrides the [inherited function]{@link module:alfresco/forms/controls/BaseFormControl#getValue}
       * to return the current value that has been generated.
       *
       * @instance
       * @extendable
       * @returns {object} The current value of the field.
       */
      getValue: function alfresco_forms_controls_FilePicker__getValue() {
         var value = this.value;
         if (value && this.valueDelimiter && ObjectTypeUtils.isArray(value))
         {
            value = value.join(this.valueDelimiter);
         }
         else if (!value && !this.valueDelimiter)
         {
            // When we don't have a value and we're not using the valueDelimiter we want to always
            // ensure that the default value is an empty array and NOT an empty string. This needs
            // to be done for the purposes of ensuring that form rules configured for FilePicker
            // widgets behave as expected as they will be written for arrays and not strings!
            value = [];
         }
         return value;
      },

      /**
       * Overrides the [inherited function]{@link module:alfresco/forms/controls/BaseFormControl#setValue}
       * to make sure that all Node details are retrieved for the values being set. This allows only a 
       * NodeRef to be set as a file value but for the metadata to be retrieved and displayed.
       * 
       * @instance
       * @param {object} value The value to set
       */
      setValue: function alfresco_forms_controls_FilePicker__setValue(value) {
         if (ObjectTypeUtils.isString(value))
         {
            if (this.valueDelimiter)
            {
                value = value.split(this.valueDelimiter);
            }
            else
            {
                value = [value];
            }
            
            value = array.map(value, function(valueItem) {
                var v = {};
                v[this.itemKeyProperty] = valueItem;
                return v;
            }, this);
         }

         if (value && ObjectTypeUtils.isArray(value))
         {
            if (!this.multipleItemSelection && value.length > 1)
            {
                this.alfLog("warn", "More than one element in value array set for single-selection FilePicker - only using first element", value, this);
                value = [value[0]];
            }
             
            // Because it might be necessary to retrieve the metadata for the files we need to keep
            // track of the all the values that will be handled. We can't set this.value and
            // this.selectedFiles until all metadata has been asynchronously retrieved (otherwise the
            // form value will be set with calls to getValue because the data has been retrieved). 
            // Tracking the metadata retrieval and using tmp values ensures the form value is correct
            // on load...
            var valueCount = value.length;
            var tmpValue, tmpSelectedFiles = [];
            
            tmpValue = this.multipleItemSelection ? [] : null;

            // This is possibly not the optimal way of achiving this, but it is expected that only 
            // a small number of files will be pre-selected at a time (and there is no other REST 
            // API available for retrieving the metadata in bulk). Ideally we would make a request
            // for the metadata for the supplied list of NodeRefs.
            array.forEach(value, function(file) {
               if (lang.getObject(this.itemKeyProperty, false, file))
               {
                  // Set up a one-time subscription for retrieving the metadata for the node, this
                  // will be done when no "displayName" attribute is provided (expected when the
                  // file is normalised) but a "nodeRef" is available. 
                  var responseTopic = this.generateUuid();
                  var handle = this.alfSubscribe(responseTopic + "_SUCCESS", lang.hitch(this, function(payload) {
                     this.alfUnsubscribe(handle);

                     // Get the node data and normalise it (so that it will work with the view),
                     // then update both the value and the selected files array and publish the request
                     // to update selected files... the result should be that the value is rendered correctly...
                     var updatedFile = payload.response.item;
                     this.normaliseFile(updatedFile);
                     
                     var itemKey = lang.getObject(this.itemKeyProperty, false, updatedFile);
                     if (this.multipleItemSelection)
                     {
                         tmpValue.push(itemKey);
                     }
                     else
                     {
                         tmpValue = itemKey;
                     }
                     tmpSelectedFiles.push(updatedFile);

                     valueCount--;

                     if (valueCount === 0)
                     {
                        this.selectedFiles = tmpSelectedFiles;
                        this.value = tmpValue;
                        this.updateSelectedFiles(this.showSelectedFilesTopic);
                        this.onValueChangeEvent(this.name, null, tmpValue);
                     }
                  }), true);

                  this.alfServicePublish(topics.GET_DOCUMENT, {
                     alfResponseTopic: responseTopic,
                     nodeRef: lang.getObject(this.itemKeyProperty, false, file) 
                  });
               }
            }, this);
         }
         else
         {
            this.alfLog("warn", "Non-array value tried to be set for FilePicker", value, this);
         }
      },
      
      /**
       * 
       * @instance
       * @param {string}   requestTopic  The topic to publish on to request the sites
       * @param {object[]} options       The array to populate with the site options
       * @param {string}   responseTopic The topic to publish the retrieved sites on.
       */
      getSiteOptions: function alfresco_forms_controls_FilePicker__getSiteOptions(requestTopic, options, responseTopic) {
         // Setup a one-time subscription for requesting the recent sites for the user...
         var sitesTopic = this.generateUuid();
         var handle = this.alfSubscribe(sitesTopic + "_SUCCESS", lang.hitch(this, function(pl) {
            this.alfUnsubscribe(handle);
            array.forEach(pl.response, lang.hitch(this, function(site) {
               options.push({
                  label: site.title,
                  value: site.shortName
               });
            }), this);

            this.alfPublish(responseTopic, {
               options: options
            }, true);
         }), true);

         this.alfServicePublish(requestTopic, {
            alfResponseTopic: sitesTopic
         });
      },

      /**
       * This function is called when the dialog is opened. It calls 
       * [updateSelectedFiles]{@link module:alfresco/forms/controls/FilePicker#updateSelectedFiles}
       * to ensure that the previously selected files are shown in the dialog.
       * 
       * @instance
       */
      addPreviouslySelectedFiles: function alfresco_forms_controls_FilePicker__addPreviouslySelectedFiles() {
         this.updateSelectedFiles(this.updateSelectedFilesTopic);
      },

      /**
       * Because files can be sourced from both the Search and Document Library APIs it is necessary 
       * to normalise the file data for display purposes to ensure that all the expected properties
       * are available to be rendered by the view.
       *
       * @instance
       * @param {object} file The file to be normalised.
       */
      normaliseFile: function alfresco_forms_controls_FilePicker__normaliseFile(file) {
         !!!file.displayName && (file.displayName = lang.getObject("node.properties.cm:name", false, file) || "");
         !!!file.title && (file.title = lang.getObject("node.properties.cm:title", false, file) || "");
         !!!file.description && (file.description = lang.getObject("node.properties.cm:description", false, file) || "");
         !!!file.nodeRef && (file.nodeRef = lang.getObject("node.nodeRef", false, file) || "");
         !!!file.modifiedOn && (file.modifiedOn = lang.getObject("node.properties.cm:modified.iso8601", false, file) || "");
         !!!file.modifiedBy && (file.modifiedBy = lang.getObject("node.properties.cm:modifier.displayName", false, file) || "");
         !!!file.site && (file.site = lang.getObject("location.site", false, file) || {});
         !!!file.site.shortName && (file.site.shortName = lang.getObject("location.site.name", false, file) || "");
         !!!file.path && (file.path = lang.getObject("location.path", false, file) || "");
      },

      /**
       * Handles selection of files anywhere within the picker.
       * 
       * @instance
       * @param  {object} payload The details of the file that has been selected.
       */
      onFileSelected: function alfresco_forms_controls_FilePicker__onFileSelected(payload) {
         this.normaliseFile(payload);

         // Check to see whether or not the file has already been selected...
         var fileAlreadySelected = false;
         if (this.selectedFiles)
         {
            var newKey = lang.getObject(this.itemKeyProperty, false, payload);
            fileAlreadySelected = array.some(this.selectedFiles, function(file) {
               var existingKey = lang.getObject(this.itemKeyProperty, false, file);
               return newKey === existingKey;
            }, this);
         }

         if (fileAlreadySelected)
         {
            // No action required. The file has previously been selected.
         }
         else if (this.multipleItemSelection)
         {
            // Initialise the selected files array if it is still null and then add the latest
            // file that has been selected...
            !!!this.selectedFiles && (this.selectedFiles = []);
            this.selectedFiles.push(payload);
         }
         else
         {
            this.selectedFiles = [payload];
         }

         this.updateSelectedFiles(this.updateSelectedFilesTopic);
      },

      /**
       * Handles requests to remove a previously picked item. Both from within the dialog 
       * and the main control itself.
       * 
       * @instance
       * @param {object} payload The file that has been removed
       */
      onFileRemoved: function alfresco_forms_controls_FilePicker__onFileRemoved(payload) {
         var keyToRemove = lang.getObject(this.itemKeyProperty, false, payload);
         this.selectedFiles = array.filter(this.selectedFiles, function(file) {
            var existingKey = lang.getObject(this.itemKeyProperty, false, file);
            return keyToRemove !== existingKey;
         }, this);
         
         // We need to toggle between removing items in the dialog and in the main control..
         // This can be determined by whether or not the picker dialog is displayed...
         var dialog = registry.byId(this._dialogId);
         if (dialog && dialog._isShown())
         {
            this.updateSelectedFiles(this.updateSelectedFilesTopic);
         }
         else
         {
            this.onFileSelectionConfirmed();
         }
      },

      /**
       * This function is called to update the display of selected items. The supplied topic is published
       * in order for a [DynamicWidgets]{@link module:alfresco/layout/DynamicWidgets} widget to update 
       * its display with a view of the currently selected files. 
       * 
       * @instance
       * @param {string} topic The topic to publish the widgets model on.
       */
      updateSelectedFiles: function alfresco_forms_controls_FilePicker__updateSelectedFiles(topic) {
         var widgetsForSelectedFilesView = lang.clone(this.widgetsForSelectedFilesView);
         this.processObject(["processInstanceTokens"], widgetsForSelectedFilesView);
         this.alfPublish(topic, {
            widgets: widgetsForSelectedFilesView
         }, true);
      },

      /**
       * This function is called when the user confirms that they have completed file selection.
       *
       * @instance
       */
      onFileSelectionConfirmed: function alfresco_forms_controls_FilePicker__onFileSelectionConfirmed() {
         var updatedValue = this.multipleItemSelection ? [] : null;
         
         if (this.selectedFiles)
         {
            array.forEach(this.selectedFiles, function(file) {
               var itemKey = lang.getObject(this.itemKeyProperty, false, file);
               if (itemKey)
               {
                  if (this.multipleItemSelection)
                  {
                      updatedValue.push(itemKey);
                  }
                  else
                  {
                      updatedValue = itemKey;
                  }
               }
            }, this);
         }

         this.updateSelectedFiles(this.showSelectedFilesTopic);
         var oldValue = this.value;
         this.value = updatedValue;
         this.onValueChangeEvent(this.name, oldValue, updatedValue);
      },

      /**
       * 
       * @instance
       * @param  {object} payload The request for sites. This contains the responseTopic to publish the options on.
       */
      onAllSitesOptionsRequest: function alfresco_forms_controls_FilePicker__onAllSitesOptionsRequest(payload) {
         var optionsTopic = payload.responseTopic;
         // NOTE: Commented code to ensure a recent site can be viewed without changing option...
         // if (!this.recentSites)
         // {
            this.allSites = [];
            this.getSiteOptions(topics.GET_SITES, this.allSites, optionsTopic);
         // }
         // else
         // {
         //    this.alfPublish(optionsTopic, {
         //       options: this.recentSites
         //    }, true);
         // }
      },

      /**
       * 
       * @instance
       * @param  {object} payload The request for recent sites. This contains the responseTopic to publish the options on.
       */
      onRecentSitesOptionsRequest: function alfresco_forms_controls_FilePicker__onRecentSitesOptionsRequest(payload) {
         var optionsTopic = payload.responseTopic;
         // NOTE: Commented code to ensure a recent site can be viewed without changing option...
         // if (!this.recentSites)
         // {
            this.recentSites = [];
            this.getSiteOptions(topics.GET_RECENT_SITES, this.recentSites, optionsTopic);
         // }
         // else
         // {
         //    this.alfPublish(optionsTopic, {
         //       options: this.recentSites
         //    }, true);
         // }
      },

      /**
       * 
       * @instance
       * @param  {object} payload The request for favourite sites. This contains the responseTopic to publish the options on.
       */
      onFavouriteSitesOptionsRequest: function alfresco_forms_controls_FilePicker__onFavouriteSitesOptionsRequest(payload) {
         var optionsTopic = payload.responseTopic;
         // NOTE: Commented code to ensure a favourite site can be viewed without changing option...
         // if (!this.favouriteSites)
         // {
            this.favouriteSites = [];
            this.getSiteOptions(topics.GET_FAVOURITE_SITES, this.favouriteSites, optionsTopic);
         // }
         // else
         // {
         //    this.alfPublish(optionsTopic, {
         //       options: this.favouriteSites
         //    }, true);
         // }
      },

      /**
       * This function is called whenever the user changes the site that they want to browse for files in. This
       * site can be from the drop-down showing favourites or recent sites, but the effect is the same - to 
       * update a [DynamicWidgets]{@link module:alfresco/layout/DynamicWidgets} widget with a model that allows
       * the user to browse the selected site.
       * 
       * @instance
       * @param {string} topic The topic to publish a new widget model on
       * @param {object} payload The payload of the changed selecte widget containing the new site browse
       */
      onShowSiteBrowser: function alfresco_forms_controls_FilePicker__onShowSiteBrowser(topic, payload) {
         this.alfPublish(topic, {
            widgets: [
               {
                  name: "alfresco/layout/HorizontalWidgets",
                  config: {
                     widgets: [
                        {
                           name: "alfresco/navigation/PathTree",
                           config: {
                              siteId: payload.value,
                              containerId: "documentLibrary",
                              rootNode: null,
                              showRoot: true,
                              rootLabel: "filepicker.sites.tree.root.label", // TODO: correct folder name?
                              useHash: false
                           }
                        },
                        {
                           name: "alfresco/layout/VerticalWidgets",
                           config: {
                              widgets: [
                                 {
                                    name: "alfresco/lists/Paginator",
                                    config: {
                                       pageSizePreferenceName: "org.alfresco.share.filepicker.documentsPerPage",
                                       documentsPerPage: 10,
                                       pageSizes: [5,10,20]
                                    }
                                 },
                                 {
                                    name: "alfresco/documentlibrary/AlfDocumentList",
                                    config: {
                                       pageSizePreferenceName: "org.alfresco.share.filepicker.documentsPerPage",
                                       currentPageSize: 10,
                                       waitForPageWidgets: false,
                                       rawData: false,
                                       useHash: false,
                                       siteId: payload.value,
                                       containerId: "documentLibrary",
                                       rootNode: null,
                                       usePagination: true,
                                       showFolders: true,
                                       sortAscending: true,
                                       sortField: "cm:name", // TODO: Check this
                                       widgets: this.widgetsForBrowseView
                                    }
                                 }
                              ]
                           }
                        }
                     ]
                  }
               }
            ]
         }, true);
      },

      /**
       * 
       * @instance
       * @type {object[]}
       */
      widgetsForSelectedFilesView: [
         {
            id: "{id}_SELECTED_FILES_VIEW",
            name: "alfresco/lists/views/AlfListView",
            config: {
               noItemsMessage: "filepicker.noitems.message",
               currentData: {
                  items: "{selectedFiles}"
               },
               widgets: [
                  {
                     name: "alfresco/lists/views/layouts/Row",
                     config: {
                        widgets: [
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 width: "40px",
                                 widgets: [
                                    {
                                       id: "{id}_SELECTED_FILES_THUMBNAIL",
                                       name: "alfresco/search/SearchThumbnail",
                                       config: {
                                          width: "32px",
                                          showDocumentPreview: true
                                       }
                                    }
                                 ]
                              }
                           },
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 widgets: [
                                    {
                                       id: "{id}_SELECTED_FILES_NAME",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "displayName",
                                          renderSize: "large"
                                       }
                                    },
                                    {
                                       id: "{id}_SELECTED_FILES_TITLE",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "title",
                                          renderSize: "small",
                                          renderedValuePrefix: "(",
                                          renderedValueSuffix: ")"
                                       }
                                    },
                                    {
                                       id: "{id}_SELECTED_FILES_DATE",
                                       name: "alfresco/renderers/Date",
                                       config: {
                                          renderSize: "small",
                                          deemphasized: true,
                                          renderOnNewLine: true,
                                          modifiedDateProperty: "modifiedOn",
                                          modifiedByProperty: "modifiedBy"
                                       }
                                    },
                                    {
                                       id: "{id}_SELECTED_FILES_DESCRIPTION",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "description",
                                          renderSize: "small",
                                          renderOnNewLine: true
                                       }
                                    },
                                    {
                                       id: "{id}_SELECTED_FILES_SITE",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "site.title",
                                          renderSize: "small",
                                          label: "filepicker.item.site.prefix",
                                          renderOnNewLine: true
                                       }
                                    },
                                    {
                                       id: "{id}_SELECTED_FILES_PATH",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "path",
                                          renderSize: "small",
                                          label: "filepicker.item.folder.prefix",
                                          renderOnNewLine: true
                                       }
                                    }
                                 ]
                              }
                           },
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 width: "20px",
                                 widgets: [
                                    {
                                       id: "{id}_SELECTED_FILES_REMOVE",
                                       name: "alfresco/renderers/PublishAction",
                                       config: {
                                          iconClass: "delete-16",
                                          publishTopic: "{removeFileTopic}",
                                          publishPayloadType: "CURRENT_ITEM",
                                          publishGlobal: true
                                       }
                                    }
                                 ]
                              }
                           }
                        ]
                     }
                  }
               ]
            }
         }
      ],

      /**
       * The model used for the view when browsing folders returned by the 
       * [DocumentService]{@link module:alfresco/services/DocumentService}.
       * 
       * @instance
       * @type {object[]}
       */
      widgetsForBrowseView: [
         {
            id: "{id}_BROWSE_VIEW",
            name: "alfresco/lists/views/AlfListView",
            config: {
               widgets: [
                  {
                     name: "alfresco/lists/views/layouts/Row",
                     config: {
                        widgets: [
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 widgets: [
                                    {
                                       id: "{id}_BROWSE_THUMBNAIL",
                                       name: "alfresco/renderers/Thumbnail",
                                       config: {
                                          width: "32px",
                                          showDocumentPreview: true
                                       }
                                    }
                                 ]
                              }
                           },
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 widgets: [
                                    {
                                       id: "{id}_BROWSE_NAME",
                                       name: "alfresco/renderers/InlineEditPropertyLink",
                                       config: {
                                          propertyToRender: "node.properties.cm:name",
                                          permissionProperty: "prevent.editing", // Hack to work around lack of mixin in PropertyLink
                                          renderSize: "large"
                                       }
                                    },
                                    {
                                       id: "{id}_BROWSE_TITLE",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "node.properties.cm:title",
                                          renderSize: "small",
                                          renderedValuePrefix: "(",
                                          renderedValueSuffix: ")"
                                       }
                                    },
                                    {
                                       id: "{id}_BROWSE_DATE",
                                       name: "alfresco/renderers/Date",
                                       config: {
                                          propertyToRender: "node.properties.cm:title",
                                          renderSize: "small",
                                          deemphasized: true,
                                          renderOnNewLine: true
                                       }
                                    },
                                    {
                                       id: "{id}_BROWSE_DESCRIPTION",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "node.properties.cm:description",
                                          renderSize: "small",
                                          renderOnNewLine: true
                                       }
                                    }
                                 ]
                              }
                           },
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 width: "20px",
                                 widgets: [
                                    {
                                       id: "{id}_BROWSE_ADD",
                                       name: "alfresco/renderers/PublishAction",
                                       config: {
                                          publishTopic: "{addFileTopic}",
                                          publishPayloadType: "CURRENT_ITEM",
                                          publishGlobal: true,
                                          renderFilter: [
                                             {
                                                property: "node.isContainer",
                                                values: [false]
                                             }
                                          ]
                                       }
                                    }
                                 ]
                              }
                           }
                        ]
                     }
                  }
               ]
            }
         }
      ],

      /**
       * This is the model for the search view.
       * 
       * @instance
       * @type {object[]}
       */
      widgetsForSearchView: [
         {
            id: "{id}_SEARCH_VIEW",
            name: "alfresco/lists/views/AlfListView",
            config: {
               widgets: [
                  {
                     name: "alfresco/lists/views/layouts/Row",
                     config: {
                        widgets: [
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 widgets: [
                                    {
                                       id: "{id}_SEARCH_THUMBNAIL",
                                       name: "alfresco/search/SearchThumbnail",
                                       config: {
                                          width: "32px",
                                          showDocumentPreview: true
                                       }
                                    }
                                 ]
                              }
                           },
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 widgets: [
                                    {
                                       id: "{id}_SEARCH_NAME",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "displayName",
                                          renderSize: "large"
                                       }
                                    },
                                    {
                                       id: "{id}_SEARCH_TITLE",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "title",
                                          renderSize: "small",
                                          renderedValuePrefix: "(",
                                          renderedValueSuffix: ")"
                                       }
                                    },
                                    {
                                       id: "{id}_SEARCH_DATE",
                                       name: "alfresco/renderers/Date",
                                       config: {
                                          renderSize: "small",
                                          deemphasized: true,
                                          renderOnNewLine: true,
                                          modifiedDateProperty: "modifiedOn",
                                          modifiedByProperty: "modifiedBy"
                                       }
                                    },
                                    {
                                       id: "{id}_SEARCH_DESCRIPTION",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "description",
                                          renderSize: "small",
                                          renderOnNewLine: true
                                       }
                                    },
                                    {
                                       id: "{id}_SEARCH_SITE",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "site.title",
                                          renderSize: "small",
                                          label: "filepicker.item.site.prefix",
                                          renderOnNewLine: true
                                       }
                                    },
                                    {
                                       id: "{id}_SEARCH_PATH",
                                       name: "alfresco/renderers/Property",
                                       config: {
                                          propertyToRender: "path",
                                          renderSize: "small",
                                          label: "filepicker.item.folder.prefix",
                                          renderOnNewLine: true
                                       }
                                    }
                                 ]
                              }
                           },
                           {
                              name: "alfresco/lists/views/layouts/Cell",
                              config: {
                                 width: "20px",
                                 widgets: [
                                    {
                                       id: "{id}_SEARCH_ADD",
                                       name: "alfresco/renderers/PublishAction",
                                       config: {
                                          publishTopic: "{addFileTopic}",
                                          publishPayloadType: "CURRENT_ITEM",
                                          publishGlobal: true
                                       }
                                    }
                                 ]
                              }
                           }
                        ]
                     }
                  }
               ]
            }
         }
      ],

      /**
       * The model to use in the file selection dialog.
       *
       * @instance
       * @type {object[]}
       */
      widgetsForDialog: [
         {
            name: "alfresco/layout/FixedHeaderFooter",
            config: {
               heightMode: "DIALOG",
               widgetsForHeader: [
                  {
                     id: "{id}_SELECTED_FILES",
                     name: "alfresco/layout/VerticalWidgets",
                     config: {
                        widgets: [
                           {
                              name: "alfresco/layout/DynamicWidgets",
                              config: {
                                 subscriptionTopic: "{updateSelectedFilesTopic}",
                                 subscribeGlobal: true
                              }
                           }
                        ]
                     }
                  }
               ],
               widgets: [
                  {
                     id: "{id}_TABCONTAINER",
                     name: "alfresco/layout/AlfTabContainer",
                     config: {
                        padded: true,
                        currentItem: {
                           showSearch: "{showSearch}",
                           showRepository: "{showRepository}",
                           showAllSites: "{showAllSites}",
                           showFavouriteSites: "{showFavouriteSites}",
                           showRecentSites: "{showRecentSites}"
                        },
                        widgets: [
                           {
                              id: "{id}_SEARCH_TAB",
                              title: "filepicker.search.tab.label",
                              name: "alfresco/layout/VerticalWidgets",
                              config: {
                                 pubSubScope: "{searchTabScope}",
                                 widgetMarginTop: 10,
                                 widgets: [
                                    {
                                       id: "{id}_SEARCH_FIELD",
                                       name: "alfresco/forms/SingleComboBoxForm",
                                       config: {
                                          useHash: true,
                                          okButtonLabel: "filepicker.search.button.label",
                                          okButtonPublishTopic : "ALF_SET_SEARCH_TERM",
                                          okButtonPublishGlobal: false,
                                          okButtonIconClass: "alf-white-search-icon",
                                          okButtonClass: "call-to-action",
                                          textFieldName: "searchTerm",
                                          textBoxIconClass: "alf-search-icon",
                                          textBoxCssClasses: "long hiddenlabel",
                                          queryAttribute: "term",
                                          optionsPublishTopic: "ALF_AUTO_SUGGEST_SEARCH",
                                          optionsPublishPayload: {
                                             resultsProperty: "response.suggestions"
                                          }
                                       }
                                    },
                                    {
                                       name: "alfresco/lists/Paginator",
                                       config: {
                                          pageSizePreferenceName: "org.alfresco.share.filepicker.documentsPerPage",
                                          documentsPerPage: 10,
                                          pageSizes: [5,10,20]
                                       }
                                    },
                                    {
                                       id: "{id}_SEARCH_RESULTS",
                                       name: "alfresco/documentlibrary/AlfSearchList",
                                       config: {
                                          _resetVars: ["facetFilters"], // NOTE: Stops query being reset...
                                          query: {
                                             datatype: "cm:content" // NOTE: Restricts search to files!
                                          },
                                          pageSizePreferenceName: "org.alfresco.share.filepicker.documentsPerPage",
                                          currentPageSize: 10,
                                          waitForPageWidgets: false,
                                          loadDataImmediately: false,
                                          useHash: false,
                                          selectedScope: "repo",
                                          useInfiniteScroll: false,
                                          siteId: null,
                                          rootNode: null, 
                                          repo: true,
                                          widgets: "{widgetsForSearchView}"
                                       }
                                    }
                                 ],
                                 renderFilter: [
                                    {
                                       property: "showSearch",
                                       values: [true]
                                    }
                                 ]
                              }
                           },
                           {
                              id: "{id}_RECENT_SITES_TAB",
                              title: "filepicker.recent.tab.label",
                              name: "alfresco/layout/VerticalWidgets",
                              config: {
                                 pubSubScope: "{recentSitesTabScope}",
                                 widgetMarginTop: 10,
                                 widgets: [
                                    {
                                       id: "{id}_SELECT_RECENT_SITE",
                                       name: "alfresco/forms/controls/Select",
                                       config: {
                                          fieldId: "RECENT_SITE_SELECTION",
                                          label: "filepicker.recent.site.selection.label",
                                          name: "recentSite",
                                          optionsConfig: {
                                             publishTopic: "{recentSitesRequestTopic}"
                                          }
                                       }
                                    },
                                    {
                                       id: "{id}_RECENT_SITES",
                                       name: "alfresco/layout/DynamicWidgets",
                                       config: {
                                          subscriptionTopic: "{showRecentSiteBrowserTopic}",
                                          subscribeGlobal: true
                                       }
                                    }
                                 ],
                                 renderFilter: [
                                    {
                                       property: "showRecentSites",
                                       values: [true]
                                    }
                                 ]
                              }
                           },
                           {
                              id: "{id}_FAVOURITE_SITES_TAB",
                              title: "filepicker.favourite.tab.label",
                              name: "alfresco/layout/VerticalWidgets",
                              config: {
                                 pubSubScope: "{favouriteSitesTabScope}",
                                 widgetMarginTop: 10,
                                 widgets: [
                                    {
                                       id: "{id}_SELECT_FAVOURITE_SITE",
                                       name: "alfresco/forms/controls/Select",
                                       config: {
                                          fieldId: "FAVOURITE_SITE_SELECTION",
                                          label: "filepicker.favourite.site.selection.label",
                                          name: "favouriteSite",
                                          optionsConfig: {
                                             publishTopic: "{favouriteSitesRequestTopic}"
                                          }
                                       }
                                    },
                                    {
                                       id: "{id}_FAVOURITE_SITES",
                                       name: "alfresco/layout/DynamicWidgets",
                                       config: {
                                          subscriptionTopic: "{showFavouriteSiteBrowserTopic}",
                                          subscribeGlobal: true
                                       }
                                    }
                                 ],
                                 renderFilter: [
                                    {
                                       property: "showFavouriteSites",
                                       values: [true]
                                    }
                                 ]
                              }
                           },
                           {
                              id: "{id}_ALL_SITES_TAB",
                              title: "filepicker.allsites.tab.label",
                              name: "alfresco/layout/VerticalWidgets",
                              config: {
                                 pubSubScope: "{allSitesTabScope}",
                                 widgetMarginTop: 10,
                                 widgets: [
                                    {
                                       id: "{id}_SELECT_SITE",
                                       name: "alfresco/forms/controls/Select",
                                       config: {
                                          fieldId: "SITE_SELECTION",
                                          label: "filepicker.site.selection.label",
                                          name: "site",
                                          optionsConfig: {
                                             publishTopic: "{allSitesRequestTopic}"
                                          }
                                       }
                                    },
                                    {
                                       id: "{id}_FAVOURITE_SITES",
                                       name: "alfresco/layout/DynamicWidgets",
                                       config: {
                                          subscriptionTopic: "{showSiteBrowserTopic}",
                                          subscribeGlobal: true
                                       }
                                    }
                                 ],
                                 renderFilter: [
                                    {
                                       property: "showAllSites",
                                       values: [true]
                                    }
                                 ]
                              }
                           },
                           {
                              id: "{id}_REPOSITORY_TAB",
                              title: "filepicker.repository.tab.label",
                              name: "alfresco/layout/VerticalWidgets",
                              config: {
                                 pubSubScope: "{repositoryTabScope}",
                                 widgetMarginTop: 10,
                                 widgets: [
                                    {
                                       name: "alfresco/layout/HorizontalWidgets",
                                       config: {
                                          widgets: [
                                             {
                                                name: "alfresco/navigation/PathTree",
                                                config: {
                                                   siteId: null,
                                                   containerId: null,
                                                   rootNode: "{repositoryRootNode}",
                                                   rootLabel: "filepicker.repository.tree.root.label",
                                                   useHash: false
                                                }
                                             },
                                             {
                                                name: "alfresco/layout/VerticalWidgets",
                                                config: {
                                                   widgets: [
                                                      {
                                                         name: "alfresco/lists/Paginator",
                                                         config: {
                                                            pageSizePreferenceName: "org.alfresco.share.filepicker.documentsPerPage",
                                                            documentsPerPage: 10,
                                                            pageSizes: [5,10,20]
                                                         }
                                                      },
                                                      {
                                                         name: "alfresco/documentlibrary/AlfDocumentList",
                                                         config: {
                                                            pageSizePreferenceName: "org.alfresco.share.filepicker.documentsPerPage",
                                                            currentPageSize: 10,
                                                            waitForPageWidgets: false,
                                                            rawData: false,
                                                            useHash: false,
                                                            siteId: null,
                                                            containerId: null,
                                                            rootNode: null,
                                                            usePagination: true,
                                                            showFolders: true,
                                                            sortAscending: true,
                                                            sortField: "cm:name", // TODO: Check this
                                                            widgets: "{widgetsForBrowseView}"
                                                         }
                                                      }
                                                   ]
                                                }
                                             }
                                          ]
                                       }
                                    }
                                 ],
                                 renderFilter: [
                                    {
                                       property: "showRepository",
                                       values: [true]
                                    }
                                 ]
                              }
                           }
                        ]
                     }
                  }
               ]
            }
         }
      ]
   });
});