/**
* 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/>.
*/
/**
* An Alfresco styled notification.
*
* @module alfresco/notifications/AlfNotification
* @author Martin Doyle
*/
define(["alfresco/core/Core",
"alfresco/core/CoreWidgetProcessing",
"dojo/_base/array",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/Deferred",
"dojo/dom-class",
"dijit/_TemplatedMixin",
"dijit/_WidgetBase",
"dijit/registry",
"dojo/text!./templates/AlfNotification.html"],
function(AlfCore, CoreWidgetProcessing, array, declare, lang, Deferred, domClass, _TemplatedMixin, _WidgetBase, registry, template) {
return declare([_WidgetBase, _TemplatedMixin, AlfCore, CoreWidgetProcessing], {
/**
* An array of the CSS files to use with this widget.
*
* @instance cssRequirements {Array}
* @type {object[]}
* @default [{cssFile:"./css/AlfNotification.css"}]
*/
cssRequirements: [{
cssFile: "./css/AlfNotification.css"
}],
/**
* The HTML template to use for the widget.
*
* @instance
* @type {String}
*/
templateString: template,
/**
* Whether to remain open and not automatically close.
*
* @instance
* @type {boolean}
* @default
* @since 1.0.63
*/
autoClose: true,
/**
* If this property is specified, then it will be possible to close this notification by
* publishing to this topic.
*
* @instance
* @type {String}
* @default
* @since 1.0.65
*/
closeTopic: null,
/**
* How many milliseconds to wait before destroying this widget after the notification has been hidden
*
* @instance
* @type {number}
* @default
*/
destroyAfterHideMs: 1000,
/**
* Variable to hold the Deferred object that will resolve once this notification is destroyed
*
* @type {object}
*/
destroyDeferred: null,
/**
* The notification ID (helps with customisation)
*
* @instance
* @type {String}
* @default
* @since 1.0.63
*/
id: null,
/**
* This allows a simple inline-link to be added to the notification which, when clicked, will
* publish the provided topic and payload.
*
* @instance
* @type {Object}
* @property {String} label The text to display on the link
* @property {String} publishTopic The topic to be published
* @property {Object} [publishPayload] The payload to be published
* @default
* @since 1.0.63
*/
inlineLink: null,
/**
* Estimate how many seconds it might take a user to focus on a notification
*
* @instance
* @type {number}
* @default
*/
notificationFocusSecs: 1,
/**
* How many seconds to add on for each included widget
*
* @instance
* @type {number}
* @default
* @since 1.0.63
*/
widgetSecs: 1,
/**
* An array of widgets to be inserted into the notification, underneath the message.
*
* @instance
* @type {Object[]}
* @default
* @since 1.0.63
*/
widgets: null,
/**
* If the inlineLink object has been specified then use this widgets structure
* to create the button to be inserted.
*
* @instance
* @type {Object[]}
* @since 1.0.63
*/
widgetsForInlineLink: [{
name: "alfresco/navigation/Link",
config: {}
}],
/**
* How many words per second a person will read, used to determine how long to display the message.
* First attempt to gauge how long to show message ... may need refining!
*
* @instance
* @type {number}
* @default
*/
wordsPerSecond: 5,
/**
* This is run after the properties have been mixed in, but before the
* widget is created.
*
* @instance
* @override
* @since 1.0.63
*/
postMixInProperties: function alfresco_notifications_AlfNotification__postMixInProperties() {
if (!this.id || registry.byId(this.id)) {
this.id = this.generateUuid();
}
if (this.closeTopic) {
var closeSubscription = this.alfSubscribe(this.closeTopic, lang.hitch(this, function() {
this.alfUnsubscribe(closeSubscription);
this._hide();
}));
}
this.inherited(arguments);
},
/**
* Called after widget created, but not sub-widgets
*
* @instance
* @override
*/
postCreate: function alfresco_notifications_AlfNotification__postCreate() {
// Make sure to call the chained methods
this.inherited(arguments);
// Update the CSS state if auto-close is enabled
if (this.autoClose) {
domClass.add(this.domNode, "alfresco-notifications-AlfNotification--auto-close");
}
// Display either the inline button or the widgets (inline takes priority)
if (this.inlineLink) {
domClass.add(this.domNode, "alfresco-notifications-AlfNotification--has-inline-button");
var inlineLinkWidgets = lang.clone(this.widgetsForInlineLink);
lang.mixin(inlineLinkWidgets[0].config, {
label: this.inlineLink.label,
publishTopic: this.inlineLink.publishTopic,
publishPayload: this.inlineLink.publishPayload
});
this.processWidgets(inlineLinkWidgets, this.widgetsNode);
this.containerNode.insertBefore(this.widgetsNode, this.messageNode);
} else if (this.widgets && this.widgets.length) {
domClass.add(this.domNode, "alfresco-notifications-AlfNotification--has-widgets");
this.processWidgets(lang.clone(this.widgets), this.widgetsNode);
}
// Add this widget to the end of the body
document.body.appendChild(this.domNode);
},
/**
* Called when widget is destroyed
*
* @instance
*/
destroy: function alfresco_notifications_AlfNotification__destroy() {
this.destroyDeferred.resolve();
this.inherited(arguments);
},
/**
* Display the notification.
*
* @instance
* @returns {object} A promise that will resolve once the notification is destroyed.
*/
display: function alfresco_notifications_AlfNotification__display() {
this.destroyDeferred = new Deferred();
setTimeout(lang.hitch(this, this._show), 0); // Add to page before showing, else transition fails
return this.destroyDeferred.promise;
},
/**
* Count the number of widgets provided in the config
*
* @instance
* @private
* @returns {number} The number of widgets
* @since 1.0.63
*/
_countWidgets: function alfresco_notifications_AlfNotification___countWidgets() {
var numWidgets = 0;
(function countWidgets(widgets) {
if (!widgets || !widgets.length) {
return;
}
if (widgets.constructor === Array) {
numWidgets += widgets.length;
}
array.forEach(widgets, function(widget) {
var conf = widget.config;
if (conf) {
for (var propName in conf) {
if (conf.hasOwnProperty(propName) && propName.indexOf("widgets") === 0) {
countWidgets(conf[propName]);
}
}
}
});
})(this.widgets);
return numWidgets;
},
/**
* Hide the notification (and destroy it)
*
* @instance
* @private
*/
_hide: function alfresco_notifications_AlfNotification___hide() {
if (this.domNode && this.domNode.parentNode === document.body) {
domClass.remove(this.domNode, "alfresco-notifications-AlfNotification--visible");
setTimeout(lang.hitch(this, this.destroy), this.destroyAfterHideMs);
}
},
/**
* Handle clicks on the close button
*
* @instance
* @private
* @param {Object} evt Dojo-normalised event object
*/
_onCloseClick: function alfresco_notifications_AlfNotification___onCloseClick( /*jshint unused:false*/ evt) {
this._hide();
},
/**
* Show the notification
*
* @instance
* @private
*/
_show: function alfresco_notifications_AlfNotification___show() {
domClass.add(this.domNode, "alfresco-notifications-AlfNotification--visible");
var messageText = this.messageNode.textContent || this.message.innerText || "",
messageWords = messageText.split(/\W+/),
numWidgets = this._countWidgets(),
autoHideSecs = Math.ceil(messageWords.length / this.wordsPerSecond) + Math.ceil(numWidgets * this.widgetSecs) + this.notificationFocusSecs;
if (this.autoClose) {
setTimeout(lang.hitch(this, this._hide), autoHideSecs * 1000);
}
}
});
});