toolkit/content/widgets/notification.xml

changeset 0
6474c204b198
     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>

mercurial