Source: services/OptionsService.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 service provides a way of requesting options data for form controls, providing
 * normalization of the data so that it adheres to the structure expected by form controls
 *
 * @example <caption>Example publication configuration (url.context available in WebScript controller)</caption>
 * publishTopic: "ALF_GET_FORM_CONTROL_OPTIONS",
 * publishPayload: {
 *   url: url.context + "/proxy/alfresco/api/people",
 *   itemsAttribute: "people",
 *   labelAttribute: "userName",
 *   valueAttribute: "userName"
 * }
 *
 * @module alfresco/services/OptionsService
 * @extends module:alfresco/services/BaseService
 * @mixes module:alfresco/core/CoreXhr
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "alfresco/services/BaseService",
        "alfresco/core/CoreXhr",
        "alfresco/core/topics",
        "dojo/_base/lang",
        "dojo/_base/array",
        "service/constants/Default",
        "alfresco/core/NotificationUtils"],
        function(declare, BaseService, CoreXhr, topics, lang, array, AlfConstants, NotificationUtils) {

   return declare([BaseService, CoreXhr, NotificationUtils], {

      /**
       * Sets up the subscriptions for the OptionsService
       *
       * @instance
       * @since 1.0.32
       * @listens module:alfresco/core/topics#GET_FORM_CONTROL_OPTIONS
       */
      registerSubscriptions: function alfresco_services_OptionsService__registerSubscriptions() {
         this.alfSubscribe(topics.GET_FORM_CONTROL_OPTIONS, lang.hitch(this, this.onOptionsRequest));
      },

      /**
       * <p>Handles request to retrieve and normalize options data, the following attributes must be
       * provided on the payload:</p>
       * <ul>url (e.g. AlfConstants.PROXY_URI + "api/groups")<li></li>
       * <li>itemsAttribute - dot-notation address of items array (e.g. "data")(</li>
       * <li>labelAttribute - dot-notation for label within each item (e.g. "displayName")</li>
       * <li>valueAttribute - dot-notation for value within each item (e.g. "fullName")</li>
       * <li>responseTopic - this is automatically provided by Aikau form controls</li></ul>
       *
       * @instance
       * @param {object} payload
       */
      onOptionsRequest: function alfresco_services_OptionsService__onOptionsRequest(payload) {
         if (payload.url &&
             (payload.itemsAttribute || payload.itemsAttribute === "") &&
             payload.labelAttribute &&
             payload.valueAttribute &&
             (payload.responseTopic || payload.alfResponseTopic))
         {
            this.serviceXhr({
               url : payload.url,
               data: payload,
               method: "GET",
               successCallback: this.optionsSuccess,
               failureCallback: this.optionsFailure,
               progressCallback: this.optionsProgress,
               callbackScope: this
            });
         }
         else
         {
            this.alfLog("warn", "A request was made to retrieve form control options, but required payload attributes are missing", payload, this);
         }
      },

      /**
       * Handles progress updates by doing nothing. See AKU-884.
       * 
       * @instance
       * @param {object} response
       * @param {object} originalRequestConfig
       * @since 1.0.60
       */
      optionsProgress: function alfresco_services_OptionsService__optionsProgress(/*jshint unused:false*/ response, originalRequestConfig) {
         // No action intentionally
      },

      /**
       * This function is called whenever the raw options data is successfully retrieved. It locates
       * the attribute within the reponse that contains the options (via the "itemsAttribute") and
       * then calls the [processOptions function]{@link module:alfresco/services/OptionsService#processOptions}
       * to convert the raw data into the expected structure (e.g. an array of objects containing
       * "label" and "value" attributes).
       *
       * @instance
       * @param {object} response
       * @param {object} originalRequestConfig
       */
      optionsSuccess: function alfresco_services_OptionsService__optionsSuccess(response, originalRequestConfig) {
         this.alfLog("log", "Successfully retrieved form control options", response, originalRequestConfig);
         var options = [];
         var items = null;
         if (originalRequestConfig.data.itemsAttribute === "")
         {
            items = response;
         }
         else
         {
            items = lang.getObject(originalRequestConfig.data.itemsAttribute, false, response);
         }
         if (items !== null)
         {
            array.forEach(items, lang.hitch(this, this.processOptions, options, originalRequestConfig.data));
         }

         // See AKU-884...
         // The topic that the options are currently published on is tactically chosen to only use the
         // alfResponseScope in tandem with the alfResponseTopic - but for the responseScope to be used by itself
         // this is to retain backwards compatibility with form controls that do not use the ServiceStore (such
         // as select) and those that do (such as FilteringSelect)...
         var topic;
         if (originalRequestConfig.data.alfResponseTopic)
         {
            topic = (originalRequestConfig.data.alfResponseScope || "") + originalRequestConfig.data.alfResponseTopic;
         }
         else
         {
            topic = originalRequestConfig.data.responseTopic;
         }
         this.alfPublish(topic, {
            options: options
         });
      },

      /**
       * Uses the dot-notation addresses for the label and value to add a new option to the supplied
       * option array.
       *
       * @instance
       * @param {array} options The array to add the processed item to
       * @param {object} config The configuration to use for processing the option
       * @param {object} item The current item to process as an option
       * @param {number} index The index of the item in the items list
       */
      processOptions: function alfresco_services_OptionsService__processOptions(options, config, item, /*jshint unused:false*/ index) {
         /*jshint eqnull:true*/
         var label = lang.getObject(config.labelAttribute, false, item);
         var value = lang.getObject(config.valueAttribute, false, item);
         if (label == null && value == null)
         {
            this.alfLog("warn", "Neither the label or value could be found in the item", item);
         }
         else
         {
            options.push({
               label: (label != null) ? label : value,
               value: value
            });
         }
      },

      /**
       * @instance
       * @param {object} response
       * @param {object} originalRequestConfig
       */
      optionsFailure: function alfresco_services_OptionsService__optionsFailure(response, originalRequestConfig) {
         this.alfLog("error", "Failed to retrieve form control options", response, originalRequestConfig);
         // TODO: Handle error better (e.g. localization)...
         this.displayMessage(this.message("Could not retrieve options", [originalRequestConfig.data.name]));
      }
   });
});