author Sam Foster <>
Thu, 06 Mar 2014 09:45:15 -0500
changeset 183179 f081a9d022d66ad09716899b08d3818e5878bbf9
parent 159584 35a772328e246abec98b50226213514ce9d5fe43
permissions -rw-r--r--
Bug 967793 - Download notification disappears after a download link opens in a new tab (Aurora roll-up). r=mbrubeck, a=sledru

<?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 -->

<!DOCTYPE bindings [
<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd">

<bindings id="notificationBindings"

  <binding id="notificationbox" extends="chrome://global/content/bindings/notification.xml#notificationbox">
      <xul:stack xbl:inherits="hidden=notificationshidden"
        <children includes="notification"/>
      <html:div anonid="layer1" class="notification-layer"></html:div>
      <html:div anonid="layer2" class="notification-layer"></html:div>

          this.addEventListener("AlertActive", this.handleEvent, true);
          this.addEventListener("AlertClose", this.handleEvent, true);
          this.setAttribute("count", 0);
          this.removeEventListener("AlertActive", this.handleEvent, true);
          this.removeEventListener("AlertClose", this.handleEvent, true);
      <method name="adoptNotification">
        <parameter name="aItem"/>
            // insert an existing notification element
            // XXX: borrows code from appendNotification in toolkit/content/widgets/notification.xml
            // if this sticks around, we'll want to refactor both to eliminate duplication

            let priority = aItem.priority;
            // check for where the notification should be inserted according to
            // priority. If two are equal, the existing one appears on top.
            let notifications = this.allNotifications;
            let insertPos = null;
            for (let n = notifications.length - 1; n >= 0; n--) {
              if (notifications[n].priority < priority)
              insertPos = notifications[n];
            if (!insertPos) {
     = "fixed";
     = "100%";
     = "-15px";
     = "0";
            let label = aItem.label;
            this.insertBefore(aItem, insertPos);
            aItem.label = label;

            if (!insertPos)
              this._showNotification(aItem, true, true);

            // Fire event for accessibility APIs
            var event = document.createEvent("Events");
            event.initEvent("AlertActive", true, true);

            return aItem;
      <method name="removeNotification">
        <parameter name="aItem"/>
        <parameter name="aSkipAnimation"/>
            if (aItem == this.currentNotification)
            else if (aItem != this._closedNotification)

            // Fire notification closed event.
            let event = new Event('AlertClose');
            event.notification = aItem;

            return aItem;
      <method name="handleEvent">
        <parameter name="aEvent"/>
            switch (aEvent.type) {
              case "AlertActive":
              case "AlertClose":
                this.setAttribute("count", this.allNotifications.length);

  <binding id="notification" role="xul:alert" extends="chrome://global/content/bindings/notification.xml#notification">
      <property name="_messageContainer" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'messageText');"/>
      <property name="label">
          if (this._messageContainer.childElementCount) {
            // return a document fragment when our label is a complex value containing elements
            // by cloning childNodes into a document fragment, the returned value
            // is *not* live and will survive unbinding of this notification
            let frag = this.ownerDocument.createDocumentFragment();
            let containerNode = this._messageContainer;
            for(let cnode of containerNode.childNodes) {
            return frag;
          } else {
            return String.trim(this._messageContainer.textContent) ||
            // accept a string or node (e.g. document fragment, element or text node) as label value
            if (val && "object" == typeof val && ('nodeType' in val)) {
              let containerNode = this._messageContainer;
              let cnode;
              while((cnode = containerNode.firstChild)) {
              if (val.ownerDocument !== this.ownerDocument) {
                val = this.ownerDocument.importNode(val, true);
              return containerNode.appendChild(val);
            } else {
              return (this._messageContainer.textContent = val);