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