diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 210f7a334c8e..15e14ab5da69 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -1024,7 +1024,7 @@ pref("apz.fling_curve_function_y1", "0.0"); pref("apz.fling_curve_function_x2", "0.80"); pref("apz.fling_curve_function_y2", "1.0"); pref("apz.fling_curve_threshold_inches_per_ms", "0.01"); -pref("apz.fling_friction", "0.00238"); +pref("apz.fling_friction", "0.0019"); pref("apz.max_velocity_inches_per_ms", "0.07"); // Tweak default displayport values to reduce the risk of running out of @@ -1039,9 +1039,9 @@ pref("apz.axis_lock.mode", 2); // Overscroll-related settings pref("apz.overscroll.enabled", true); -pref("apz.overscroll.stretch_factor", "0.15"); -pref("apz.overscroll.spring_stiffness", "0.002"); -pref("apz.overscroll.spring_friction", "0.02"); +pref("apz.overscroll.stretch_factor", "0.35"); +pref("apz.overscroll.spring_stiffness", "0.0018"); +pref("apz.overscroll.spring_friction", "0.015"); pref("apz.overscroll.stop_distance_threshold", "5.0"); pref("apz.overscroll.stop_velocity_threshold", "0.01"); diff --git a/b2g/chrome/content/devtools/debugger.js b/b2g/chrome/content/devtools/debugger.js index 45c56db88065..35911a20bc81 100644 --- a/b2g/chrome/content/devtools/debugger.js +++ b/b2g/chrome/content/devtools/debugger.js @@ -178,6 +178,11 @@ let RemoteDebugger = { let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps"); DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges); + // Allow debugging of chrome for any process + if (!restrictPrivileges) { + DebuggerServer.allowChromeProcess = true; + } + /** * Construct a root actor appropriate for use in a server running in B2G. * The returned root actor respects the factories registered with diff --git a/browser/base/content/browser-readinglist.js b/browser/base/content/browser-readinglist.js index 9e534837120a..3c5767474911 100644 --- a/browser/base/content/browser-readinglist.js +++ b/browser/base/content/browser-readinglist.js @@ -89,7 +89,7 @@ let ReadingListUI = { } }, - onReadingListPopupShowing(target) { + onReadingListPopupShowing: Task.async(function* (target) { if (target.id == "BMB_readingListPopup") { // Setting this class in the .xul file messes with the way // browser-places.js inserts bookmarks in the menu. @@ -105,55 +105,56 @@ let ReadingListUI = { if (insertPoint.classList.contains("subviewbutton")) classList += " subviewbutton"; - ReadingList.getItems().then(items => { - for (let item of items) { - let menuitem = document.createElement("menuitem"); - menuitem.setAttribute("label", item.title || item.url.spec); - menuitem.setAttribute("class", classList); + let hasItems = false; + yield ReadingList.forEachItem(item => { + hasItems = true; - let node = menuitem._placesNode = { - // Passing the PlacesUtils.nodeIsURI check is required for the - // onCommand handler to load our URI. - type: Ci.nsINavHistoryResultNode.RESULT_TYPE_URI, + let menuitem = document.createElement("menuitem"); + menuitem.setAttribute("label", item.title || item.url); + menuitem.setAttribute("class", classList); - // makes PlacesUIUtils.canUserRemove return false. - // The context menu is broken without this. - parent: {type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER}, + let node = menuitem._placesNode = { + // Passing the PlacesUtils.nodeIsURI check is required for the + // onCommand handler to load our URI. + type: Ci.nsINavHistoryResultNode.RESULT_TYPE_URI, - // A -1 id makes this item a non-bookmark, which avoids calling - // PlacesUtils.annotations.itemHasAnnotation to check if the - // bookmark should be opened in the sidebar (this call fails for - // readinglist item, and breaks loading our URI). - itemId: -1, + // makes PlacesUIUtils.canUserRemove return false. + // The context menu is broken without this. + parent: {type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER}, - // Used by the tooltip and onCommand handlers. - uri: item.url.spec, + // A -1 id makes this item a non-bookmark, which avoids calling + // PlacesUtils.annotations.itemHasAnnotation to check if the + // bookmark should be opened in the sidebar (this call fails for + // readinglist item, and breaks loading our URI). + itemId: -1, - // Used by the tooltip. - title: item.title - }; + // Used by the tooltip and onCommand handlers. + uri: item.url, - Favicons.getFaviconURLForPage(item.url, uri => { - if (uri) { - menuitem.setAttribute("image", - Favicons.getFaviconLinkForIcon(uri).spec); - } - }); + // Used by the tooltip. + title: item.title + }; - target.insertBefore(menuitem, insertPoint); - } + Favicons.getFaviconURLForPage(item.uri, uri => { + if (uri) { + menuitem.setAttribute("image", + Favicons.getFaviconLinkForIcon(uri).spec); + } + }); - if (!items.length) { - let menuitem = document.createElement("menuitem"); - let bundle = - Services.strings.createBundle("chrome://browser/locale/places/places.properties"); - menuitem.setAttribute("label", bundle.GetStringFromName("bookmarksMenuEmptyFolder")); - menuitem.setAttribute("class", "bookmark-item"); - menuitem.setAttribute("disabled", true); - target.insertBefore(menuitem, insertPoint); - } + target.insertBefore(menuitem, insertPoint); }); - }, + + if (!hasItems) { + let menuitem = document.createElement("menuitem"); + let bundle = + Services.strings.createBundle("chrome://browser/locale/places/places.properties"); + menuitem.setAttribute("label", bundle.GetStringFromName("bookmarksMenuEmptyFolder")); + menuitem.setAttribute("class", "bookmark-item"); + menuitem.setAttribute("disabled", true); + target.insertBefore(menuitem, insertPoint); + } + }), /** * Hide the ReadingList sidebar, if it is currently shown. diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js index eaba45b1df6b..8c4a82e9aad2 100644 --- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -637,8 +637,8 @@ SocialShare = { // containing the open graph data. let _dataFn; if (!pageData || sharedURI == gBrowser.currentURI) { - messageManager.addMessageListener("Social:PageDataResult", _dataFn = (msg) => { - messageManager.removeMessageListener("Social:PageDataResult", _dataFn); + messageManager.addMessageListener("PageMetadata:PageDataResult", _dataFn = (msg) => { + messageManager.removeMessageListener("PageMetadata:PageDataResult", _dataFn); let pageData = msg.json; if (graphData) { // overwrite data retreived from page with data given to us as a param @@ -648,17 +648,17 @@ SocialShare = { } this.sharePage(providerOrigin, pageData, target); }); - gBrowser.selectedBrowser.messageManager.sendAsyncMessage("Social:GetPageData"); + gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData"); return; } // if this is a share of a selected item, get any microdata if (!pageData.microdata && target) { - messageManager.addMessageListener("Social:PageDataResult", _dataFn = (msg) => { - messageManager.removeMessageListener("Social:PageDataResult", _dataFn); + messageManager.addMessageListener("PageMetadata:MicrodataResult", _dataFn = (msg) => { + messageManager.removeMessageListener("PageMetadata:MicrodataResult", _dataFn); pageData.microdata = msg.data; this.sharePage(providerOrigin, pageData, target); }); - gBrowser.selectedBrowser.messageManager.sendAsyncMessage("Social:GetMicrodata", null, target); + gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicrodata", null, target); return; } this.currentShare = pageData; diff --git a/browser/base/content/content.js b/browser/base/content/content.js index 7b65624d0aad..8c055d0055b1 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -32,6 +32,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AboutReader", "resource://gre/modules/AboutReader.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata", + "resource://gre/modules/PageMetadata.jsm"); XPCOMUtils.defineLazyGetter(this, "SimpleServiceDiscovery", function() { let ssdp = Cu.import("resource://gre/modules/SimpleServiceDiscovery.jsm", {}).SimpleServiceDiscovery; // Register targets @@ -153,6 +155,12 @@ let handleContentContextMenu = function (event) { subject.wrappedJSObject = subject; Services.obs.notifyObservers(subject, "content-contextmenu", null); + let doc = event.target.ownerDocument; + let docLocation = doc.location.href; + let charSet = doc.characterSet; + let baseURI = doc.baseURI; + let referrer = doc.referrer; + if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) { let editFlags = SpellCheckHelper.isEditable(event.target, content); let spellInfo; @@ -163,9 +171,10 @@ let handleContentContextMenu = function (event) { } let customMenuItems = PageMenuChild.build(event.target); - let principal = event.target.ownerDocument.nodePrincipal; + let principal = doc.nodePrincipal; sendSyncMessage("contextmenu", - { editFlags, spellInfo, customMenuItems, addonInfo, principal }, + { editFlags, spellInfo, customMenuItems, addonInfo, + principal, docLocation, charSet, baseURI, referrer }, { event, popupNode: event.target }); } else { @@ -178,6 +187,10 @@ let handleContentContextMenu = function (event) { popupNode: event.target, browser: browser, addonInfo: addonInfo, + documentURIObject: doc.documentURIObject, + docLocation: docLocation, + charSet: charSet, + referrer: referrer, }; } } @@ -1000,30 +1013,29 @@ addEventListener("pageshow", function(event) { } }); -let SocialMessenger = { +let PageMetadataMessenger = { init: function() { - addMessageListener("Social:GetPageData", this); - addMessageListener("Social:GetMicrodata", this); - - XPCOMUtils.defineLazyGetter(this, "og", function() { - let tmp = {}; - Cu.import("resource:///modules/Social.jsm", tmp); - return tmp.OpenGraphBuilder; - }); + addMessageListener("PageMetadata:GetPageData", this); + addMessageListener("PageMetadata:GetMicrodata", this); }, receiveMessage: function(aMessage) { switch(aMessage.name) { - case "Social:GetPageData": - sendAsyncMessage("Social:PageDataResult", this.og.getData(content.document)); + case "PageMetadata:GetPageData": { + let result = PageMetadata.getData(content.document); + sendAsyncMessage("PageMetadata:PageDataResult", result); break; - case "Social:GetMicrodata": + } + + case "PageMetadata:GetMicrodata": { let target = aMessage.objects; - sendAsyncMessage("Social:PageDataResult", this.og.getMicrodata(content.document, target)); + let result = PageMetadata.getMicrodata(content.document, target); + sendAsyncMessage("PageMetadata:MicrodataResult", result); break; + } } } } -SocialMessenger.init(); +PageMetadataMessenger.init(); addEventListener("ActivateSocialFeature", function (aEvent) { let document = content.document; diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 7d58b73ff73b..2b5bbba3cd6e 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -576,6 +576,7 @@ nsContextMenu.prototype = { this.linkURL = ""; this.linkURI = null; this.linkProtocol = ""; + this.linkHasNoReferrer = false; this.onMathML = false; this.inFrame = false; this.inSrcdocFrame = false; @@ -738,6 +739,7 @@ nsContextMenu.prototype = { this.linkProtocol = this.getLinkProtocol(); this.onMailtoLink = (this.linkProtocol == "mailto"); this.onSaveableLink = this.isLinkSaveable( this.link ); + this.linkHasNoReferrer = BrowserUtils.linkHasNoReferrer(elem); } // Background image? Don't bother if we've already found a @@ -864,10 +866,10 @@ nsContextMenu.prototype = { return aNode.spellcheck; }, - _openLinkInParameters : function (doc, extra) { - let params = { charset: doc.characterSet, - referrerURI: doc.documentURIObject, - noReferrer: BrowserUtils.linkHasNoReferrer(this.link) }; + _openLinkInParameters : function (extra) { + let params = { charset: gContextMenuContentData.charSet, + referrerURI: gContextMenuContentData.documentURIObject, + noReferrer: this.linkHasNoReferrer }; for (let p in extra) params[p] = extra[p]; return params; @@ -875,41 +877,38 @@ nsContextMenu.prototype = { // Open linked-to URL in a new window. openLink : function () { - var doc = this.target.ownerDocument; urlSecurityCheck(this.linkURL, this.principal); - openLinkIn(this.linkURL, "window", this._openLinkInParameters(doc)); + openLinkIn(this.linkURL, "window", this._openLinkInParameters()); }, // Open linked-to URL in a new private window. openLinkInPrivateWindow : function () { - var doc = this.target.ownerDocument; urlSecurityCheck(this.linkURL, this.principal); openLinkIn(this.linkURL, "window", - this._openLinkInParameters(doc, { private: true })); + this._openLinkInParameters({ private: true })); }, // Open linked-to URL in a new tab. openLinkInTab: function() { - var doc = this.target.ownerDocument; urlSecurityCheck(this.linkURL, this.principal); - var referrerURI = doc.documentURIObject; + let referrerURI = gContextMenuContentData.documentURIObject; // if the mixedContentChannel is present and the referring URI passes // a same origin check with the target URI, we can preserve the users // decision of disabling MCB on a page for it's child tabs. - var persistAllowMixedContentInChildTab = false; + let persistAllowMixedContentInChildTab = false; if (this.browser.docShell && this.browser.docShell.mixedContentChannel) { const sm = Services.scriptSecurityManager; try { - var targetURI = this.linkURI; + let targetURI = this.linkURI; sm.checkSameOriginURI(referrerURI, targetURI, false); persistAllowMixedContentInChildTab = true; } catch (e) { } } - let params = this._openLinkInParameters(doc, { + let params = this._openLinkInParameters({ allowMixedContent: persistAllowMixedContentInChildTab, }); openLinkIn(this.linkURL, "tab", params); @@ -917,18 +916,15 @@ nsContextMenu.prototype = { // open URL in current tab openLinkInCurrent: function() { - var doc = this.target.ownerDocument; urlSecurityCheck(this.linkURL, this.principal); - openLinkIn(this.linkURL, "current", this._openLinkInParameters(doc)); + openLinkIn(this.linkURL, "current", this._openLinkInParameters()); }, // Open frame in a new tab. openFrameInTab: function() { - var doc = this.target.ownerDocument; - var frameURL = doc.location.href; - var referrer = doc.referrer; - openLinkIn(frameURL, "tab", - { charset: doc.characterSet, + let referrer = gContextMenuContentData.referrer; + openLinkIn(gContextMenuContentData.docLocation, "tab", + { charset: gContextMenuContentData.charSet, referrerURI: referrer ? makeURI(referrer) : null }); }, @@ -939,25 +935,21 @@ nsContextMenu.prototype = { // Open clicked-in frame in its own window. openFrame: function() { - var doc = this.target.ownerDocument; - var frameURL = doc.location.href; - var referrer = doc.referrer; - openLinkIn(frameURL, "window", - { charset: doc.characterSet, + let referrer = gContextMenuContentData.referrer; + openLinkIn(gContextMenuContentData.docLocation, "window", + { charset: gContextMenuContentData.charSet, referrerURI: referrer ? makeURI(referrer) : null }); }, // Open clicked-in frame in the same window. showOnlyThisFrame: function() { - var doc = this.target.ownerDocument; - var frameURL = doc.location.href; - - urlSecurityCheck(frameURL, + urlSecurityCheck(gContextMenuContentData.docLocation, this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); - var referrer = doc.referrer; - openUILinkIn(frameURL, "current", { disallowInheritPrincipal: true, - referrerURI: referrer ? makeURI(referrer) : null }); + let referrer = gContextMenuContentData.referrer; + openUILinkIn(gContextMenuContentData.docLocation, "current", + { disallowInheritPrincipal: true, + referrerURI: referrer ? makeURI(referrer) : null }); }, reload: function(event) { diff --git a/browser/base/content/socialmarks.xml b/browser/base/content/socialmarks.xml index 3498efd7cd43..fa6de9dcde1b 100644 --- a/browser/base/content/socialmarks.xml +++ b/browser/base/content/socialmarks.xml @@ -150,21 +150,21 @@ let URLTemplate = provider.markURL; let _dataFn; if (!pageData) { - messageManager.addMessageListener("Social:PageDataResult", _dataFn = (msg) => { - messageManager.removeMessageListener("Social:PageDataResult", _dataFn); + messageManager.addMessageListener("PageMetadata:PageDataResult", _dataFn = (msg) => { + messageManager.removeMessageListener("PageMetadata:PageDataResult", _dataFn); this.loadPanel(msg.json, target); }); - gBrowser.selectedBrowser.messageManager.sendAsyncMessage("Social:GetPageData"); + gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData"); return; } // if this is a share of a selected item, get any microdata if (!pageData.microdata && target) { - messageManager.addMessageListener("Social:PageDataResult", _dataFn = (msg) => { - messageManager.removeMessageListener("Social:PageDataResult", _dataFn); + messageManager.addMessageListener("PageMetadata:MicrodataResult", _dataFn = (msg) => { + messageManager.removeMessageListener("PageMetadata:MicrodataResult", _dataFn); pageData.microdata = msg.data; this.loadPanel(pageData, target); }); - gBrowser.selectedBrowser.messageManager.sendAsyncMessage("Social:GetMicrodata", null, target); + gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicrodata", null, target); return; } this.pageData = pageData; diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 0db907fcdf73..dddc2164f789 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3218,6 +3218,9 @@ let spellInfo = aMessage.data.spellInfo; if (spellInfo) spellInfo.target = aMessage.target.messageManager; + let documentURIObject = makeURI(aMessage.data.docLocation, + aMessage.data.charSet, + makeURI(aMessage.data.baseURI)); gContextMenuContentData = { isRemote: true, event: aMessage.objects.event, popupNode: aMessage.objects.popupNode, @@ -3226,7 +3229,11 @@ spellInfo: spellInfo, principal: aMessage.data.principal, customMenuItems: aMessage.data.customMenuItems, - addonInfo: aMessage.data.addonInfo }; + addonInfo: aMessage.data.addonInfo, + documentURIObject: documentURIObject, + docLocation: aMessage.data.docLocation, + charSet: aMessage.data.charSet, + referrer: aMessage.data.referrer }; let popup = browser.ownerDocument.getElementById("contentAreaContextMenu"); let event = gContextMenuContentData.event; let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY); diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index da8d1d35ea15..209c444bb229 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -12,6 +12,7 @@ support-files = browser_bug678392-2.html browser_bug970746.xhtml browser_fxa_oauth.html + browser_fxa_profile_channel.html browser_registerProtocolHandler_notification.html browser_ssl_error_reports_content.js browser_star_hsts.sjs @@ -319,6 +320,7 @@ skip-if = e10s skip-if = buildapp == 'mulet' || e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575. [browser_fxa_migrate.js] [browser_fxa_oauth.js] +[browser_fxa_profile_channel.js] [browser_gestureSupport.js] skip-if = e10s # Bug 863514 - no gesture support. [browser_getshortcutoruri.js] diff --git a/browser/base/content/test/general/browser_bug734076.js b/browser/base/content/test/general/browser_bug734076.js index 3e1cae71693a..b58db66e08d6 100644 --- a/browser/base/content/test/general/browser_bug734076.js +++ b/browser/base/content/test/general/browser_bug734076.js @@ -26,8 +26,7 @@ function test() { cb(); }); - let contextMenu = initContextMenu(contentBody); - contextMenu.viewBGImage(); + doContextCommand(contentBody, "context-viewbgimage"); } }, { @@ -45,8 +44,7 @@ function test() { img.setAttribute("src", writeDomainURL); doc.body.appendChild(img); - let contextMenu = initContextMenu(img); - contextMenu.viewMedia(); + doContextCommand(img, "context-viewimage"); } }, { @@ -65,8 +63,8 @@ function test() { doc.body.appendChild(iframe); iframe.addEventListener("load", function onload() { - let contextMenu = initContextMenu(iframe.contentDocument.body); - contextMenu.showOnlyThisFrame(); + doContextCommand(iframe.contentDocument.body, + "context-showonlythisframe"); }, false); } } @@ -99,9 +97,8 @@ function test() { doNext(); } -function initContextMenu(aNode) { - document.popupNode = aNode; - let contentAreaContextMenu = document.getElementById("contentAreaContextMenu"); - let contextMenu = new nsContextMenu(contentAreaContextMenu); - return contextMenu; +function doContextCommand(aNode, aCmd) { + EventUtils.sendMouseEvent({ type: "contextmenu" }, aNode); + document.getElementById(aCmd).click(); + document.getElementById("contentAreaContextMenu").hidePopup(); } diff --git a/browser/base/content/test/general/browser_fxa_profile_channel.html b/browser/base/content/test/general/browser_fxa_profile_channel.html new file mode 100644 index 000000000000..2382eaad5e69 --- /dev/null +++ b/browser/base/content/test/general/browser_fxa_profile_channel.html @@ -0,0 +1,26 @@ + + + + + fxa_profile_channel_test + + + + + diff --git a/browser/base/content/test/general/browser_fxa_profile_channel.js b/browser/base/content/test/general/browser_fxa_profile_channel.js new file mode 100644 index 000000000000..0e974b074d52 --- /dev/null +++ b/browser/base/content/test/general/browser_fxa_profile_channel.js @@ -0,0 +1,90 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Cu.import("resource://gre/modules/Promise.jsm"); +Cu.import("resource://gre/modules/Task.jsm"); + +XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () { + return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {}); +}); + +XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsProfileChannel", + "resource://gre/modules/FxAccountsProfileChannel.jsm"); + +const HTTP_PATH = "http://example.com"; + +let gTests = [ + { + desc: "FxA Profile Channel - should receive message about account updates", + run: function* () { + return new Promise(function(resolve, reject) { + let tabOpened = false; + let properUrl = "http://example.com/browser/browser/base/content/test/general/browser_fxa_profile_channel.html"; + + waitForTab(function (tab) { + Assert.ok("Tab successfully opened"); + let match = gBrowser.currentURI.spec == properUrl; + Assert.ok(match); + + tabOpened = true; + }); + + let client = new FxAccountsProfileChannel({ + content_uri: HTTP_PATH, + }); + + makeObserver(FxAccountsCommon.ONPROFILE_IMAGE_CHANGE_NOTIFICATION, function (subject, topic, data) { + Assert.ok(tabOpened); + Assert.equal(data, "abc123"); + resolve(); + gBrowser.removeCurrentTab(); + }); + + gBrowser.selectedTab = gBrowser.addTab(properUrl); + }); + } + } +]; // gTests + +function makeObserver(aObserveTopic, aObserveFunc) { + let callback = function (aSubject, aTopic, aData) { + if (aTopic == aObserveTopic) { + removeMe(); + aObserveFunc(aSubject, aTopic, aData); + } + }; + + function removeMe() { + Services.obs.removeObserver(callback, aObserveTopic); + } + + Services.obs.addObserver(callback, aObserveTopic, false); + return removeMe; +} + +function waitForTab(aCallback) { + let container = gBrowser.tabContainer; + container.addEventListener("TabOpen", function tabOpener(event) { + container.removeEventListener("TabOpen", tabOpener, false); + gBrowser.addEventListener("load", function listener() { + gBrowser.removeEventListener("load", listener, true); + let tab = event.target; + aCallback(tab); + }, true); + }, false); +} + +function test() { + waitForExplicitFinish(); + + Task.spawn(function () { + for (let test of gTests) { + info("Running: " + test.desc); + yield test.run(); + } + }).then(finish, ex => { + Assert.ok(false, "Unexpected Exception: " + ex); + finish(); + }); +} diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index e14f48b05832..7d165dec5481 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -414,29 +414,36 @@ function waitForDocLoadAndStopIt(aExpectedURL, aBrowser=gBrowser.selectedBrowser * @return promise */ function waitForDocLoadComplete(aBrowser=gBrowser) { - let deferred = Promise.defer(); - let progressListener = { - onStateChange: function (webProgress, req, flags, status) { - let docStop = Ci.nsIWebProgressListener.STATE_IS_NETWORK | - Ci.nsIWebProgressListener.STATE_STOP; - info("Saw state " + flags.toString(16) + " and status " + status.toString(16)); + return new Promise(resolve => { + let listener = { + onStateChange: function (webProgress, req, flags, status) { + let docStop = Ci.nsIWebProgressListener.STATE_IS_NETWORK | + Ci.nsIWebProgressListener.STATE_STOP; + info("Saw state " + flags.toString(16) + " and status " + status.toString(16)); - // When a load needs to be retargetted to a new process it is cancelled - // with NS_BINDING_ABORTED so ignore that case - if ((flags & docStop) == docStop && status != Cr.NS_BINDING_ABORTED) { - aBrowser.removeProgressListener(progressListener); - info("Browser loaded " + aBrowser.contentWindow.location); - deferred.resolve(); - } - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, - Ci.nsISupportsWeakReference]) - }; - aBrowser.addProgressListener(progressListener); - info("Waiting for browser load"); - return deferred.promise; + // When a load needs to be retargetted to a new process it is cancelled + // with NS_BINDING_ABORTED so ignore that case + if ((flags & docStop) == docStop && status != Cr.NS_BINDING_ABORTED) { + aBrowser.removeProgressListener(this); + waitForDocLoadComplete.listeners.delete(this); + info("Browser loaded " + aBrowser.contentWindow.location); + resolve(); + } + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, + Ci.nsISupportsWeakReference]) + }; + aBrowser.addProgressListener(listener); + waitForDocLoadComplete.listeners.add(listener); + info("Waiting for browser load"); + }); } +// Keep a set of progress listeners for waitForDocLoadComplete() to make sure +// they're not GC'ed before we saw the page load. +waitForDocLoadComplete.listeners = new Set(); +registerCleanupFunction(() => waitForDocLoadComplete.listeners.clear()); + let FullZoomHelper = { selectTabAndWaitForLocationChange: function selectTabAndWaitForLocationChange(tab) { diff --git a/browser/components/downloads/moz.build b/browser/components/downloads/moz.build index b0b4ceb84c4b..ca290d67c15a 100644 --- a/browser/components/downloads/moz.build +++ b/browser/components/downloads/moz.build @@ -4,6 +4,9 @@ # 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/. +with Files('*'): + BUG_COMPONENT = ('Firefox', 'Downloads Panel') + XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini'] BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini'] diff --git a/browser/components/loop/content/js/roomViews.js b/browser/components/loop/content/js/roomViews.js index cc1f19aa34b8..66d0e2767154 100644 --- a/browser/components/loop/content/js/roomViews.js +++ b/browser/components/loop/content/js/roomViews.js @@ -166,7 +166,8 @@ loop.roomViews = (function(mozL10n) { ActiveRoomStoreMixin, sharedMixins.DocumentTitleMixin, sharedMixins.MediaSetupMixin, - sharedMixins.RoomsAudioMixin + sharedMixins.RoomsAudioMixin, + sharedMixins.WindowCloseMixin ], propTypes: { @@ -204,14 +205,11 @@ loop.roomViews = (function(mozL10n) { * User clicked on the "Leave" button. */ leaveRoom: function() { - this.props.dispatcher.dispatch(new sharedActions.LeaveRoom()); - }, - - /** - * Closes the window if the cancel button is pressed in the generic failure view. - */ - closeWindow: function() { - window.close(); + if (this.state.used) { + this.props.dispatcher.dispatch(new sharedActions.LeaveRoom()); + } else { + this.closeWindow(); + } }, /** @@ -255,15 +253,9 @@ loop.roomViews = (function(mozL10n) { ); } case ROOM_STATES.ENDED: { - if (this.state.used) - return React.createElement(sharedViews.FeedbackView, { - onAfterFeedbackReceived: this.closeWindow} - ); - - // In case the room was not used (no one was here), we - // bypass the feedback form. - this.closeWindow(); - return null; + return React.createElement(sharedViews.FeedbackView, { + onAfterFeedbackReceived: this.closeWindow} + ); } default: { return ( diff --git a/browser/components/loop/content/js/roomViews.jsx b/browser/components/loop/content/js/roomViews.jsx index 64c172bc92f1..26fae87059f8 100644 --- a/browser/components/loop/content/js/roomViews.jsx +++ b/browser/components/loop/content/js/roomViews.jsx @@ -166,7 +166,8 @@ loop.roomViews = (function(mozL10n) { ActiveRoomStoreMixin, sharedMixins.DocumentTitleMixin, sharedMixins.MediaSetupMixin, - sharedMixins.RoomsAudioMixin + sharedMixins.RoomsAudioMixin, + sharedMixins.WindowCloseMixin ], propTypes: { @@ -204,14 +205,11 @@ loop.roomViews = (function(mozL10n) { * User clicked on the "Leave" button. */ leaveRoom: function() { - this.props.dispatcher.dispatch(new sharedActions.LeaveRoom()); - }, - - /** - * Closes the window if the cancel button is pressed in the generic failure view. - */ - closeWindow: function() { - window.close(); + if (this.state.used) { + this.props.dispatcher.dispatch(new sharedActions.LeaveRoom()); + } else { + this.closeWindow(); + } }, /** @@ -255,15 +253,9 @@ loop.roomViews = (function(mozL10n) { />; } case ROOM_STATES.ENDED: { - if (this.state.used) - return ; - - // In case the room was not used (no one was here), we - // bypass the feedback form. - this.closeWindow(); - return null; + return ; } default: { return ( diff --git a/browser/components/loop/content/shared/js/activeRoomStore.js b/browser/components/loop/content/shared/js/activeRoomStore.js index f529a04eef7a..0ddced145370 100644 --- a/browser/components/loop/content/shared/js/activeRoomStore.js +++ b/browser/components/loop/content/shared/js/activeRoomStore.js @@ -497,13 +497,6 @@ loop.store.ActiveRoomStore = (function() { windowUnload: function() { this._leaveRoom(ROOM_STATES.CLOSING); - // If we're closing the window, then ensure the screensharing state - // is cleared. We don't do this on leave room, as we might still be - // sharing. - this._mozLoop.setScreenShareState( - this.getStoreState().windowId, - false); - if (!this._onUpdateListener) { return; } @@ -520,7 +513,7 @@ loop.store.ActiveRoomStore = (function() { * Handles a room being left. */ leaveRoom: function() { - this._leaveRoom(); + this._leaveRoom(ROOM_STATES.ENDED); }, /** @@ -554,14 +547,24 @@ loop.store.ActiveRoomStore = (function() { * Handles leaving a room. Clears any membership timeouts, then * signals to the server the leave of the room. * - * @param {ROOM_STATES} nextState Optional; the next state to switch to. - * Switches to READY if undefined. + * @param {ROOM_STATES} nextState The next state to switch to. */ _leaveRoom: function(nextState) { if (loop.standaloneMedia) { loop.standaloneMedia.multiplexGum.reset(); } + this._mozLoop.setScreenShareState( + this.getStoreState().windowId, + false); + + if (this._browserSharingListener) { + // Remove the browser sharing listener as we don't need it now. + this._mozLoop.removeBrowserSharingListener(this._browserSharingListener); + this._browserSharingListener = null; + } + + // We probably don't need to end screen share separately, but lets be safe. this._sdkDriver.disconnectSession(); if (this._timeout) { @@ -577,7 +580,7 @@ loop.store.ActiveRoomStore = (function() { this._storeState.sessionToken); } - this.setStoreState({roomState: nextState || ROOM_STATES.ENDED}); + this.setStoreState({roomState: nextState}); }, /** diff --git a/browser/components/loop/content/shared/js/roomStates.js b/browser/components/loop/content/shared/js/roomStates.js index 9b2deabb7ff7..c0014a04408d 100644 --- a/browser/components/loop/content/shared/js/roomStates.js +++ b/browser/components/loop/content/shared/js/roomStates.js @@ -28,7 +28,7 @@ loop.store.ROOM_STATES = { FAILED: "room-failed", // The room is full FULL: "room-full", - // The room conversation has ended + // The room conversation has ended, displays the feedback view. ENDED: "room-ended", // The window is closing CLOSING: "room-closing" diff --git a/browser/components/loop/content/shared/libs/sdk.js b/browser/components/loop/content/shared/libs/sdk.js index 531ed773f1da..c662fffa08f3 100755 --- a/browser/components/loop/content/shared/libs/sdk.js +++ b/browser/components/loop/content/shared/libs/sdk.js @@ -1,12 +1,12 @@ /** - * @license OpenTok JavaScript Library v2.4.0 54ae164 HEAD + * @license OpenTok JavaScript Library v2.5.0 17447b9 HEAD * http://www.tokbox.com/ * * Copyright (c) 2014 TokBox, Inc. * Released under the MIT license * http://opensource.org/licenses/MIT * - * Date: January 08 08:54:40 2015 + * Date: March 02 09:16:29 2015 */ @@ -15,12 +15,12 @@ !(function(window, OTHelpers, undefined) { /** - * @license Common JS Helpers on OpenTok 0.2.0 ef06638 2014Q4-2.2 + * @license Common JS Helpers on OpenTok 0.3.0 f4918b4 2014Q4-2.2.patch.1 * http://www.tokbox.com/ * * Copyright (c) 2015 TokBox, Inc. * - * Date: January 08 08:54:29 2015 + * Date: March 02 09:16:17 2015 * */ @@ -1908,106 +1908,6 @@ OTHelpers.Collection = function(idField) { /*jshint browser:true, smarttabs:true*/ -// tb_require('../helpers.js') - -OTHelpers.castToBoolean = function(value, defaultValue) { - if (value === undefined) return defaultValue; - return value === 'true' || value === true; -}; - -OTHelpers.roundFloat = function(value, places) { - return Number(value.toFixed(places)); -}; - -/*jshint browser:true, smarttabs:true*/ - -// tb_require('../helpers.js') - -(function() { - - var capabilities = {}; - - // Registers a new capability type and a function that will indicate - // whether this client has that capability. - // - // OTHelpers.registerCapability('bundle', function() { - // return OTHelpers.hasCapabilities('webrtc') && - // (OTHelpers.env.name === 'Chrome' || TBPlugin.isInstalled()); - // }); - // - OTHelpers.registerCapability = function(name, callback) { - var _name = name.toLowerCase(); - - if (capabilities.hasOwnProperty(_name)) { - OTHelpers.error('Attempted to register', name, 'capability more than once'); - return; - } - - if (!OTHelpers.isFunction(callback)) { - OTHelpers.error('Attempted to register', name, - 'capability with a callback that isn\' a function'); - return; - } - - memoriseCapabilityTest(_name, callback); - }; - - - // Wrap up a capability test in a function that memorises the - // result. - var memoriseCapabilityTest = function (name, callback) { - capabilities[name] = function() { - var result = callback(); - capabilities[name] = function() { - return result; - }; - - return result; - }; - }; - - var testCapability = function (name) { - return capabilities[name](); - }; - - - // Returns true if all of the capability names passed in - // exist and are met. - // - // OTHelpers.hasCapabilities('bundle', 'rtcpMux') - // - OTHelpers.hasCapabilities = function(/* capability1, capability2, ..., capabilityN */) { - var capNames = prototypeSlice.call(arguments), - name; - - for (var i=0; i