1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/widgets/notification.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,500 @@ 1.4 +<?xml version="1.0"?> 1.5 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.6 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.8 + 1.9 + 1.10 +<!DOCTYPE bindings [ 1.11 +<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd"> 1.12 +%notificationDTD; 1.13 +]> 1.14 + 1.15 +<bindings id="notificationBindings" 1.16 + xmlns="http://www.mozilla.org/xbl" 1.17 + xmlns:xbl="http://www.mozilla.org/xbl" 1.18 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 1.19 + 1.20 + <binding id="notificationbox"> 1.21 + <content> 1.22 + <xul:stack xbl:inherits="hidden=notificationshidden" 1.23 + class="notificationbox-stack"> 1.24 + <xul:spacer/> 1.25 + <children includes="notification"/> 1.26 + </xul:stack> 1.27 + <children/> 1.28 + </content> 1.29 + 1.30 + <implementation> 1.31 + <field name="PRIORITY_INFO_LOW" readonly="true">1</field> 1.32 + <field name="PRIORITY_INFO_MEDIUM" readonly="true">2</field> 1.33 + <field name="PRIORITY_INFO_HIGH" readonly="true">3</field> 1.34 + <field name="PRIORITY_WARNING_LOW" readonly="true">4</field> 1.35 + <field name="PRIORITY_WARNING_MEDIUM" readonly="true">5</field> 1.36 + <field name="PRIORITY_WARNING_HIGH" readonly="true">6</field> 1.37 + <field name="PRIORITY_CRITICAL_LOW" readonly="true">7</field> 1.38 + <field name="PRIORITY_CRITICAL_MEDIUM" readonly="true">8</field> 1.39 + <field name="PRIORITY_CRITICAL_HIGH" readonly="true">9</field> 1.40 + <field name="PRIORITY_CRITICAL_BLOCK" readonly="true">10</field> 1.41 + 1.42 + <field name="currentNotification">null</field> 1.43 + 1.44 + <field name="_closedNotification">null</field> 1.45 + <field name="_blockingCanvas">null</field> 1.46 + <field name="_animating">false</field> 1.47 + 1.48 + <property name="notificationsHidden" 1.49 + onget="return this.getAttribute('notificationshidden') == 'true';"> 1.50 + <setter> 1.51 + if (val) 1.52 + this.setAttribute('notificationshidden', true); 1.53 + else this.removeAttribute('notificationshidden'); 1.54 + return val; 1.55 + </setter> 1.56 + </property> 1.57 + 1.58 + <property name="allNotifications" readonly="true"> 1.59 + <getter> 1.60 + <![CDATA[ 1.61 + var closedNotification = this._closedNotification; 1.62 + var notifications = this.getElementsByTagName('notification'); 1.63 + return Array.filter(notifications, function(n) n != closedNotification); 1.64 + ]]> 1.65 + </getter> 1.66 + </property> 1.67 + 1.68 + <method name="getNotificationWithValue"> 1.69 + <parameter name="aValue"/> 1.70 + <body> 1.71 + <![CDATA[ 1.72 + var notifications = this.allNotifications; 1.73 + for (var n = notifications.length - 1; n >= 0; n--) { 1.74 + if (aValue == notifications[n].getAttribute("value")) 1.75 + return notifications[n]; 1.76 + } 1.77 + return null; 1.78 + ]]> 1.79 + </body> 1.80 + </method> 1.81 + 1.82 + <method name="appendNotification"> 1.83 + <parameter name="aLabel"/> 1.84 + <parameter name="aValue"/> 1.85 + <parameter name="aImage"/> 1.86 + <parameter name="aPriority"/> 1.87 + <parameter name="aButtons"/> 1.88 + <parameter name="aEventCallback"/> 1.89 + <body> 1.90 + <![CDATA[ 1.91 + if (aPriority < this.PRIORITY_INFO_LOW || 1.92 + aPriority > this.PRIORITY_CRITICAL_BLOCK) 1.93 + throw "Invalid notification priority " + aPriority; 1.94 + 1.95 + // check for where the notification should be inserted according to 1.96 + // priority. If two are equal, the existing one appears on top. 1.97 + var notifications = this.allNotifications; 1.98 + var insertPos = null; 1.99 + for (var n = notifications.length - 1; n >= 0; n--) { 1.100 + if (notifications[n].priority < aPriority) 1.101 + break; 1.102 + insertPos = notifications[n]; 1.103 + } 1.104 + 1.105 + const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.106 + var newitem = document.createElementNS(XULNS, "notification"); 1.107 + newitem.setAttribute("label", aLabel); 1.108 + newitem.setAttribute("value", aValue); 1.109 + if (aImage) 1.110 + newitem.setAttribute("image", aImage); 1.111 + newitem.eventCallback = aEventCallback; 1.112 + 1.113 + if (aButtons) { 1.114 + // The notification-button-default class is added to the button 1.115 + // with isDefault set to true. If there is no such button, it is 1.116 + // added to the first button (unless that button has isDefault 1.117 + // set to false). There cannot be multiple default buttons. 1.118 + var defaultElem; 1.119 + 1.120 + for (var b = 0; b < aButtons.length; b++) { 1.121 + var button = aButtons[b]; 1.122 + var buttonElem = document.createElementNS(XULNS, "button"); 1.123 + buttonElem.setAttribute("label", button.label); 1.124 + buttonElem.setAttribute("accesskey", button.accessKey); 1.125 + buttonElem.classList.add("notification-button"); 1.126 + 1.127 + if (button.isDefault || 1.128 + b == 0 && !("isDefault" in button)) 1.129 + defaultElem = buttonElem; 1.130 + 1.131 + newitem.appendChild(buttonElem); 1.132 + buttonElem.buttonInfo = button; 1.133 + } 1.134 + 1.135 + if (defaultElem) 1.136 + defaultElem.classList.add("notification-button-default"); 1.137 + } 1.138 + 1.139 + newitem.setAttribute("priority", aPriority); 1.140 + if (aPriority >= this.PRIORITY_CRITICAL_LOW) 1.141 + newitem.setAttribute("type", "critical"); 1.142 + else if (aPriority <= this.PRIORITY_INFO_HIGH) 1.143 + newitem.setAttribute("type", "info"); 1.144 + else 1.145 + newitem.setAttribute("type", "warning"); 1.146 + 1.147 + if (!insertPos) { 1.148 + newitem.style.position = "fixed"; 1.149 + newitem.style.top = "100%"; 1.150 + newitem.style.marginTop = "-15px"; 1.151 + newitem.style.opacity = "0"; 1.152 + } 1.153 + this.insertBefore(newitem, insertPos); 1.154 + if (!insertPos) 1.155 + this._showNotification(newitem, true); 1.156 + 1.157 + // Fire event for accessibility APIs 1.158 + var event = document.createEvent("Events"); 1.159 + event.initEvent("AlertActive", true, true); 1.160 + newitem.dispatchEvent(event); 1.161 + 1.162 + return newitem; 1.163 + ]]> 1.164 + </body> 1.165 + </method> 1.166 + 1.167 + <method name="removeNotification"> 1.168 + <parameter name="aItem"/> 1.169 + <parameter name="aSkipAnimation"/> 1.170 + <body> 1.171 + <![CDATA[ 1.172 + if (aItem == this.currentNotification) 1.173 + this.removeCurrentNotification(aSkipAnimation); 1.174 + else if (aItem != this._closedNotification) 1.175 + this._removeNotificationElement(aItem); 1.176 + return aItem; 1.177 + ]]> 1.178 + </body> 1.179 + </method> 1.180 + 1.181 + <method name="_removeNotificationElement"> 1.182 + <parameter name="aChild"/> 1.183 + <body> 1.184 + <![CDATA[ 1.185 + if (aChild.eventCallback) 1.186 + aChild.eventCallback("removed"); 1.187 + this.removeChild(aChild); 1.188 + 1.189 + // make sure focus doesn't get lost (workaround for bug 570835) 1.190 + let fm = Components.classes["@mozilla.org/focus-manager;1"] 1.191 + .getService(Components.interfaces.nsIFocusManager); 1.192 + if (!fm.getFocusedElementForWindow(window, false, {})) 1.193 + fm.moveFocus(window, this, fm.MOVEFOCUS_FORWARD, 0); 1.194 + ]]> 1.195 + </body> 1.196 + </method> 1.197 + 1.198 + <method name="removeCurrentNotification"> 1.199 + <parameter name="aSkipAnimation"/> 1.200 + <body> 1.201 + <![CDATA[ 1.202 + this._showNotification(this.currentNotification, false, aSkipAnimation); 1.203 + ]]> 1.204 + </body> 1.205 + </method> 1.206 + 1.207 + <method name="removeAllNotifications"> 1.208 + <parameter name="aImmediate"/> 1.209 + <body> 1.210 + <![CDATA[ 1.211 + var notifications = this.allNotifications; 1.212 + for (var n = notifications.length - 1; n >= 0; n--) { 1.213 + if (aImmediate) 1.214 + this._removeNotificationElement(notifications[n]); 1.215 + else 1.216 + this.removeNotification(notifications[n]); 1.217 + } 1.218 + this.currentNotification = null; 1.219 + 1.220 + // Must clear up any currently animating notification 1.221 + if (aImmediate) 1.222 + this._finishAnimation(); 1.223 + ]]> 1.224 + </body> 1.225 + </method> 1.226 + 1.227 + <method name="removeTransientNotifications"> 1.228 + <body> 1.229 + <![CDATA[ 1.230 + var notifications = this.allNotifications; 1.231 + for (var n = notifications.length - 1; n >= 0; n--) { 1.232 + var notification = notifications[n]; 1.233 + if (notification.persistence) 1.234 + notification.persistence--; 1.235 + else if (Date.now() > notification.timeout) 1.236 + this.removeNotification(notification); 1.237 + } 1.238 + ]]> 1.239 + </body> 1.240 + </method> 1.241 + 1.242 + <method name="_showNotification"> 1.243 + <parameter name="aNotification"/> 1.244 + <parameter name="aSlideIn"/> 1.245 + <parameter name="aSkipAnimation"/> 1.246 + <body> 1.247 + <![CDATA[ 1.248 + this._finishAnimation(); 1.249 + 1.250 + var height = aNotification.boxObject.height; 1.251 + var skipAnimation = aSkipAnimation || (height == 0); 1.252 + 1.253 + if (aSlideIn) { 1.254 + this.currentNotification = aNotification; 1.255 + aNotification.style.removeProperty("position"); 1.256 + aNotification.style.removeProperty("top"); 1.257 + aNotification.style.removeProperty("margin-top"); 1.258 + aNotification.style.removeProperty("opacity"); 1.259 + 1.260 + if (skipAnimation) { 1.261 + this._setBlockingState(this.currentNotification); 1.262 + return; 1.263 + } 1.264 + } 1.265 + else { 1.266 + this._closedNotification = aNotification; 1.267 + var notifications = this.allNotifications; 1.268 + var idx = notifications.length - 1; 1.269 + this.currentNotification = (idx >= 0) ? notifications[idx] : null; 1.270 + 1.271 + if (skipAnimation) { 1.272 + this._removeNotificationElement(this._closedNotification); 1.273 + this._closedNotification = null; 1.274 + this._setBlockingState(this.currentNotification); 1.275 + return; 1.276 + } 1.277 + 1.278 + aNotification.style.marginTop = -height + "px"; 1.279 + aNotification.style.opacity = 0; 1.280 + } 1.281 + 1.282 + this._animating = true; 1.283 + ]]> 1.284 + </body> 1.285 + </method> 1.286 + 1.287 + <method name="_finishAnimation"> 1.288 + <body><![CDATA[ 1.289 + if (this._animating) { 1.290 + this._animating = false; 1.291 + if (this._closedNotification) { 1.292 + this._removeNotificationElement(this._closedNotification); 1.293 + this._closedNotification = null; 1.294 + } 1.295 + this._setBlockingState(this.currentNotification); 1.296 + } 1.297 + ]]></body> 1.298 + </method> 1.299 + 1.300 + <method name="_setBlockingState"> 1.301 + <parameter name="aNotification"/> 1.302 + <body> 1.303 + <![CDATA[ 1.304 + var isblock = aNotification && 1.305 + aNotification.priority == this.PRIORITY_CRITICAL_BLOCK; 1.306 + var canvas = this._blockingCanvas; 1.307 + if (isblock) { 1.308 + if (!canvas) 1.309 + canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); 1.310 + const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.311 + var content = this.firstChild; 1.312 + if (!content || 1.313 + content.namespaceURI != XULNS || 1.314 + content.localName != "browser") 1.315 + return; 1.316 + 1.317 + var width = content.boxObject.width; 1.318 + var height = content.boxObject.height; 1.319 + content.collapsed = true; 1.320 + 1.321 + canvas.setAttribute("width", width); 1.322 + canvas.setAttribute("height", height); 1.323 + canvas.setAttribute("flex", "1"); 1.324 + 1.325 + this.appendChild(canvas); 1.326 + this._blockingCanvas = canvas; 1.327 + 1.328 + var bgcolor = "white"; 1.329 + try { 1.330 + var prefService = Components.classes["@mozilla.org/preferences-service;1"]. 1.331 + getService(Components.interfaces.nsIPrefBranch); 1.332 + bgcolor = prefService.getCharPref("browser.display.background_color"); 1.333 + 1.334 + var win = content.contentWindow; 1.335 + var context = canvas.getContext("2d"); 1.336 + context.globalAlpha = 0.5; 1.337 + context.drawWindow(win, win.scrollX, win.scrollY, 1.338 + width, height, bgcolor); 1.339 + } 1.340 + catch(ex) { }; 1.341 + } 1.342 + else if (canvas) { 1.343 + canvas.parentNode.removeChild(canvas); 1.344 + this._blockingCanvas = null; 1.345 + var content = this.firstChild; 1.346 + if (content) 1.347 + content.collapsed = false; 1.348 + } 1.349 + ]]> 1.350 + </body> 1.351 + </method> 1.352 + 1.353 + </implementation> 1.354 + 1.355 + <handlers> 1.356 + <handler event="transitionend"><![CDATA[ 1.357 + if (event.target.localName == "notification" && 1.358 + event.propertyName == "margin-top") 1.359 + this._finishAnimation(); 1.360 + ]]></handler> 1.361 + </handlers> 1.362 + 1.363 + </binding> 1.364 + 1.365 + <binding id="notification" role="xul:alert"> 1.366 + <content> 1.367 + <xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type"> 1.368 + <xul:hbox anonid="details" align="center" flex="1" 1.369 + oncommand="this.parentNode.parentNode._doButtonCommand(event);"> 1.370 + <xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image,type,value"/> 1.371 + <xul:description anonid="messageText" class="messageText" flex="1" xbl:inherits="xbl:text=label"/> 1.372 + <xul:spacer flex="1"/> 1.373 + <children/> 1.374 + </xul:hbox> 1.375 + <xul:toolbarbutton ondblclick="event.stopPropagation();" 1.376 + class="messageCloseButton close-icon tabbable" 1.377 + xbl:inherits="hidden=hideclose" 1.378 + tooltiptext="&closeNotification.tooltip;" 1.379 + oncommand="document.getBindingParent(this).close();"/> 1.380 + </xul:hbox> 1.381 + </content> 1.382 + <resources> 1.383 + <stylesheet src="chrome://global/skin/notification.css"/> 1.384 + </resources> 1.385 + <implementation> 1.386 + <property name="label" onset="this.setAttribute('label', val); return val;" 1.387 + onget="return this.getAttribute('label');"/> 1.388 + <property name="value" onset="this.setAttribute('value', val); return val;" 1.389 + onget="return this.getAttribute('value');"/> 1.390 + <property name="image" onset="this.setAttribute('image', val); return val;" 1.391 + onget="return this.getAttribute('image');"/> 1.392 + <property name="type" onset="this.setAttribute('type', val); return val;" 1.393 + onget="return this.getAttribute('type');"/> 1.394 + <property name="priority" onget="return parseInt(this.getAttribute('priority')) || 0;" 1.395 + onset="this.setAttribute('priority', val); return val;"/> 1.396 + <property name="persistence" onget="return parseInt(this.getAttribute('persistence')) || 0;" 1.397 + onset="this.setAttribute('persistence', val); return val;"/> 1.398 + <field name="timeout">0</field> 1.399 + 1.400 + <property name="control" readonly="true"> 1.401 + <getter> 1.402 + <![CDATA[ 1.403 + var parent = this.parentNode; 1.404 + while (parent) { 1.405 + if (parent.localName == "notificationbox") 1.406 + return parent; 1.407 + parent = parent.parentNode; 1.408 + } 1.409 + return null; 1.410 + ]]> 1.411 + </getter> 1.412 + </property> 1.413 + 1.414 + <method name="close"> 1.415 + <body> 1.416 + <![CDATA[ 1.417 + var control = this.control; 1.418 + if (control) 1.419 + control.removeNotification(this); 1.420 + else 1.421 + this.hidden = true; 1.422 + ]]> 1.423 + </body> 1.424 + </method> 1.425 + 1.426 + <method name="_doButtonCommand"> 1.427 + <parameter name="aEvent"/> 1.428 + <body> 1.429 + <![CDATA[ 1.430 + if (!("buttonInfo" in aEvent.target)) 1.431 + return; 1.432 + 1.433 + var button = aEvent.target.buttonInfo; 1.434 + if (button.popup) { 1.435 + document.getElementById(button.popup). 1.436 + openPopup(aEvent.originalTarget, "after_start", 0, 0, false, false, aEvent); 1.437 + aEvent.stopPropagation(); 1.438 + } 1.439 + else { 1.440 + var callback = button.callback; 1.441 + if (callback) { 1.442 + var result = callback(this, button); 1.443 + if (!result) 1.444 + this.close(); 1.445 + aEvent.stopPropagation(); 1.446 + } 1.447 + } 1.448 + ]]> 1.449 + </body> 1.450 + </method> 1.451 + </implementation> 1.452 + </binding> 1.453 + 1.454 + <binding id="popup-notification"> 1.455 + <content align="start"> 1.456 + <xul:image class="popup-notification-icon" 1.457 + xbl:inherits="popupid,src=icon"/> 1.458 + <xul:vbox flex="1"> 1.459 + <xul:description class="popup-notification-description" 1.460 + xbl:inherits="xbl:text=label"/> 1.461 + <children includes="popupnotificationcontent"/> 1.462 + <xul:label class="text-link popup-notification-learnmore-link" 1.463 + xbl:inherits="href=learnmoreurl">&learnMore;</xul:label> 1.464 + <xul:spacer flex="1"/> 1.465 + <xul:hbox class="popup-notification-button-container" 1.466 + pack="end" align="center"> 1.467 + <xul:button anonid="button" 1.468 + class="popup-notification-menubutton" 1.469 + type="menu-button" 1.470 + xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey"> 1.471 + <xul:menupopup anonid="menupopup" 1.472 + xbl:inherits="oncommand=menucommand"> 1.473 + <children/> 1.474 + <xul:menuitem class="menuitem-iconic popup-notification-closeitem" 1.475 + label="&closeNotificationItem.label;" 1.476 + xbl:inherits="oncommand=closeitemcommand,hidden=hidenotnow"/> 1.477 + </xul:menupopup> 1.478 + </xul:button> 1.479 + </xul:hbox> 1.480 + </xul:vbox> 1.481 + <xul:vbox pack="start"> 1.482 + <xul:toolbarbutton anonid="closebutton" 1.483 + class="messageCloseButton close-icon popup-notification-closebutton tabbable" 1.484 + xbl:inherits="oncommand=closebuttoncommand" 1.485 + tooltiptext="&closeNotification.tooltip;"/> 1.486 + </xul:vbox> 1.487 + </content> 1.488 + <resources> 1.489 + <stylesheet src="chrome://global/skin/notification.css"/> 1.490 + </resources> 1.491 + <implementation> 1.492 + <field name="closebutton" readonly="true"> 1.493 + document.getAnonymousElementByAttribute(this, "anonid", "closebutton"); 1.494 + </field> 1.495 + <field name="button" readonly="true"> 1.496 + document.getAnonymousElementByAttribute(this, "anonid", "button"); 1.497 + </field> 1.498 + <field name="menupopup" readonly="true"> 1.499 + document.getAnonymousElementByAttribute(this, "anonid", "menupopup"); 1.500 + </field> 1.501 + </implementation> 1.502 + </binding> 1.503 +</bindings>