Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 <?xml version="1.0"?>
3 <bindings id="socialMarkBindings"
4 xmlns="http://www.mozilla.org/xbl"
5 xmlns:xbl="http://www.mozilla.org/xbl"
6 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
9 <binding id="toolbarbutton-marks" display="xul:button"
10 extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
11 <content disabled="true">
12 <xul:panel anonid="panel" hidden="true" type="arrow" class="social-panel"/>
13 <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
14 <xul:label class="toolbarbutton-text" crop="right" flex="1"
15 xbl:inherits="value=label,accesskey,crop,wrap"/>
16 <xul:label class="toolbarbutton-multiline-text" flex="1"
17 xbl:inherits="xbl:text=label,accesskey,wrap"/>
18 </content>
19 <implementation implements="nsIDOMEventListener, nsIObserver">
20 <field name="inMenuPanel">false</field>
22 <property name="panel">
23 <getter>
24 let widgetGroup = CustomizableUI.getWidget(this.getAttribute("id"));
25 let widget = widgetGroup.forWindow(window);
26 this.inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
27 if (this.inMenuPanel) {
28 widget.node.setAttribute("closemenu", "none");
29 return document.getElementById("PanelUI-socialapi");
30 }
31 return document.getAnonymousElementByAttribute(this, "anonid", "panel");
32 </getter>
33 </property>
35 <property name="content">
36 <getter><![CDATA[
37 if (this._frame)
38 return this._frame;
39 let notificationFrameId = "social-mark-frame-" + this.getAttribute("origin");
40 this._frame = SharedFrame.createFrame(
41 notificationFrameId, /* frame name */
42 this.panel, /* parent */
43 {
44 "type": "content",
45 "mozbrowser": "true",
46 "class": "social-panel-frame",
47 "id": notificationFrameId,
48 "tooltip": "aHTMLTooltip",
49 "flex": "1",
50 "context": "contentAreaContextMenu",
51 "origin": this.getAttribute("origin"),
52 "src": "about:blank"
53 }
54 );
55 this._frame.addEventListener("DOMLinkAdded", this);
56 this.setAttribute("notificationFrameId", notificationFrameId);
57 return this._frame;
58 ]]></getter>
59 </property>
61 <property name="contentWindow">
62 <getter>
63 return this.content.contentWindow;
64 </getter>
65 </property>
67 <property name="contentDocument">
68 <getter>
69 return this.content.contentDocument;
70 </getter>
71 </property>
73 <property name="provider">
74 <getter>
75 return Social._getProviderFromOrigin(this.getAttribute("origin"));
76 </getter>
77 </property>
79 <property name="isMarked">
80 <setter><![CDATA[
81 this._isMarked = val;
82 let provider = this.provider;
83 // we cannot size the image when we apply it via listStyleImage, so
84 // use the toolbar image
85 let place = CustomizableUI.getPlaceForItem(this);
86 val = val && place != "palette";
87 let icon = val ? provider.markedIcon : provider.unmarkedIcon;
88 let iconURL = icon || provider.icon32URL || provider.iconURL;
89 this.setAttribute("image", iconURL);
90 ]]></setter>
91 <getter>
92 return this._isMarked;
93 </getter>
94 </property>
96 <method name="update">
97 <body><![CDATA[
98 // update the button for use with the current tab
99 let provider = this.provider;
100 if (this._dynamicResizer) {
101 this._dynamicResizer.stop();
102 this._dynamicResizer = null;
103 }
104 this.content.setAttribute("src", "about:blank");
106 // do we have a savable page loaded?
107 let aURI = gBrowser.currentURI;
108 this.disabled = !aURI || !(aURI.schemeIs('http') || aURI.schemeIs('https'));
109 if (this.disabled) {
110 this.isMarked = false;
111 } else {
112 Social.isURIMarked(provider.origin, aURI, (isMarked) => {
113 this.isMarked = isMarked;
114 });
115 }
117 this.content.setAttribute("origin", provider.origin);
118 if (!this.inMenuPanel) {
119 let panel = this.panel;
120 // if customization is currently happening, we may not have a panel
121 // that we can hide
122 if (panel.hidePopup) {
123 panel.hidePopup();
124 panel.hidden = true;
125 }
126 }
127 this.pageData = null;
128 ]]></body>
129 </method>
131 <method name="loadPanel">
132 <parameter name="pageData"/>
133 <body><![CDATA[
134 let provider = this.provider;
135 let panel = this.panel;
136 panel.hidden = false;
138 // reparent the iframe if we've been customized to a new location
139 if (this.content.parentNode != panel)
140 panel.appendChild(this.content);
142 let URLTemplate = provider.markURL;
143 this.pageData = pageData || OpenGraphBuilder.getData(gBrowser);
144 let endpoint = OpenGraphBuilder.generateEndpointURL(URLTemplate, this.pageData);
146 // setup listeners
147 let DOMContentLoaded = (event) => {
148 if (event.target != this.contentDocument)
149 return;
150 this._loading = false;
151 this.content.removeEventListener("DOMContentLoaded", DOMContentLoaded, true);
152 // add our resizer after the dom is ready
153 if (!this.inMenuPanel) {
154 let DynamicResizeWatcher = Cu.import("resource:///modules/Social.jsm", {}).DynamicResizeWatcher;
155 this._dynamicResizer = new DynamicResizeWatcher();
156 this._dynamicResizer.start(this.panel, this.content);
157 } else if (this._dynamicResizer) {
158 this._dynamicResizer.stop();
159 this._dynamicResizer = null;
160 }
161 // send the opengraph data
162 let evt = this.contentDocument.createEvent("CustomEvent");
163 evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(this.pageData));
164 this.contentDocument.documentElement.dispatchEvent(evt);
166 let contentWindow = this.contentWindow;
167 let markUpdate = function(event) {
168 // update the annotation based on this event, then update the
169 // icon as well
170 this.isMarked = JSON.parse(event.detail).marked;
171 let uri = Services.io.newURI(this.pageData.url, null, null);
172 if (this.isMarked) {
173 Social.markURI(provider.origin, uri);
174 } else {
175 Social.unmarkURI(provider.origin, uri, () => {
176 this.update();
177 });
178 }
179 }.bind(this);
180 contentWindow.addEventListener("socialMarkUpdate", markUpdate);
181 contentWindow.addEventListener("unload", function unload() {
182 contentWindow.removeEventListener("unload", unload);
183 contentWindow.removeEventListener("socialMarkUpdate", markUpdate);
184 });
185 }
186 this.content.addEventListener("DOMContentLoaded", DOMContentLoaded, true);
187 this._loading = true;
188 this.content.setAttribute("src", endpoint);
189 ]]></body>
190 </method>
192 <method name="openPanel">
193 <parameter name="aResetOnClose"/>
194 <body><![CDATA[
195 let panel = this.panel;
196 let frameId = this.getAttribute("notificationFrameId");
198 let wasAlive = SharedFrame.isGroupAlive(frameId);
199 SharedFrame.setOwner(frameId, this.content);
201 // Clear dimensions on all browsers so the panel size will
202 // only use the selected browser.
203 let frameIter = panel.firstElementChild;
204 while (frameIter) {
205 frameIter.collapsed = (frameIter != this.content);
206 frameIter = frameIter.nextElementSibling;
207 }
209 // if we're a slice in the hambuger, use that panel instead
210 let widgetGroup = CustomizableUI.getWidget(this.getAttribute("id"));
211 let widget = widgetGroup.forWindow(window);
212 let inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
213 if (inMenuPanel) {
214 PanelUI.showSubView("PanelUI-socialapi", widget.node,
215 CustomizableUI.AREA_PANEL);
216 } else {
217 let anchor = document.getAnonymousElementByAttribute(this, "class", "toolbarbutton-icon");
218 panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
219 this.setAttribute("open", "true");
220 }
221 if (aResetOnClose) {
222 let evName = inMenuPanel ? "ViewHiding": "popuphidden";
223 let _hidden = () => {
224 panel.removeEventListener(evName, _hidden);
225 this.update();
226 };
227 panel.addEventListener(evName, _hidden, false);
228 }
229 ]]></body>
230 </method>
232 <method name="markCurrentPage">
233 <parameter name="aOpenPanel"/>
234 <body><![CDATA[
235 // we always set the src on click if it has not been set for this tab,
236 // but we only want to open the panel if it was previously annotated.
237 let openPanel = this.isMarked || aOpenPanel ||
238 this.inMenuPanel || !this.provider.haveLoggedInUser();
239 let src = this.content.getAttribute("src");
240 if (!src || src == "about:blank") {
241 this.loadPanel();
242 }
243 if (openPanel)
244 this.openPanel();
245 ]]></body>
246 </method>
248 <method name="markLink">
249 <parameter name="aUrl"/>
250 <body><![CDATA[
251 if (!aUrl) {
252 this.markCurrentPage(true);
253 return;
254 }
255 // initiated form an external source, such as gContextMenu, where
256 // pageData is passed into us. In this case, we always load the iframe
257 // and show it since the url may not be the browser tab, but an image,
258 // link, etc. inside the page. We also "update" the iframe to the
259 // previous url when it is closed.
260 this.content.setAttribute("src", "about:blank");
261 this.loadPanel({ url: aUrl });
262 this.openPanel(true);
263 ]]></body>
264 </method>
266 <method name="dispatchPanelEvent">
267 <parameter name="name"/>
268 <body><![CDATA[
269 let evt = this.contentDocument.createEvent("CustomEvent");
270 evt.initCustomEvent(name, true, true, {});
271 this.contentDocument.documentElement.dispatchEvent(evt);
272 ]]></body>
273 </method>
275 <method name="onShown">
276 <body><![CDATA[
277 // because the panel may be preloaded, we need to size the panel when
278 // showing as well as after load
279 let sizeSocialPanelToContent = Cu.import("resource:///modules/Social.jsm", {}).sizeSocialPanelToContent;
280 if (!this._loading && this.contentDocument &&
281 this.contentDocument.readyState == "complete") {
282 this.dispatchPanelEvent("socialFrameShow");
283 if (!this.inMenuPanel)
284 sizeSocialPanelToContent(this.panel, this.content);
285 } else {
286 let panelBrowserOnload = (e) => {
287 this.content.removeEventListener("load", panelBrowserOnload, true);
288 this.dispatchPanelEvent("socialFrameShow");
289 if (!this.inMenuPanel)
290 sizeSocialPanelToContent(this.panel, this.content);
291 };
292 this.content.addEventListener("load", panelBrowserOnload, true);
293 }
294 ]]></body>
295 </method>
297 <method name="handleEvent">
298 <parameter name="aEvent"/>
299 <body><![CDATA[
300 if (aEvent.eventPhase != aEvent.BUBBLING_PHASE)
301 return;
302 switch(aEvent.type) {
303 case "DOMLinkAdded": {
304 // much of this logic is from DOMLinkHandler in browser.js, this sets
305 // the presence icon for a chat user, we simply use favicon style
306 // updating
307 let link = aEvent.originalTarget;
308 let rel = link.rel && link.rel.toLowerCase();
309 if (!link || !link.ownerDocument || !rel || !link.href)
310 return;
311 if (link.rel.indexOf("icon") < 0)
312 return;
314 let ContentLinkHandler = Cu.import("resource:///modules/ContentLinkHandler.jsm", {}).ContentLinkHandler;
315 let uri = ContentLinkHandler.getLinkIconURI(link);
316 if (!uri)
317 return;
319 // we cannot size the image when we apply it via listStyleImage, so
320 // use the toolbar image
321 this.setAttribute("image", uri.spec);
322 }
323 break;
324 case "ViewShowing":
325 this.onShown();
326 break;
327 case "ViewHiding":
328 this.dispatchPanelEvent("socialFrameHide");
329 break;
330 }
331 ]]></body>
332 </method>
334 </implementation>
335 <handlers>
336 <handler event="popupshown"><![CDATA[
337 this.onShown();
338 ]]></handler>
339 <handler event="popuphidden"><![CDATA[
340 this.dispatchPanelEvent("socialFrameHide");
341 this.removeAttribute("open");
342 ]]></handler>
343 <handler event="command"><![CDATA[
344 this.markCurrentPage();
345 ]]></handler>
346 </handlers>
347 </binding>
349 </bindings>