|
1 <?xml version="1.0"?> |
|
2 |
|
3 <!-- This Source Code Form is subject to the terms of the Mozilla Public |
|
4 - License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> |
|
6 |
|
7 <!DOCTYPE bindings [ |
|
8 <!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd"> |
|
9 %notificationDTD; |
|
10 ]> |
|
11 |
|
12 <bindings id="notificationBindings" |
|
13 xmlns="http://www.mozilla.org/xbl" |
|
14 xmlns:xbl="http://www.mozilla.org/xbl" |
|
15 xmlns:html="http://www.w3.org/1999/xhtml" |
|
16 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> |
|
17 |
|
18 <binding id="notificationbox" extends="chrome://global/content/bindings/notification.xml#notificationbox"> |
|
19 <content> |
|
20 <xul:stack xbl:inherits="hidden=notificationshidden" |
|
21 class="notificationbox-stack"> |
|
22 <xul:spacer/> |
|
23 <children includes="notification"/> |
|
24 </xul:stack> |
|
25 <html:div anonid="layer1" class="notification-layer"></html:div> |
|
26 <html:div anonid="layer2" class="notification-layer"></html:div> |
|
27 <children/> |
|
28 </content> |
|
29 |
|
30 <implementation> |
|
31 <constructor> |
|
32 <![CDATA[ |
|
33 this.addEventListener("AlertActive", this.handleEvent, true); |
|
34 this.addEventListener("AlertClose", this.handleEvent, true); |
|
35 this.setAttribute("count", 0); |
|
36 ]]> |
|
37 </constructor> |
|
38 <destructor> |
|
39 <![CDATA[ |
|
40 this.removeEventListener("AlertActive", this.handleEvent, true); |
|
41 this.removeEventListener("AlertClose", this.handleEvent, true); |
|
42 ]]> |
|
43 </destructor> |
|
44 <method name="adoptNotification"> |
|
45 <parameter name="aItem"/> |
|
46 <body> |
|
47 <![CDATA[ |
|
48 // insert an existing notification element |
|
49 // XXX: borrows code from appendNotification in toolkit/content/widgets/notification.xml |
|
50 // if this sticks around, we'll want to refactor both to eliminate duplication |
|
51 |
|
52 let priority = aItem.priority; |
|
53 // check for where the notification should be inserted according to |
|
54 // priority. If two are equal, the existing one appears on top. |
|
55 let notifications = this.allNotifications; |
|
56 let insertPos = null; |
|
57 for (let n = notifications.length - 1; n >= 0; n--) { |
|
58 if (notifications[n].priority < priority) |
|
59 break; |
|
60 insertPos = notifications[n]; |
|
61 } |
|
62 if (!insertPos) { |
|
63 aItem.style.position = "fixed"; |
|
64 aItem.style.top = "100%"; |
|
65 aItem.style.marginTop = "-15px"; |
|
66 aItem.style.opacity = "0"; |
|
67 } |
|
68 let label = aItem.label; |
|
69 this.insertBefore(aItem, insertPos); |
|
70 aItem.label = label; |
|
71 |
|
72 if (!insertPos) |
|
73 this._showNotification(aItem, true, true); |
|
74 |
|
75 // Fire event for accessibility APIs |
|
76 var event = document.createEvent("Events"); |
|
77 event.initEvent("AlertActive", true, true); |
|
78 aItem.dispatchEvent(event); |
|
79 |
|
80 return aItem; |
|
81 ]]> |
|
82 </body> |
|
83 </method> |
|
84 <method name="removeNotification"> |
|
85 <parameter name="aItem"/> |
|
86 <parameter name="aSkipAnimation"/> |
|
87 <body> |
|
88 <![CDATA[ |
|
89 if (aItem == this.currentNotification) |
|
90 this.removeCurrentNotification(aSkipAnimation); |
|
91 else if (aItem != this._closedNotification) |
|
92 this._removeNotificationElement(aItem); |
|
93 |
|
94 // Fire notification closed event. |
|
95 let event = new Event('AlertClose'); |
|
96 event.notification = aItem; |
|
97 this.dispatchEvent(event); |
|
98 |
|
99 return aItem; |
|
100 ]]> |
|
101 </body> |
|
102 </method> |
|
103 <method name="handleEvent"> |
|
104 <parameter name="aEvent"/> |
|
105 <body> |
|
106 <![CDATA[ |
|
107 switch (aEvent.type) { |
|
108 case "AlertActive": |
|
109 case "AlertClose": |
|
110 this.setAttribute("count", this.allNotifications.length); |
|
111 break; |
|
112 } |
|
113 ]]> |
|
114 </body> |
|
115 </method> |
|
116 </implementation> |
|
117 </binding> |
|
118 |
|
119 <binding id="notification" role="xul:alert" extends="chrome://global/content/bindings/notification.xml#notification"> |
|
120 <implementation> |
|
121 <property name="_messageContainer" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'messageText');"/> |
|
122 <property name="label"> |
|
123 <getter><![CDATA[ |
|
124 if (this._messageContainer.childElementCount) { |
|
125 // return a document fragment when our label is a complex value containing elements |
|
126 // by cloning childNodes into a document fragment, the returned value |
|
127 // is *not* live and will survive unbinding of this notification |
|
128 let frag = this.ownerDocument.createDocumentFragment(); |
|
129 let containerNode = this._messageContainer; |
|
130 for(let cnode of containerNode.childNodes) { |
|
131 frag.appendChild(cnode.cloneNode(true)); |
|
132 } |
|
133 return frag; |
|
134 } else { |
|
135 return String.trim(this._messageContainer.textContent) || |
|
136 this.getAttribute("label"); |
|
137 } |
|
138 ]]></getter> |
|
139 <setter><![CDATA[ |
|
140 // accept a string or node (e.g. document fragment, element or text node) as label value |
|
141 if (val && "object" == typeof val && ('nodeType' in val)) { |
|
142 let containerNode = this._messageContainer; |
|
143 let cnode; |
|
144 while((cnode = containerNode.firstChild)) { |
|
145 cnode.remove(); |
|
146 } |
|
147 if (val.ownerDocument !== this.ownerDocument) { |
|
148 val = this.ownerDocument.importNode(val, true); |
|
149 } |
|
150 return containerNode.appendChild(val); |
|
151 } else { |
|
152 return (this._messageContainer.textContent = val); |
|
153 } |
|
154 ]]></setter> |
|
155 </property> |
|
156 </implementation> |
|
157 </binding> |
|
158 </bindings> |