1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * Singleton alert class that alerts the user by popping up a message on the desktop. 26 * @class 27 * @private 28 */ 29 ZmDesktopAlert = function() { 30 if (window.webkitNotifications) { 31 this.useWebkit = true; 32 } else if (window.Notification) { 33 this.useNotification = true; 34 } else if (appCtxt.isOffline && window.platform && (AjxEnv.isWindows || AjxEnv.isMac)) { 35 this.usePrism = true; 36 } 37 }; 38 39 ZmDesktopAlert.prototype = new ZmAlert; 40 ZmDesktopAlert.prototype.constructor = ZmDesktopAlert; 41 42 ZmDesktopAlert.prototype.toString = 43 function() { 44 return "ZmDesktopAlert"; 45 }; 46 47 ZmDesktopAlert.getInstance = 48 function() { 49 return ZmDesktopAlert.INSTANCE = ZmDesktopAlert.INSTANCE || new ZmDesktopAlert(); 50 }; 51 52 /** 53 * Returns text to show in a prefs page next to the checkbox to enable this type of alert. 54 */ 55 ZmDesktopAlert.prototype.getDisplayText = 56 function() { 57 if (this.useWebkit || this.useNotification) { 58 return ZmMsg.showPopup; 59 } else if (this.usePrism) { 60 return AjxEnv.isMac ? ZmMsg.showPopupMac : ZmMsg.showPopup; 61 } 62 }; 63 64 ZmDesktopAlert.prototype.start = 65 function(title, message, sticky) { 66 if (this.useWebkit) { 67 var allowedCallback = this._showWebkitNotification.bind(this, title, message, sticky); 68 this._checkWebkitPermission(allowedCallback); 69 } else if (this.useNotification) { 70 var notificationCallback = this._showNotification.bind(this, title, message, sticky); 71 this._checkNotificationPermission(notificationCallback); 72 } else if (this.usePrism) { 73 if (AjxEnv.isMac) { 74 try { 75 window.platform.showNotification(title, message, "resource://webapp/icons/default/launcher.icns"); 76 } catch (err) {} 77 } 78 else if (AjxEnv.isWindows) { 79 try { 80 window.platform.icon().showNotification(title, message, 5); 81 } catch (err) {} 82 } 83 } 84 }; 85 86 /* Checks if we have permission to use webkit notifications. If so, or when the user 87 * grants permission, allowedCallback is called. 88 */ 89 ZmDesktopAlert.prototype._checkWebkitPermission = 90 function(allowedCallback) { 91 var allowed = window.webkitNotifications.checkPermission() == 0; 92 if (allowed) { 93 allowedCallback(); 94 } else if (!ZmDesktopAlert.requestedPermission) { 95 ZmDesktopAlert.requestedPermission = true; // Prevents multiple permission requests in one session. 96 window.webkitNotifications.requestPermission(this._checkWebkitPermission.bind(this, allowedCallback)); 97 } 98 }; 99 100 ZmDesktopAlert.prototype._showWebkitNotification = 101 function(title, message, sticky) { 102 sticky = sticky || false; 103 // Icon: I chose to use the favIcon because it's already overridable by skins. 104 // It's a little ugly though. 105 // change for bug#67359: Broken notification image in chrome browser 106 // //var icon = window.favIconUrl; 107 var icon = skin.hints.notificationBanner; 108 var popup = window.webkitNotifications.createNotification(icon, title, message); 109 popup.show(); 110 popup.onclick = function() {popup.cancel();}; 111 if (sticky) { 112 if (!ZmDesktopAlert.notificationArray) { 113 ZmDesktopAlert.notificationArray = []; 114 } 115 ZmDesktopAlert.notificationArray.push(popup); 116 } 117 else { 118 // Close the popup after 5 seconds. 119 setTimeout(popup.cancel.bind(popup), 5000); 120 } 121 }; 122 123 /* Checks if we have permission to use the notification api. If so, or when the user 124 * grants permission, allowedCallback is called. 125 */ 126 ZmDesktopAlert.prototype._checkNotificationPermission = function(allowedCallback) { 127 var allowed = window.Notification.permission === 'granted'; 128 if (allowed) { 129 allowedCallback(); 130 } else if (!ZmDesktopAlert.requestedPermission) { 131 ZmDesktopAlert.requestedPermission = true; // Prevents multiple permission requests in one session. 132 // Currently, cannot directly call requestPermission. Re-test when Chrome 37 is released 133 //window.Notification.requestPermission(this._checkNotificationPermission.bind(this, allowedCallback)); 134 var requestCallback = this._checkNotificationPermission.bind(this, allowedCallback); 135 this.requestRequestPermission(requestCallback); 136 } 137 }; 138 139 // Chrome Notification only allows requesting permission in response to a user action, not a programmatic call. 140 // The issue may be fixed in Chrome 37, whenever that comes out. See: 141 // https://code.google.com/p/chromium/issues/detail?id=274284 142 ZmDesktopAlert.prototype.requestRequestPermission = function(requestCallback) { 143 var msgDialog = appCtxt.getYesNoMsgDialog(); 144 var callback = this._doRequestPermission.bind(this, msgDialog, requestCallback); 145 msgDialog.registerCallback(DwtDialog.YES_BUTTON, callback); 146 msgDialog.setMessage(ZmMsg.notificationPermission, DwtMessageDialog.INFO_STYLE); 147 msgDialog.popup(); 148 }; 149 150 ZmDesktopAlert.prototype._doRequestPermission = function(msgDialog, requestCallback) { 151 msgDialog.popdown(); 152 window.Notification.requestPermission(requestCallback); 153 } 154 155 ZmDesktopAlert.prototype._showNotification = function(title, message, sticky) { 156 var icon = skin.hints.notificationBanner; 157 158 var popup = new Notification(title, { body: message, icon: icon}); 159 //popup.show(); 160 popup.onclick = function() {popup.close();}; 161 if (sticky) { 162 if (!ZmDesktopAlert.notificationArray) { 163 ZmDesktopAlert.notificationArray = []; 164 } 165 ZmDesktopAlert.notificationArray.push(popup); 166 } 167 else { 168 // Close the popup after 5 seconds. 169 setTimeout(popup.close.bind(popup), 5000); 170 } 171 }; 172 173 ZmDesktopAlert.prototype._notifyServiceCallback = 174 function(title, message, service) { 175 try { 176 service.show({ title: title, message: message }, function(){}); 177 } catch (err) {} 178 }; 179 180 /** 181 * Closes desktop notification if any during onbeforeunload event 182 */ 183 ZmDesktopAlert.closeNotification = 184 function() { 185 var notificationArray = ZmDesktopAlert.notificationArray, 186 popup; 187 188 if (notificationArray) { 189 while (popup = notificationArray.pop()) { 190 //notifications may be already closed by the user go for try catch 191 try { 192 popup.cancel(); 193 } 194 catch (e) { 195 } 196 } 197 } 198 }; 199