Source: menus/AlfMenuBarToggle.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 provides a basic on/off state toggle button that can be placed on a
 * [menu bar]{@link module:alfresco/menus/AlfMenuBar}. By default it simply renders
 * a switch with localized "On" and "Off" labels and doesn't actually perform any
 * action beyond rendering it's current state.</p>
 * <p>It can be configured with custom labels and/or icons to represent state. Ideally
 * each state should be given a publish topic and payload so that it can interact
 * with other widgets and perform a useful action. This is done by configuing the "onConfig"
 * and "offConfig" attributes.</p>
 * <p>Example configuration:</p>
 * <p><pre>{
 *    name: "alfresco/menus/AlfMenuBarToggle",
 *    config: {
 *       id: "MyToggle",
 *       checked: true,
 *       onConfig: {
 *          label: "Turned On",
 *          title: "Click to turn off",
 *          iconClass: "on-icon",
 *          iconAltText: "Toggle is on",
 *          publishTopic: "toggle_changed",
 *          publishPayload: {
 *             value: "ON"
 *          }
 *       },
 *       offConfig: {
 *          label: "Turned Off",
 *          title: "Click to turn on",
 *          iconClass: "off-icon",
 *          iconAltText: "Toggle is off",
 *          publishTopic: "toggle_changed",
 *          publishPayload: {
 *             value: "OFF"
 *          }
 *       }
 *    }
 * }</pre></p>
 *
 * @module alfresco/menus/AlfMenuBarToggle
 * @extends module:alfresco/menus/AlfMenuBarItem
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "alfresco/menus/AlfMenuBarItem",
        "alfresco/documentlibrary/_AlfDocumentListTopicMixin",
        "alfresco/documentlibrary/_AlfHashMixin",
        "dojo/dom-construct",
        "dojo/dom-class",
        "dojo/dom-attr",
        "dojo/_base/lang",
        "alfresco/util/hashUtils"], 
        function(declare, AlfMenuBarItem, _AlfDocumentListTopicMixin, _AlfHashMixin, domConstruct, domClass, domAttr, 
                 lang, hashUtils) {
   
   return declare([AlfMenuBarItem, _AlfDocumentListTopicMixin, _AlfHashMixin], {
      
      /**
       * An array of the CSS files to use with this widget.
       * 
       * @instance
       * @type {object[]}
       * @default [{cssFile:"./css/AlfMenuBarToggle.css"}]
       */
      cssRequirements: [{cssFile:"./css/AlfMenuBarToggle.css"}],
      
      /**
       * An array of the i18n files to use with this widget.
       * 
       * @instance
       * @type {object[]}
       * @default [{i18nFile: "./i18n/AlfMenuBarToggle.properties"}]
       */
      i18nRequirements: [{i18nFile: "./i18n/AlfMenuBarToggle.properties"}],
   
      /**
       * Indicates the on/off state. True is on, false is off.
       * 
       * @instance
       * @type {boolean}
       * @default
       */
      checked: false,
      
      /**
       * The configuration representing the toggle in it's 'on' state
       *
       * @instance
       * @type {object} 
       * @default
       */
      onConfig: null,
      
      /**
       * The configuration representing the toggle in it's 'off' state
       *
       * @instance
       * @type {object} 
       * @default
       */
      offConfig: null,
      
      /**
       * This sets default values for the [onConfig]{@link module:alfresco/menus/AlfMenuBarToggle#onConfig}
       * and [offConfig]{@link module:alfresco/menus/AlfMenuBarToggle#offConfig} attributes if they 
       * have not been configured. The defaults are localised "On" and "Off" labels with no publication
       * data for either state.
       *
       * @instance
       */
      constructor: function alfresco_menus_AlfMenuBarToggle__constructor(args) {
         /*jshint eqnull:true*/
         
         this.alfLog("log", "Create toggle", args);
         
         if (this.onConfig == null)
         {
            this.onConfig = 
            {
               label: "default.on.label"
            };
         }
         
         if (this.offConfig == null)
         {
            this.offConfig = {
               label: "default.off.label"
            };
         }
      },

      /**
       * This is a topic that can be subscribed to that when published on will set the state of the
       * toggle
       * 
       * @instance
       * @type {string}
       * @default
       */
      subscriptionTopic: null,

      /**
       * This is the attribute to look for in the payload when handling external requests to control
       * the toggle.
       *
       * @instance
       * @type {string}
       * @default
       */
      subscriptionAttribute: "value",

      /**
       * This is the value that indicates the toggle should be checked. It defaults to "true" and should
       * be overridden as necessary.
       *
       * @instance
       * @type {string}
       * @default
       */
      checkedValue: "true",

      /**
       * Subscribe the document list topics.
       * 
       * @instance
       */
      postMixInProperties: function alfresco_menus_AlfMenuBarToggle__postMixInProperties() {
         if (this.subscriptionTopic)
         {
            this.alfSubscribe(this.subscriptionTopic, lang.hitch(this, this.setState));
         }
      },

      /**
       * If this instance should be set according to a hash fragment value then this attribute should be
       * set to the name of the fragment parameter to use. If the hash fragment parameter exists and 
       * the value is "true" then the toggle will be automatically checked.
       * 
       * @instance
       * @type {string}
       * @default
       */
      hashName: null,

      /**
       * Sets up the initial state of the widget based on the [onConfig]{@link module:alfresco/menus/AlfMenuBarToggle#onConfig}
       * and [offConfig]{@link module:alfresco/menus/AlfMenuBarToggle#offConfig} attributes. The
       * [renderToggle]{@link module:alfresco/menus/AlfMenuBarToggle#renderToggle} function is called
       * to render the starting state.
       *
       * @instance
       */
      postCreate: function alfresco_menus_AlfMenuBarToggle__postCreate() {
         // Set an iconClass attribute if either the off or on configuration
         // provides it (it doesn't matter what gets set initially as it will
         // be overridden by the call to renderToggle). However, what this does
         // is ensure that an iconNode is created if required (this will be
         // done in the call to inherited(arguments)...
         if (this.onConfig && this.onConfig.iconClass)
         {
            this.iconClass = this.onConfig.iconClass;
         }
         else if (this.offConfig && this.offConfig.iconClass)
         {
            this.iconClass = this.offConfig.iconClass;
         }

         if (this.hashName)
         {
            var currHash = hashUtils.getHash();
            this.checked = (currHash[this.hashName] && currHash[this.hashName] === "true");
            this.alfSubscribe(this.hashChangeTopic, lang.hitch(this, this.setState));
         }

         this.inherited(arguments);
         if (this.checked)
         {
            this.renderToggle(this.onConfig, this.offConfig);
         }
         else
         {
            this.renderToggle(this.offConfig, this.onConfig);
         }
      },

      /**
       * This performs the rendering of the toggle when the widget is instantiated and 
       * when the state is changed. The labels and icons are updated to reflect the new
       * state.
       * 
       * @instance
       * @param {object} newConfig The new configuration to apply to the toggle button
       * @param {object} oldConfig The old configuration being removed from the toggle button.
       */
      renderToggle: function alfresco_menus_AlfMenuBarToggle__renderToggle(newConfig, oldConfig) {

         // New config has a label - set it
         if (newConfig && newConfig.label)
         {
            this.label = newConfig.label;
            this.set("label", this.message(newConfig.label));
            this.title = newConfig.title;
         }

         // New config has a title - set it
         if (newConfig && newConfig.title)
         {
            this.title = newConfig.title;
            var title = this.message(newConfig.title);
            this.set("title", title);
            domAttr.set(this.iconNode, "title", title);
         }

         // New config has iconAltText - set it on the iconNode
         if (newConfig && newConfig.iconAltText)
         {
            this.iconAltText = newConfig.iconAltText;
            domAttr.set(this.iconNode, "alt", newConfig.iconAltText);
         }

         // Remove old iconClass
         if (oldConfig && oldConfig.iconClass)
         {
            domClass.remove(this.iconNode, oldConfig.iconClass);
         }

         // New config has an iconClass - add it
         if (newConfig && newConfig.iconClass)
         {
            this.iconClass = newConfig.iconClass;
            domClass.add(this.iconNode, newConfig.iconClass);
         }

         // Clicking on the check cell will result in the menu item being marked as selected
         // but we want to ensure that this is not the case so always remove the class that 
         // indicates selection...
         domClass.remove(this.domNode, "dijitMenuItemSelected");
      },

      /**
       * This handles the user clicking on the toggle. The state is changed (e.g. from OFF on ON)
       * and any data associated with the new state is published on the configured topic. 
       *
       * @instance
       */
      onClick: function alfresco_menus_AlfMenuBarToggle__onClick() {
         this.alfLog("log", "Toggling!");
         this.checked = !this.checked;
         if (this.checked)
         {
            this.renderToggle(this.onConfig, this.offConfig);
            if (this.onConfig.publishTopic)
            {
               this.alfPublish(this.onConfig.publishTopic, this.onConfig.publishPayload);
            }
         }
         else
         {
            this.renderToggle(this.offConfig, this.onConfig);
            if (this.offConfig.publishTopic)
            {
               this.alfPublish(this.offConfig.publishTopic, this.offConfig.publishPayload);
            }
         }
      },

      /**
       * This handles the toggle being set by a 3rd party widget. It does not publish but just 
       * changes the display.
       *
       * @instance
       */
      setState: function alfresco_menus_AlfMenuBarToggle__setState(payload) {
         /*jshint eqnull:true*/
         if (payload && payload[this.subscriptionAttribute] != null)
         {
            this.alfLog("log", "Setting toggle state", payload, this);
            this.checked = (this.checkedValue === payload[this.subscriptionAttribute]);
            if (this.checked)
            {
               this.renderToggle(this.onConfig, this.offConfig);
            }
            else
            {
               this.renderToggle(this.offConfig, this.onConfig);
            }
         }
      }
   });
});