<?xml version="1.0"?> <!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <!DOCTYPE bindings [ <!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd"> %notificationDTD; ]> <bindings id="notificationBindings" xmlns="http://www.mozilla.org/xbl" xmlns:xbl="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <binding id="notificationbox"> <content> <xul:stack xbl:inherits="hidden=notificationshidden" class="notificationbox-stack"> <xul:spacer/> <children includes="notification"/> </xul:stack> <children/> </content> <implementation> <field name="PRIORITY_INFO_LOW" readonly="true">1</field> <field name="PRIORITY_INFO_MEDIUM" readonly="true">2</field> <field name="PRIORITY_INFO_HIGH" readonly="true">3</field> <field name="PRIORITY_WARNING_LOW" readonly="true">4</field> <field name="PRIORITY_WARNING_MEDIUM" readonly="true">5</field> <field name="PRIORITY_WARNING_HIGH" readonly="true">6</field> <field name="PRIORITY_CRITICAL_LOW" readonly="true">7</field> <field name="PRIORITY_CRITICAL_MEDIUM" readonly="true">8</field> <field name="PRIORITY_CRITICAL_HIGH" readonly="true">9</field> <field name="PRIORITY_CRITICAL_BLOCK" readonly="true">10</field> <field name="currentNotification">null</field> <field name="_closedNotification">null</field> <field name="_blockingCanvas">null</field> <field name="_animating">false</field> <property name="notificationsHidden" onget="return this.getAttribute('notificationshidden') == 'true';"> <setter> if (val) this.setAttribute('notificationshidden', true); else this.removeAttribute('notificationshidden'); return val; </setter> </property> <property name="allNotifications" readonly="true"> <getter> <![CDATA[ var closedNotification = this._closedNotification; var notifications = this.getElementsByTagName('notification'); return Array.filter(notifications, n => n != closedNotification); ]]> </getter> </property> <method name="getNotificationWithValue"> <parameter name="aValue"/> <body> <![CDATA[ var notifications = this.allNotifications; for (var n = notifications.length - 1; n >= 0; n--) { if (aValue == notifications[n].getAttribute("value")) return notifications[n]; } return null; ]]> </body> </method> <method name="appendNotification"> <parameter name="aLabel"/> <parameter name="aValue"/> <parameter name="aImage"/> <parameter name="aPriority"/> <parameter name="aButtons"/> <parameter name="aEventCallback"/> <body> <![CDATA[ if (aPriority < this.PRIORITY_INFO_LOW || aPriority > this.PRIORITY_CRITICAL_BLOCK) throw "Invalid notification priority " + aPriority; // check for where the notification should be inserted according to // priority. If two are equal, the existing one appears on top. var notifications = this.allNotifications; var insertPos = null; for (var n = notifications.length - 1; n >= 0; n--) { if (notifications[n].priority < aPriority) break; insertPos = notifications[n]; } const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var newitem = document.createElementNS(XULNS, "notification"); // Can't use instanceof in case this was created from a different document: let labelIsDocFragment = aLabel && typeof aLabel == "object" && aLabel.nodeType && aLabel.nodeType == aLabel.DOCUMENT_FRAGMENT_NODE; if (!labelIsDocFragment) newitem.setAttribute("label", aLabel); newitem.setAttribute("value", aValue); if (aImage) newitem.setAttribute("image", aImage); newitem.eventCallback = aEventCallback; if (aButtons) { // The notification-button-default class is added to the button // with isDefault set to true. If there is no such button, it is // added to the first button (unless that button has isDefault // set to false). There cannot be multiple default buttons. var defaultElem; for (var b = 0; b < aButtons.length; b++) { var button = aButtons[b]; var buttonElem = document.createElementNS(XULNS, "button"); buttonElem.setAttribute("label", button.label); if (typeof button.accessKey == "string") buttonElem.setAttribute("accesskey", button.accessKey); if (typeof button.type == "string") { buttonElem.setAttribute("type", button.type); if ((button.type == "menu-button" || button.type == "menu") && "popup" in button) { buttonElem.appendChild(button.popup); delete button.popup; } if (typeof button.anchor == "string") buttonElem.setAttribute("anchor", button.anchor); } buttonElem.classList.add("notification-button"); if (button.isDefault || b == 0 && !("isDefault" in button)) defaultElem = buttonElem; newitem.appendChild(buttonElem); buttonElem.buttonInfo = button; } if (defaultElem) defaultElem.classList.add("notification-button-default"); } newitem.setAttribute("priority", aPriority); if (aPriority >= this.PRIORITY_CRITICAL_LOW) newitem.setAttribute("type", "critical"); else if (aPriority <= this.PRIORITY_INFO_HIGH) newitem.setAttribute("type", "info"); else newitem.setAttribute("type", "warning"); if (!insertPos) { newitem.style.position = "fixed"; newitem.style.top = "100%"; newitem.style.marginTop = "-15px"; newitem.style.opacity = "0"; } this.insertBefore(newitem, insertPos); // Can only insert the document fragment after the item has been created because // otherwise the XBL structure isn't there yet: if (labelIsDocFragment) { document.getAnonymousElementByAttribute(newitem, "anonid", "messageText") .appendChild(aLabel); } if (!insertPos) this._showNotification(newitem, true); // Fire event for accessibility APIs var event = document.createEvent("Events"); event.initEvent("AlertActive", true, true); newitem.dispatchEvent(event); return newitem; ]]> </body> </method> <method name="removeNotification"> <parameter name="aItem"/> <parameter name="aSkipAnimation"/> <body> <![CDATA[ if (aItem == this.currentNotification) this.removeCurrentNotification(aSkipAnimation); else if (aItem != this._closedNotification) this._removeNotificationElement(aItem); return aItem; ]]> </body> </method> <method name="_removeNotificationElement"> <parameter name="aChild"/> <body> <![CDATA[ if (aChild.eventCallback) aChild.eventCallback("removed"); this.removeChild(aChild); // make sure focus doesn't get lost (workaround for bug 570835) let fm = Components.classes["@mozilla.org/focus-manager;1"] .getService(Components.interfaces.nsIFocusManager); if (!fm.getFocusedElementForWindow(window, false, {})) fm.moveFocus(window, this, fm.MOVEFOCUS_FORWARD, 0); ]]> </body> </method> <method name="removeCurrentNotification"> <parameter name="aSkipAnimation"/> <body> <![CDATA[ this._showNotification(this.currentNotification, false, aSkipAnimation); ]]> </body> </method> <method name="removeAllNotifications"> <parameter name="aImmediate"/> <body> <![CDATA[ var notifications = this.allNotifications; for (var n = notifications.length - 1; n >= 0; n--) { if (aImmediate) this._removeNotificationElement(notifications[n]); else this.removeNotification(notifications[n]); } this.currentNotification = null; // Must clear up any currently animating notification if (aImmediate) this._finishAnimation(); ]]> </body> </method> <method name="removeTransientNotifications"> <body> <![CDATA[ var notifications = this.allNotifications; for (var n = notifications.length - 1; n >= 0; n--) { var notification = notifications[n]; if (notification.persistence) notification.persistence--; else if (Date.now() > notification.timeout) this.removeNotification(notification); } ]]> </body> </method> <method name="_showNotification"> <parameter name="aNotification"/> <parameter name="aSlideIn"/> <parameter name="aSkipAnimation"/> <body> <![CDATA[ this._finishAnimation(); var height = aNotification.boxObject.height; var skipAnimation = aSkipAnimation || (height == 0); if (aSlideIn) { this.currentNotification = aNotification; aNotification.style.removeProperty("position"); aNotification.style.removeProperty("top"); aNotification.style.removeProperty("margin-top"); aNotification.style.removeProperty("opacity"); if (skipAnimation) { this._setBlockingState(this.currentNotification); return; } } else { this._closedNotification = aNotification; var notifications = this.allNotifications; var idx = notifications.length - 1; this.currentNotification = (idx >= 0) ? notifications[idx] : null; if (skipAnimation) { this._removeNotificationElement(this._closedNotification); this._closedNotification = null; this._setBlockingState(this.currentNotification); return; } aNotification.style.marginTop = -height + "px"; aNotification.style.opacity = 0; } this._animating = true; ]]> </body> </method> <method name="_finishAnimation"> <body><![CDATA[ if (this._animating) { this._animating = false; if (this._closedNotification) { this._removeNotificationElement(this._closedNotification); this._closedNotification = null; } this._setBlockingState(this.currentNotification); } ]]></body> </method> <method name="_setBlockingState"> <parameter name="aNotification"/> <body> <![CDATA[ var isblock = aNotification && aNotification.priority == this.PRIORITY_CRITICAL_BLOCK; var canvas = this._blockingCanvas; if (isblock) { if (!canvas) canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; let content = this.firstChild; if (!content || content.namespaceURI != XULNS || content.localName != "browser") return; var width = content.boxObject.width; var height = content.boxObject.height; content.collapsed = true; canvas.setAttribute("width", width); canvas.setAttribute("height", height); canvas.setAttribute("flex", "1"); this.appendChild(canvas); this._blockingCanvas = canvas; var bgcolor = "white"; try { var prefService = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); bgcolor = prefService.getCharPref("browser.display.background_color"); var win = content.contentWindow; var context = canvas.getContext("2d"); context.globalAlpha = 0.5; context.drawWindow(win, win.scrollX, win.scrollY, width, height, bgcolor); } catch (ex) { } } else if (canvas) { canvas.parentNode.removeChild(canvas); this._blockingCanvas = null; let content = this.firstChild; if (content) content.collapsed = false; } ]]> </body> </method> </implementation> <handlers> <handler event="transitionend"><![CDATA[ if (event.target.localName == "notification" && event.propertyName == "margin-top") this._finishAnimation(); ]]></handler> </handlers> </binding> <binding id="notification" role="xul:alert"> <content> <xul:hbox class="notification-inner" flex="1" xbl:inherits="type"> <xul:hbox anonid="details" align="center" flex="1" oncommand="this.parentNode.parentNode._doButtonCommand(event);"> <xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image,type,value"/> <xul:description anonid="messageText" class="messageText" flex="1" xbl:inherits="xbl:text=label"/> <xul:spacer flex="1"/> <children/> </xul:hbox> <xul:toolbarbutton ondblclick="event.stopPropagation();" class="messageCloseButton close-icon tabbable" xbl:inherits="hidden=hideclose" tooltiptext="&closeNotification.tooltip;" oncommand="document.getBindingParent(this).dismiss();"/> </xul:hbox> </content> <resources> <stylesheet src="chrome://global/skin/notification.css"/> </resources> <implementation> <property name="label" onset="this.setAttribute('label', val); return val;" onget="return this.getAttribute('label');"/> <property name="value" onset="this.setAttribute('value', val); return val;" onget="return this.getAttribute('value');"/> <property name="image" onset="this.setAttribute('image', val); return val;" onget="return this.getAttribute('image');"/> <property name="type" onset="this.setAttribute('type', val); return val;" onget="return this.getAttribute('type');"/> <property name="priority" onget="return parseInt(this.getAttribute('priority')) || 0;" onset="this.setAttribute('priority', val); return val;"/> <property name="persistence" onget="return parseInt(this.getAttribute('persistence')) || 0;" onset="this.setAttribute('persistence', val); return val;"/> <field name="timeout">0</field> <property name="control" readonly="true"> <getter> <![CDATA[ var parent = this.parentNode; while (parent) { if (parent.localName == "notificationbox") return parent; parent = parent.parentNode; } return null; ]]> </getter> </property> <!-- This method should only be called when the user has manually closed the notification. If you want to programmatically close the notification, you should call close() instead. --> <method name="dismiss"> <body> <![CDATA[ if (this.eventCallback) { this.eventCallback("dismissed"); } this.close(); ]]> </body> </method> <method name="close"> <body> <![CDATA[ var control = this.control; if (control) control.removeNotification(this); else this.hidden = true; ]]> </body> </method> <method name="_doButtonCommand"> <parameter name="aEvent"/> <body> <![CDATA[ if (!("buttonInfo" in aEvent.target)) return; var button = aEvent.target.buttonInfo; if (button.popup) { document.getElementById(button.popup). openPopup(aEvent.originalTarget, "after_start", 0, 0, false, false, aEvent); aEvent.stopPropagation(); } else { var callback = button.callback; if (callback) { var result = callback(this, button, aEvent.target); if (!result) this.close(); aEvent.stopPropagation(); } } ]]> </body> </method> </implementation> </binding> <binding id="popup-notification"> <content> <xul:vbox> <xul:image class="popup-notification-icon" xbl:inherits="popupid,src=icon,class=iconclass"/> </xul:vbox> <xul:vbox class="popup-notification-body" xbl:inherits="popupid"> <xul:hbox align="start"> <xul:vbox flex="1"> <xul:label class="popup-notification-origin header" xbl:inherits="value=origin,tooltiptext=origin" crop="center"/> <xul:description class="popup-notification-description" xbl:inherits="xbl:text=label,popupid"/> </xul:vbox> <xul:toolbarbutton anonid="closebutton" class="messageCloseButton close-icon popup-notification-closebutton tabbable" xbl:inherits="oncommand=closebuttoncommand" tooltiptext="&closeNotification.tooltip;"/> </xul:hbox> <children includes="popupnotificationcontent"/> <xul:label class="text-link popup-notification-learnmore-link" xbl:inherits="onclick=learnmoreclick,href=learnmoreurl">&learnMore;</xul:label> <xul:checkbox anonid="checkbox" xbl:inherits="hidden=checkboxhidden,checked=checkboxchecked,label=checkboxlabel,oncommand=checkboxcommand" /> <xul:description class="popup-notification-warning" xbl:inherits="hidden=warninghidden,xbl:text=warninglabel"/> <xul:spacer flex="1"/> <xul:hbox class="popup-notification-button-container" pack="end" align="center"> <children includes="button"/> <xul:button anonid="button" class="popup-notification-menubutton" type="menu-button" xbl:inherits="oncommand=buttoncommand,onpopupshown=buttonpopupshown,label=buttonlabel,accesskey=buttonaccesskey,disabled=mainactiondisabled"> <xul:menupopup anonid="menupopup" xbl:inherits="oncommand=menucommand"> <children/> <xul:menuitem class="menuitem-iconic popup-notification-closeitem" label="&closeNotificationItem.label;" xbl:inherits="oncommand=closeitemcommand,hidden=hidenotnow"/> </xul:menupopup> </xul:button> </xul:hbox> </xul:vbox> </content> <resources> <stylesheet src="chrome://global/skin/notification.css"/> </resources> <implementation> <field name="checkbox" readonly="true"> document.getAnonymousElementByAttribute(this, "anonid", "checkbox"); </field> <field name="closebutton" readonly="true"> document.getAnonymousElementByAttribute(this, "anonid", "closebutton"); </field> <field name="button" readonly="true"> document.getAnonymousElementByAttribute(this, "anonid", "button"); </field> <field name="menupopup" readonly="true"> document.getAnonymousElementByAttribute(this, "anonid", "menupopup"); </field> </implementation> </binding> </bindings>