Path: blob/master/webroot/rsrc/js/core/Notification.js
12241 views
/**1* @requires javelin-install2* javelin-dom3* javelin-stratcom4* javelin-util5* phabricator-notification-css6* @provides phabricator-notification7* @javelin8*/910/**11* Show a notification popup on screen. Usage:12*13* var n = new JX.Notification()14* .setContent('click me!');15* n.listen('activate', function(e) { alert('you clicked!'); });16* n.show();17*18*/19JX.install('Notification', {2021events : ['activate', 'close'],2223members : {24_container : null,25_visible : false,26_hideTimer : null,27_duration : 12000,28_asDesktop : false,29_asWeb : true,30_key : null,31_title : null,32_body : null,33_href : null,34_icon : null,3536show : function() {37var self = JX.Notification;3839if (!this._visible) {40this._visible = true;4142self._show(this);43this._updateTimer();44}4546if (self.supportsDesktopNotifications() &&47self.desktopNotificationsEnabled() &&48this._asDesktop) {49// Note: specifying "tag" means that notifications with matching50// keys will aggregate.51var n = new window.Notification(this._title, {52icon: this._icon,53body: this._body,54tag: this._key,55});56n.onclick = JX.bind(n, function (href) {57this.close();58window.focus();59if (href) {60JX.$U(href).go();61}62}, this._href);63// Note: some OS / browsers do this automagically; make the behavior64// happen everywhere.65setTimeout(n.close.bind(n), this._duration);66}67return this;68},6970hide : function() {71if (this._visible) {72this._visible = false;7374var self = JX.Notification;75self._hide(this);76this._updateTimer();77}78return this;79},8081alterClassName : function(name, enable) {82JX.DOM.alterClass(this._getContainer(), name, enable);83return this;84},8586setContent : function(content) {87JX.DOM.setContent(this._getContainer(), content);88return this;89},9091setShowAsWebNotification: function(mode) {92this._asWeb = mode;93return this;94},9596setShowAsDesktopNotification : function(mode) {97this._asDesktop = mode;98return this;99},100101setTitle : function(title) {102this._title = title;103return this;104},105106setBody : function(body) {107this._body = body;108return this;109},110111setHref : function(href) {112this._href = href;113return this;114},115116setKey : function(key) {117this._key = key;118return this;119},120121setIcon : function(icon) {122this._icon = icon;123return this;124},125126/**127* Set duration before the notification fades away, in milliseconds. If set128* to 0, the notification persists until dismissed.129*130* @param int Notification duration, in milliseconds.131* @return this132*/133setDuration : function(milliseconds) {134this._duration = milliseconds;135this._updateTimer(false);136return this;137},138139_updateTimer : function() {140if (this._hideTimer) {141clearTimeout(this._hideTimer);142this._hideTimer = null;143}144145if (this._visible && this._duration) {146this._hideTimer = setTimeout(JX.bind(this, this.hide), this._duration);147}148},149150_getContainer : function() {151if (!this._container) {152this._container = JX.$N(153'div',154{155className: 'jx-notification',156sigil: 'jx-notification'157});158}159return this._container;160}161},162163statics : {164supportsDesktopNotifications : function () {165return 'Notification' in window;166},167desktopNotificationsEnabled : function () {168return window.Notification.permission === 'granted';169},170_container : null,171_listening : false,172_active : [],173_show : function(notification) {174var self = JX.Notification;175176self._installListener();177self._active.push(notification);178self._redraw();179},180_hide : function(notification) {181var self = JX.Notification;182183for (var ii = 0; ii < self._active.length; ii++) {184if (self._active[ii] === notification) {185notification.invoke('close');186self._active.splice(ii, 1);187break;188}189}190191self._redraw();192},193_installListener : function() {194var self = JX.Notification;195196if (self._listening) {197return;198} else {199self._listening = true;200}201202JX.Stratcom.listen(203'click',204'jx-notification',205function(e) {206// NOTE: Don't kill the event since the user might have clicked a207// link, and we want to follow the link if they did. Instead, invoke208// the activate event for the active notification and dismiss it if it209// isn't handled.210211var target = e.getNode('jx-notification');212for (var ii = 0; ii < self._active.length; ii++) {213var n = self._active[ii];214if (n._getContainer() === target) {215var activation = n.invoke('activate');216if (!activation.getPrevented()) {217n.hide();218}219return;220}221}222223});224},225_redraw : function() {226var self = JX.Notification;227228if (!self._active.length) {229if (self._container) {230JX.DOM.remove(self._container);231self._container = null;232}233return;234}235236if (!self._container) {237self._container = JX.$N(238'div',239{240className: 'jx-notification-container'241});242document.body.appendChild(self._container);243}244245// Show only a limited number of notifications at once.246var limit = 5;247248var notifications = [];249for (var ii = 0; ii < self._active.length; ii++) {250251// Don't render this notification if it's not configured to show as252// a web notification.253if (!self._active[ii]._asWeb) {254continue;255}256257notifications.push(self._active[ii]._getContainer());258if (!(--limit)) {259break;260}261}262263JX.DOM.setContent(self._container, notifications);264}265}266267});268269270