Source: buttons/AlfDynamicPayloadButton.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>Extends the standard Aikau button to allow the payload to dynamically be updated on published topics.
 * This allows a button to be contextually sensitive to changes on the page. Configure the updates by 
 * setting the [publishPayloadSubscriptions]{@link module:alfresco/buttons/AlfDynamicPayloadButton#publishPayloadSubscriptions}.</p>
 * <p>It is also possible to configure the button to udpate the payload as the browser URL hash fragment
 * changes (again using an optional mapping).
 *
 * @example <caption>This is an example configuration:</caption>
 * {
 *    "name": "alfresco/buttons/AlfDynamicPayloadButton",
 *    "config": {
 *       "publishTopic": "MY_TOPIC_WHEN_CLICKED",
 *       "publishPayload": {
 *          "value": "A"
 *       },
 *       "publishPayloadSubscriptions": [
 *          {
 *             "topic": "MIXIN_COMPLETE_PAYLOAD"
 *          },
 *          {
 *             "topic": "MAP_SELECTED_DATA",
 *             "dataMapping": {
 *                "incomingPayloadProperty": "buttonPayloadProperty"
 *             }
 *          }
 *       ],
 *       "useHash": true,
 *       "hashDataMapping": {
 *          "hashFragmentParameterName": "buttonPayloadProperty"
 *       }
 *    }
 * }
 * 
 * @module alfresco/buttons/AlfDynamicPayloadButton
 * @extends alfresco/buttons/AlfButton
 * @mixes module:alfresco/documentlibrary/_AlfHashMixin
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "alfresco/buttons/AlfButton", 
        "alfresco/documentlibrary/_AlfHashMixin",
        "dojo/_base/array",
        "dojo/_base/lang",
        "dojo/io-query",
        "alfresco/util/hashUtils"], 
        function(declare, AlfButton, _AlfHashMixin, array, lang, ioQuery, hashUtils) {
   
   return declare([AlfButton, _AlfHashMixin], {

      /**
       * Indicates whether not has values can be used to map data into the button payload.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      useHash: false,

      /**
       * An optional mapping of hash fragment data to publish payload data. This allows only certain elements
       * of the hash to be used and for them to be assigned to specific properties of the published payload.
       *
       * @instance
       * @type {object}
       * @default
       */
      hashDataMapping: null,

      /**
       * Represents the topics that will trigger an update of the button payload. Each topic can have it's own
       * mapping of data. If no 'dataMapping' attribute is provided then the entire published payload will be
       * mixed into the payload for the button.
       * 
       * @instance
       * @type {array}
       * @default
       */
      publishPayloadSubscriptions: null,

      /**
       * Extends the [inherited function]{@link module:alfresco/buttons/AlfButton#postMixInProperties} to set up the
       * subscriptions for the [publishPayloadSubscriptions]
       * {@link module:alfresco/buttons/AlfDynamicPayloadButton#publishPayloadSubscriptions}
       * entries.
       *
       * @instance
       */
      postMixInProperties: function alfresco_buttons_AlfDynamicPayloadButton__postMixInProperties() {
         this.inherited(arguments);
         array.forEach(this.publishPayloadSubscriptions, lang.hitch(this, this.setupPayloadSubscriptions));
      },

      /**
       * Extends the [inherited function]{@link module:alfresco/buttons/AlfButton#postCreate} to check
       * update the payload based on the browser URL hash and set up handlers for hash changes (if 
       * [useHash]{@link module:alfresco/buttons/AlfDynamicPayloadButton#useHash} is true).
       * 
       * @instance
       */
      postCreate: function alfresco_buttons_AlfDynamicPayloadButton__postCreate() {
         this.inherited(arguments);
         if (this.useHash)
         {
            var currHash = hashUtils.getHash();
            if (this.hashDataMapping)
            {
               this.mapData(this.hashDataMapping, currHash);
            }
            else
            {
               // If no data mapping has been provided then mix the entire hash in
               lang.mixin(this.publishPayload, currHash);
            }

            this.alfSubscribe(this.hashChangeTopic, lang.hitch(this, this.onHashChanged));
         }
      },

      /**
       * Sets up subscriptions for each configured 
       * [publishPayloadSubscription]{@link module:alfresco/buttons/AlfDynamicPayloadButton#publishPayloadSubscriptions} entry.
       *
       * @instance
       */
      setupPayloadSubscriptions: function alfresco_buttons_AlfDynamicPayloadButton__setupPayloadSubscriptions(pps) {
         if (pps.topic)
         {
            this.alfSubscribe(pps.topic, 
                              lang.hitch(this, this.onPayloadUpdate, pps.dataMapping), 
                              pps.subscribeGlobal,
                              pps.subscribeParent,
                              pps.subscribeScope);
         }
         else
         {
            this.alfLog("warn", "A publishPayloadSubscription is configured without a 'topic' attribute", pps, this);
         }
      },

      /**
       * This handles the mapping of data for a subscribed topic. It ensures that a publishPayload object exists
       * and then attempts to map the requested data defined in the supplied dataMapping argument from the payload
       * argument into the publishPayload object. If no dataMapping argument is provided then the entire payload
       * is mixed in.
       *
       * @instance
       */
      onPayloadUpdate: function alfresco_buttons_AlfDynamicPayloadButton__onPayloadUpdate(dataMapping, payload) {
         // Make sure that there is a payload object to work with...
         if (!this.publishPayload)
         {
            this.publishPayload = {};
         }

         if (dataMapping)
         {
            // Map data as requested...
            this.mapData(dataMapping, payload);
         }
         else
         {
            // Mixin the entire payload if none is provided...
            lang.mixin(this.publishPayload, payload);
         }
      },

      /**
       * Maps the data provided into the payload based on the dataMapping provided.
       *
       * @instance
       * @param {object} dataMapping The mapping to use for the data
       * @param {object} data The data to be mapped
       */
      mapData: function alfresco_buttons_AlfDynamicPayloadButton__mapData(dataMapping, data) {
         for (var key in dataMapping)
         {
            if (dataMapping.hasOwnProperty(key))
            {
               // Check that the data actually exists...
               if (lang.exists(key, data))
               {
                  var value = lang.getObject(key, false, data);
                  // ...and then set it as requested
                  lang.setObject(dataMapping[key], value, this.publishPayload);
               }
            }
         }
      },

      /**
       * This function is called whenever the browser URL hash fragment is changed.e end of the fragment
       * 
       * @instance
       * @param {object} payload
       */
      onHashChanged: function alfresco_buttons_AlfDynamicPayloadButton__onHashChanged(payload) {
         if (this.hashDataMapping)
         {
            this.mapData(this.hashDataMapping, payload);
         }
         else
         {
            // If no data mapping has been provided then mix the entire hash in
            lang.mixin(this.publishPayload, payload);
         }
      }
   });
});