summaryrefslogtreecommitdiffstats
path: root/toolkit/content/widgets/notification.xml
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/widgets/notification.xml')
-rw-r--r--toolkit/content/widgets/notification.xml551
1 files changed, 551 insertions, 0 deletions
diff --git a/toolkit/content/widgets/notification.xml b/toolkit/content/widgets/notification.xml
new file mode 100644
index 000000000..2cc2f4b2c
--- /dev/null
+++ b/toolkit/content/widgets/notification.xml
@@ -0,0 +1,551 @@
+<?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>