diff options
author | Pale Moon <git-repo@palemoon.org> | 2015-08-18 08:53:17 +0200 |
---|---|---|
committer | Pale Moon <git-repo@palemoon.org> | 2015-08-18 08:53:17 +0200 |
commit | 06a219b34d4c19c9368f53dcf97e3414402b75a5 (patch) | |
tree | 7191e779b8f090336cc7463d7fda1aca88090445 /browser/base/content | |
parent | cc3205520eca5c6e7ef8412ffbe0075f182d521c (diff) | |
download | palemoon-gre-06a219b34d4c19c9368f53dcf97e3414402b75a5.tar.gz |
Remove the social API
Diffstat (limited to 'browser/base/content')
-rw-r--r-- | browser/base/content/aboutSocialError.xhtml | 124 | ||||
-rw-r--r-- | browser/base/content/browser-context.inc | 26 | ||||
-rw-r--r-- | browser/base/content/browser-menubar.inc | 47 | ||||
-rw-r--r-- | browser/base/content/browser-sets.inc | 16 | ||||
-rw-r--r-- | browser/base/content/browser-social.js | 1406 | ||||
-rw-r--r-- | browser/base/content/browser.css | 53 | ||||
-rw-r--r-- | browser/base/content/browser.js | 17 | ||||
-rw-r--r-- | browser/base/content/browser.xul | 138 | ||||
-rw-r--r-- | browser/base/content/chatWindow.xul | 109 | ||||
-rw-r--r-- | browser/base/content/nsContextMenu.js | 85 | ||||
-rw-r--r-- | browser/base/content/socialchat.xml | 747 |
11 files changed, 8 insertions, 2760 deletions
diff --git a/browser/base/content/aboutSocialError.xhtml b/browser/base/content/aboutSocialError.xhtml deleted file mode 100644 index 6bef2d7bd..000000000 --- a/browser/base/content/aboutSocialError.xhtml +++ /dev/null @@ -1,124 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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 http://mozilla.org/MPL/2.0/. --> - -<!DOCTYPE html [ - <!ENTITY % htmlDTD - PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "DTD/xhtml1-strict.dtd"> - %htmlDTD; - <!ENTITY % netErrorDTD SYSTEM "chrome://global/locale/netError.dtd"> - %netErrorDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <title>&loadError.label;</title> - <link rel="stylesheet" type="text/css" media="all" - href="chrome://browser/skin/aboutSocialError.css"/> - </head> - - <body> - <div id="error-box"> - <p id="main-error-msg"></p> - <p id="helper-error-msg"></p> - </div> - <div id="button-box"> - <button id="btnTryAgain" onclick="tryAgainButton()"/> - <button id="btnCloseSidebar" onclick="closeSidebarButton()"/> - </div> - </body> - - <script type="text/javascript;version=1.8"><![CDATA[ - const Cu = Components.utils; - - Cu.import("resource://gre/modules/Services.jsm"); - Cu.import("resource:///modules/Social.jsm"); - - let config = { - tryAgainCallback: reloadProvider - } - - function parseQueryString() { - let url = document.documentURI; - let queryString = url.replace(/^about:socialerror\??/, ""); - - let modeMatch = queryString.match(/mode=([^&]+)/); - let mode = modeMatch && modeMatch[1] ? modeMatch[1] : ""; - let originMatch = queryString.match(/origin=([^&]+)/); - config.origin = originMatch && originMatch[1] ? decodeURIComponent(originMatch[1]) : ""; - - switch (mode) { - case "compactInfo": - document.getElementById("btnTryAgain").style.display = 'none'; - document.getElementById("btnCloseSidebar").style.display = 'none'; - break; - case "tryAgainOnly": - document.getElementById("btnCloseSidebar").style.display = 'none'; - //intentional fall-through - case "tryAgain": - let urlMatch = queryString.match(/url=([^&]+)/); - let encodedURL = urlMatch && urlMatch[1] ? urlMatch[1] : ""; - let url = decodeURIComponent(encodedURL); - - config.tryAgainCallback = loadQueryURL; - config.queryURL = url; - break; - case "workerFailure": - config.tryAgainCallback = reloadProvider; - break; - default: - break; - } - } - - function setUpStrings() { - let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties"); - let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); - - let productName = brandBundle.GetStringFromName("brandShortName"); - let provider = Social && Social.provider; - if (config.origin) { - provider = Social && Social._getProviderFromOrigin(config.origin); - } - let providerName = provider && provider.name; - - // Sets up the error message - let msg = browserBundle.formatStringFromName("social.error.message", [productName, providerName], 2); - document.getElementById("main-error-msg").textContent = msg; - - // Sets up the buttons' labels and accesskeys - let btnTryAgain = document.getElementById("btnTryAgain"); - btnTryAgain.textContent = browserBundle.GetStringFromName("social.error.tryAgain.label"); - btnTryAgain.accessKey = browserBundle.GetStringFromName("social.error.tryAgain.accesskey"); - - let btnCloseSidebar = document.getElementById("btnCloseSidebar"); - btnCloseSidebar.textContent = browserBundle.GetStringFromName("social.error.closeSidebar.label"); - btnCloseSidebar.accessKey = browserBundle.GetStringFromName("social.error.closeSidebar.accesskey"); - } - - function closeSidebarButton() { - Social.toggleSidebar(); - } - - function tryAgainButton() { - config.tryAgainCallback(); - } - - function loadQueryURL() { - window.location.href = config.queryURL; - } - - function reloadProvider() { - Social.enabled = false; - Services.tm.mainThread.dispatch(function() { - Social.enabled = true; - }, Components.interfaces.nsIThread.DISPATCH_NORMAL); - } - - parseQueryString(); - setUpStrings(); - ]]></script> -</html> diff --git a/browser/base/content/browser-context.inc b/browser/base/content/browser-context.inc index 0c2f058ca..b9314a823 100644 --- a/browser/base/content/browser-context.inc +++ b/browser/base/content/browser-context.inc @@ -37,13 +37,6 @@ label="&bookmarkThisLinkCmd.label;" accesskey="&bookmarkThisLinkCmd.accesskey;" oncommand="gContextMenu.bookmarkLink();"/> - <menuitem id="context-marklink" - accesskey="&social.marklink.accesskey;" - oncommand="gContextMenu.markLink();"/> - <menuitem id="context-sharelink" - label="&shareLinkCmd.label;" - accesskey="&shareLinkCmd.accesskey;" - oncommand="gContextMenu.shareLink();"/> <menuitem id="context-savelink" label="&saveLinkCmd.label;" accesskey="&saveLinkCmd.accesskey;" @@ -168,10 +161,6 @@ label="&saveImageCmd.label;" accesskey="&saveImageCmd.accesskey;" oncommand="gContextMenu.saveMedia();"/> - <menuitem id="context-shareimage" - label="&shareImageCmd.label;" - accesskey="&shareImageCmd.accesskey;" - oncommand="gContextMenu.shareImage();"/> <menuitem id="context-sendimage" label="&emailImageCmd.label;" accesskey="&emailImageCmd.accesskey;" @@ -188,10 +177,6 @@ label="&saveVideoCmd.label;" accesskey="&saveVideoCmd.accesskey;" oncommand="gContextMenu.saveMedia();"/> - <menuitem id="context-sharevideo" - label="&shareVideoCmd.label;" - accesskey="&shareVideoCmd.accesskey;" - oncommand="gContextMenu.shareVideo();"/> <menuitem id="context-saveaudio" label="&saveAudioCmd.label;" accesskey="&saveAudioCmd.accesskey;" @@ -241,13 +226,6 @@ label="&bookmarkPageCmd2.label;" accesskey="&bookmarkPageCmd2.accesskey;" oncommand="gContextMenu.bookmarkThisPage();"/> - <menuitem id="context-markpage" - accesskey="&social.markpage.accesskey;" - command="Social:TogglePageMark"/> - <menuitem id="context-sharepage" - label="&sharePageCmd.label;" - accesskey="&sharePageCmd.accesskey;" - oncommand="SocialShare.sharePage();"/> <menuitem id="context-savepage" label="&savePageCmd.label;" accesskey="&savePageCmd.accesskey2;" @@ -295,10 +273,6 @@ oncommand="AddKeywordForSearchField();"/> <menuitem id="context-searchselect" oncommand="BrowserSearch.loadSearchFromContext(getBrowserSelection());"/> - <menuitem id="context-shareselect" - label="&shareSelectCmd.label;" - accesskey="&shareSelectCmd.accesskey;" - oncommand="gContextMenu.shareSelect(getBrowserSelection());"/> <menuseparator id="frame-sep"/> <menu id="frame" label="&thisFrameMenu.label;" accesskey="&thisFrameMenu.accesskey;"> <menupopup> diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index 6d52f12d3..081ed8d65 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -207,10 +207,6 @@ key="key_gotoHistory" observes="viewHistorySidebar" label="&historyButton.label;"/> - <menuitem id="menu_socialSidebar" - type="checkbox" - autocheck="false" - command="Social:ToggleSidebar"/> </menupopup> </menu> <menuseparator/> @@ -506,49 +502,6 @@ accesskey="&addons.accesskey;" key="key_openAddons" command="Tools:Addons"/> - <menu id="menu_socialAmbientMenu" - observes="socialActiveBroadcaster"> - <menupopup id="menu_social-statusarea-popup"> - <menuitem class="social-statusarea-user menuitem-iconic" pack="start" align="center" - observes="socialBroadcaster_userDetails" - oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"> - <image class="social-statusarea-user-portrait" - observes="socialBroadcaster_userDetails"/> - <vbox> - <label class="social-statusarea-loggedInStatus" - observes="socialBroadcaster_userDetails"/> - </vbox> - </menuitem> -#ifndef XP_WIN - <menuseparator class="social-statusarea-separator"/> -#endif - <menuseparator id="socialAmbientMenuSeparator" - hidden="true"/> - <menuitem class="social-toggle-sidebar-menuitem" - type="checkbox" - autocheck="false" - command="Social:ToggleSidebar" - label="&social.toggleSidebar.label;" - accesskey="&social.toggleSidebar.accesskey;"/> - <menuitem class="social-toggle-notifications-menuitem" - type="checkbox" - autocheck="false" - command="Social:ToggleNotifications" - label="&social.toggleNotifications.label;" - accesskey="&social.toggleNotifications.accesskey;"/> - <menuitem id="menu_focusChatBar" - label="&social.chatBar.label;" - accesskey="&social.chatBar.accesskey;" - key="focusChatBar" - command="Social:FocusChat" - class="show-only-for-keyboard"/> - <menuitem class="social-toggle-menuitem" command="Social:Toggle"/> - <menuseparator class="social-statusarea-separator"/> - <menuseparator class="social-provider-menu" hidden="true"/> - <menuitem class="social-addons-menuitem" command="Social:Addons" - label="&social.addons.label;"/> - </menupopup> - </menu> #ifdef MOZ_SERVICES_SYNC <!-- only one of sync-setup or sync-menu will be showing at once --> <menuitem id="sync-setup" diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index c017c669b..b8a639fe6 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -112,13 +112,6 @@ <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/> <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/> <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/> - <command id="Social:TogglePageMark" oncommand="SocialMark.togglePageMark();" disabled="true"/> - <command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/> - <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/> - <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/> - <command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/> - <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/> - <command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/> </commandset> <commandset id="placesCommands"> @@ -171,8 +164,6 @@ <broadcaster id="sync-syncnow-state"/> #endif <broadcaster id="workOfflineMenuitemState"/> - <broadcaster id="socialSidebarBroadcaster" hidden="true"/> - <broadcaster id="socialActiveBroadcaster" hidden="true"/> #ifdef MOZ_DEVTOOLS <!-- DevTools broadcasters --> @@ -218,10 +209,6 @@ label="&devtoolsConnect.label;" command="Tools:DevToolsConnect"/> #endif - - <!-- SocialAPI broadcasters --> - <broadcaster id="socialBroadcaster_userDetails" - notLoggedInLabel="&social.notLoggedIn.label;"/> </broadcasterset> <keyset id="mainKeyset"> @@ -361,9 +348,6 @@ <key id="viewBookmarksSidebarWinKb" key="&bookmarksWinCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/> #endif - <key id="markPage" key="&markPageCmd.commandkey;" command="Social:TogglePageMark" modifiers="accel,shift"/> - <key id="focusChatBar" key="&social.chatBar.commandkey;" command="Social:FocusChat" modifiers="accel,shift"/> - <key id="key_stop" keycode="VK_ESCAPE" command="Browser:Stop"/> #ifdef XP_MACOSX diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js deleted file mode 100644 index 7a0ab726c..000000000 --- a/browser/base/content/browser-social.js +++ /dev/null @@ -1,1406 +0,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 http://mozilla.org/MPL/2.0/. - -// the "exported" symbols -let SocialUI, - SocialChatBar, - SocialFlyout, - SocialMark, - SocialShare, - SocialMenu, - SocialToolbar, - SocialSidebar; - -(function() { - -// The minimum sizes for the auto-resize panel code. -const PANEL_MIN_HEIGHT = 100; -const PANEL_MIN_WIDTH = 330; - -XPCOMUtils.defineLazyModuleGetter(this, "SharedFrame", - "resource:///modules/SharedFrame.jsm"); - -XPCOMUtils.defineLazyGetter(this, "OpenGraphBuilder", function() { - let tmp = {}; - Cu.import("resource:///modules/Social.jsm", tmp); - return tmp.OpenGraphBuilder; -}); - -SocialUI = { - // Called on delayed startup to initialize the UI - init: function SocialUI_init() { - Services.obs.addObserver(this, "social:ambient-notification-changed", false); - Services.obs.addObserver(this, "social:profile-changed", false); - Services.obs.addObserver(this, "social:page-mark-config", false); - Services.obs.addObserver(this, "social:frameworker-error", false); - Services.obs.addObserver(this, "social:provider-set", false); - Services.obs.addObserver(this, "social:providers-changed", false); - - Services.prefs.addObserver("social.sidebar.open", this, false); - Services.prefs.addObserver("social.toast-notifications.enabled", this, false); - - gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler.bind(this), true, true); - - SocialChatBar.init(); - SocialMark.init(); - SocialShare.init(); - SocialMenu.init(); - SocialToolbar.init(); - SocialSidebar.init(); - - if (!Social.initialized) { - Social.init(); - } else { - // social was previously initialized, so it's not going to notify us of - // anything, so handle that now. - this.observe(null, "social:providers-changed", null); - this.observe(null, "social:provider-set", Social.provider ? Social.provider.origin : null); - } - }, - - // Called on window unload - uninit: function SocialUI_uninit() { - Services.obs.removeObserver(this, "social:ambient-notification-changed"); - Services.obs.removeObserver(this, "social:profile-changed"); - Services.obs.removeObserver(this, "social:page-mark-config"); - Services.obs.removeObserver(this, "social:frameworker-error"); - Services.obs.removeObserver(this, "social:provider-set"); - Services.obs.removeObserver(this, "social:providers-changed"); - - Services.prefs.removeObserver("social.sidebar.open", this); - Services.prefs.removeObserver("social.toast-notifications.enabled", this); - }, - - _matchesCurrentProvider: function (origin) { - return Social.provider && Social.provider.origin == origin; - }, - - observe: function SocialUI_observe(subject, topic, data) { - // Exceptions here sometimes don't get reported properly, report them - // manually :( - try { - switch (topic) { - case "social:provider-set": - // Social.provider has changed (possibly to null), update any state - // which depends on it. - this._updateActiveUI(); - this._updateMenuItems(); - - SocialFlyout.unload(); - SocialChatBar.update(); - SocialShare.update(); - SocialSidebar.update(); - SocialMark.update(); - SocialToolbar.update(); - SocialMenu.populate(); - break; - case "social:providers-changed": - // the list of providers changed - this may impact the "active" UI. - this._updateActiveUI(); - // and the multi-provider menu - SocialToolbar.populateProviderMenus(); - SocialShare.populateProviderMenu(); - break; - - // Provider-specific notifications - case "social:ambient-notification-changed": - if (this._matchesCurrentProvider(data)) { - SocialToolbar.updateButton(); - SocialMenu.populate(); - } - break; - case "social:profile-changed": - if (this._matchesCurrentProvider(data)) { - SocialToolbar.updateProvider(); - SocialMark.update(); - SocialChatBar.update(); - } - break; - case "social:page-mark-config": - if (this._matchesCurrentProvider(data)) { - SocialMark.updateMarkState(); - } - break; - case "social:frameworker-error": - if (this.enabled && Social.provider.origin == data) { - SocialSidebar.setSidebarErrorMessage(); - } - break; - - case "nsPref:changed": - if (data == "social.sidebar.open") { - SocialSidebar.update(); - } else if (data == "social.toast-notifications.enabled") { - SocialToolbar.updateButton(); - } - break; - } - } catch (e) { - Components.utils.reportError(e + "\n" + e.stack); - throw e; - } - }, - - nonBrowserWindowInit: function SocialUI_nonBrowserInit() { - // Disable the social menu item in non-browser windows - document.getElementById("menu_socialAmbientMenu").hidden = true; - }, - - // Miscellaneous helpers - showProfile: function SocialUI_showProfile() { - if (Social.haveLoggedInUser()) - openUILinkIn(Social.provider.profile.profileURL, "tab"); - else { - // XXX Bug 789585 will implement an API for provider-specified login pages. - openUILinkIn(Social.provider.origin, "tab"); - } - }, - - _updateActiveUI: function SocialUI_updateActiveUI() { - // The "active" UI isn't dependent on there being a provider, just on - // social being "active" (but also chromeless/PB) - let enabled = Social.providers.length > 0 && !this._chromeless && - !PrivateBrowsingUtils.isWindowPrivate(window); - let broadcaster = document.getElementById("socialActiveBroadcaster"); - broadcaster.hidden = !enabled; - - let toggleCommand = document.getElementById("Social:Toggle"); - toggleCommand.setAttribute("hidden", enabled ? "false" : "true"); - - if (enabled) { - // enabled == true means we at least have a defaultProvider - let provider = Social.provider || Social.defaultProvider; - // We only need to update the command itself - all our menu items use it. - let label = gNavigatorBundle.getFormattedString(Social.provider ? - "social.turnOff.label" : - "social.turnOn.label", - [provider.name]); - let accesskey = gNavigatorBundle.getString(Social.provider ? - "social.turnOff.accesskey" : - "social.turnOn.accesskey"); - toggleCommand.setAttribute("label", label); - toggleCommand.setAttribute("accesskey", accesskey); - } - }, - - _updateMenuItems: function () { - let provider = Social.provider || Social.defaultProvider; - if (!provider) - return; - // The View->Sidebar and Menubar->Tools menu. - for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"]) - document.getElementById(id).setAttribute("label", provider.name); - }, - - // This handles "ActivateSocialFeature" events fired against content documents - // in this window. - _activationEventHandler: function SocialUI_activationHandler(e) { - let targetDoc; - let node; - if (e.target instanceof HTMLDocument) { - // version 0 support - targetDoc = e.target; - node = targetDoc.documentElement - } else { - targetDoc = e.target.ownerDocument; - node = e.target; - } - if (!(targetDoc instanceof HTMLDocument)) - return; - - // Ignore events fired in background tabs or iframes - if (targetDoc.defaultView != content) - return; - - // If we are in PB mode, we silently do nothing (bug 829404 exists to - // do something sensible here...) - if (PrivateBrowsingUtils.isWindowPrivate(window)) - return; - - // If the last event was received < 1s ago, ignore this one - let now = Date.now(); - if (now - Social.lastEventReceived < 1000) - return; - Social.lastEventReceived = now; - - // We only want to activate if it is as a result of user input. - let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - if (!dwu.isHandlingUserInput) { - Cu.reportError("attempt to activate provider without user input from " + targetDoc.nodePrincipal.origin); - return; - } - - let data = node.getAttribute("data-service"); - if (data) { - try { - data = JSON.parse(data); - } catch(e) { - Cu.reportError("Social Service manifest parse error: "+e); - return; - } - } - Social.installProvider(targetDoc, data, function(manifest) { - this.doActivation(manifest.origin); - }.bind(this)); - }, - - doActivation: function SocialUI_doActivation(origin) { - // Keep track of the old provider in case of undo - let oldOrigin = Social.provider ? Social.provider.origin : ""; - - // Enable the social functionality, and indicate that it was activated - Social.activateFromOrigin(origin, function(provider) { - // Provider to activate may not have been found - if (!provider) - return; - - // Show a warning, allow undoing the activation - let description = document.getElementById("social-activation-message"); - let labels = description.getElementsByTagName("label"); - let uri = Services.io.newURI(provider.origin, null, null) - labels[0].setAttribute("value", uri.host); - labels[1].setAttribute("onclick", "BrowserOpenAddonsMgr('addons://list/service'); SocialUI.activationPanel.hidePopup();") - - let icon = document.getElementById("social-activation-icon"); - if (provider.icon64URL || provider.icon32URL) { - icon.setAttribute('src', provider.icon64URL || provider.icon32URL); - icon.hidden = false; - } else { - icon.removeAttribute('src'); - icon.hidden = true; - } - - let notificationPanel = SocialUI.activationPanel; - // Set the origin being activated and the previously active one, to allow undo - notificationPanel.setAttribute("origin", provider.origin); - notificationPanel.setAttribute("oldorigin", oldOrigin); - - // Show the panel - notificationPanel.hidden = false; - setTimeout(function () { - notificationPanel.openPopup(SocialToolbar.button, "bottomcenter topright"); - }, 0); - }); - }, - - undoActivation: function SocialUI_undoActivation() { - let origin = this.activationPanel.getAttribute("origin"); - let oldOrigin = this.activationPanel.getAttribute("oldorigin"); - Social.deactivateFromOrigin(origin, oldOrigin); - this.activationPanel.hidePopup(); - Social.uninstallProvider(origin); - }, - - showLearnMore: function() { - this.activationPanel.hidePopup(); - let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "social-api"; - openUILinkIn(url, "tab"); - }, - - get activationPanel() { - return document.getElementById("socialActivatedNotification"); - }, - - closeSocialPanelForLinkTraversal: function (target, linkNode) { - // No need to close the panel if this traversal was not retargeted - if (target == "" || target == "_self") - return; - - // Check to see whether this link traversal was in a social panel - let win = linkNode.ownerDocument.defaultView; - let container = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler; - let containerParent = container.parentNode; - if (containerParent.classList.contains("social-panel") && - containerParent instanceof Ci.nsIDOMXULPopupElement) { - // allow the link traversal to finish before closing the panel - setTimeout(() => { - containerParent.hidePopup(); - }, 0); - } - }, - - get _chromeless() { - // Is this a popup window that doesn't want chrome shown? - let docElem = document.documentElement; - // extrachrome is not restored during session restore, so we need - // to check for the toolbar as well. - let chromeless = docElem.getAttribute("chromehidden").contains("extrachrome") || - docElem.getAttribute('chromehidden').contains("toolbar"); - // This property is "fixed" for a window, so avoid doing the check above - // multiple times... - delete this._chromeless; - this._chromeless = chromeless; - return chromeless; - }, - - get enabled() { - // Returns whether social is enabled *for this window*. - if (this._chromeless || PrivateBrowsingUtils.isWindowPrivate(window)) - return false; - return !!Social.provider; - }, - -} - -SocialChatBar = { - init: function() { - }, - get chatbar() { - return document.getElementById("pinnedchats"); - }, - // Whether the chatbar is available for this window. Note that in full-screen - // mode chats are available, but not shown. - get isAvailable() { - return SocialUI.enabled && Social.haveLoggedInUser(); - }, - // Does this chatbar have any chats (whether minimized, collapsed or normal) - get hasChats() { - return !!this.chatbar.firstElementChild; - }, - openChat: function(aProvider, aURL, aCallback, aMode) { - if (!this.isAvailable) - return false; - this.chatbar.openChat(aProvider, aURL, aCallback, aMode); - // We only want to focus the chat if it is as a result of user input. - let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - if (dwu.isHandlingUserInput) - this.chatbar.focus(); - return true; - }, - update: function() { - let command = document.getElementById("Social:FocusChat"); - if (!this.isAvailable) { - this.chatbar.removeAll(); - this.chatbar.hidden = command.hidden = true; - } else { - this.chatbar.hidden = command.hidden = false; - } - command.setAttribute("disabled", command.hidden ? "true" : "false"); - }, - focus: function SocialChatBar_focus() { - this.chatbar.focus(); - } -} - -function sizeSocialPanelToContent(panel, iframe) { - // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here? - let doc = iframe.contentDocument; - if (!doc || !doc.body) { - return; - } - // We need an element to use for sizing our panel. See if the body defines - // an id for that element, otherwise use the body itself. - let body = doc.body; - let bodyId = body.getAttribute("contentid"); - if (bodyId) { - body = doc.getElementById(bodyId) || doc.body; - } - // offsetHeight/Width don't include margins, so account for that. - let cs = doc.defaultView.getComputedStyle(body); - let computedHeight = parseInt(cs.marginTop) + body.offsetHeight + parseInt(cs.marginBottom); - let height = Math.max(computedHeight, PANEL_MIN_HEIGHT); - let computedWidth = parseInt(cs.marginLeft) + body.offsetWidth + parseInt(cs.marginRight); - let width = Math.max(computedWidth, PANEL_MIN_WIDTH); - iframe.style.width = width + "px"; - iframe.style.height = height + "px"; - // since we do not use panel.sizeTo, we need to adjust the arrow ourselves - if (panel.state == "open") - panel.adjustArrowPosition(); -} - -function DynamicResizeWatcher() { - this._mutationObserver = null; -} - -DynamicResizeWatcher.prototype = { - start: function DynamicResizeWatcher_start(panel, iframe) { - this.stop(); // just in case... - let doc = iframe.contentDocument; - this._mutationObserver = new iframe.contentWindow.MutationObserver(function(mutations) { - sizeSocialPanelToContent(panel, iframe); - }); - // Observe anything that causes the size to change. - let config = {attributes: true, characterData: true, childList: true, subtree: true}; - this._mutationObserver.observe(doc, config); - // and since this may be setup after the load event has fired we do an - // initial resize now. - sizeSocialPanelToContent(panel, iframe); - }, - stop: function DynamicResizeWatcher_stop() { - if (this._mutationObserver) { - try { - this._mutationObserver.disconnect(); - } catch (ex) { - // may get "TypeError: can't access dead object" which seems strange, - // but doesn't seem to indicate a real problem, so ignore it... - } - this._mutationObserver = null; - } - } -} - -SocialFlyout = { - get panel() { - return document.getElementById("social-flyout-panel"); - }, - - get iframe() { - if (!this.panel.firstChild) - this._createFrame(); - return this.panel.firstChild; - }, - - dispatchPanelEvent: function(name) { - let doc = this.iframe.contentDocument; - let evt = doc.createEvent("CustomEvent"); - evt.initCustomEvent(name, true, true, {}); - doc.documentElement.dispatchEvent(evt); - }, - - _createFrame: function() { - let panel = this.panel; - if (!SocialUI.enabled || panel.firstChild) - return; - // create and initialize the panel for this window - let iframe = document.createElement("iframe"); - iframe.setAttribute("type", "content"); - iframe.setAttribute("class", "social-panel-frame"); - iframe.setAttribute("flex", "1"); - iframe.setAttribute("tooltip", "aHTMLTooltip"); - iframe.setAttribute("origin", Social.provider.origin); - panel.appendChild(iframe); - }, - - setFlyoutErrorMessage: function SF_setFlyoutErrorMessage() { - this.iframe.removeAttribute("src"); - this.iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo", null, null, null, null); - sizeSocialPanelToContent(this.panel, this.iframe); - }, - - unload: function() { - let panel = this.panel; - panel.hidePopup(); - if (!panel.firstChild) - return - let iframe = panel.firstChild; - if (iframe.socialErrorListener) - iframe.socialErrorListener.remove(); - panel.removeChild(iframe); - }, - - onShown: function(aEvent) { - let panel = this.panel; - let iframe = this.iframe; - this._dynamicResizer = new DynamicResizeWatcher(); - iframe.docShell.isActive = true; - iframe.docShell.isAppTab = true; - if (iframe.contentDocument.readyState == "complete") { - this._dynamicResizer.start(panel, iframe); - this.dispatchPanelEvent("socialFrameShow"); - } else { - // first time load, wait for load and dispatch after load - iframe.addEventListener("load", function panelBrowserOnload(e) { - iframe.removeEventListener("load", panelBrowserOnload, true); - setTimeout(function() { - if (SocialFlyout._dynamicResizer) { // may go null if hidden quickly - SocialFlyout._dynamicResizer.start(panel, iframe); - SocialFlyout.dispatchPanelEvent("socialFrameShow"); - } - }, 0); - }, true); - } - }, - - onHidden: function(aEvent) { - this._dynamicResizer.stop(); - this._dynamicResizer = null; - this.iframe.docShell.isActive = false; - this.dispatchPanelEvent("socialFrameHide"); - }, - - load: function(aURL, cb) { - if (!Social.provider) - return; - - this.panel.hidden = false; - let iframe = this.iframe; - // same url with only ref difference does not cause a new load, so we - // want to go right to the callback - let src = iframe.contentDocument && iframe.contentDocument.documentURIObject; - if (!src || !src.equalsExceptRef(Services.io.newURI(aURL, null, null))) { - iframe.addEventListener("load", function documentLoaded() { - iframe.removeEventListener("load", documentLoaded, true); - cb(); - }, true); - // Force a layout flush by calling .clientTop so - // that the docShell of this frame is created - iframe.clientTop; - Social.setErrorListener(iframe, SocialFlyout.setFlyoutErrorMessage.bind(SocialFlyout)) - iframe.setAttribute("src", aURL); - } else { - // we still need to set the src to trigger the contents hashchange event - // for ref changes - iframe.setAttribute("src", aURL); - cb(); - } - }, - - open: function(aURL, yOffset, aCallback) { - // Hide any other social panels that may be open. - document.getElementById("social-notification-panel").hidePopup(); - - if (!SocialUI.enabled) - return; - let panel = this.panel; - let iframe = this.iframe; - - this.load(aURL, function() { - sizeSocialPanelToContent(panel, iframe); - let anchor = document.getElementById("social-sidebar-browser"); - if (panel.state == "open") { - panel.moveToAnchor(anchor, "start_before", 0, yOffset, false); - } else { - panel.openPopup(anchor, "start_before", 0, yOffset, false, false); - } - if (aCallback) { - try { - aCallback(iframe.contentWindow); - } catch(e) { - Cu.reportError(e); - } - } - }); - } -} - -SocialShare = { - // Called once, after window load, when the Social.provider object is initialized - init: function() {}, - - get panel() { - return document.getElementById("social-share-panel"); - }, - - get iframe() { - // first element is our menu vbox. - if (this.panel.childElementCount == 1) - return null; - else - return this.panel.lastChild; - }, - - _createFrame: function() { - let panel = this.panel; - if (!SocialUI.enabled || this.iframe) - return; - this.panel.hidden = false; - // create and initialize the panel for this window - let iframe = document.createElement("iframe"); - iframe.setAttribute("type", "content"); - iframe.setAttribute("class", "social-share-frame"); - iframe.setAttribute("flex", "1"); - panel.appendChild(iframe); - this.populateProviderMenu(); - }, - - getSelectedProvider: function() { - let provider; - let lastProviderOrigin = this.iframe && this.iframe.getAttribute("origin"); - if (lastProviderOrigin) { - provider = Social._getProviderFromOrigin(lastProviderOrigin); - } - if (!provider) - provider = Social.provider || Social.defaultProvider; - // if our provider has no shareURL, select the first one that does - if (provider && !provider.shareURL) { - let providers = [p for (p of Social.providers) if (p.shareURL)]; - provider = providers.length > 0 && providers[0]; - } - return provider; - }, - - populateProviderMenu: function() { - if (!this.iframe) - return; - let providers = [p for (p of Social.providers) if (p.shareURL)]; - let hbox = document.getElementById("social-share-provider-buttons"); - // selectable providers are inserted before the provider-menu seperator, - // remove any menuitems in that area - while (hbox.firstChild) { - hbox.removeChild(hbox.firstChild); - } - // reset our share toolbar - // only show a selection if there is more than one - if (!SocialUI.enabled || providers.length < 2) { - this.panel.firstChild.hidden = true; - return; - } - let selectedProvider = this.getSelectedProvider(); - for (let provider of providers) { - let button = document.createElement("toolbarbutton"); - button.setAttribute("class", "toolbarbutton share-provider-button"); - button.setAttribute("type", "radio"); - button.setAttribute("group", "share-providers"); - button.setAttribute("image", provider.iconURL); - button.setAttribute("tooltiptext", provider.name); - button.setAttribute("origin", provider.origin); - button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin')); this.checked=true;"); - if (provider == selectedProvider) { - this.defaultButton = button; - } - hbox.appendChild(button); - } - if (!this.defaultButton) { - this.defaultButton = hbox.firstChild - } - this.defaultButton.setAttribute("checked", "true"); - this.panel.firstChild.hidden = false; - }, - - get shareButton() { - return document.getElementById("social-share-button"); - }, - - canSharePage: function(aURI) { - // we do not enable sharing from private sessions - if (PrivateBrowsingUtils.isWindowPrivate(window)) - return false; - - if (!aURI || !(aURI.schemeIs('http') || aURI.schemeIs('https'))) - return false; - return true; - }, - - update: function() { - let shareButton = this.shareButton; - shareButton.hidden = !SocialUI.enabled || - [p for (p of Social.providers) if (p.shareURL)].length == 0; - shareButton.disabled = shareButton.hidden || !this.canSharePage(gBrowser.currentURI); - - // also update the relevent command's disabled state so the keyboard - // shortcut only works when available. - let cmd = document.getElementById("Social:SharePage"); - cmd.setAttribute("disabled", shareButton.disabled ? "true" : "false"); - }, - - onShowing: function() { - this.shareButton.setAttribute("open", "true"); - }, - - onHidden: function() { - this.shareButton.removeAttribute("open"); - this.iframe.setAttribute("src", "data:text/plain;charset=utf8,"); - this.currentShare = null; - }, - - setErrorMessage: function() { - let iframe = this.iframe; - if (!iframe) - return; - - iframe.removeAttribute("src"); - iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" + - encodeURIComponent(iframe.getAttribute("origin")), - null, null, null, null); - sizeSocialPanelToContent(this.panel, iframe); - }, - - sharePage: function(providerOrigin, graphData) { - // if providerOrigin is undefined, we use the last-used provider, or the - // current/default provider. The provider selection in the share panel - // will call sharePage with an origin for us to switch to. - this._createFrame(); - let iframe = this.iframe; - let provider; - if (providerOrigin) - provider = Social._getProviderFromOrigin(providerOrigin); - else - provider = this.getSelectedProvider(); - if (!provider || !provider.shareURL) - return; - - // graphData is an optional param that either defines the full set of data - // to be shared, or partial data about the current page. It is set by a call - // in mozSocial API, or via nsContentMenu calls. If it is present, it MUST - // define at least url. If it is undefined, we're sharing the current url in - // the browser tab. - let sharedURI = graphData ? Services.io.newURI(graphData.url, null, null) : - gBrowser.currentURI; - if (!this.canSharePage(sharedURI)) - return; - - // the point of this action type is that we can use existing share - // endpoints (e.g. oexchange) that do not support additional - // socialapi functionality. One tweak is that we shoot an event - // containing the open graph data. - let pageData = graphData ? graphData : this.currentShare; - if (!pageData || sharedURI == gBrowser.currentURI) { - pageData = OpenGraphBuilder.getData(gBrowser); - if (graphData) { - // overwrite data retreived from page with data given to us as a param - for (let p in graphData) { - pageData[p] = graphData[p]; - } - } - } - this.currentShare = pageData; - - let shareEndpoint = this._generateShareEndpointURL(provider.shareURL, pageData); - - this._dynamicResizer = new DynamicResizeWatcher(); - // if we've already loaded this provider/page share endpoint, we don't want - // to add another load event listener. - let reload = true; - let endpointMatch = shareEndpoint == iframe.getAttribute("src"); - let docLoaded = iframe.contentDocument && iframe.contentDocument.readyState == "complete"; - if (endpointMatch && docLoaded) { - reload = shareEndpoint != iframe.contentDocument.location.spec; - } - if (!reload) { - this._dynamicResizer.start(this.panel, iframe); - iframe.docShell.isActive = true; - iframe.docShell.isAppTab = true; - let evt = iframe.contentDocument.createEvent("CustomEvent"); - evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData)); - iframe.contentDocument.documentElement.dispatchEvent(evt); - } else { - // first time load, wait for load and dispatch after load - iframe.addEventListener("load", function panelBrowserOnload(e) { - iframe.removeEventListener("load", panelBrowserOnload, true); - iframe.docShell.isActive = true; - iframe.docShell.isAppTab = true; - setTimeout(function() { - if (SocialShare._dynamicResizer) { // may go null if hidden quickly - SocialShare._dynamicResizer.start(iframe.parentNode, iframe); - } - }, 0); - let evt = iframe.contentDocument.createEvent("CustomEvent"); - evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData)); - iframe.contentDocument.documentElement.dispatchEvent(evt); - }, true); - } - // always ensure that origin belongs to the endpoint - let uri = Services.io.newURI(shareEndpoint, null, null); - iframe.setAttribute("origin", provider.origin); - iframe.setAttribute("src", shareEndpoint); - - let navBar = document.getElementById("nav-bar"); - let anchor = navBar.getAttribute("mode") == "text" ? - document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-text") : - document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon"); - this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false); - Social.setErrorListener(iframe, this.setErrorMessage.bind(this)); - }, - - _generateShareEndpointURL: function(shareURL, pageData) { - // support for existing share endpoints by supporting their querystring - // arguments. parse the query string template and do replacements where - // necessary the query names may be different than ours, so we could see - // u=%{url} or url=%{url} - let [shareEndpoint, queryString] = shareURL.split("?"); - let query = {}; - if (queryString) { - queryString.split('&').forEach(function (val) { - let [name, value] = val.split('='); - let p = /%\{(.+)\}/.exec(value); - if (!p) { - // preserve non-template query vars - query[name] = value; - } else if (pageData[p[1]]) { - query[name] = pageData[p[1]]; - } else if (p[1] == "body") { - // build a body for emailers - let body = ""; - if (pageData.title) - body += pageData.title + "\n\n"; - if (pageData.description) - body += pageData.description + "\n\n"; - if (pageData.text) - body += pageData.text + "\n\n"; - body += pageData.url; - query["body"] = body; - } - }); - } - var str = []; - for (let p in query) - str.push(p + "=" + encodeURIComponent(query[p])); - if (str.length) - shareEndpoint = shareEndpoint + "?" + str.join("&"); - return shareEndpoint; - } -}; - -SocialMark = { - // Called once, after window load, when the Social.provider object is initialized - init: function SSB_init() { - }, - - get button() { - return document.getElementById("social-mark-button"); - }, - - canMarkPage: function SSB_canMarkPage(aURI) { - // We only allow sharing of http or https - return aURI && (aURI.schemeIs('http') || aURI.schemeIs('https')); - }, - - // Called when the Social.provider changes - update: function SSB_updateButtonState() { - let markButton = this.button; - // always show button if provider supports marks - markButton.hidden = !SocialUI.enabled || Social.provider.pageMarkInfo == null; - markButton.disabled = markButton.hidden || !this.canMarkPage(gBrowser.currentURI); - - // also update the relevent command's disabled state so the keyboard - // shortcut only works when available. - let cmd = document.getElementById("Social:TogglePageMark"); - cmd.setAttribute("disabled", markButton.disabled ? "true" : "false"); - }, - - togglePageMark: function(aCallback) { - if (this.button.disabled) - return; - this.toggleURIMark(gBrowser.currentURI, aCallback) - }, - - toggleURIMark: function(aURI, aCallback) { - let update = function(marked) { - this._updateMarkState(marked); - if (aCallback) - aCallback(marked); - }.bind(this); - Social.isURIMarked(aURI, function(marked) { - if (marked) { - Social.unmarkURI(aURI, update); - } else { - Social.markURI(aURI, update); - } - }); - }, - - updateMarkState: function SSB_updateMarkState() { - this.update(); - if (!this.button.hidden) - Social.isURIMarked(gBrowser.currentURI, this._updateMarkState.bind(this)); - }, - - _updateMarkState: function(currentPageMarked) { - // callback for isURIMarked - let markButton = this.button; - let pageMarkInfo = SocialUI.enabled ? Social.provider.pageMarkInfo : null; - - // Update the mark button, if present - if (!markButton || markButton.hidden || !pageMarkInfo) - return; - - let imageURL; - if (!markButton.disabled && currentPageMarked) { - markButton.setAttribute("marked", "true"); - markButton.setAttribute("label", pageMarkInfo.messages.markedLabel); - markButton.setAttribute("tooltiptext", pageMarkInfo.messages.markedTooltip); - imageURL = pageMarkInfo.images.marked; - } else { - markButton.removeAttribute("marked"); - markButton.setAttribute("label", pageMarkInfo.messages.unmarkedLabel); - markButton.setAttribute("tooltiptext", pageMarkInfo.messages.unmarkedTooltip); - imageURL = pageMarkInfo.images.unmarked; - } - markButton.style.listStyleImage = "url(" + imageURL + ")"; - } -}; - -SocialMenu = { - init: function SocialMenu_init() { - }, - - populate: function SocialMenu_populate() { - let submenu = document.getElementById("menu_social-statusarea-popup"); - let ambientMenuItems = submenu.getElementsByClassName("ambient-menuitem"); - while (ambientMenuItems.length) - submenu.removeChild(ambientMenuItems.item(0)); - - let separator = document.getElementById("socialAmbientMenuSeparator"); - separator.hidden = true; - let provider = SocialUI.enabled ? Social.provider : null; - if (!provider) - return; - - let iconNames = Object.keys(provider.ambientNotificationIcons); - for (let name of iconNames) { - let icon = provider.ambientNotificationIcons[name]; - if (!icon.label || !icon.menuURL) - continue; - separator.hidden = false; - let menuitem = document.createElement("menuitem"); - menuitem.setAttribute("label", icon.label); - menuitem.classList.add("ambient-menuitem"); - menuitem.addEventListener("command", function() { - openUILinkIn(icon.menuURL, "tab"); - }, false); - submenu.insertBefore(menuitem, separator); - } - } -}; - -// XXX Need to audit that this is being initialized correctly -SocialToolbar = { - // Called once, after window load, when the Social.provider object is - // initialized. - init: function SocialToolbar_init() { - this._dynamicResizer = new DynamicResizeWatcher(); - }, - - update: function() { - this._updateButtonHiddenState(); - this.updateProvider(); - this.populateProviderMenus(); - }, - - // Called when the Social.provider changes - updateProvider: function () { - let provider = Social.provider; - if (provider) { - this.button.setAttribute("label", provider.name); - this.button.setAttribute("tooltiptext", provider.name); - this.button.style.listStyleImage = "url(" + provider.iconURL + ")"; - - this.updateProfile(); - } else { - this.button.setAttribute("label", gNavigatorBundle.getString("service.toolbarbutton.label")); - this.button.setAttribute("tooltiptext", gNavigatorBundle.getString("service.toolbarbutton.tooltiptext")); - this.button.style.removeProperty("list-style-image"); - } - this.updateButton(); - }, - - get button() { - return document.getElementById("social-provider-button"); - }, - - // Note: this doesn't actually handle hiding the toolbar button, - // socialActiveBroadcaster is responsible for that. - _updateButtonHiddenState: function SocialToolbar_updateButtonHiddenState() { - let socialEnabled = SocialUI.enabled; - for (let className of ["social-statusarea-separator", "social-statusarea-user"]) { - for (let element of document.getElementsByClassName(className)) - element.hidden = !socialEnabled; - } - let toggleNotificationsCommand = document.getElementById("Social:ToggleNotifications"); - toggleNotificationsCommand.setAttribute("hidden", !socialEnabled); - - if (!Social.haveLoggedInUser() || !socialEnabled) { - let parent = document.getElementById("social-notification-panel"); - while (parent.hasChildNodes()) { - let frame = parent.firstChild; - SharedFrame.forgetGroup(frame.id); - parent.removeChild(frame); - } - - let tbi = document.getElementById("social-toolbar-item"); - if (tbi) { - // SocialMark is the last button allways - let next = SocialMark.button.previousSibling; - while (next != this.button) { - tbi.removeChild(next); - next = SocialMark.button.previousSibling; - } - } - } - }, - - updateProfile: function SocialToolbar_updateProfile() { - // Profile may not have been initialized yet, since it depends on a worker - // response. In that case we'll be called again when it's available, via - // social:profile-changed - if (!Social.provider) - return; - let profile = Social.provider.profile || {}; - let userPortrait = profile.portrait; - - let userDetailsBroadcaster = document.getElementById("socialBroadcaster_userDetails"); - let loggedInStatusValue = profile.userName || - userDetailsBroadcaster.getAttribute("notLoggedInLabel"); - - // "image" and "label" are used by Mac's native menus that do not render the menuitem's children - // elements. "src" and "value" are used by the image/label children on the other platforms. - if (userPortrait) { - userDetailsBroadcaster.setAttribute("src", userPortrait); - userDetailsBroadcaster.setAttribute("image", userPortrait); - } else { - userDetailsBroadcaster.removeAttribute("src"); - userDetailsBroadcaster.removeAttribute("image"); - } - - userDetailsBroadcaster.setAttribute("value", loggedInStatusValue); - userDetailsBroadcaster.setAttribute("label", loggedInStatusValue); - }, - - updateButton: function SocialToolbar_updateButton() { - this._updateButtonHiddenState(); - let panel = document.getElementById("social-notification-panel"); - panel.hidden = !SocialUI.enabled; - - let command = document.getElementById("Social:ToggleNotifications"); - command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled")); - - const CACHE_PREF_NAME = "social.cached.ambientNotificationIcons"; - // provider.profile == undefined means no response yet from the provider - // to tell us whether the user is logged in or not. - if (!SocialUI.enabled || - (!Social.haveLoggedInUser() && Social.provider.profile !== undefined)) { - // Either no enabled provider, or there is a provider and it has - // responded with a profile and the user isn't loggedin. The icons - // etc have already been removed by updateButtonHiddenState, so we want - // to nuke any cached icons we have and get out of here! - Services.prefs.clearUserPref(CACHE_PREF_NAME); - return; - } - let icons = Social.provider.ambientNotificationIcons; - let iconNames = Object.keys(icons); - - if (Social.provider.profile === undefined) { - // provider has not told us about the login state yet - see if we have - // a cached version for this provider. - let cached; - try { - cached = JSON.parse(Services.prefs.getComplexValue(CACHE_PREF_NAME, - Ci.nsISupportsString).data); - } catch (ex) {} - if (cached && cached.provider == Social.provider.origin && cached.data) { - icons = cached.data; - iconNames = Object.keys(icons); - // delete the counter data as it is almost certainly stale. - for each(let name in iconNames) { - icons[name].counter = ''; - } - } - } else { - // We have a logged in user - save the current set of icons back to the - // "cache" so we can use them next startup. - let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); - str.data = JSON.stringify({provider: Social.provider.origin, data: icons}); - Services.prefs.setComplexValue(CACHE_PREF_NAME, - Ci.nsISupportsString, - str); - } - - let toolbarButtons = document.createDocumentFragment(); - - let createdFrames = []; - - for each(let name in iconNames) { - let icon = icons[name]; - - let notificationFrameId = "social-status-" + icon.name; - let notificationFrame = document.getElementById(notificationFrameId); - - if (!notificationFrame) { - notificationFrame = SharedFrame.createFrame( - notificationFrameId, /* frame name */ - panel, /* parent */ - { - "type": "content", - "mozbrowser": "true", - "class": "social-panel-frame", - "id": notificationFrameId, - "tooltip": "aHTMLTooltip", - - // work around bug 793057 - by making the panel roughly the final size - // we are more likely to have the anchor in the correct position. - "style": "width: " + PANEL_MIN_WIDTH + "px;", - - "origin": Social.provider.origin, - "src": icon.contentPanel - } - ); - - createdFrames.push(notificationFrame); - } else { - notificationFrame.setAttribute("origin", Social.provider.origin); - SharedFrame.updateURL(notificationFrameId, icon.contentPanel); - } - - let toolbarButtonId = "social-notification-icon-" + icon.name; - let toolbarButton = document.getElementById(toolbarButtonId); - if (!toolbarButton) { - toolbarButton = document.createElement("toolbarbutton"); - toolbarButton.setAttribute("type", "badged"); - toolbarButton.classList.add("toolbarbutton-1"); - toolbarButton.setAttribute("id", toolbarButtonId); - toolbarButton.setAttribute("notificationFrameId", notificationFrameId); - toolbarButton.addEventListener("mousedown", function (event) { - if (event.button == 0 && panel.state == "closed") - SocialToolbar.showAmbientPopup(toolbarButton); - }); - - toolbarButtons.appendChild(toolbarButton); - } - - toolbarButton.style.listStyleImage = "url(" + icon.iconURL + ")"; - toolbarButton.setAttribute("label", icon.label); - toolbarButton.setAttribute("tooltiptext", icon.label); - - let badge = icon.counter || ""; - toolbarButton.setAttribute("badge", badge); - let ariaLabel = icon.label; - // if there is a badge value, we must use a localizable string to insert it. - if (badge) - ariaLabel = gNavigatorBundle.getFormattedString("social.aria.toolbarButtonBadgeText", - [ariaLabel, badge]); - toolbarButton.setAttribute("aria-label", ariaLabel); - } - let socialToolbarItem = document.getElementById("social-toolbar-item"); - socialToolbarItem.insertBefore(toolbarButtons, SocialMark.button); - - for (let frame of createdFrames) { - if (frame.socialErrorListener) { - frame.socialErrorListener.remove(); - } - if (frame.docShell) { - frame.docShell.isActive = false; - Social.setErrorListener(frame, this.setPanelErrorMessage.bind(this)); - } - } - }, - - showAmbientPopup: function SocialToolbar_showAmbientPopup(aToolbarButton) { - // Hide any other social panels that may be open. - SocialFlyout.panel.hidePopup(); - - let panel = document.getElementById("social-notification-panel"); - let notificationFrameId = aToolbarButton.getAttribute("notificationFrameId"); - let notificationFrame = document.getElementById(notificationFrameId); - - let wasAlive = SharedFrame.isGroupAlive(notificationFrameId); - SharedFrame.setOwner(notificationFrameId, notificationFrame); - - // Clear dimensions on all browsers so the panel size will - // only use the selected browser. - let frameIter = panel.firstElementChild; - while (frameIter) { - frameIter.collapsed = (frameIter != notificationFrame); - frameIter = frameIter.nextElementSibling; - } - - function dispatchPanelEvent(name) { - let evt = notificationFrame.contentDocument.createEvent("CustomEvent"); - evt.initCustomEvent(name, true, true, {}); - notificationFrame.contentDocument.documentElement.dispatchEvent(evt); - } - - let dynamicResizer = this._dynamicResizer; - panel.addEventListener("popuphidden", function onpopuphiding() { - panel.removeEventListener("popuphidden", onpopuphiding); - aToolbarButton.removeAttribute("open"); - aToolbarButton.parentNode.removeAttribute("open"); - dynamicResizer.stop(); - notificationFrame.docShell.isActive = false; - dispatchPanelEvent("socialFrameHide"); - }); - - panel.addEventListener("popupshown", function onpopupshown() { - panel.removeEventListener("popupshown", onpopupshown); - // This attribute is needed on both the button and the - // containing toolbaritem since the buttons on OS X have - // moz-appearance:none, while their container gets - // moz-appearance:toolbarbutton due to the way that toolbar buttons - // get combined on OS X. - aToolbarButton.setAttribute("open", "true"); - aToolbarButton.parentNode.setAttribute("open", "true"); - notificationFrame.docShell.isActive = true; - notificationFrame.docShell.isAppTab = true; - if (notificationFrame.contentDocument.readyState == "complete" && wasAlive) { - dynamicResizer.start(panel, notificationFrame); - dispatchPanelEvent("socialFrameShow"); - } else { - // first time load, wait for load and dispatch after load - notificationFrame.addEventListener("load", function panelBrowserOnload(e) { - notificationFrame.removeEventListener("load", panelBrowserOnload, true); - dynamicResizer.start(panel, notificationFrame); - setTimeout(function() { - dispatchPanelEvent("socialFrameShow"); - }, 0); - }, true); - } - }); - - let navBar = document.getElementById("nav-bar"); - let anchor = navBar.getAttribute("mode") == "text" ? - document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-text") : - document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container"); - // Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup - // handling from preventing it being opened in some cases. - setTimeout(function() { - panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false); - }, 0); - }, - - setPanelErrorMessage: function SocialToolbar_setPanelErrorMessage(aNotificationFrame) { - if (!aNotificationFrame) - return; - - let src = aNotificationFrame.getAttribute("src"); - aNotificationFrame.removeAttribute("src"); - aNotificationFrame.webNavigation.loadURI("about:socialerror?mode=tryAgainOnly&url=" + - encodeURIComponent(src), null, null, null, null); - let panel = aNotificationFrame.parentNode; - sizeSocialPanelToContent(panel, aNotificationFrame); - }, - - populateProviderMenus: function SocialToolbar_renderProviderMenus() { - let providerMenuSeps = document.getElementsByClassName("social-provider-menu"); - for (let providerMenuSep of providerMenuSeps) - this._populateProviderMenu(providerMenuSep); - }, - - _populateProviderMenu: function SocialToolbar_renderProviderMenu(providerMenuSep) { - let menu = providerMenuSep.parentNode; - // selectable providers are inserted before the provider-menu seperator, - // remove any menuitems in that area - while (providerMenuSep.previousSibling.nodeName == "menuitem") { - menu.removeChild(providerMenuSep.previousSibling); - } - // only show a selection if enabled and there is more than one - let providers = [p for (p of Social.providers) if (p.workerURL || p.sidebarURL)]; - if (providers.length < 2) { - providerMenuSep.hidden = true; - return; - } - for (let provider of providers) { - let menuitem = document.createElement("menuitem"); - menuitem.className = "menuitem-iconic social-provider-menuitem"; - menuitem.setAttribute("image", provider.iconURL); - menuitem.setAttribute("label", provider.name); - menuitem.setAttribute("origin", provider.origin); - if (provider == Social.provider) { - menuitem.setAttribute("checked", "true"); - } else { - menuitem.setAttribute("oncommand", "Social.setProviderByOrigin(this.getAttribute('origin'));"); - } - menu.insertBefore(menuitem, providerMenuSep); - } - providerMenuSep.hidden = false; - } -} - -SocialSidebar = { - // Called once, after window load, when the Social.provider object is initialized - init: function SocialSidebar_init() { - let sbrowser = document.getElementById("social-sidebar-browser"); - Social.setErrorListener(sbrowser, this.setSidebarErrorMessage.bind(this)); - // setting isAppTab causes clicks on untargeted links to open new tabs - sbrowser.docShell.isAppTab = true; - }, - - // Whether the sidebar can be shown for this window. - get canShow() { - return SocialUI.enabled && Social.provider.sidebarURL; - }, - - // Whether the user has toggled the sidebar on (for windows where it can appear) - get opened() { - return Services.prefs.getBoolPref("social.sidebar.open") && !document.mozFullScreen; - }, - - setSidebarVisibilityState: function(aEnabled) { - let sbrowser = document.getElementById("social-sidebar-browser"); - // it's possible we'll be called twice with aEnabled=false so let's - // just assume we may often be called with the same state. - if (aEnabled == sbrowser.docShellIsActive) - return; - sbrowser.docShellIsActive = aEnabled; - let evt = sbrowser.contentDocument.createEvent("CustomEvent"); - evt.initCustomEvent(aEnabled ? "socialFrameShow" : "socialFrameHide", true, true, {}); - sbrowser.contentDocument.documentElement.dispatchEvent(evt); - }, - - update: function SocialSidebar_update() { - clearTimeout(this._unloadTimeoutId); - // Hide the toggle menu item if the sidebar cannot appear - let command = document.getElementById("Social:ToggleSidebar"); - command.setAttribute("hidden", this.canShow ? "false" : "true"); - - // Hide the sidebar if it cannot appear, or has been toggled off. - // Also set the command "checked" state accordingly. - let hideSidebar = !this.canShow || !this.opened; - let broadcaster = document.getElementById("socialSidebarBroadcaster"); - broadcaster.hidden = hideSidebar; - command.setAttribute("checked", !hideSidebar); - - let sbrowser = document.getElementById("social-sidebar-browser"); - - if (hideSidebar) { - sbrowser.removeEventListener("load", SocialSidebar._loadListener, true); - this.setSidebarVisibilityState(false); - // If we've been disabled, unload the sidebar content immediately; - // if the sidebar was just toggled to invisible, wait a timeout - // before unloading. - if (!this.canShow) { - this.unloadSidebar(); - } else { - this._unloadTimeoutId = setTimeout( - this.unloadSidebar, - Services.prefs.getIntPref("social.sidebar.unload_timeout_ms") - ); - } - } else { - sbrowser.setAttribute("origin", Social.provider.origin); - if (Social.provider.errorState == "frameworker-error") { - SocialSidebar.setSidebarErrorMessage(); - return; - } - - // Make sure the right sidebar URL is loaded - if (sbrowser.getAttribute("src") != Social.provider.sidebarURL) { - sbrowser.setAttribute("src", Social.provider.sidebarURL); - PopupNotifications.locationChange(sbrowser); - } - - // if the document has not loaded, delay until it is - if (sbrowser.contentDocument.readyState != "complete") { - sbrowser.addEventListener("load", SocialSidebar._loadListener, true); - } else { - this.setSidebarVisibilityState(true); - } - } - }, - - _loadListener: function SocialSidebar_loadListener() { - let sbrowser = document.getElementById("social-sidebar-browser"); - sbrowser.removeEventListener("load", SocialSidebar._loadListener, true); - SocialSidebar.setSidebarVisibilityState(true); - }, - - unloadSidebar: function SocialSidebar_unloadSidebar() { - let sbrowser = document.getElementById("social-sidebar-browser"); - if (!sbrowser.hasAttribute("origin")) - return; - - sbrowser.stop(); - sbrowser.removeAttribute("origin"); - sbrowser.setAttribute("src", "about:blank"); - SocialFlyout.unload(); - }, - - _unloadTimeoutId: 0, - - setSidebarErrorMessage: function() { - let sbrowser = document.getElementById("social-sidebar-browser"); - // a frameworker error "trumps" a sidebar error. - if (Social.provider.errorState == "frameworker-error") { - sbrowser.setAttribute("src", "about:socialerror?mode=workerFailure"); - } else { - let url = encodeURIComponent(Social.provider.sidebarURL); - sbrowser.loadURI("about:socialerror?mode=tryAgain&url=" + url, null, null); - } - } -} - -})(); diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index d7a1c3591..a44b46195 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -668,56 +668,3 @@ html|*#gcli-output-frame, toolbarbutton[type="badged"] { -moz-binding: url("chrome://browser/content/urlbarBindings.xml#toolbarbutton-badged"); } - -/* Note the chatbox 'width' values are duplicated in socialchat.xml */ -chatbox { - -moz-binding: url("chrome://browser/content/socialchat.xml#chatbox"); - transition: height 150ms ease-out, width 150ms ease-out; - height: 285px; - width: 260px; /* CHAT_WIDTH_OPEN in socialchat.xml */ -} - -chatbox[minimized="true"] { - width: 160px; - height: 20px; /* CHAT_WIDTH_MINIMIZED in socialchat.xml */ -} - -chatbar { - -moz-binding: url("chrome://browser/content/socialchat.xml#chatbar"); - height: 0; - max-height: 0; -} - -/* full screen chat window support */ -chatbar:-moz-full-screen-ancestor, -chatbox:-moz-full-screen-ancestor { - border: none; - position: fixed !important; - top: 0 !important; - left: 0 !important; - right: 0 !important; - bottom: 0 !important; - width: 100% !important; - height: 100% !important; - margin: 0 !important; - min-width: 0 !important; - max-width: none !important; - min-height: 0 !important; - max-height: none !important; - box-sizing: border-box !important; -} - -/* hide chat chrome when chat is fullscreen */ -chatbox:-moz-full-screen-ancestor > .chat-titlebar { - display: none; -} - -/* hide chatbar if browser tab is fullscreen */ -*:-moz-full-screen-ancestor chatbar:not(:-moz-full-screen-ancestor) { - display: none; -} - -/* hide sidebar when fullscreen */ -*:-moz-full-screen-ancestor #social-sidebar-box:not(:-moz-full-screen-ancestor) { - display: none; -} diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index a832b7841..2c5dbc9d9 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -123,9 +123,6 @@ XPCOMUtils.defineLazyGetter(this, "BrowserDebuggerProcess", function() { }); #endif -XPCOMUtils.defineLazyModuleGetter(this, "Social", - "resource:///modules/Social.jsm"); - XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", "resource://gre/modules/PageThumbs.jsm"); @@ -158,7 +155,6 @@ let gInitialPages = [ #ifdef MOZ_SAFE_BROWSING #include browser-safebrowsing.js #endif -#include browser-social.js #include browser-tabPreviews.js #include browser-thumbnails.js #include browser-webrtcUI.js @@ -805,10 +801,6 @@ var gBrowserInit = { // setup our MozApplicationManifest listener gBrowser.addEventListener("MozApplicationManifest", OfflineApps, false); - // listen for offline apps on social - let socialBrowser = document.getElementById("social-sidebar-browser"); - socialBrowser.addEventListener("MozApplicationManifest", - OfflineApps, false); // setup simple gestures support gGestureSupport.init(true); @@ -1025,7 +1017,6 @@ var gBrowserInit = { OfflineApps.init(); IndexedDBPromptHelper.init(); gFormSubmitObserver.init(); - SocialUI.init(); AddonManager.addAddonListener(AddonsMgrListener); WebrtcIndicator.init(); @@ -1396,7 +1387,6 @@ var gBrowserInit = { OfflineApps.uninit(); IndexedDBPromptHelper.uninit(); AddonManager.removeAddonListener(AddonsMgrListener); - SocialUI.uninit(); } // Final window teardown, do this last. @@ -1463,8 +1453,6 @@ var gBrowserInit = { } } - SocialUI.nonBrowserWindowInit(); - if (PrivateBrowsingUtils.permanentPrivateBrowsing) { document.getElementById("macDockMenuNewWindow").hidden = true; } @@ -3474,8 +3462,6 @@ function BrowserToolboxCustomizeDone(aToolboxChanged) { URLBarSetURI(); XULBrowserWindow.asyncUpdateUI(); BookmarkingUI.updateStarState(); - SocialMark.updateMarkState(); - SocialShare.update(); } TabsInTitlebar.allowedBy("customizing-toolbars", true); @@ -3767,7 +3753,6 @@ var XULBrowserWindow = { // Called before links are navigated to to allow us to retarget them if needed. onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { let target = this._onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab); - SocialUI.closeSocialPanelForLinkTraversal(target, linkNode); return target; }, @@ -3959,8 +3944,6 @@ var XULBrowserWindow = { // Update starring UI BookmarkingUI.updateStarState(); - SocialMark.updateMarkState(); - SocialShare.update(); } // Show or hide browser chrome based on the whitelist diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 8cdbf2fe7..2fde1c9cb 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -181,65 +181,6 @@ </hbox> </panel> - <panel id="socialActivatedNotification" - type="arrow" - hidden="true" - consumeoutsideclicks="true" - align="start" - orient="horizontal" - role="alert"> - <image id="social-activation-icon" class="popup-notification-icon"/> - <vbox flex="1"> - <description id="social-activation-message" class="popup-notification-description">&social.activated.description;</description> - <spacer flex="1"/> - <hbox pack="start" align="center" class="popup-notification-button-container"> - <label id="social-undoactivation-button" - class="text-link" - value="&social.activated.undo.label;" - accesskey="&social.activated.undo.accesskey;" - onclick="SocialUI.undoActivation(this);"/> - <spacer flex="1"/> - <button id="social-activation-button" - default="true" - autofocus="autofocus" - label="&social.ok.label;" - accesskey="&social.ok.accesskey;" - oncommand="SocialUI.activationPanel.hidePopup();"/> - </hbox> - </vbox> - </panel> - - <panel id="social-share-panel" - class="social-panel" - type="arrow" - orient="horizontal" - onpopupshowing="SocialShare.onShowing()" - onpopuphidden="SocialShare.onHidden()" - consumeoutsideclicks="true" - hidden="true"> - <vbox class="social-share-toolbar"> - <vbox id="social-share-provider-buttons" flex="1"/> - </vbox> - </panel> - - <panel id="social-notification-panel" - class="social-panel" - type="arrow" - hidden="true" - noautofocus="true"/> - <panel id="social-flyout-panel" - class="social-panel" - onpopupshown="SocialFlyout.onShown()" - onpopuphidden="SocialFlyout.onHidden()" - side="right" - type="arrow" - hidden="true" - flip="slide" - rolluponmousewheel="true" - consumeoutsideclicks="false" - noautofocus="true" - position="topcenter topright"/> - <menupopup id="toolbar-context-menu" onpopupshowing="onViewToolbarsPopupShowing(event);"> <menuseparator/> @@ -664,69 +605,6 @@ </menupopup> </toolbarbutton> - <toolbarbutton id="social-share-button" - class="toolbarbutton-1 chromeclass-toolbar-additional" - hidden="true" - label="&sharePageCmd.label;" - tooltiptext="&sharePageCmd.label;" - command="Social:SharePage"/> - - <toolbaritem id="social-toolbar-item" - class="chromeclass-toolbar-additional" - removable="false" - title="&socialToolbar.title;" - hidden="true" - skipintoolbarset="true" - observes="socialActiveBroadcaster"> - <toolbarbutton id="social-notification-icon" class="default-notification-icon toolbarbutton-1 notification-anchor-icon" - oncommand="PopupNotifications._reshowNotifications(this, - document.getElementById('social-sidebar-browser'));"/> - <toolbarbutton id="social-provider-button" - class="toolbarbutton-1" - type="menu"> - <menupopup id="social-statusarea-popup"> - <menuitem class="social-statusarea-user menuitem-iconic" pack="start" align="center" - observes="socialBroadcaster_userDetails" - oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"> - <image class="social-statusarea-user-portrait" - observes="socialBroadcaster_userDetails"/> - <vbox> - <label class="social-statusarea-loggedInStatus" - observes="socialBroadcaster_userDetails"/> - </vbox> - </menuitem> -#ifndef XP_WIN - <menuseparator class="social-statusarea-separator"/> -#endif - <menuitem class="social-toggle-sidebar-menuitem" - type="checkbox" - autocheck="false" - command="Social:ToggleSidebar" - label="&social.toggleSidebar.label;" - accesskey="&social.toggleSidebar.accesskey;"/> - <menuitem class="social-toggle-notifications-menuitem" - type="checkbox" - autocheck="false" - command="Social:ToggleNotifications" - label="&social.toggleNotifications.label;" - accesskey="&social.toggleNotifications.accesskey;"/> - <menuitem class="social-toggle-menuitem" command="Social:Toggle"/> - <menuseparator/> - <menuseparator class="social-provider-menu" hidden="true"/> - <menuitem class="social-addons-menuitem" command="Social:Addons" - label="&social.addons.label;"/> - <menuitem label="&social.learnMore.label;" - accesskey="&social.learnMore.accesskey;" - oncommand="SocialUI.showLearnMore();"/> - </menupopup> - </toolbarbutton> - <toolbarbutton id="social-mark-button" - class="toolbarbutton-1" - hidden="true" - disabled="true" - command="Social:TogglePageMark"/> - </toolbaritem> - <hbox id="window-controls" hidden="true" pack="end"> <toolbarbutton id="minimize-button" tooltiptext="&fullScreenMinimize.tooltip;" @@ -993,22 +871,6 @@ <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/> <statuspanel id="statusbar-display" inactive="true"/> </vbox> - <splitter id="social-sidebar-splitter" - class="chromeclass-extrachrome sidebar-splitter" - observes="socialSidebarBroadcaster"/> - <vbox id="social-sidebar-box" - class="chromeclass-extrachrome" - observes="socialSidebarBroadcaster" - persist="width"> - <browser id="social-sidebar-browser" - type="content" - context="contentAreaContextMenu" - disableglobalhistory="true" - tooltip="aHTMLTooltip" - popupnotificationanchor="social-notification-icon" - flex="1" - style="min-width: 14em; width: 18em; max-width: 36em;"/> - </vbox> <vbox id="browser-border-end" hidden="true" layer="true"/> </hbox> diff --git a/browser/base/content/chatWindow.xul b/browser/base/content/chatWindow.xul deleted file mode 100644 index 4b240acf6..000000000 --- a/browser/base/content/chatWindow.xul +++ /dev/null @@ -1,109 +0,0 @@ -#filter substitution -<?xml version="1.0"?> - -# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -# 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 http://mozilla.org/MPL/2.0/. - -<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?> -<?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?> -<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?> -<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?> - -#include browser-doctype.inc - -<window id="chat-window" - windowtype="Social:Chat" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - title="&mainWindow.title;@PRE_RELEASE_SUFFIX@" - onload="gChatWindow.onLoad();" - onunload="gChatWindow.onUnload();" - macanimationtype="document" - fullscreenbutton="true" -# width and height are also used in socialchat.xml: chatbar dragend handler - width="400px" - height="420px" - persist="screenX screenY width height sizemode"> - - <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/> - <script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/> - <script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/> - -#include global-scripts.inc - -<script type="application/javascript"> - -var gChatWindow = { - // cargo-culted from browser.js for nonBrowserStartup, but we're slightly - // different what what we need to leave enabled - onLoad: function() { - // Disable inappropriate commands / submenus - var disabledItems = ['Browser:SavePage', - 'Browser:SendLink', 'cmd_pageSetup', 'cmd_print', 'cmd_find', 'cmd_findAgain', - 'viewToolbarsMenu', 'viewSidebarMenuMenu', - 'viewFullZoomMenu', 'pageStyleMenu', 'charsetMenu', - 'viewHistorySidebar', 'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs', - 'Browser:ToggleTabView', 'Browser:ToggleAddonBar']; - - for (let disabledItem of disabledItems) { - document.getElementById(disabledItem).setAttribute("disabled", "true"); - } - - // initialise the offline listener - BrowserOffline.init(); - }, - - onUnload: function() { - BrowserOffline.uninit(); - } -} - -// define a popupnotifications handler for this window. we don't use -// an iconbox here, and only support the browser frame for chat. -XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () { - let tmp = {}; - Cu.import("resource://gre/modules/PopupNotifications.jsm", tmp); - try { - return new tmp.PopupNotifications(document.getElementById("chatter").content, - document.getElementById("notification-popup"), - null); - } catch (ex) { - console.error(ex); - return null; - } -}); - -</script> - -#include browser-sets.inc - -#ifdef XP_MACOSX -#include browser-menubar.inc -#endif - - <popupset id="mainPopupSet"> - <tooltip id="aHTMLTooltip" page="true"/> - <menupopup id="contentAreaContextMenu" pagemenu="start" - onpopupshowing="if (event.target != this) - return true; - gContextMenu = new nsContextMenu(this, event.shiftKey); - if (gContextMenu.shouldDisplay) - document.popupNode = this.triggerNode; - return gContextMenu.shouldDisplay;" - onpopuphiding="if (event.target != this) - return; - gContextMenu.hiding(); - gContextMenu = null;"> -#include browser-context.inc - </menupopup> - -#include popup-notifications.inc - - </popupset> - - <commandset id="editMenuCommands"/> - <chatbox id="chatter" flex="1"/> -</window> diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 4debf1307..e3db24e87 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -148,15 +148,15 @@ nsContextMenu.prototype = { initNavigationItems: function CM_initNavigationItems() { var shouldShow = !(this.isContentSelected || this.onLink || this.onImage || this.onCanvas || this.onVideo || this.onAudio || - this.onTextInput || this.onSocial); + this.onTextInput); this.showItem("context-back", shouldShow); this.showItem("context-forward", shouldShow); let stopped = XULBrowserWindow.stopCommand.getAttribute("disabled") == "true"; let stopReloadItem = ""; - if (shouldShow || this.onSocial) { - stopReloadItem = (stopped || this.onSocial) ? "reload" : "stop"; + if (shouldShow) { + stopReloadItem = stopped ? "reload" : "stop"; } this.showItem("context-reload", stopReloadItem == "reload"); @@ -217,7 +217,7 @@ nsContextMenu.prototype = { this.showItem("context-viewsource", shouldShow); this.showItem("context-viewinfo", shouldShow); #ifdef MOZ_DEVTOOLS - var showInspect = !this.onSocial && gPrefService.getBoolPref("devtools.inspector.enabled"); + var showInspect = gPrefService.getBoolPref("devtools.inspector.enabled"); this.showItem("inspect-separator", showInspect); this.showItem("context-inspect", showInspect); #endif @@ -273,9 +273,9 @@ nsContextMenu.prototype = { // Use "Bookmark This Link" if on a link. this.showItem("context-bookmarkpage", !(this.isContentSelected || this.onTextInput || this.onLink || - this.onImage || this.onVideo || this.onAudio || this.onSocial)); - this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink && - !this.onSocial) || this.onPlainTextLink); + this.onImage || this.onVideo || this.onAudio)); + this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink) || + this.onPlainTextLink); this.showItem("context-searchselect", isTextSelected); this.showItem("context-keywordfield", this.onTextInput && this.onKeywordField); @@ -308,45 +308,6 @@ nsContextMenu.prototype = { this.onTextInput && top.gBidiUI); this.showItem("context-bidi-page-direction-toggle", !this.onTextInput && top.gBidiUI); - - // SocialMarks - let marksEnabled = SocialUI.enabled && Social.provider.pageMarkInfo; - let enablePageMark = marksEnabled && !(this.isContentSelected || - this.onTextInput || this.onLink || this.onImage || - this.onVideo || this.onAudio || this.onSocial); - let enableLinkMark = marksEnabled && ((this.onLink && !this.onMailtoLink && - !this.onSocial) || this.onPlainTextLink); - if (enablePageMark) { - Social.isURIMarked(gBrowser.currentURI, function(marked) { - let label = marked ? "social.unmarkpage.label" : "social.markpage.label"; - let provider = Social.provider || Social.defaultProvider; - let menuLabel = gNavigatorBundle.getFormattedString(label, [provider.name]); - this.setItemAttr("context-markpage", "label", menuLabel); - }.bind(this)); - } - this.showItem("context-markpage", enablePageMark); - if (enableLinkMark) { - Social.isURIMarked(this.linkURI, function(marked) { - let label = marked ? "social.unmarklink.label" : "social.marklink.label"; - let provider = Social.provider || Social.defaultProvider; - let menuLabel = gNavigatorBundle.getFormattedString(label, [provider.name]); - this.setItemAttr("context-marklink", "label", menuLabel); - }.bind(this)); - } - this.showItem("context-marklink", enableLinkMark); - - // SocialShare - let shareButton = SocialShare.shareButton; - let shareEnabled = shareButton && !shareButton.disabled && !this.onSocial; - let pageShare = shareEnabled && !(this.isContentSelected || - this.onTextInput || this.onLink || this.onImage || - this.onVideo || this.onAudio); - this.showItem("context-sharepage", pageShare); - this.showItem("context-shareselect", shareEnabled && this.isContentSelected); - this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink); - this.showItem("context-shareimage", shareEnabled && this.onImage); - this.showItem("context-sharevideo", shareEnabled && this.onVideo); - this.setItemAttr("context-sharevideo", "disabled", !this.mediaURL); }, initSpellingItems: function() { @@ -547,7 +508,6 @@ nsContextMenu.prototype = { .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell) .chromeEventHandler; - this.onSocial = !!this.browser.getAttribute("origin"); // Check if we are in a synthetic document (stand alone image, video, etc.). this.inSyntheticDoc = this.target.ownerDocument.mozSyntheticDocument; @@ -869,15 +829,7 @@ nsContextMenu.prototype = { }, reload: function(event) { - if (this.onSocial) { - // full reload of social provider - Social.enabled = false; - Services.tm.mainThread.dispatch(function() { - Social.enabled = true; - }, Components.interfaces.nsIThread.DISPATCH_NORMAL); - } else { - BrowserReloadOrDuplicate(event); - } + BrowserReloadOrDuplicate(event); }, // View Partial Source @@ -1559,27 +1511,6 @@ nsContextMenu.prototype = { } }, - markLink: function CM_markLink() { - // send link to social - SocialMark.toggleURIMark(this.linkURI); - }, - - shareLink: function CM_shareLink() { - SocialShare.sharePage(null, { url: this.linkURI.spec }); - }, - - shareImage: function CM_shareImage() { - SocialShare.sharePage(null, { url: this.imageURL, previews: [ this.mediaURL ] }); - }, - - shareVideo: function CM_shareVideo() { - SocialShare.sharePage(null, { url: this.mediaURL, source: this.mediaURL }); - }, - - shareSelect: function CM_shareSelect(selection) { - SocialShare.sharePage(null, { url: this.browser.currentURI.spec, text: selection }); - }, - savePageAs: function CM_savePageAs() { saveDocument(this.browser.contentDocument); }, diff --git a/browser/base/content/socialchat.xml b/browser/base/content/socialchat.xml deleted file mode 100644 index a4843eefa..000000000 --- a/browser/base/content/socialchat.xml +++ /dev/null @@ -1,747 +0,0 @@ -<?xml version="1.0"?> - -<bindings id="socialChatBindings" - xmlns="http://www.mozilla.org/xbl" - xmlns:xbl="http://www.mozilla.org/xbl" - xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - - <binding id="chatbox"> - <content orient="vertical" mousethrough="never"> - <xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected,activity" align="baseline"> - <xul:hbox flex="1" onclick="document.getBindingParent(this).onTitlebarClick(event);"> - <xul:image class="chat-status-icon" xbl:inherits="src=image"/> - <xul:label class="chat-title" flex="1" xbl:inherits="value=label" crop="center"/> - </xul:hbox> - <xul:toolbarbutton id="notification-icon" class="notification-anchor-icon chat-toolbarbutton" - oncommand="document.getBindingParent(this).showNotifications(); event.stopPropagation();"/> - <xul:toolbarbutton anonid="minimize" class="chat-minimize-button chat-toolbarbutton" - oncommand="document.getBindingParent(this).toggle();"/> - <xul:toolbarbutton anonid="swap" class="chat-swap-button chat-toolbarbutton" - oncommand="document.getBindingParent(this).swapWindows();"/> - <xul:toolbarbutton anonid="close" class="chat-close-button chat-toolbarbutton" - oncommand="document.getBindingParent(this).close();"/> - </xul:hbox> - <xul:browser anonid="content" class="chat-frame" flex="1" - context="contentAreaContextMenu" - disableglobalhistory="true" - tooltip="aHTMLTooltip" - xbl:inherits="src,origin" type="content"/> - </content> - - <implementation implements="nsIDOMEventListener"> - <constructor><![CDATA[ - let Social = Components.utils.import("resource:///modules/Social.jsm", {}).Social; - this.content.__defineGetter__("popupnotificationanchor", - () => document.getAnonymousElementByAttribute(this, "id", "notification-icon")); - Social.setErrorListener(this.content, function(aBrowser) { - aBrowser.webNavigation.loadURI("about:socialerror?mode=compactInfo", null, null, null, null); - }); - if (!this.chatbar) { - document.getAnonymousElementByAttribute(this, "anonid", "minimize").hidden = true; - document.getAnonymousElementByAttribute(this, "anonid", "close").hidden = true; - } - let contentWindow = this.contentWindow; - this.addEventListener("DOMContentLoaded", function DOMContentLoaded(event) { - if (event.target != this.contentDocument) - return; - this.removeEventListener("DOMContentLoaded", DOMContentLoaded, true); - this.isActive = !this.minimized; - // process this._callbacks, then set to null so the chatbox creator - // knows to make new callbacks immediately. - if (this._callbacks) { - for (let callback of this._callbacks) { - if (callback) - callback(contentWindow); - } - this._callbacks = null; - } - - // content can send a socialChatActivity event to have the UI update. - let chatActivity = function() { - this.setAttribute("activity", true); - if (this.chatbar) - this.chatbar.updateTitlebar(this); - }.bind(this); - contentWindow.addEventListener("socialChatActivity", chatActivity); - contentWindow.addEventListener("unload", function unload() { - contentWindow.removeEventListener("unload", unload); - contentWindow.removeEventListener("socialChatActivity", chatActivity); - }); - }, true); - if (this.src) - this.setAttribute("src", this.src); - ]]></constructor> - - <field name="content" readonly="true"> - document.getAnonymousElementByAttribute(this, "anonid", "content"); - </field> - - <property name="contentWindow"> - <getter> - return this.content.contentWindow; - </getter> - </property> - - <property name="contentDocument"> - <getter> - return this.content.contentDocument; - </getter> - </property> - - <property name="minimized"> - <getter> - return this.getAttribute("minimized") == "true"; - </getter> - <setter><![CDATA[ - // Note that this.isActive is set via our transitionend handler so - // the content doesn't see intermediate values. - let parent = this.chatbar; - if (val) { - this.setAttribute("minimized", "true"); - // If this chat is the selected one a new one needs to be selected. - if (parent && parent.selectedChat == this) - parent._selectAnotherChat(); - } else { - this.removeAttribute("minimized"); - // this chat gets selected. - if (parent) - parent.selectedChat = this; - } - ]]></setter> - </property> - - <property name="chatbar"> - <getter> - if (this.parentNode.nodeName == "chatbar") - return this.parentNode; - return null; - </getter> - </property> - - <property name="isActive"> - <getter> - return this.content.docShell.isActive; - </getter> - <setter> - this.content.docShell.isActive = !!val; - - // let the chat frame know if it is being shown or hidden - let evt = this.contentDocument.createEvent("CustomEvent"); - evt.initCustomEvent(val ? "socialFrameShow" : "socialFrameHide", true, true, {}); - this.contentDocument.documentElement.dispatchEvent(evt); - </setter> - </property> - - <method name="showNotifications"> - <body><![CDATA[ - PopupNotifications._reshowNotifications(this.content.popupnotificationanchor, - this.content); - ]]></body> - </method> - - <method name="swapDocShells"> - <parameter name="aTarget"/> - <body><![CDATA[ - aTarget.setAttribute('label', this.contentDocument.title); - aTarget.content.setAttribute("origin", this.content.getAttribute("origin")); - aTarget.content.popupnotificationanchor.className = this.content.popupnotificationanchor.className; - this.content.socialErrorListener.remove(); - aTarget.content.socialErrorListener.remove(); - this.content.swapDocShells(aTarget.content); - Social.setErrorListener(this.content, function(aBrowser) {}); // 'this' will be destroyed soon. - Social.setErrorListener(aTarget.content, function(aBrowser) { - aBrowser.webNavigation.loadURI("about:socialerror?mode=compactInfo", null, null, null, null); - }); - ]]></body> - </method> - - <method name="onTitlebarClick"> - <parameter name="aEvent"/> - <body><![CDATA[ - if (!this.chatbar) - return; - if (aEvent.button == 0) { // left-click: toggle minimized. - this.toggle(); - // if we restored it, we want to focus it. - if (!this.minimized) - this.chatbar.focus(); - } else if (aEvent.button == 1) // middle-click: close chat - this.close(); - ]]></body> - </method> - - <method name="close"> - <body><![CDATA[ - if (this.chatbar) - this.chatbar.remove(this); - else - window.close(); - ]]></body> - </method> - - <method name="swapWindows"> - <body><![CDATA[ - let provider = Social._getProviderFromOrigin(this.content.getAttribute("origin")); - if (this.chatbar) { - this.chatbar.detachChatbox(this, { "centerscreen": "yes" }, win => { - win.document.title = provider.name; - }); - } else { - // attach this chatbox to the topmost browser window - let findChromeWindowForChats = Cu.import("resource://gre/modules/MozSocialAPI.jsm").findChromeWindowForChats; - let win = findChromeWindowForChats(); - let chatbar = win.SocialChatBar.chatbar; - chatbar.openChat(provider, "about:blank", win => { - this.swapDocShells(chatbar.selectedChat); - chatbar.focus(); - this.close(); - }); - } - ]]></body> - </method> - - <method name="toggle"> - <body><![CDATA[ - this.minimized = !this.minimized; - ]]></body> - </method> - </implementation> - - <handlers> - <handler event="focus" phase="capturing"> - if (this.chatbar) - this.chatbar.selectedChat = this; - </handler> - <handler event="DOMTitleChanged"><![CDATA[ - this.setAttribute('label', this.contentDocument.title); - if (this.chatbar) - this.chatbar.updateTitlebar(this); - ]]></handler> - <handler event="DOMLinkAdded"><![CDATA[ - // much of this logic is from DOMLinkHandler in browser.js - // this sets the presence icon for a chat user, we simply use favicon style updating - let link = event.originalTarget; - let rel = link.rel && link.rel.toLowerCase(); - if (!link || !link.ownerDocument || !rel || !link.href) - return; - if (link.rel.indexOf("icon") < 0) - return; - - let uri = DOMLinkHandler.getLinkIconURI(link); - if (!uri) - return; - - // we made it this far, use it - this.setAttribute('image', uri.spec); - if (this.chatbar) - this.chatbar.updateTitlebar(this); - ]]></handler> - <handler event="transitionend"> - if (this.isActive == this.minimized) - this.isActive = !this.minimized; - </handler> - </handlers> - </binding> - - <binding id="chatbar"> - <content> - <xul:hbox align="end" pack="end" anonid="innerbox" class="chatbar-innerbox" mousethrough="always" flex="1"> - <xul:spacer flex="1" anonid="spacer" class="chatbar-overflow-spacer"/> - <xul:toolbarbutton anonid="nub" class="chatbar-button" type="menu" collapsed="true" mousethrough="never"> - <xul:menupopup anonid="nubMenu" oncommand="document.getBindingParent(this).showChat(event.target.chat)"/> - </xul:toolbarbutton> - <children/> - </xul:hbox> - </content> - - <implementation implements="nsIDOMEventListener"> - <constructor> - // to avoid reflows we cache the width of the nub. - this.cachedWidthNub = 0; - this._selectedChat = null; - </constructor> - - <field name="innerbox" readonly="true"> - document.getAnonymousElementByAttribute(this, "anonid", "innerbox"); - </field> - - <field name="menupopup" readonly="true"> - document.getAnonymousElementByAttribute(this, "anonid", "nubMenu"); - </field> - - <field name="nub" readonly="true"> - document.getAnonymousElementByAttribute(this, "anonid", "nub"); - </field> - - <method name="focus"> - <body><![CDATA[ - if (!this.selectedChat) - return; - Services.focus.focusedWindow = this.selectedChat.contentWindow; - ]]></body> - </method> - - <method name="_isChatFocused"> - <parameter name="aChatbox"/> - <body><![CDATA[ - // If there are no XBL bindings for the chat it can't be focused. - if (!aChatbox.content) - return false; - let fw = Services.focus.focusedWindow; - if (!fw) - return false; - // We want to see if the focused window is in the subtree below our browser... - let containingBrowser = fw.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler; - return containingBrowser == aChatbox.content; - ]]></body> - </method> - - <property name="selectedChat"> - <getter><![CDATA[ - return this._selectedChat; - ]]></getter> - <setter><![CDATA[ - // this is pretty horrible, but we: - // * want to avoid doing touching 'selected' attribute when the - // specified chat is already selected. - // * remove 'activity' attribute on newly selected tab *even if* - // newly selected is already selected. - // * need to handle either current or new being null. - if (this._selectedChat != val) { - if (this._selectedChat) { - this._selectedChat.removeAttribute("selected"); - } - this._selectedChat = val; - if (val) { - this._selectedChat.setAttribute("selected", "true"); - } - } - if (val) { - this._selectedChat.removeAttribute("activity"); - } - ]]></setter> - </property> - - <field name="menuitemMap">new WeakMap()</field> - <field name="chatboxForURL">new Map();</field> - - <property name="hasCollapsedChildren"> - <getter><![CDATA[ - return !!this.querySelector("[collapsed]"); - ]]></getter> - </property> - - <property name="collapsedChildren"> - <getter><![CDATA[ - // A generator yielding all collapsed chatboxes, in the order in - // which they should be restored. - let child = this.lastElementChild; - while (child) { - if (child.collapsed) - yield child; - child = child.previousElementSibling; - } - ]]></getter> - </property> - - <property name="visibleChildren"> - <getter><![CDATA[ - // A generator yielding all non-collapsed chatboxes. - let child = this.firstElementChild; - while (child) { - if (!child.collapsed) - yield child; - child = child.nextElementSibling; - } - ]]></getter> - </property> - - <property name="collapsibleChildren"> - <getter><![CDATA[ - // A generator yielding all children which are able to be collapsed - // in the order in which they should be collapsed. - // (currently this is all visible ones other than the selected one.) - for (let child of this.visibleChildren) - if (child != this.selectedChat) - yield child; - ]]></getter> - </property> - - <method name="_selectAnotherChat"> - <body><![CDATA[ - // Select a different chat (as the currently selected one is no - // longer suitable as the selection - maybe it is being minimized or - // closed.) We only select non-minimized and non-collapsed chats, - // and if none are found, set the selectedChat to null. - // It's possible in the future we will track most-recently-selected - // chats or similar to find the "best" candidate - for now though - // the choice is somewhat arbitrary. - let moveFocus = this.selectedChat && this._isChatFocused(this.selectedChat); - for (let other of this.children) { - if (other != this.selectedChat && !other.minimized && !other.collapsed) { - this.selectedChat = other; - if (moveFocus) - this.focus(); - return; - } - } - // can't find another - so set no chat as selected. - this.selectedChat = null; - ]]></body> - </method> - - <method name="updateTitlebar"> - <parameter name="aChatbox"/> - <body><![CDATA[ - if (aChatbox.collapsed) { - let menuitem = this.menuitemMap.get(aChatbox); - if (aChatbox.getAttribute("activity")) { - menuitem.setAttribute("activity", true); - this.nub.setAttribute("activity", true); - } - menuitem.setAttribute("label", aChatbox.getAttribute("label")); - menuitem.setAttribute("image", aChatbox.getAttribute("image")); - } - ]]></body> - </method> - - <method name="calcTotalWidthOf"> - <parameter name="aElement"/> - <body><![CDATA[ - let cs = document.defaultView.getComputedStyle(aElement); - let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight); - return aElement.getBoundingClientRect().width + margins; - ]]></body> - </method> - - <method name="getTotalChildWidth"> - <parameter name="aChatbox"/> - <body><![CDATA[ - // These are from the CSS for the chatbox and must be kept in sync. - // We can't use calcTotalWidthOf due to the transitions... - const CHAT_WIDTH_OPEN = 260; - const CHAT_WIDTH_MINIMIZED = 160; - return aChatbox.minimized ? CHAT_WIDTH_MINIMIZED : CHAT_WIDTH_OPEN; - ]]></body> - </method> - - <method name="collapseChat"> - <parameter name="aChatbox"/> - <body><![CDATA[ - // we ensure that the cached width for a child of this type is - // up-to-date so we can use it when resizing. - this.getTotalChildWidth(aChatbox); - aChatbox.collapsed = true; - aChatbox.isActive = false; - let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem"); - menu.setAttribute("class", "menuitem-iconic"); - menu.setAttribute("label", aChatbox.contentDocument.title); - menu.setAttribute("image", aChatbox.getAttribute("image")); - menu.chat = aChatbox; - this.menuitemMap.set(aChatbox, menu); - this.menupopup.appendChild(menu); - this.nub.collapsed = false; - ]]></body> - </method> - - <method name="showChat"> - <parameter name="aChatbox"/> - <parameter name="aMode"/> - <body><![CDATA[ - if ((aMode != "minimized") && aChatbox.minimized) - aChatbox.minimized = false; - if (this.selectedChat != aChatbox) - this.selectedChat = aChatbox; - if (!aChatbox.collapsed) - return; // already showing - no more to do. - this._showChat(aChatbox); - // showing a collapsed chat might mean another needs to be collapsed - // to make room... - this.resize(); - ]]></body> - </method> - - <method name="_showChat"> - <parameter name="aChatbox"/> - <body><![CDATA[ - // the actual implementation - doesn't check for overflow, assumes - // collapsed, etc. - let menuitem = this.menuitemMap.get(aChatbox); - this.menuitemMap.delete(aChatbox); - this.menupopup.removeChild(menuitem); - aChatbox.collapsed = false; - aChatbox.isActive = !aChatbox.minimized; - ]]></body> - </method> - - <method name="remove"> - <parameter name="aChatbox"/> - <body><![CDATA[ - this._remove(aChatbox); - // The removal of a chat may mean a collapsed one can spring up, - // or that the popup should be hidden. We also defer the selection - // of another chat until after a resize, as a new candidate may - // become uncollapsed after the resize. - this.resize(); - if (this.selectedChat == aChatbox) { - this._selectAnotherChat(); - } - ]]></body> - </method> - - <method name="_remove"> - <parameter name="aChatbox"/> - <body><![CDATA[ - aChatbox.content.socialErrorListener.remove(); - this.removeChild(aChatbox); - // child might have been collapsed. - let menuitem = this.menuitemMap.get(aChatbox); - if (menuitem) { - this.menuitemMap.delete(aChatbox); - this.menupopup.removeChild(menuitem); - } - this.chatboxForURL.delete(aChatbox.getAttribute('src')); - ]]></body> - </method> - - <method name="removeAll"> - <body><![CDATA[ - this.selectedChat = null; - while (this.firstElementChild) { - this._remove(this.firstElementChild); - } - // and the nub/popup must also die. - this.nub.collapsed = true; - ]]></body> - </method> - - <method name="openChat"> - <parameter name="aProvider"/> - <parameter name="aURL"/> - <parameter name="aCallback"/> - <parameter name="aMode"/> - <body><![CDATA[ - let cb = this.chatboxForURL.get(aURL); - if (cb) { - cb = cb.get(); - if (cb.parentNode) { - this.showChat(cb, aMode); - if (aCallback) { - if (cb._callbacks == null) { - // DOMContentLoaded has already fired, so callback now. - aCallback(cb.contentWindow); - } else { - // DOMContentLoaded for this chat is yet to fire... - cb._callbacks.push(aCallback); - } - } - return; - } - this.chatboxForURL.delete(aURL); - } - cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox"); - // _callbacks is a javascript property instead of a <field> as it - // must exist before the (possibly delayed) bindings are created. - cb._callbacks = [aCallback]; - // src also a javascript property; the src attribute is set in the ctor. - cb.src = aURL; - if (aMode == "minimized") - cb.setAttribute("minimized", "true"); - cb.setAttribute("origin", aProvider.origin); - this.insertBefore(cb, this.firstChild); - this.selectedChat = cb; - this.chatboxForURL.set(aURL, Cu.getWeakReference(cb)); - this.resize(); - ]]></body> - </method> - - <method name="resize"> - <body><![CDATA[ - // Checks the current size against the collapsed state of children - // and collapses or expands as necessary such that as many as possible - // are shown. - // So 2 basic strategies: - // * Collapse/Expand one at a time until we can't collapse/expand any - // more - but this is one reflow per change. - // * Calculate the dimensions ourself and choose how many to collapse - // or expand based on this, then do them all in one go. This is one - // reflow regardless of how many we change. - // So we go the more complicated but more efficient second option... - let availWidth = this.getBoundingClientRect().width; - let currentWidth = 0; - if (!this.nub.collapsed) { // the nub is visible. - if (!this.cachedWidthNub) - this.cachedWidthNub = this.calcTotalWidthOf(this.nub); - currentWidth += this.cachedWidthNub; - } - for (let child of this.visibleChildren) { - currentWidth += this.getTotalChildWidth(child); - } - - if (currentWidth > availWidth) { - // we need to collapse some. - let toCollapse = []; - for (let child of this.collapsibleChildren) { - if (currentWidth <= availWidth) - break; - toCollapse.push(child); - currentWidth -= this.getTotalChildWidth(child); - } - if (toCollapse.length) { - for (let child of toCollapse) - this.collapseChat(child); - } - } else if (currentWidth < availWidth) { - // we *might* be able to expand some - see how many. - // XXX - if this was clever, it could know when removing the nub - // leaves enough space to show all collapsed - let toShow = []; - for (let child of this.collapsedChildren) { - currentWidth += this.getTotalChildWidth(child); - if (currentWidth > availWidth) - break; - toShow.push(child); - } - for (let child of toShow) - this._showChat(child); - - // If none remain collapsed remove the nub. - if (!this.hasCollapsedChildren) { - this.nub.collapsed = true; - } - } - // else: achievement unlocked - we are pixel-perfect! - ]]></body> - </method> - - <method name="handleEvent"> - <parameter name="aEvent"/> - <body><![CDATA[ - if (aEvent.type == "resize" && aEvent.eventPhase == aEvent.BUBBLING_PHASE) { - this.resize(); - } - ]]></body> - </method> - - <method name="_getDragTarget"> - <parameter name="event"/> - <body><![CDATA[ - return event.target.localName == "chatbox" ? event.target : null; - ]]></body> - </method> - - <!-- Moves a chatbox to a new window. --> - <method name="detachChatbox"> - <parameter name="aChatbox"/> - <parameter name="aOptions"/> - <parameter name="aCallback"/> - <body><![CDATA[ - let options = ""; - for (let name in aOptions) - options += "," + name + "=" + aOptions[name]; - - let otherWin = window.openDialog("chrome://browser/content/chatWindow.xul", null, "chrome,all" + options); - - otherWin.addEventListener("load", function _chatLoad(event) { - if (event.target != otherWin.document) - return; - - otherWin.removeEventListener("load", _chatLoad, true); - let otherChatbox = otherWin.document.getElementById("chatter"); - aChatbox.swapDocShells(otherChatbox); - aChatbox.close(); - if (aCallback) - aCallback(otherWin); - }, true); - ]]></body> - </method> - - </implementation> - - <handlers> - <handler event="popupshown"><![CDATA[ - this.nub.removeAttribute("activity"); - ]]></handler> - <handler event="load"><![CDATA[ - window.addEventListener("resize", this); - ]]></handler> - <handler event="unload"><![CDATA[ - window.removeEventListener("resize", this); - ]]></handler> - - <handler event="dragstart"><![CDATA[ - // chat window dragging is essentially duplicated from tabbrowser.xml - // to acheive the same visual experience - let chatbox = this._getDragTarget(event); - if (!chatbox) { - return; - } - - let dt = event.dataTransfer; - // we do not set a url in the drag data to prevent moving to tabbrowser - // or otherwise having unexpected drop handlers do something with our - // chatbox - dt.mozSetDataAt("application/x-moz-chatbox", chatbox, 0); - - // Set the cursor to an arrow during tab drags. - dt.mozCursor = "default"; - - // Create a canvas to which we capture the current tab. - // Until canvas is HiDPI-aware (bug 780362), we need to scale the desired - // canvas size (in CSS pixels) to the window's backing resolution in order - // to get a full-resolution drag image for use on HiDPI displays. - let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils); - let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom; - let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); - canvas.mozOpaque = true; - canvas.width = 160 * scale; - canvas.height = 90 * scale; - PageThumbs.captureToCanvas(chatbox.contentWindow, canvas); - dt.setDragImage(canvas, -16 * scale, -16 * scale); - - event.stopPropagation(); - ]]></handler> - - <handler event="dragend"><![CDATA[ - let dt = event.dataTransfer; - let draggedChat = dt.mozGetDataAt("application/x-moz-chatbox", 0); - if (dt.mozUserCancelled || dt.dropEffect != "none") { - return; - } - - let eX = event.screenX; - let eY = event.screenY; - // screen.availLeft et. al. only check the screen that this window is on, - // but we want to look at the screen the tab is being dropped onto. - let sX = {}, sY = {}, sWidth = {}, sHeight = {}; - Cc["@mozilla.org/gfx/screenmanager;1"] - .getService(Ci.nsIScreenManager) - .screenForRect(eX, eY, 1, 1) - .GetAvailRect(sX, sY, sWidth, sHeight); - // default size for the chat window as used in chatWindow.xul, use them - // here to attempt to keep the window fully within the screen when - // opening at the drop point. If the user has resized the window to - // something larger (which gets persisted), at least a good portion of - // the window should still be within the screen. - let winWidth = 400; - let winHeight = 420; - // ensure new window entirely within screen - let left = Math.min(Math.max(eX, sX.value), - sX.value + sWidth.value - winWidth); - let top = Math.min(Math.max(eY, sY.value), - sY.value + sHeight.value - winHeight); - - let provider = Social._getProviderFromOrigin(draggedChat.content.getAttribute("origin")); - this.detachChatbox(draggedChat, { screenX: left, screenY: top }, win => { - win.document.title = provider.name; - }); - - event.stopPropagation(); - ]]></handler> - </handlers> - </binding> - -</bindings> |