Source: renderers/ToggleStateActions.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 is an extension to the 'alfresco/renderers/Actions' widget that adds a secondary "off" state where no 
 * actions are available. Clicking the button toggles the widget into the "on" state and allows the actions menu 
 * to be displayed. The original use case for this widget was in sharing documents - the "off" state was the document 
 * not being shared, clicking the button would share the document (and move it into the "on" state) and provide 
 * additional actions in the drop-down menu.</p>
 *
 * @example <caption>Basic Example</caption>
 * {
 *   name: "alfresco/renderers/ToggleStateActions",
 *   config: {
 *     itemKeyProperty: "nodeRef",
 *     toggleOnWhenPropertySet: true,
 *     toggleStateProperty: "node.properties.qshare:sharedId",
 *     toggleOnStateLabel: "Shared",
 *     toggleOffStateLabel: "Share",
 *     toggleOnRequestTopic: "SHARE",
 *     toggleOnSuccessTopic: "SHARE",
 *     toggleOffSuccessTopic: "UNSHARED",
 *     customActions: [
 *        {
 *           label: "Copy Link",
 *           publishTopic: "COPY"
 *        },
 *        {
 *           label: "E-Mail Link",
 *           publishTopic: "EMAIL"
 *        },
 *        {
 *           label: "Stop sharing",
 *           publishTopic: "UNSHARED"
 *        }
 *     ]
 *   }
 * }
 *
 * @module alfresco/renderers/ToggleStateActions
 * @extends module:alfresco/renderers/Actions
 * @author Dave Draper
 * @since 1.0.64
 */
define(["dojo/_base/declare",
        "alfresco/renderers/Actions",
        "alfresco/core/topics",
        "dojo/dom-class",
        "dojo/_base/lang"], 
        function(declare, Actions, topics, domClass, lang) {

   return declare([Actions], {

      /**
       * An array of the i18n files to use with this widget.
       * 
       * @instance
       * @type {object[]}
       * @default [{i18nFile: "./i18n/ToggleStateActions.properties"}]
       */
      i18nRequirements: [{i18nFile: "./i18n/ToggleStateActions.properties"}],
      
      /**
       * The property of the current item that uniquely identifies it. This attribute is used
       * to check that any published 
       * [toggleOnSuccessTopic]{@link module:alfresco/renderers/ToggleStateActions#toggleOnSuccessTopic}
       * relates to the [currentItem]{@link module:alfresco/core/CoreWidgetProcessing#currentItem}. 
       * This allows the state to be toggled by an external widget.
       * 
       * @instance
       * @type {string}
       * @default
       */
      itemKeyProperty: "node.nodeRef",

      /**
       * This is the label to display on the button when toggled to the "on" state.
       * 
       * @instance
       * @type {string}
       * @default
       */
      toggleOnStateLabel: "toggle.state.on.label",

      /**
       * This is the topic that is published when the button is clicked when in the "off" state.
       * It makes a request to update the toggle state. Typically this topic would be subscribed
       * to by a service that would indicate a successful change in state by publishing on the
       * [toggleOnSuccessTopic]{@link module:alfresco/renderers/ToggleStateActions#toggleOnSuccessTopic}.
       * However, it is possible to skip this intermediate step and configure the 
       * [toggleOnSuccessTopic]{@link module:alfresco/renderers/ToggleStateActions#toggleOnSuccessTopic}
       * to have an idential value.
       * 
       * @instance
       * @type {string}
       * @default [TOGGLE_ON]{@link module:alfresco/core/topics#TOGGLE_ON}
       * @event
       */
      toggleOnRequestTopic: topics.TOGGLE_ON,

      /**
       * This is the topic that should be published to toggle from the "off" state to the "on" state.
       * Typically it would be published by a service that handles requests to change the toggle state
       * of an item. However, it is possible to skip this intermediate step and configure the 
       * [toggleOnRequestTopic]{@link module:alfresco/renderers/ToggleStateActions#toggleOnRequestTopic}
       * to have an idential value. The only requirement is that the 
       * [itemKeyProperty]{@link module:alfresco/renderers/ToggleStateActions#itemKeyProperty}
       * exists in the published payload to match requests against the appropriate instance of the widget.
       * 
       * @instance
       * @type {string}
       * @default [TOGGLE_ON]{@link module:alfresco/core/topics#TOGGLE_ON}
       * @event
       */
      toggleOnSuccessTopic: topics.TOGGLE_ON,

      /**
       * This is the topic that should be published to toggle from the "on" state to the "off" state.
       * It should be published either by one of the actions displayed in the drop-down menu
       * when the button is "on" state or from a service that handles requests to change the toggle state
       * of an item. It could also be published by an entirely unrelated widget or service if necessary.
       * The only requirement is that the 
       * [itemKeyProperty]{@link module:alfresco/renderers/ToggleStateActions#itemKeyProperty}
       * exists in the published payload to match requests against the appropriate instance of the widget.
       * 
       * @instance
       * @type {string}
       * @default [TOGGLE_OFF]{@link module:alfresco/core/topics#TOGGLE_OFF}
       * @event
       */
      toggleOffSuccessTopic: topics.TOGGLE_OFF,

      /**
       * This is the label to display on the button when toggled to the "off" state.
       * 
       * @instance
       * @type {string}
       * @default
       */
      toggleOffStateLabel: "toggle.state.off.label",

      /**
       * This is the value that the 
       * [toggleStateProperty]{@link module:alfresco/renderers/ToggleStateActions#toggleStateProperty}
       * must be in order for the button to be in toggled "on" state when first loaded.
       * 
       * @instance
       * @type {string}
       * @default
       */
      toggleStateOnValue: "node.properties.qshare:sharedId",

      /**
       * This is the property to compare against the 
       * [toggleStateOnValue]{@link module:alfresco/renderers/ToggleStateActions#toggleStateOnValue} to
       * determine whether or not the button is in the toggled "on" state. If 
       * [toggleOnWhenPropertySet]{@link module:alfresco/renderers/ToggleStateActions#toggleOnWhenPropertySet}
       * is configured to be true then the button will be toggled to the "on" state if the property
       * exists.
       * 
       * @instance
       * @type {string}
       * @default
       */
      toggleStateProperty: null,

      /**
       * If this is configured to be true then the 
       * [toggleStateProperty]{@link module:alfresco/renderers/ToggleStateActions#toggleStateProperty} only needs
       * to exist in order for the button to be toggled to the "on" state.
       * 
       * @instance
       * @type {string}
       * @default
       */
      toggleOnWhenPropertySet: false,

      /**
       * Private attribute used to determine whether or not the actions are enabled (actions are enabled
       * when the button is toggled to the "on" state).
       * 
       * @instance
       * @type {string}
       * @default
       */
      _actionsEnabled: true,

      /**
       * The unique value that uniquely identifies the item. This is set once in 
       * [postCreate]{@link module:alfresco/renderers/ToggleStateActions#postCreate} using the value of
       * [itemKeyProperty]{@link module:alfresco/renderers/ToggleStateActions#itemKeyProperty} from the
       * [currentItem]{@link module:alfresco/core/CoreWidgetProcessing#currentItem}.
       * 
       * @instance
       * @type {object}
       * @default
       */
      _itemKey: null,

      /**
       * Extends the [inherited function]{@link module:alfresco/renderers/Actions#postCreate} to 
       * retrieve the [itemKeyProperty]{@link module:alfresco/renderers/ToggleStateActions#itemKeyProperty} 
       * from the [currentItem]{@link module:alfresco/core/CoreWidgetProcessing#currentItem}, set
       * the initial toggle state and to update the label, topic and payload of the associated button.
       * 
       * @instance
       * @listens module:alfresco/renderers/ToggleStateActions#toggleOnSuccessTopic
       * @listens module:alfresco/renderers/ToggleStateActions#toggleOffSuccessTopic
       */
      postCreate: function alfresco_renderers_ToggleStateActions__postCreate() {
         this.inherited(arguments);

         // Set the item key so that we can compare it against the toggle publications to
         // check whether or not the publication relates to this widget...
         this._itemKey = lang.getObject(this.itemKeyProperty, false, this.currentItem);

         // Set the initial state...
         if (this.toggleStateProperty)
         {
            if (this.toggleOnWhenPropertySet)
            {
               this._actionsEnabled = lang.exists(this.toggleStateProperty, this.currentItem);
            }
            else
            {
               var toggleState = lang.getObject(this.toggleStateProperty, false, this.currentItem);
               this._actionsEnabled = (toggleState === this.toggleStateOnValue);
            }
         }

         // Set up subscriptions to the success topics...
         this.alfSubscribe(this.toggleOnSuccessTopic, lang.hitch(this, this.toggleOn));
         this.alfSubscribe(this.toggleOffSuccessTopic, lang.hitch(this, this.toggleOff));

         // Update the button as necessary...
         this._button.publishTopic = this.toggleOnRequestTopic;
         lang.setObject("publishPayload." + this.itemKeyProperty, this._itemKey, this._button);
         this.updateButtonLabel();
      },

      /**
       * Extends the function inherited from dijit/_HasDropDown to only allow the drop-down actions
       * menu to be displayed when [_actionsEnabled]{@link module:alfresco/renderers/ToggleStateActions#_actionsEnabled}
       * is set to true.
       * 
       * @instance
       */
      toggleDropDown: function alfresco_renderers_ToggleStateActions__toggleDropDown() {
         if (this._actionsEnabled)
         {
            this.inherited(arguments);
         }
      },

      /** 
       * Handles requests to toggle the state of the button to off. The payload is checked
       * that the [_itemKey]{@link module:alfresco/renderers/ToggleStateActions#_itemKey}
       * matches the [itemKeyProperty]{@link module:alfresco/renderers/ToggleStateActions#itemKeyProperty}.
       * 
       * @instance
       * @param {object} payload The payload published requesting to toggle to the off state
       */
      toggleOn: function alfresco_renderers_ToggleStateActions__toggleOn(payload) {
         var targetItemKey = lang.getObject(this.itemKeyProperty, false, payload);
         if (targetItemKey === this._itemKey)
         {
            this._actionsEnabled = true;
            this.updateButtonLabel();
         }
      },

      /** 
       * Handles requests to toggle the state of the button to off. The payload is checked
       * that the [_itemKey]{@link module:alfresco/renderers/ToggleStateActions#_itemKey}
       * matches either the [itemKeyProperty]{@link module:alfresco/renderers/ToggleStateActions#itemKeyProperty}
       * or the [itemKeyProperty]{@link module:alfresco/renderers/ToggleStateActions#itemKeyProperty} prefixed
       * by "document.". This latter condition exists to satisfy the case where there is not intermediate
       * service between toggle request and response where the action menu item includes the
       * [currentItem]{@link module:alfresco/core/CoreWidgetProcessing#currentItem} assigned to 
       * the "document" attribute in the published payload.
       * 
       * @instance
       * @param {object} payload The payload published requesting to toggle to the off state
       */
      toggleOff: function alfresco_renderers_ToggleStateActions__toggleOn(payload) {
         var extTargetItemKey = lang.getObject(this.itemKeyProperty, false, payload);
         var intTargetItemKey = lang.getObject("document." + this.itemKeyProperty, false, payload);
         if (extTargetItemKey === this._itemKey || intTargetItemKey === this._itemKey)
         {
            this._actionsEnabled = false;
            this.updateButtonLabel();
         }
      },

      /** 
       * Sets the label of the button with either the
       * [toggleOnStateLabel]{@link module:alfresco/renderers/ToggleStateActions#toggleOnStateLabel}
       * or the [toggleOffStateLabel]{@link module:alfresco/renderers/ToggleStateActions#toggleOffStateLabel}
       * depending upon the value of 
       * [_actionsEnabled]{@link module:alfresco/renderers/ToggleStateActions#_actionsEnabled}.
       * 
       * @instance
       * @param {object} payload The payload published requesting to toggle to the off state
       */
      updateButtonLabel: function alfresco_renderers_ToggleStateActions__updateButtonLabel() {
         if (this._actionsEnabled)
         {
            this._button.set("label", this.message(this.toggleOnStateLabel));
            domClass.add(this._button.domNode, "call-to-action");
         }
         else
         {
            this._button.set("label", this.message(this.toggleOffStateLabel));
            domClass.remove(this._button.domNode, "call-to-action");
         }
      }
   });
});