/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Logan Byam
*/
/* eslint-env browser */
/**
* @module bajaux/util/CommandButton
*/
define([ 'jquery',
'Promise',
'underscore',
'bajaux/events',
'bajaux/Widget',
'bajaux/commands/Command',
'bajaux/commands/ToggleCommand',
'bajaux/icon/iconUtils',
'nmodule/js/rc/log/Log' ], function (
$,
Promise,
_,
events,
Widget,
Command,
ToggleCommand,
iconUtils,
Log) {
'use strict';
var COMMAND_CHANGE_EVENT = events.command.CHANGE_EVENT,
toHtml = iconUtils.toHtml,
cmdButtonsWaiting = [],
logError = Log.logMessage.bind(Log,
'nmodule.bajaux.rc.util.CommandButton', Log.Level.SEVERE);
var updateAll = _.debounce(function () {
cmdButtonsWaiting.forEach(function (button) {
button.$updateDom().catch(logError);
});
cmdButtonsWaiting = [];
}, 250);
/**
* When enabling/disabling multiple buttons at once, don't throttle each call
* separately as they'll resolve at different times and give you multiple
* repaints. Throttle all commands at once to minimize repaints.
* @param {module:bajaux/util/CommandButton} cmdButton
*/
function updateCommandButtonDom(cmdButton) {
if (!_.contains(cmdButtonsWaiting, cmdButton)) {
cmdButtonsWaiting.push(cmdButton);
updateAll();
}
}
/**
* A widget for displaying and invoking a Command.
*
* @class
* @extends module:bajaux/Widget
* @alias module:bajaux/util/CommandButton
*/
var CommandButton = function CommandButton() {
Widget.apply(this, arguments);
};
CommandButton.prototype = Object.create(Widget.prototype);
CommandButton.prototype.constructor = CommandButton;
/**
* Get the element that will hold the icon `img`s.
*
* @private
* @returns {JQuery}
*/
CommandButton.prototype.$getIconElement = function () {
return this.jq().children('.display').children('.icon');
};
/**
* Get the element that will hold the command's display name.
*
* @private
* @returns {JQuery}
*/
CommandButton.prototype.$getDisplayNameElement = function () {
return this.jq().children('.display').children('.displayName');
};
/**
* Arms a click handler that will invoke the loaded Command. Adds a
* `CommandButton` CSS class.
*
* Technically, this widget can be initialized in any DOM element, but makes
* the most sense in a `button` element.
*
* @param {JQuery} dom
*/
CommandButton.prototype.doInitialize = function (dom) {
var that = this;
dom.on('click', function () {
var cmd = that.value();
if (cmd.isEnabled() && that.isEnabled()) {
cmd.invoke().catch(logError);
}
});
const el = dom[0];
if (!el) { return; }
el.classList.add('CommandButton');
const displaySpan = document.createElement('span');
displaySpan.className = 'display';
const iconSpan = document.createElement('span');
iconSpan.className = 'icon';
const displayNameSpan = document.createElement('span');
displayNameSpan.className = 'displayName';
displaySpan.appendChild(iconSpan);
displaySpan.appendChild(displayNameSpan);
el.append(displaySpan);
};
/**
* Updates the display name, description, icon, and enabled status of the
* button widget. Should be called once on load and whenever the loaded
* Command changes.
*
* @private
* @returns {Promise} promise to be resolved when the DOM has finished
* updating
*/
CommandButton.prototype.$updateDom = function () {
var that = this,
jq = that.jq(),
cmd = that.value();
if (!jq || !jq.length) {
return Promise.resolve();
}
return Promise.all([ cmd.toDisplayName(), cmd.toDescription() ])
.then(([ displayName, description ]) => {
if (!that.isInitialized()) { return; }
var iconElement = that.$getIconElement(),
displayNameElement = that.$getDisplayNameElement(),
isToggled = cmd.isToggleCommand() && cmd.isSelected(),
icon = cmd.getIcon(),
cmdEnabled = cmd.isEnabled(),
btnEnabled = that.isEnabled();
jq.attr('title', description);
displayNameElement.text(displayName);
jq.toggleClass('ux-toggled', isToggled);
return Promise.all([
(btnEnabled !== cmdEnabled) && that.setEnabled(cmdEnabled),
icon && toHtml(icon).then((html) => iconElement.html(html))
]);
});
};
/**
* Loads a Command. Binds an event handler to update the DOM whenever the
* Command's properties are changed.
*
* @param {module:bajaux/commands/Command} cmd
* @returns {Promise} promise to be resolved when the `Command` is
* loaded, or rejected if no `Command` given
*/
CommandButton.prototype.doLoad = function (cmd) {
if (!(cmd instanceof Command)) {
throw new Error('Command required');
}
var that = this,
changeHandler = that.$changeHandler;
cmd.loading().then(function () {
if (changeHandler) {
cmd.off(COMMAND_CHANGE_EVENT, changeHandler);
}
cmd.on(COMMAND_CHANGE_EVENT, that.$changeHandler = function () {
updateCommandButtonDom(that);
});
})
.catch(logError);
return that.$updateDom();
};
/**
* Removes the click handler and CSS class from `doInitialize`.
*/
CommandButton.prototype.doDestroy = function () {
this.jq()
.removeClass('CommandButton')
.removeClass('ux-disabled');
var cmd = this.value();
if (cmd) {
cmd.off(COMMAND_CHANGE_EVENT, this.$changeHandler);
}
};
/**
* Adds or removes the `disabled` property from the DOM.
*
* @param {Boolean} enabled
*/
CommandButton.prototype.doEnabled = function (enabled) {
this.jq().prop('disabled', !enabled).toggleClass('ux-disabled', !enabled);
};
return CommandButton;
});