1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/socialmarks.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,349 @@ 1.4 +<?xml version="1.0"?> 1.5 + 1.6 +<bindings id="socialMarkBindings" 1.7 + xmlns="http://www.mozilla.org/xbl" 1.8 + xmlns:xbl="http://www.mozilla.org/xbl" 1.9 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 1.10 + 1.11 + 1.12 + <binding id="toolbarbutton-marks" display="xul:button" 1.13 + extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton"> 1.14 + <content disabled="true"> 1.15 + <xul:panel anonid="panel" hidden="true" type="arrow" class="social-panel"/> 1.16 + <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/> 1.17 + <xul:label class="toolbarbutton-text" crop="right" flex="1" 1.18 + xbl:inherits="value=label,accesskey,crop,wrap"/> 1.19 + <xul:label class="toolbarbutton-multiline-text" flex="1" 1.20 + xbl:inherits="xbl:text=label,accesskey,wrap"/> 1.21 + </content> 1.22 + <implementation implements="nsIDOMEventListener, nsIObserver"> 1.23 + <field name="inMenuPanel">false</field> 1.24 + 1.25 + <property name="panel"> 1.26 + <getter> 1.27 + let widgetGroup = CustomizableUI.getWidget(this.getAttribute("id")); 1.28 + let widget = widgetGroup.forWindow(window); 1.29 + this.inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL; 1.30 + if (this.inMenuPanel) { 1.31 + widget.node.setAttribute("closemenu", "none"); 1.32 + return document.getElementById("PanelUI-socialapi"); 1.33 + } 1.34 + return document.getAnonymousElementByAttribute(this, "anonid", "panel"); 1.35 + </getter> 1.36 + </property> 1.37 + 1.38 + <property name="content"> 1.39 + <getter><![CDATA[ 1.40 + if (this._frame) 1.41 + return this._frame; 1.42 + let notificationFrameId = "social-mark-frame-" + this.getAttribute("origin"); 1.43 + this._frame = SharedFrame.createFrame( 1.44 + notificationFrameId, /* frame name */ 1.45 + this.panel, /* parent */ 1.46 + { 1.47 + "type": "content", 1.48 + "mozbrowser": "true", 1.49 + "class": "social-panel-frame", 1.50 + "id": notificationFrameId, 1.51 + "tooltip": "aHTMLTooltip", 1.52 + "flex": "1", 1.53 + "context": "contentAreaContextMenu", 1.54 + "origin": this.getAttribute("origin"), 1.55 + "src": "about:blank" 1.56 + } 1.57 + ); 1.58 + this._frame.addEventListener("DOMLinkAdded", this); 1.59 + this.setAttribute("notificationFrameId", notificationFrameId); 1.60 + return this._frame; 1.61 + ]]></getter> 1.62 + </property> 1.63 + 1.64 + <property name="contentWindow"> 1.65 + <getter> 1.66 + return this.content.contentWindow; 1.67 + </getter> 1.68 + </property> 1.69 + 1.70 + <property name="contentDocument"> 1.71 + <getter> 1.72 + return this.content.contentDocument; 1.73 + </getter> 1.74 + </property> 1.75 + 1.76 + <property name="provider"> 1.77 + <getter> 1.78 + return Social._getProviderFromOrigin(this.getAttribute("origin")); 1.79 + </getter> 1.80 + </property> 1.81 + 1.82 + <property name="isMarked"> 1.83 + <setter><![CDATA[ 1.84 + this._isMarked = val; 1.85 + let provider = this.provider; 1.86 + // we cannot size the image when we apply it via listStyleImage, so 1.87 + // use the toolbar image 1.88 + let place = CustomizableUI.getPlaceForItem(this); 1.89 + val = val && place != "palette"; 1.90 + let icon = val ? provider.markedIcon : provider.unmarkedIcon; 1.91 + let iconURL = icon || provider.icon32URL || provider.iconURL; 1.92 + this.setAttribute("image", iconURL); 1.93 + ]]></setter> 1.94 + <getter> 1.95 + return this._isMarked; 1.96 + </getter> 1.97 + </property> 1.98 + 1.99 + <method name="update"> 1.100 + <body><![CDATA[ 1.101 + // update the button for use with the current tab 1.102 + let provider = this.provider; 1.103 + if (this._dynamicResizer) { 1.104 + this._dynamicResizer.stop(); 1.105 + this._dynamicResizer = null; 1.106 + } 1.107 + this.content.setAttribute("src", "about:blank"); 1.108 + 1.109 + // do we have a savable page loaded? 1.110 + let aURI = gBrowser.currentURI; 1.111 + this.disabled = !aURI || !(aURI.schemeIs('http') || aURI.schemeIs('https')); 1.112 + if (this.disabled) { 1.113 + this.isMarked = false; 1.114 + } else { 1.115 + Social.isURIMarked(provider.origin, aURI, (isMarked) => { 1.116 + this.isMarked = isMarked; 1.117 + }); 1.118 + } 1.119 + 1.120 + this.content.setAttribute("origin", provider.origin); 1.121 + if (!this.inMenuPanel) { 1.122 + let panel = this.panel; 1.123 + // if customization is currently happening, we may not have a panel 1.124 + // that we can hide 1.125 + if (panel.hidePopup) { 1.126 + panel.hidePopup(); 1.127 + panel.hidden = true; 1.128 + } 1.129 + } 1.130 + this.pageData = null; 1.131 + ]]></body> 1.132 + </method> 1.133 + 1.134 + <method name="loadPanel"> 1.135 + <parameter name="pageData"/> 1.136 + <body><![CDATA[ 1.137 + let provider = this.provider; 1.138 + let panel = this.panel; 1.139 + panel.hidden = false; 1.140 + 1.141 + // reparent the iframe if we've been customized to a new location 1.142 + if (this.content.parentNode != panel) 1.143 + panel.appendChild(this.content); 1.144 + 1.145 + let URLTemplate = provider.markURL; 1.146 + this.pageData = pageData || OpenGraphBuilder.getData(gBrowser); 1.147 + let endpoint = OpenGraphBuilder.generateEndpointURL(URLTemplate, this.pageData); 1.148 + 1.149 + // setup listeners 1.150 + let DOMContentLoaded = (event) => { 1.151 + if (event.target != this.contentDocument) 1.152 + return; 1.153 + this._loading = false; 1.154 + this.content.removeEventListener("DOMContentLoaded", DOMContentLoaded, true); 1.155 + // add our resizer after the dom is ready 1.156 + if (!this.inMenuPanel) { 1.157 + let DynamicResizeWatcher = Cu.import("resource:///modules/Social.jsm", {}).DynamicResizeWatcher; 1.158 + this._dynamicResizer = new DynamicResizeWatcher(); 1.159 + this._dynamicResizer.start(this.panel, this.content); 1.160 + } else if (this._dynamicResizer) { 1.161 + this._dynamicResizer.stop(); 1.162 + this._dynamicResizer = null; 1.163 + } 1.164 + // send the opengraph data 1.165 + let evt = this.contentDocument.createEvent("CustomEvent"); 1.166 + evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(this.pageData)); 1.167 + this.contentDocument.documentElement.dispatchEvent(evt); 1.168 + 1.169 + let contentWindow = this.contentWindow; 1.170 + let markUpdate = function(event) { 1.171 + // update the annotation based on this event, then update the 1.172 + // icon as well 1.173 + this.isMarked = JSON.parse(event.detail).marked; 1.174 + let uri = Services.io.newURI(this.pageData.url, null, null); 1.175 + if (this.isMarked) { 1.176 + Social.markURI(provider.origin, uri); 1.177 + } else { 1.178 + Social.unmarkURI(provider.origin, uri, () => { 1.179 + this.update(); 1.180 + }); 1.181 + } 1.182 + }.bind(this); 1.183 + contentWindow.addEventListener("socialMarkUpdate", markUpdate); 1.184 + contentWindow.addEventListener("unload", function unload() { 1.185 + contentWindow.removeEventListener("unload", unload); 1.186 + contentWindow.removeEventListener("socialMarkUpdate", markUpdate); 1.187 + }); 1.188 + } 1.189 + this.content.addEventListener("DOMContentLoaded", DOMContentLoaded, true); 1.190 + this._loading = true; 1.191 + this.content.setAttribute("src", endpoint); 1.192 + ]]></body> 1.193 + </method> 1.194 + 1.195 + <method name="openPanel"> 1.196 + <parameter name="aResetOnClose"/> 1.197 + <body><![CDATA[ 1.198 + let panel = this.panel; 1.199 + let frameId = this.getAttribute("notificationFrameId"); 1.200 + 1.201 + let wasAlive = SharedFrame.isGroupAlive(frameId); 1.202 + SharedFrame.setOwner(frameId, this.content); 1.203 + 1.204 + // Clear dimensions on all browsers so the panel size will 1.205 + // only use the selected browser. 1.206 + let frameIter = panel.firstElementChild; 1.207 + while (frameIter) { 1.208 + frameIter.collapsed = (frameIter != this.content); 1.209 + frameIter = frameIter.nextElementSibling; 1.210 + } 1.211 + 1.212 + // if we're a slice in the hambuger, use that panel instead 1.213 + let widgetGroup = CustomizableUI.getWidget(this.getAttribute("id")); 1.214 + let widget = widgetGroup.forWindow(window); 1.215 + let inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL; 1.216 + if (inMenuPanel) { 1.217 + PanelUI.showSubView("PanelUI-socialapi", widget.node, 1.218 + CustomizableUI.AREA_PANEL); 1.219 + } else { 1.220 + let anchor = document.getAnonymousElementByAttribute(this, "class", "toolbarbutton-icon"); 1.221 + panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false); 1.222 + this.setAttribute("open", "true"); 1.223 + } 1.224 + if (aResetOnClose) { 1.225 + let evName = inMenuPanel ? "ViewHiding": "popuphidden"; 1.226 + let _hidden = () => { 1.227 + panel.removeEventListener(evName, _hidden); 1.228 + this.update(); 1.229 + }; 1.230 + panel.addEventListener(evName, _hidden, false); 1.231 + } 1.232 + ]]></body> 1.233 + </method> 1.234 + 1.235 + <method name="markCurrentPage"> 1.236 + <parameter name="aOpenPanel"/> 1.237 + <body><![CDATA[ 1.238 + // we always set the src on click if it has not been set for this tab, 1.239 + // but we only want to open the panel if it was previously annotated. 1.240 + let openPanel = this.isMarked || aOpenPanel || 1.241 + this.inMenuPanel || !this.provider.haveLoggedInUser(); 1.242 + let src = this.content.getAttribute("src"); 1.243 + if (!src || src == "about:blank") { 1.244 + this.loadPanel(); 1.245 + } 1.246 + if (openPanel) 1.247 + this.openPanel(); 1.248 + ]]></body> 1.249 + </method> 1.250 + 1.251 + <method name="markLink"> 1.252 + <parameter name="aUrl"/> 1.253 + <body><![CDATA[ 1.254 + if (!aUrl) { 1.255 + this.markCurrentPage(true); 1.256 + return; 1.257 + } 1.258 + // initiated form an external source, such as gContextMenu, where 1.259 + // pageData is passed into us. In this case, we always load the iframe 1.260 + // and show it since the url may not be the browser tab, but an image, 1.261 + // link, etc. inside the page. We also "update" the iframe to the 1.262 + // previous url when it is closed. 1.263 + this.content.setAttribute("src", "about:blank"); 1.264 + this.loadPanel({ url: aUrl }); 1.265 + this.openPanel(true); 1.266 + ]]></body> 1.267 + </method> 1.268 + 1.269 + <method name="dispatchPanelEvent"> 1.270 + <parameter name="name"/> 1.271 + <body><![CDATA[ 1.272 + let evt = this.contentDocument.createEvent("CustomEvent"); 1.273 + evt.initCustomEvent(name, true, true, {}); 1.274 + this.contentDocument.documentElement.dispatchEvent(evt); 1.275 + ]]></body> 1.276 + </method> 1.277 + 1.278 + <method name="onShown"> 1.279 + <body><![CDATA[ 1.280 + // because the panel may be preloaded, we need to size the panel when 1.281 + // showing as well as after load 1.282 + let sizeSocialPanelToContent = Cu.import("resource:///modules/Social.jsm", {}).sizeSocialPanelToContent; 1.283 + if (!this._loading && this.contentDocument && 1.284 + this.contentDocument.readyState == "complete") { 1.285 + this.dispatchPanelEvent("socialFrameShow"); 1.286 + if (!this.inMenuPanel) 1.287 + sizeSocialPanelToContent(this.panel, this.content); 1.288 + } else { 1.289 + let panelBrowserOnload = (e) => { 1.290 + this.content.removeEventListener("load", panelBrowserOnload, true); 1.291 + this.dispatchPanelEvent("socialFrameShow"); 1.292 + if (!this.inMenuPanel) 1.293 + sizeSocialPanelToContent(this.panel, this.content); 1.294 + }; 1.295 + this.content.addEventListener("load", panelBrowserOnload, true); 1.296 + } 1.297 + ]]></body> 1.298 + </method> 1.299 + 1.300 + <method name="handleEvent"> 1.301 + <parameter name="aEvent"/> 1.302 + <body><![CDATA[ 1.303 + if (aEvent.eventPhase != aEvent.BUBBLING_PHASE) 1.304 + return; 1.305 + switch(aEvent.type) { 1.306 + case "DOMLinkAdded": { 1.307 + // much of this logic is from DOMLinkHandler in browser.js, this sets 1.308 + // the presence icon for a chat user, we simply use favicon style 1.309 + // updating 1.310 + let link = aEvent.originalTarget; 1.311 + let rel = link.rel && link.rel.toLowerCase(); 1.312 + if (!link || !link.ownerDocument || !rel || !link.href) 1.313 + return; 1.314 + if (link.rel.indexOf("icon") < 0) 1.315 + return; 1.316 + 1.317 + let ContentLinkHandler = Cu.import("resource:///modules/ContentLinkHandler.jsm", {}).ContentLinkHandler; 1.318 + let uri = ContentLinkHandler.getLinkIconURI(link); 1.319 + if (!uri) 1.320 + return; 1.321 + 1.322 + // we cannot size the image when we apply it via listStyleImage, so 1.323 + // use the toolbar image 1.324 + this.setAttribute("image", uri.spec); 1.325 + } 1.326 + break; 1.327 + case "ViewShowing": 1.328 + this.onShown(); 1.329 + break; 1.330 + case "ViewHiding": 1.331 + this.dispatchPanelEvent("socialFrameHide"); 1.332 + break; 1.333 + } 1.334 + ]]></body> 1.335 + </method> 1.336 + 1.337 + </implementation> 1.338 + <handlers> 1.339 + <handler event="popupshown"><![CDATA[ 1.340 + this.onShown(); 1.341 + ]]></handler> 1.342 + <handler event="popuphidden"><![CDATA[ 1.343 + this.dispatchPanelEvent("socialFrameHide"); 1.344 + this.removeAttribute("open"); 1.345 + ]]></handler> 1.346 + <handler event="command"><![CDATA[ 1.347 + this.markCurrentPage(); 1.348 + ]]></handler> 1.349 + </handlers> 1.350 + </binding> 1.351 + 1.352 +</bindings>