Merge fx-team to m-c. a=merge
@ -7,22 +7,27 @@ module.metadata = {
|
||||
};
|
||||
|
||||
const { Cc, Ci, Cu } = require('chrome');
|
||||
const { isNative } = require('@loader/options');
|
||||
const { rootURI, metadata, isNative } = require('@loader/options');
|
||||
const { id, loadReason } = require('../self');
|
||||
const { descriptor, Sandbox, evaluate, main, resolveURI } = require('toolkit/loader');
|
||||
const { once } = require('../system/events');
|
||||
const { exit, env, staticArgs } = require('../system');
|
||||
const { when: unload } = require('../system/unload');
|
||||
const { loadReason } = require('../self');
|
||||
const { rootURI, metadata } = require("@loader/options");
|
||||
const globals = require('../system/globals');
|
||||
const xulApp = require('../system/xul-app');
|
||||
const { id } = require('sdk/self');
|
||||
const { get } = require('../preferences/service');
|
||||
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
|
||||
getService(Ci.nsIAppShellService);
|
||||
const { preferences } = metadata;
|
||||
|
||||
const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () {
|
||||
return Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", {}).
|
||||
BrowserToolboxProcess;
|
||||
});
|
||||
|
||||
// Initializes default preferences
|
||||
function setDefaultPrefs(prefsURI) {
|
||||
const prefs = Cc['@mozilla.org/preferences-service;1'].
|
||||
@ -102,7 +107,9 @@ function run(options) {
|
||||
// native-options does stuff directly with preferences key from package.json
|
||||
if (preferences && preferences.length > 0) {
|
||||
try {
|
||||
require('../preferences/native-options').enable({ preferences: preferences, id: id });
|
||||
require('../preferences/native-options').
|
||||
enable({ preferences: preferences, id: id }).
|
||||
catch(console.exception);
|
||||
}
|
||||
catch (error) {
|
||||
console.exception(error);
|
||||
@ -141,7 +148,6 @@ function run(options) {
|
||||
unload(program.onUnload);
|
||||
|
||||
if (typeof(program.main) === 'function') {
|
||||
|
||||
program.main({
|
||||
loadReason: loadReason,
|
||||
staticArgs: staticArgs
|
||||
@ -150,6 +156,10 @@ function run(options) {
|
||||
quit: exit
|
||||
});
|
||||
}
|
||||
|
||||
if (get("extensions." + id + ".sdk.debug.show", false)) {
|
||||
BrowserToolboxProcess.init({ addonID: id });
|
||||
}
|
||||
} catch (error) {
|
||||
console.exception(error);
|
||||
throw error;
|
||||
|
@ -55,6 +55,10 @@ DEFAULT_NO_CONNECTIONS_PREFS = {
|
||||
# Disable app update
|
||||
'app.update.enabled' : False,
|
||||
|
||||
# Disable about:newtab content fetch and ping
|
||||
'browser.newtabpage.directory.source': 'data:application/json,{"jetpack":1}',
|
||||
'browser.newtabpage.directory.ping': '',
|
||||
|
||||
# Point update checks to a nonexistent local URL for fast failures.
|
||||
'extensions.update.url' : 'http://localhost/extensions-dummy/updateURL',
|
||||
'extensions.blocklist.url' : 'http://localhost/extensions-dummy/blocklistURL',
|
||||
|
17
addon-sdk/source/test/addons/author-email/main.js
Normal file
@ -0,0 +1,17 @@
|
||||
/* 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/. */
|
||||
'use strict';
|
||||
|
||||
const { Cu } = require('chrome');
|
||||
const self = require('sdk/self');
|
||||
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
|
||||
|
||||
exports.testContributors = function(assert, done) {
|
||||
AddonManager.getAddonByID(self.id, (addon) => {
|
||||
assert.equal(addon.creator.name, 'test <test@mozilla.com>', '< and > characters work');
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
4
addon-sdk/source/test/addons/author-email/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"id": "test-addon-author-email@jetpack",
|
||||
"author": "test <test@mozilla.com>"
|
||||
}
|
@ -76,7 +76,7 @@ exports['test `load` events'] = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports['test removeing listeners'] = function(assert, done) {
|
||||
exports['test removing listeners'] = function(assert, done) {
|
||||
Loader({
|
||||
onLoad: function(window) {
|
||||
assert.equal(window, this._window, 'windows should match');
|
||||
|
@ -10,18 +10,6 @@
|
||||
* Tab previews utility, produces thumbnails
|
||||
*/
|
||||
var tabPreviews = {
|
||||
aspectRatio: 0.5625, // 16:9
|
||||
|
||||
get width() {
|
||||
delete this.width;
|
||||
return this.width = Math.ceil(screen.availWidth / 5.75);
|
||||
},
|
||||
|
||||
get height() {
|
||||
delete this.height;
|
||||
return this.height = Math.round(this.width * this.aspectRatio);
|
||||
},
|
||||
|
||||
init: function tabPreviews_init() {
|
||||
if (this._selectedTab)
|
||||
return;
|
||||
@ -29,6 +17,12 @@ var tabPreviews = {
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
|
||||
gBrowser.tabContainer.addEventListener("SSTabRestored", this, false);
|
||||
|
||||
let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"]
|
||||
.getService(Ci.nsIScreenManager);
|
||||
let left = {}, top = {}, width = {}, height = {};
|
||||
screenManager.primaryScreen.GetRectDisplayPix(left, top, width, height);
|
||||
this.aspectRatio = height.value / width.value;
|
||||
},
|
||||
|
||||
get: function tabPreviews_get(aTab) {
|
||||
@ -52,31 +46,35 @@ var tabPreviews = {
|
||||
return this.capture(aTab, !aTab.hasAttribute("busy"));
|
||||
},
|
||||
|
||||
capture: function tabPreviews_capture(aTab, aStore) {
|
||||
var thumbnail = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
thumbnail.mozOpaque = true;
|
||||
thumbnail.height = this.height;
|
||||
thumbnail.width = this.width;
|
||||
capture: function tabPreviews_capture(aTab, aShouldCache) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
let uri = browser.currentURI.spec;
|
||||
|
||||
// drawWindow doesn't yet work with e10s (bug 698371)
|
||||
if (gMultiProcessBrowser)
|
||||
return thumbnail;
|
||||
// FIXME: The gBrowserThumbnails._shouldCapture determines whether
|
||||
// thumbnails should be written to disk. This should somehow be part
|
||||
// of the PageThumbs API. (bug 1062414)
|
||||
if (aShouldCache &&
|
||||
gBrowserThumbnails._shouldCapture(browser)) {
|
||||
let img = new Image;
|
||||
|
||||
var ctx = thumbnail.getContext("2d");
|
||||
var win = aTab.linkedBrowser.contentWindow;
|
||||
var snippetWidth = win.innerWidth * .6;
|
||||
var scale = this.width / snippetWidth;
|
||||
ctx.scale(scale, scale);
|
||||
ctx.drawWindow(win, win.scrollX, win.scrollY,
|
||||
snippetWidth, snippetWidth * this.aspectRatio, "rgb(255,255,255)");
|
||||
PageThumbs.captureAndStore(browser, function () {
|
||||
img.src = PageThumbs.getThumbnailURL(uri);
|
||||
});
|
||||
|
||||
if (aStore &&
|
||||
aTab.linkedBrowser /* bug 795608: the tab may got removed while drawing the thumbnail */) {
|
||||
aTab.__thumbnail = thumbnail;
|
||||
aTab.__thumbnail_lastURI = aTab.linkedBrowser.currentURI.spec;
|
||||
aTab.__thumbnail = img;
|
||||
aTab.__thumbnail_lastURI = uri;
|
||||
return img;
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
let canvas = PageThumbs.createCanvas(window);
|
||||
|
||||
if (aShouldCache) {
|
||||
aTab.__thumbnail = canvas;
|
||||
aTab.__thumbnail_lastURI = uri;
|
||||
}
|
||||
|
||||
PageThumbs.captureToCanvas(aTab.linkedBrowser.contentWindow, canvas);
|
||||
return canvas;
|
||||
},
|
||||
|
||||
handleEvent: function tabPreviews_handleEvent(event) {
|
||||
@ -182,8 +180,7 @@ var ctrlTab = {
|
||||
get isOpen () this.panel.state == "open" || this.panel.state == "showing" || this._timer,
|
||||
get tabCount () this.tabList.length,
|
||||
get tabPreviewCount () Math.min(this.previews.length - 1, this.tabCount),
|
||||
get canvasWidth () Math.min(tabPreviews.width,
|
||||
Math.ceil(screen.availWidth * .85 / this.tabPreviewCount)),
|
||||
get canvasWidth () Math.ceil(screen.availWidth * .85 / this.tabPreviewCount),
|
||||
get canvasHeight () Math.round(this.canvasWidth * tabPreviews.aspectRatio),
|
||||
|
||||
get tabList () {
|
||||
@ -505,6 +502,15 @@ var ctrlTab = {
|
||||
}
|
||||
},
|
||||
|
||||
filterForThumbnailExpiration: function (aCallback) {
|
||||
let urls = [];
|
||||
let previewCount = this.tabPreviewCount;
|
||||
for (let i = 0; i < previewCount; i++)
|
||||
urls.push(this.tabList[i].linkedBrowser.currentURI.spec);
|
||||
|
||||
aCallback(urls);
|
||||
},
|
||||
|
||||
_initRecentlyUsedTabs: function () {
|
||||
this._recentlyUsedTabs =
|
||||
Array.filter(gBrowser.tabs, tab => !tab.closing)
|
||||
@ -525,6 +531,11 @@ var ctrlTab = {
|
||||
document[toggleEventListener]("keypress", this, false);
|
||||
gBrowser.mTabBox.handleCtrlTab = !enable;
|
||||
|
||||
if (enable)
|
||||
PageThumbs.addExpirationFilter(this);
|
||||
else
|
||||
PageThumbs.removeExpirationFilter(this);
|
||||
|
||||
// If we're not running, hide the "Show All Tabs" menu item,
|
||||
// as Shift+Ctrl+Tab will be handled by the tab bar.
|
||||
document.getElementById("menu_showAllTabs").hidden = !enable;
|
||||
|
@ -103,7 +103,9 @@ let gBrowserThumbnails = {
|
||||
},
|
||||
|
||||
_capture: function Thumbnails_capture(aBrowser) {
|
||||
if (this._shouldCapture(aBrowser))
|
||||
// Only capture about:newtab top sites.
|
||||
if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) >= 0 &&
|
||||
this._shouldCapture(aBrowser))
|
||||
PageThumbs.captureAndStoreIfStale(aBrowser);
|
||||
},
|
||||
|
||||
@ -121,15 +123,12 @@ let gBrowserThumbnails = {
|
||||
this._timeouts.set(aBrowser, timeout);
|
||||
},
|
||||
|
||||
// FIXME: This should be part of the PageThumbs API. (bug 1062414)
|
||||
_shouldCapture: function Thumbnails_shouldCapture(aBrowser) {
|
||||
// Capture only if it's the currently selected tab.
|
||||
if (aBrowser != gBrowser.selectedBrowser)
|
||||
return false;
|
||||
|
||||
// Only capture about:newtab top sites.
|
||||
if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) < 0)
|
||||
return false;
|
||||
|
||||
// Don't capture in per-window private browsing mode.
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(window))
|
||||
return false;
|
||||
|
@ -672,33 +672,17 @@ var gPopupBlockerObserver = {
|
||||
}
|
||||
};
|
||||
|
||||
function gKeywordURIFixup(fixupInfo, topic, data) {
|
||||
fixupInfo.QueryInterface(Ci.nsIURIFixupInfo);
|
||||
function gKeywordURIFixup({ target: browser, data: fixupInfo }) {
|
||||
let deserializeURI = (spec) => spec ? makeURI(spec) : null;
|
||||
|
||||
// We get called irrespective of whether we did a keyword search, or
|
||||
// whether the original input would be vaguely interpretable as a URL,
|
||||
// so figure that out first.
|
||||
let alternativeURI = fixupInfo.fixedURI;
|
||||
let alternativeURI = deserializeURI(fixupInfo.fixedURI);
|
||||
if (!fixupInfo.fixupUsedKeyword || !alternativeURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should have a document loader...
|
||||
let docshellRef = fixupInfo.consumer;
|
||||
try {
|
||||
docshellRef.QueryInterface(Ci.nsIDocumentLoader);
|
||||
} catch (ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!docshellRef.document)
|
||||
return;
|
||||
|
||||
// ... from which we can deduce the browser
|
||||
let browser = gBrowser.getBrowserForDocument(docshellRef.document);
|
||||
if (!browser)
|
||||
return;
|
||||
|
||||
// At this point we're still only just about to load this URI.
|
||||
// When the async DNS lookup comes back, we may be in any of these states:
|
||||
// 1) still on the previous URI, waiting for the preferredURI (keyword
|
||||
@ -708,6 +692,7 @@ function gKeywordURIFixup(fixupInfo, topic, data) {
|
||||
// We keep track of the currentURI to detect case (1) in the DNS lookup
|
||||
// callback.
|
||||
let previousURI = browser.currentURI;
|
||||
let preferredURI = deserializeURI(fixupInfo.preferredURI);
|
||||
|
||||
// now swap for a weak ref so we don't hang on to browser needlessly
|
||||
// even if the DNS query takes forever
|
||||
@ -738,7 +723,7 @@ function gKeywordURIFixup(fixupInfo, topic, data) {
|
||||
let currentURI = browser.currentURI;
|
||||
// If we're in case (3) (see above), don't show an info bar.
|
||||
if (!currentURI.equals(previousURI) &&
|
||||
!currentURI.equals(fixupInfo.preferredURI)) {
|
||||
!currentURI.equals(preferredURI)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1025,15 +1010,12 @@ var gBrowserInit = {
|
||||
|
||||
// This pageshow listener needs to be registered before we may call
|
||||
// swapBrowsersAndCloseOther() to receive pageshow events fired by that.
|
||||
if (!gMultiProcessBrowser) {
|
||||
// pageshow handlers are being migrated to
|
||||
// content.js. Eventually this code should be removed.
|
||||
gBrowser.addEventListener("pageshow", function(event) {
|
||||
// Filter out events that are not about the document load we are interested in
|
||||
if (content && event.target == content.document)
|
||||
setTimeout(pageShowEventHandlers, 0, event.persisted);
|
||||
}, true);
|
||||
}
|
||||
let mm = window.messageManager;
|
||||
mm.addMessageListener("PageVisibility:Show", function(message) {
|
||||
if (message.target == gBrowser.selectedBrowser) {
|
||||
setTimeout(pageShowEventHandlers, 0, message.data.persisted);
|
||||
}
|
||||
});
|
||||
|
||||
if (uriToLoad && uriToLoad != "about:blank") {
|
||||
if (uriToLoad instanceof Ci.nsISupportsArray) {
|
||||
@ -1087,7 +1069,7 @@ var gBrowserInit = {
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
|
||||
Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup", false);
|
||||
window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
|
||||
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
@ -1393,7 +1375,7 @@ var gBrowserInit = {
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
|
||||
Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup");
|
||||
window.messageManager.removeMessageListener("Browser:URIFixup", gKeywordURIFixup);
|
||||
|
||||
try {
|
||||
gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton);
|
||||
@ -3561,42 +3543,11 @@ 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);
|
||||
let target = BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
|
||||
SocialUI.closeSocialPanelForLinkTraversal(target, linkNode);
|
||||
return target;
|
||||
},
|
||||
|
||||
_onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
|
||||
// Don't modify non-default targets or targets that aren't in top-level app
|
||||
// tab docshells (isAppTab will be false for app tab subframes).
|
||||
if (originalTarget != "" || !isAppTab)
|
||||
return originalTarget;
|
||||
|
||||
// External links from within app tabs should always open in new tabs
|
||||
// instead of replacing the app tab's page (Bug 575561)
|
||||
let linkHost;
|
||||
let docHost;
|
||||
try {
|
||||
linkHost = linkURI.host;
|
||||
docHost = linkNode.ownerDocument.documentURIObject.host;
|
||||
} catch(e) {
|
||||
// nsIURI.host can throw for non-nsStandardURL nsIURIs.
|
||||
// If we fail to get either host, just return originalTarget.
|
||||
return originalTarget;
|
||||
}
|
||||
|
||||
if (docHost == linkHost)
|
||||
return originalTarget;
|
||||
|
||||
// Special case: ignore "www" prefix if it is part of host string
|
||||
let [longHost, shortHost] =
|
||||
linkHost.length > docHost.length ? [linkHost, docHost] : [docHost, linkHost];
|
||||
if (longHost == "www." + shortHost)
|
||||
return originalTarget;
|
||||
|
||||
return "_blank";
|
||||
},
|
||||
|
||||
onProgressChange: function (aWebProgress, aRequest,
|
||||
aCurSelfProgress, aMaxSelfProgress,
|
||||
aCurTotalProgress, aMaxTotalProgress) {
|
||||
@ -7367,9 +7318,17 @@ let ToolbarIconColor = {
|
||||
toolbarSelector += ":not([type=menubar])";
|
||||
#endif
|
||||
|
||||
// The getComputedStyle calls and setting the brighttext are separated in
|
||||
// two loops to avoid flushing layout and making it dirty repeatedly.
|
||||
|
||||
let luminances = new Map;
|
||||
for (let toolbar of document.querySelectorAll(toolbarSelector)) {
|
||||
let [r, g, b] = parseRGB(getComputedStyle(toolbar).color);
|
||||
let luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b;
|
||||
luminances.set(toolbar, luminance);
|
||||
}
|
||||
|
||||
for (let [toolbar, luminance] of luminances) {
|
||||
if (luminance <= 110)
|
||||
toolbar.removeAttribute("brighttext");
|
||||
else
|
||||
|
@ -633,3 +633,54 @@ let DOMFullscreenHandler = {
|
||||
}
|
||||
};
|
||||
DOMFullscreenHandler.init();
|
||||
|
||||
function gKeywordURIFixup(fixupInfo) {
|
||||
fixupInfo.QueryInterface(Ci.nsIURIFixupInfo);
|
||||
|
||||
// Ignore info from other docshells
|
||||
let parent = fixupInfo.consumer.QueryInterface(Ci.nsIDocShellTreeItem).sameTypeRootTreeItem;
|
||||
if (parent != docShell)
|
||||
return;
|
||||
|
||||
let data = {};
|
||||
for (let f of Object.keys(fixupInfo)) {
|
||||
if (f == "consumer" || typeof fixupInfo[f] == "function")
|
||||
continue;
|
||||
|
||||
if (fixupInfo[f] && fixupInfo[f] instanceof Ci.nsIURI) {
|
||||
data[f] = fixupInfo[f].spec;
|
||||
} else {
|
||||
data[f] = fixupInfo[f];
|
||||
}
|
||||
}
|
||||
|
||||
sendAsyncMessage("Browser:URIFixup", data);
|
||||
}
|
||||
Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup", false);
|
||||
addEventListener("unload", () => {
|
||||
Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup");
|
||||
}, false);
|
||||
|
||||
addMessageListener("Browser:AppTab", function(message) {
|
||||
docShell.isAppTab = message.data.isAppTab;
|
||||
});
|
||||
|
||||
let WebBrowserChrome = {
|
||||
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
|
||||
return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
|
||||
},
|
||||
};
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsITabChild);
|
||||
tabchild.webBrowserChrome = WebBrowserChrome;
|
||||
}
|
||||
|
||||
addEventListener("pageshow", function(event) {
|
||||
if (event.target == content.document) {
|
||||
sendAsyncMessage("PageVisibility:Show", {
|
||||
persisted: event.persisted,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -289,9 +289,7 @@
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
||||
// Bug 961867 - [e10s] Implement the logic for app tabs
|
||||
if (!gMultiProcessBrowser)
|
||||
this.getBrowserForTab(aTab).docShell.isAppTab = true;
|
||||
this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: true })
|
||||
|
||||
if (aTab.selected)
|
||||
this._setCloseKeyState(false);
|
||||
@ -315,9 +313,7 @@
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
||||
// Bug 961867 - [e10s] Implement the logic for app tabs
|
||||
if (!gMultiProcessBrowser)
|
||||
this.getBrowserForTab(aTab).docShell.isAppTab = false;
|
||||
this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: false })
|
||||
|
||||
if (aTab.selected)
|
||||
this._setCloseKeyState(true);
|
||||
@ -5330,7 +5326,8 @@
|
||||
let switchPromise = gBrowser._prepareForTabSwitch(toTab, fromTab);
|
||||
|
||||
var panel = this._selectedPanel;
|
||||
this._selectedPanel = this.childNodes[val];
|
||||
var newPanel = this.childNodes[val];
|
||||
this._selectedPanel = newPanel;
|
||||
if (this._selectedPanel != panel) {
|
||||
var event = document.createEvent("Events");
|
||||
event.initEvent("select", true, true);
|
||||
@ -5340,8 +5337,16 @@
|
||||
this._selectedIndex = val;
|
||||
|
||||
switchPromise.then(() => {
|
||||
this.setAttribute("selectedIndex", val);
|
||||
gBrowser._finalizeTabSwitch(toTab, fromTab);
|
||||
// If we cannot find the tabpanel that we were trying to switch to, then
|
||||
// it must have been removed before our Promise could be resolved. In
|
||||
// that case, we just cancel the tab switch.
|
||||
var updatedTabIndex = Array.indexOf(this.childNodes, newPanel);
|
||||
if (updatedTabIndex == -1) {
|
||||
gBrowser._cancelTabSwitch(toTab);
|
||||
} else {
|
||||
this.setAttribute("selectedIndex", updatedTabIndex);
|
||||
gBrowser._finalizeTabSwitch(toTab, fromTab);
|
||||
}
|
||||
}, () => {
|
||||
// If the promise rejected, that means we don't want to actually
|
||||
// flip the deck, so we cancel the tab switch.
|
||||
|
@ -198,17 +198,13 @@ skip-if = e10s # Bug 940195 - XULBrowserWindow.isBusy is false as a remote tab s
|
||||
run-if = toolkit == "cocoa"
|
||||
[browser_bug567306.js]
|
||||
[browser_bug575561.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_bug575830.js]
|
||||
skip-if = e10s # Bug 691614 - no e10s zoom support yet
|
||||
[browser_bug577121.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_bug578534.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
[browser_bug579872.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_bug580638.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_bug580956.js]
|
||||
skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
|
||||
[browser_bug581242.js]
|
||||
@ -217,19 +213,16 @@ skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined"
|
||||
skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null)
|
||||
[browser_bug581947.js]
|
||||
[browser_bug585558.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_bug585785.js]
|
||||
[browser_bug585830.js]
|
||||
[browser_bug590206.js]
|
||||
[browser_bug592338.js]
|
||||
skip-if = e10s # Bug 653065 - Make the lightweight theme web installer ready for e10s
|
||||
[browser_bug594131.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_bug595507.js]
|
||||
skip-if = e10s # Bug 691601 - no form submit observers
|
||||
[browser_bug596687.js]
|
||||
[browser_bug597218.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_bug609700.js]
|
||||
skip-if = e10s # Bug 516755 - SessionStore disabled for e10s (calls duplicateTabIn, which uses SessionStore)
|
||||
[browser_bug623155.js]
|
||||
@ -336,7 +329,6 @@ skip-if = buildapp == 'mulet' || e10s # Bug ?????? - uncaught exception - Error:
|
||||
[browser_offlineQuotaNotification.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (gBrowser.selectedBrowser.contentWindow.applicationCache.oncached = function() {...})
|
||||
[browser_overflowScroll.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_pageInfo.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug 866413 - PageInfo doesn't work in e10s
|
||||
[browser_page_style_menu.js]
|
||||
@ -347,7 +339,6 @@ skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
skip-if = debug || asan # Times out on debug/asan, and we are less picky about our JS there
|
||||
|
||||
[browser_pinnedTabs.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_plainTextLinks.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content (creates and fetches elements directly from content document)
|
||||
[browser_popupUI.js]
|
||||
@ -360,7 +351,6 @@ skip-if = buildapp == 'mulet'
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_relatedTabs.js]
|
||||
[browser_removeTabsToTheEnd.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_removeUnsafeProtocolsFromURLBarPaste.js]
|
||||
[browser_sanitize-download-history.js]
|
||||
skip-if = true # bug 432425
|
||||
@ -438,13 +428,10 @@ skip-if = e10s # Bug ?????? - FHR tests failing (either with "no data for today"
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
[browser_visibleLabel.js]
|
||||
[browser_visibleTabs.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_visibleTabs_bookmarkAllPages.js]
|
||||
skip-if = true # Bug 1005420 - fails intermittently. also with e10s enabled: bizarre problem with hidden tab having _mouseenter called, via _setPositionalAttributes, and tab not being found resulting in 'candidate is undefined'
|
||||
[browser_visibleTabs_bookmarkAllTabs.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_visibleTabs_contextMenu.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
[browser_visibleTabs_tabPreview.js]
|
||||
skip-if = (os == "win" && !debug) || e10s # Bug 1007418 / Bug 698371 - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
|
||||
[browser_web_channel.js]
|
||||
|
@ -43,16 +43,8 @@ function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) {
|
||||
if (pinTab)
|
||||
gBrowser.pinTab(appTab);
|
||||
gBrowser.selectedTab = appTab;
|
||||
appTab.linkedBrowser.addEventListener("load", onLoad, true);
|
||||
|
||||
let loadCount = 0;
|
||||
function onLoad() {
|
||||
loadCount++;
|
||||
if (loadCount < 2)
|
||||
return;
|
||||
|
||||
appTab.linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
|
||||
waitForDocLoadComplete(appTab.linkedBrowser).then(function() {
|
||||
let browser = gBrowser.getBrowserForTab(appTab);
|
||||
if (testSubFrame)
|
||||
browser = browser.contentDocument.getElementsByTagName("iframe")[0];
|
||||
@ -62,7 +54,7 @@ function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) {
|
||||
if (expectNewTab)
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
|
||||
else
|
||||
browser.addEventListener("load", onPageLoad, true);
|
||||
waitForDocLoadComplete(appTab.linkedBrowser).then(onPageLoad);
|
||||
|
||||
info("Clicking " + links[aLinkIndex].textContent);
|
||||
EventUtils.sendMouseEvent({type:"click"}, links[aLinkIndex], browser.contentWindow);
|
||||
@ -80,11 +72,13 @@ function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) {
|
||||
function onTabOpen(event) {
|
||||
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
|
||||
ok(true, "Link should open a new tab");
|
||||
executeSoon(function(){
|
||||
gBrowser.removeTab(appTab);
|
||||
gBrowser.removeCurrentTab();
|
||||
nextTest();
|
||||
waitForDocLoadComplete(event.target.linkedBrowser).then(function() {
|
||||
executeSoon(function(){
|
||||
gBrowser.removeTab(appTab);
|
||||
gBrowser.removeCurrentTab();
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -49,14 +49,6 @@ const EXPECTED_REFLOWS = [
|
||||
"ssi_updateWindowFeatures/<@resource:///modules/sessionstore/SessionStore.jsm|" +
|
||||
"ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" +
|
||||
"ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|",
|
||||
|
||||
// tabPreviews.capture()
|
||||
"tabPreviews_capture@chrome://browser/content/browser.js|" +
|
||||
"tabPreviews_handleEvent/<@chrome://browser/content/browser.js|",
|
||||
|
||||
// tabPreviews.capture()
|
||||
"tabPreviews_capture@chrome://browser/content/browser.js|" +
|
||||
"@chrome://browser/content/browser.js|"
|
||||
];
|
||||
|
||||
const PREF_PRELOAD = "browser.newtab.preload";
|
||||
|
@ -15,8 +15,10 @@ function promiseNotificationForTab(aBrowser, value, expected, tab=aBrowser.selec
|
||||
let deferred = Promise.defer();
|
||||
let notificationBox = aBrowser.getNotificationBox(tab.linkedBrowser);
|
||||
if (expected) {
|
||||
info("Waiting for " + value + " notification");
|
||||
let checkForNotification = function() {
|
||||
if (notificationBox.getNotificationWithValue(value)) {
|
||||
info("Saw the notification");
|
||||
notificationObserver.disconnect();
|
||||
notificationObserver = null;
|
||||
deferred.resolve();
|
||||
@ -48,12 +50,13 @@ function* runURLBarSearchTest(valueToOpen, expectSearch, expectNotification, aWi
|
||||
expectedURI = Services.search.defaultEngine.getSubmission(valueToOpen, null, "keyword").uri.spec;
|
||||
}
|
||||
aWindow.gURLBar.focus();
|
||||
let docLoadPromise = waitForDocLoadAndStopIt(expectedURI, aWindow.gBrowser);
|
||||
let docLoadPromise = waitForDocLoadAndStopIt(expectedURI, aWindow.gBrowser.selectedBrowser);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, aWindow);
|
||||
|
||||
yield docLoadPromise;
|
||||
|
||||
yield promiseNotificationForTab(aWindow.gBrowser, "keyword-uri-fixup", expectNotification);
|
||||
yield Promise.all([
|
||||
docLoadPromise,
|
||||
promiseNotificationForTab(aWindow.gBrowser, "keyword-uri-fixup", expectNotification)
|
||||
]);
|
||||
}
|
||||
|
||||
add_task(function* test_navigate_full_domain() {
|
||||
@ -88,7 +91,7 @@ function get_test_function_for_localhost_with_hostname(hostName, isPrivate) {
|
||||
|
||||
let notificationBox = browser.getNotificationBox(tab.linkedBrowser);
|
||||
let notification = notificationBox.getNotificationWithValue("keyword-uri-fixup");
|
||||
let docLoadPromise = waitForDocLoadAndStopIt("http://" + hostName + "/", browser);
|
||||
let docLoadPromise = waitForDocLoadAndStopIt("http://" + hostName + "/", tab.linkedBrowser);
|
||||
notification.querySelector(".notification-button-default").click();
|
||||
|
||||
// check pref value
|
||||
|
@ -394,26 +394,66 @@ function promiseClearHistory() {
|
||||
* The URL of the document that is expected to load.
|
||||
* @return promise
|
||||
*/
|
||||
function waitForDocLoadAndStopIt(aExpectedURL, aBrowser=gBrowser) {
|
||||
function waitForDocLoadAndStopIt(aExpectedURL, aBrowser=gBrowser.selectedBrowser) {
|
||||
function content_script() {
|
||||
let { interfaces: Ci, utils: Cu } = Components;
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
let wp = docShell.QueryInterface(Ci.nsIWebProgress);
|
||||
|
||||
let progressListener = {
|
||||
onStateChange: function (webProgress, req, flags, status) {
|
||||
dump("waitForDocLoadAndStopIt: onStateChange " + flags.toString(16) + ": " + req.name + "\n");
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if (((flags & docStart) == docStart) && webProgress.isTopLevel) {
|
||||
dump("waitForDocLoadAndStopIt: Document start: " +
|
||||
req.QueryInterface(Ci.nsIChannel).URI.spec + "\n");
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
wp.removeProgressListener(progressListener);
|
||||
sendAsyncMessage("Test:WaitForDocLoadAndStopIt", { uri: req.originalURI.spec });
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference"])
|
||||
};
|
||||
wp.addProgressListener(progressListener, wp.NOTIFY_ALL);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
function complete({ data }) {
|
||||
is(data.uri, aExpectedURL, "waitForDocLoadAndStopIt: The expected URL was loaded");
|
||||
mm.removeMessageListener("Test:WaitForDocLoadAndStopIt", complete);
|
||||
resolve();
|
||||
}
|
||||
|
||||
let mm = aBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + content_script.toString() + ")();", true);
|
||||
mm.addMessageListener("Test:WaitForDocLoadAndStopIt", complete);
|
||||
info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the next load to complete in the current browser.
|
||||
*
|
||||
* @return promise
|
||||
*/
|
||||
function waitForDocLoadComplete(aBrowser=gBrowser) {
|
||||
let deferred = Promise.defer();
|
||||
let progressListener = {
|
||||
onStateChange: function (webProgress, req, flags, status) {
|
||||
info("waitForDocLoadAndStopIt: onStateChange: " + req.name);
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if ((flags & docStart) && webProgress.isTopLevel) {
|
||||
info("waitForDocLoadAndStopIt: Document start: " +
|
||||
req.QueryInterface(Ci.nsIChannel).URI.spec);
|
||||
is(req.originalURI.spec, aExpectedURL,
|
||||
"waitForDocLoadAndStopIt: The expected URL was loaded");
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_NETWORK |
|
||||
Ci.nsIWebProgressListener.STATE_STOP;
|
||||
if ((flags & docStart) == docStart) {
|
||||
aBrowser.removeProgressListener(progressListener);
|
||||
info("Browser loaded");
|
||||
deferred.resolve();
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
aBrowser.addProgressListener(progressListener);
|
||||
info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
|
||||
info("Waiting for browser load");
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
*/
|
||||
let MozLoopPushHandler = {
|
||||
// This is the uri of the push server.
|
||||
pushServerUri: Services.prefs.getCharPref("services.push.serverURL"),
|
||||
pushServerUri: undefined,
|
||||
// This is the channel id we're using for notifications
|
||||
channelID: "8b1081ce-9b35-42b5-b8f5-3ff8cb813a50",
|
||||
// This is the UserAgent UUID assigned by the PushServer
|
||||
@ -211,8 +211,51 @@ let MozLoopPushHandler = {
|
||||
}
|
||||
|
||||
this._websocket.protocol = "push-notification";
|
||||
let uri = Services.io.newURI(this.pushServerUri, null, null);
|
||||
this._websocket.asyncOpen(uri, this.pushServerUri, this, null);
|
||||
|
||||
let performOpen = () => {
|
||||
let uri = Services.io.newURI(this.pushServerUri, null, null);
|
||||
this._websocket.asyncOpen(uri, this.pushServerUri, this, null);
|
||||
}
|
||||
|
||||
let pushServerURLFetchError = () => {
|
||||
console.warn("MozLoopPushHandler - Could not retrieve push server URL from Loop server; using default");
|
||||
this.pushServerUri = Services.prefs.getCharPref("services.push.serverURL");
|
||||
performOpen();
|
||||
}
|
||||
|
||||
if (!this.pushServerUri) {
|
||||
// Get push server to use from the Loop server
|
||||
let pushUrlEndpoint = Services.prefs.getCharPref("loop.server") + "/push-server-config";
|
||||
let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Ci.nsIXMLHttpRequest);
|
||||
req.open("GET", pushUrlEndpoint);
|
||||
req.onload = () => {
|
||||
if (req.status >= 200 && req.status < 300) {
|
||||
let pushServerConfig;
|
||||
try {
|
||||
pushServerConfig = JSON.parse(req.responseText);
|
||||
} catch (e) {
|
||||
console.warn("MozLoopPushHandler - Error parsing JSON response for push server URL");
|
||||
pushServerURLFetchError();
|
||||
}
|
||||
if (pushServerConfig.pushServerURI) {
|
||||
this.pushServerUri = pushServerConfig.pushServerURI;
|
||||
performOpen();
|
||||
} else {
|
||||
console.warn("MozLoopPushHandler - push server URL config lacks pushServerURI parameter");
|
||||
pushServerURLFetchError();
|
||||
}
|
||||
} else {
|
||||
console.warn("MozLoopPushHandler - push server URL retrieve error: " + req.status);
|
||||
pushServerURLFetchError();
|
||||
}
|
||||
};
|
||||
req.onerror = pushServerURLFetchError;
|
||||
req.send();
|
||||
} else {
|
||||
// this.pushServerUri already set -- just open the channel
|
||||
performOpen();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -57,9 +57,17 @@ function loadLoopPanel() {
|
||||
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
|
||||
Services.prefs.setCharPref("loop.server", "http://localhost/");
|
||||
|
||||
// Turn off the network for loop tests, so that we don't
|
||||
// try to access the remote servers. If we want to turn this
|
||||
// back on in future, be careful to check for intermittent
|
||||
// failures.
|
||||
let wasOffline = Services.io.offline;
|
||||
Services.io.offline = true;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("services.push.serverURL");
|
||||
Services.prefs.clearUserPref("loop.server");
|
||||
Services.io.offline = wasOffline;
|
||||
});
|
||||
|
||||
// Turn off animations to make tests quicker.
|
||||
|
@ -54,6 +54,8 @@
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
setupFakeLoopServer();
|
||||
|
||||
Services.prefs.setCharPref("services.push.serverURL", kServerPushUrl);
|
||||
Services.prefs.setIntPref("loop.retry_delay.start", 10); // 10 ms
|
||||
Services.prefs.setIntPref("loop.retry_delay.limit", 20); // 20 ms
|
||||
|
@ -7,6 +7,8 @@ function expiryTimePref() {
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setupFakeLoopServer();
|
||||
|
||||
Services.prefs.setIntPref("loop.urlsExpiryTimeSeconds", 0);
|
||||
|
||||
MozLoopService.noteCallUrlExpiry(1000);
|
||||
|
@ -50,6 +50,8 @@ add_task(function test_initialize_starts_timer() {
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setupFakeLoopServer();
|
||||
|
||||
// Override MozLoopService's initializeTimer, so that we can verify the timeout is called
|
||||
// correctly.
|
||||
MozLoopService.initializeTimerFunc = function() {
|
||||
|
@ -22,6 +22,8 @@ function test_getStrings() {
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setupFakeLoopServer();
|
||||
|
||||
test_locale();
|
||||
test_getStrings();
|
||||
}
|
||||
|
@ -89,6 +89,8 @@ function test_getLoopBoolPref_not_found()
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setupFakeLoopServer();
|
||||
|
||||
test_getLoopCharPref();
|
||||
test_getLoopCharPref_not_found();
|
||||
test_getLoopCharPref_non_coercible_type();
|
||||
|
@ -76,6 +76,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -90,6 +93,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -80,6 +80,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -94,6 +97,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -51,6 +51,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -65,6 +68,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -51,6 +51,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -65,6 +68,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -81,6 +81,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -95,6 +98,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -51,6 +51,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -65,6 +68,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -51,6 +51,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -65,6 +68,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -51,6 +51,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -65,6 +68,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -51,6 +51,9 @@ const TEST_DATA = [
|
||||
" var handler9 = function divKeyDown() {\n" +
|
||||
" alert(9);\n" +
|
||||
" };\n" +
|
||||
" var handler10 = function divDragOut() {\n" +
|
||||
" alert(10);\n" +
|
||||
" };\n" +
|
||||
"\n" +
|
||||
" if ($(\"#livediv\").live) {\n" +
|
||||
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
|
||||
@ -65,6 +68,7 @@ const TEST_DATA = [
|
||||
" if ($(\"#livediv\").on) {\n" +
|
||||
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
|
||||
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
|
||||
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var div = $(\"div\")[0];\n" +
|
||||
|
@ -34,6 +34,7 @@
|
||||
var handler7 = function divClick1() { alert(7); };
|
||||
var handler8 = function divClick2() { alert(8); };
|
||||
var handler9 = function divKeyDown() { alert(9); };
|
||||
var handler10 = function divDragOut() { alert(10); };
|
||||
|
||||
if ($("#livediv").live) {
|
||||
$("#livediv").live( "dblclick", handler1);
|
||||
@ -48,6 +49,7 @@
|
||||
if ($("#livediv").on) {
|
||||
$(document).on( "drop", "#livediv", handler5);
|
||||
$(document).on( "dragover", "#livediv", handler6);
|
||||
$(document).on( "dragout", "#livediv:xxxxx", handler10);
|
||||
}
|
||||
|
||||
var div = $("div")[0];
|
||||
|
@ -324,38 +324,83 @@ CssHtmlTree.prototype = {
|
||||
* returns null of the node isn't anything we care about
|
||||
*/
|
||||
getNodeInfo: function(node) {
|
||||
let type, value;
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let classes = node.classList;
|
||||
|
||||
if (classes.contains("property-name") ||
|
||||
classes.contains("property-value") ||
|
||||
(classes.contains("theme-link") && !classes.contains("link"))) {
|
||||
// Go up to the common parent to find the property and value
|
||||
let parent = node.parentNode;
|
||||
while (!parent.classList.contains("property-view")) {
|
||||
parent = parent.parentNode;
|
||||
// Check if the node isn't a selector first since this doesn't require
|
||||
// walking the DOM
|
||||
if (classes.contains("matched") ||
|
||||
classes.contains("bestmatch") ||
|
||||
classes.contains("parentmatch")) {
|
||||
let selectorText = "";
|
||||
for (let child of node.childNodes) {
|
||||
if (child.nodeType === node.TEXT_NODE) {
|
||||
selectorText += child.textContent;
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: overlays.VIEW_NODE_SELECTOR_TYPE,
|
||||
value: selectorText.trim()
|
||||
}
|
||||
}
|
||||
|
||||
// Walk up the nodes to find out where node is
|
||||
let propertyView;
|
||||
let propertyContent;
|
||||
let parent = node;
|
||||
while (parent.parentNode) {
|
||||
if (parent.classList.contains("property-view")) {
|
||||
propertyView = parent;
|
||||
break;
|
||||
}
|
||||
if (parent.classList.contains("property-content")) {
|
||||
propertyContent = parent;
|
||||
break;
|
||||
}
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
if (!propertyView && !propertyContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let value, type;
|
||||
|
||||
// Get the property and value for a node that's a property name or value
|
||||
let isHref = classes.contains("theme-link") && !classes.contains("link");
|
||||
if (propertyView && (classes.contains("property-name") ||
|
||||
classes.contains("property-value") ||
|
||||
isHref)) {
|
||||
value = {
|
||||
property: parent.querySelector(".property-name").textContent,
|
||||
value: parent.querySelector(".property-value").textContent
|
||||
};
|
||||
}
|
||||
if (propertyContent && (classes.contains("other-property-value") ||
|
||||
isHref)) {
|
||||
let view = propertyContent.previousSibling;
|
||||
value = {
|
||||
property: view.querySelector(".property-name").textContent,
|
||||
value: node.textContent
|
||||
};
|
||||
}
|
||||
|
||||
// Get the type
|
||||
if (classes.contains("property-name")) {
|
||||
type = overlays.VIEW_NODE_PROPERTY_TYPE;
|
||||
} else if (classes.contains("property-value")) {
|
||||
} else if (classes.contains("property-value") ||
|
||||
classes.contains("other-property-value")) {
|
||||
type = overlays.VIEW_NODE_VALUE_TYPE;
|
||||
} else if (classes.contains("theme-link")) {
|
||||
} else if (isHref) {
|
||||
type = overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
value.url = node.href;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: type,
|
||||
value: value
|
||||
};
|
||||
return {type, value};
|
||||
},
|
||||
|
||||
_createPropertyViews: function()
|
||||
|
@ -1248,6 +1248,10 @@ CssRuleView.prototype = {
|
||||
* returns null of the node isn't anything we care about
|
||||
*/
|
||||
getNodeInfo: function(node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let type, value;
|
||||
let classes = node.classList;
|
||||
let prop = getParentTextProperty(node);
|
||||
|
@ -25,6 +25,7 @@ support-files =
|
||||
head.js
|
||||
|
||||
[browser_computedview_browser-styles.js]
|
||||
[browser_computedview_getNodeInfo.js]
|
||||
[browser_computedview_keybindings_01.js]
|
||||
[browser_computedview_keybindings_02.js]
|
||||
[browser_computedview_matched-selectors-toggle.js]
|
||||
|
@ -0,0 +1,177 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test various output of the computed-view's getNodeInfo method.
|
||||
// This method is used by the style-inspector-overlay on mouseover to decide
|
||||
// which tooltip or highlighter to show when hovering over a value/name/selector
|
||||
// if any.
|
||||
// For instance, browser_ruleview_selector-highlighter_01.js and
|
||||
// browser_ruleview_selector-highlighter_02.js test that the selector
|
||||
// highlighter appear when hovering over a selector in the rule-view.
|
||||
// Since the code to make this work for the computed-view is 90% the same, there
|
||||
// is no need for testing it again here.
|
||||
// This test however serves as a unit test for getNodeInfo.
|
||||
|
||||
const {
|
||||
VIEW_NODE_SELECTOR_TYPE,
|
||||
VIEW_NODE_PROPERTY_TYPE,
|
||||
VIEW_NODE_VALUE_TYPE,
|
||||
VIEW_NODE_IMAGE_URL_TYPE
|
||||
} = devtools.require("devtools/styleinspector/style-inspector-overlays");
|
||||
|
||||
const PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' body {',
|
||||
' background: red;',
|
||||
' color: white;',
|
||||
' }',
|
||||
' div {',
|
||||
' background: green;',
|
||||
' }',
|
||||
' div div {',
|
||||
' background-color: yellow;',
|
||||
' background-image: url(chrome://global/skin/icons/warning-64.png);',
|
||||
' color: red;',
|
||||
' }',
|
||||
'</style>',
|
||||
'<div><div id="testElement">Test element</div></div>'
|
||||
].join("\n");
|
||||
|
||||
// Each item in this array must have the following properties:
|
||||
// - desc {String} will be logged for information
|
||||
// - getHoveredNode {Generator Function} received the computed-view instance as
|
||||
// argument and must return the node to be tested
|
||||
// - assertNodeInfo {Function} should check the validity of the nodeInfo
|
||||
// argument it receives
|
||||
const TEST_DATA = [
|
||||
{
|
||||
desc: "Testing a null node",
|
||||
getHoveredNode: function*() {
|
||||
return null;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo, null);
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a useless node",
|
||||
getHoveredNode: function*(view) {
|
||||
return view.element;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo, null);
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a property name",
|
||||
getHoveredNode: function*(view) {
|
||||
return getComputedViewProperty(view, "color").nameSpan;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_PROPERTY_TYPE);
|
||||
ok("property" in nodeInfo.value);
|
||||
ok("value" in nodeInfo.value);
|
||||
is(nodeInfo.value.property, "color");
|
||||
is(nodeInfo.value.value, "#F00");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a property value",
|
||||
getHoveredNode: function*(view) {
|
||||
return getComputedViewProperty(view, "color").valueSpan;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
|
||||
ok("property" in nodeInfo.value);
|
||||
ok("value" in nodeInfo.value);
|
||||
is(nodeInfo.value.property, "color");
|
||||
is(nodeInfo.value.value, "#F00");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing an image url",
|
||||
getHoveredNode: function*(view) {
|
||||
let {valueSpan} = getComputedViewProperty(view, "background-image");
|
||||
return valueSpan.querySelector(".theme-link");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_IMAGE_URL_TYPE);
|
||||
ok("property" in nodeInfo.value);
|
||||
ok("value" in nodeInfo.value);
|
||||
is(nodeInfo.value.property, "background-image");
|
||||
is(nodeInfo.value.value, "url(\"chrome://global/skin/icons/warning-64.png\")");
|
||||
is(nodeInfo.value.url, "chrome://global/skin/icons/warning-64.png");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule selector (bestmatch)",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "background-color");
|
||||
return content.querySelector(".bestmatch");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
|
||||
is(nodeInfo.value, "div div");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule selector (matched)",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "background-color");
|
||||
return content.querySelector(".matched");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
|
||||
is(nodeInfo.value, "div");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule selector (parentmatch)",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "color");
|
||||
return content.querySelector(".parentmatch");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
|
||||
is(nodeInfo.value, "body");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule value",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "color");
|
||||
return content.querySelector(".other-property-value");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
|
||||
is(nodeInfo.value.property, "color");
|
||||
is(nodeInfo.value.value, "#F00");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule stylesheet link",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "color");
|
||||
return content.querySelector(".rule-link .theme-link");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo, null);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + PAGE_CONTENT);
|
||||
|
||||
let {inspector, view} = yield openComputedView();
|
||||
yield selectNode("#testElement", inspector);
|
||||
|
||||
for (let {desc, getHoveredNode, assertNodeInfo} of TEST_DATA) {
|
||||
info(desc);
|
||||
let nodeInfo = view.getNodeInfo(yield getHoveredNode(view));
|
||||
assertNodeInfo(nodeInfo);
|
||||
}
|
||||
});
|
@ -23,7 +23,7 @@ let test = asyncTest(function*() {
|
||||
yield selectNode("div", inspector);
|
||||
|
||||
info("Expanding the first property");
|
||||
yield expandComputedViewPropertyByIndex(view, inspector, 0);
|
||||
yield expandComputedViewPropertyByIndex(view, 0);
|
||||
|
||||
info("Verifying the link text");
|
||||
yield verifyLinkText(view, SCSS_LOC);
|
||||
|
@ -61,7 +61,7 @@ let test = asyncTest(function*() {
|
||||
function* testInlineStyle(view, inspector) {
|
||||
info("Testing inline style");
|
||||
|
||||
yield expandComputedViewPropertyByIndex(view, inspector, 0);
|
||||
yield expandComputedViewPropertyByIndex(view, 0);
|
||||
|
||||
let onWindow = waitForWindow();
|
||||
info("Clicking on the first rule-link in the computed-view");
|
||||
|
@ -35,6 +35,8 @@ let test = asyncTest(function*() {
|
||||
let {toolbox, inspector, view} = yield openComputedView();
|
||||
|
||||
yield testComputedView(view, inspector.selection.nodeFront);
|
||||
|
||||
yield testExpandedComputedViewProperty(view, inspector.selection.nodeFront);
|
||||
});
|
||||
|
||||
function* testRuleView(ruleView, nodeFront) {
|
||||
@ -77,3 +79,39 @@ function* testComputedView(computedView, nodeFront) {
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
||||
function* testExpandedComputedViewProperty(computedView, nodeFront) {
|
||||
info("Testing font-family tooltips in expanded properties of the computed view");
|
||||
|
||||
info("Expanding the font-family property to reveal matched selectors");
|
||||
let propertyView = getPropertyView(computedView, "font-family");
|
||||
propertyView.matchedExpanded = true;
|
||||
yield propertyView.refreshMatchedSelectors();
|
||||
|
||||
let valueSpan = propertyView.matchedSelectorsContainer
|
||||
.querySelector(".bestmatch .other-property-value");
|
||||
|
||||
let tooltip = computedView.tooltips.previewTooltip;
|
||||
let panel = tooltip.panel;
|
||||
|
||||
yield assertHoverTooltipOn(tooltip, valueSpan);
|
||||
|
||||
let images = panel.getElementsByTagName("image");
|
||||
is(images.length, 1, "Tooltip contains an image");
|
||||
ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri image as expected");
|
||||
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
||||
function getPropertyView(computedView, name) {
|
||||
let propertyView = null;
|
||||
computedView.propertyViews.some(function(view) {
|
||||
if (view.name == name) {
|
||||
propertyView = view;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return propertyView;
|
||||
}
|
||||
|
@ -28,11 +28,6 @@ let test = asyncTest(function*() {
|
||||
yield selectNode("#testElement", inspector);
|
||||
|
||||
yield testRuleView(view, inspector.selection.nodeFront);
|
||||
|
||||
info("Opening the computed view");
|
||||
let {toolbox, inspector, view} = yield openComputedView();
|
||||
|
||||
yield testComputedView(view, inspector.selection.nodeFront);
|
||||
});
|
||||
|
||||
function* testRuleView(ruleView, nodeFront) {
|
||||
@ -63,21 +58,3 @@ function* testRuleView(ruleView, nodeFront) {
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
||||
function* testComputedView(computedView, nodeFront) {
|
||||
info("Testing font-family tooltips in the computed view");
|
||||
|
||||
let tooltip = computedView.tooltips.previewTooltip;
|
||||
let panel = tooltip.panel;
|
||||
|
||||
let {valueSpan} = getComputedViewProperty(computedView, "font-family");
|
||||
|
||||
yield assertHoverTooltipOn(tooltip, valueSpan);
|
||||
|
||||
let images = panel.getElementsByTagName("image");
|
||||
is(images.length, 1, "Tooltip contains an image");
|
||||
ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri image as expected");
|
||||
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
@ -752,32 +752,6 @@ let createNewRuleViewProperty = Task.async(function*(ruleEditor, inputValue) {
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
// TO BE UNCOMMENTED WHEN THE EYEDROPPER FINALLY LANDS
|
||||
// /**
|
||||
// * Given a color swatch in the ruleview, click on it to open the color picker
|
||||
// * and then click on the eyedropper button to start the eyedropper tool
|
||||
// * @param {CssRuleView} view The instance of the rule-view panel
|
||||
// * @param {DOMNode} swatch The color swatch to be clicked on
|
||||
// * @return A promise that resolves when the dropper is opened
|
||||
// */
|
||||
// let openRuleViewEyeDropper = Task.async(function*(view, swatch) {
|
||||
// info("Opening the colorpicker tooltip on a colorswatch");
|
||||
// let tooltip = view.colorPicker.tooltip;
|
||||
// let onTooltipShown = tooltip.once("shown");
|
||||
// swatch.click();
|
||||
// yield onTooltipShown;
|
||||
|
||||
// info("Finding the eyedropper icon in the colorpicker document");
|
||||
// let tooltipDoc = tooltip.content.contentDocument;
|
||||
// let dropperButton = tooltipDoc.querySelector("#eyedropper-button");
|
||||
// ok(dropperButton, "Found the eyedropper icon");
|
||||
|
||||
// info("Opening the eyedropper");
|
||||
// let onOpen = tooltip.once("eyedropper-opened");
|
||||
// dropperButton.click();
|
||||
// return yield onOpen;
|
||||
// });
|
||||
|
||||
/* *********************************************
|
||||
* COMPUTED-VIEW
|
||||
* *********************************************
|
||||
@ -806,6 +780,40 @@ function getComputedViewProperty(view, name) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the property-content element for a given property name in
|
||||
* the computed-view.
|
||||
* A property-content element always follows (nextSibling) the property itself
|
||||
* and is only shown when the twisty icon is expanded on the property.
|
||||
* A property-content element contains matched rules, with selectors, properties,
|
||||
* values and stylesheet links
|
||||
* @param {CssHtmlTree} view The instance of the computed view panel
|
||||
* @param {String} name The name of the property to retrieve
|
||||
* @return {Promise} A promise that resolves to the property matched rules
|
||||
* container
|
||||
*/
|
||||
let getComputedViewMatchedRules = Task.async(function*(view, name) {
|
||||
let expander;
|
||||
let propertyContent;
|
||||
for (let property of view.styleDocument.querySelectorAll(".property-view")) {
|
||||
let nameSpan = property.querySelector(".property-name");
|
||||
if (nameSpan.textContent === name) {
|
||||
expander = property.querySelector(".expandable");
|
||||
propertyContent = property.nextSibling;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!expander.hasAttribute("open")) {
|
||||
// Need to expand the property
|
||||
let onExpand = view.inspector.once("computed-view-property-expanded");
|
||||
expander.click();
|
||||
yield onExpand;
|
||||
}
|
||||
|
||||
return propertyContent;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given name in the
|
||||
* computed-view
|
||||
@ -813,8 +821,8 @@ function getComputedViewProperty(view, name) {
|
||||
* @param {String} name The name of the property to retrieve
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getComputedViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getComputedViewProperty(view, selectorText, propertyName)
|
||||
function getComputedViewPropertyValue(view, name, propertyName) {
|
||||
return getComputedViewProperty(view, name, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
@ -822,19 +830,18 @@ function getComputedViewPropertyValue(view, selectorText, propertyName) {
|
||||
* Expand a given property, given its index in the current property list of
|
||||
* the computed view
|
||||
* @param {CssHtmlTree} view The instance of the computed view panel
|
||||
* @param {InspectorPanel} inspector The instance of the inspector panel
|
||||
* @param {Number} index The index of the property to be expanded
|
||||
* @return a promise that resolves when the property has been expanded, or
|
||||
* rejects if the property was not found
|
||||
*/
|
||||
function expandComputedViewPropertyByIndex(view, inspector, index) {
|
||||
function expandComputedViewPropertyByIndex(view, index) {
|
||||
info("Expanding property " + index + " in the computed view");
|
||||
let expandos = view.styleDocument.querySelectorAll(".expandable");
|
||||
if (!expandos.length || !expandos[index]) {
|
||||
return promise.reject();
|
||||
}
|
||||
|
||||
let onExpand = inspector.once("computed-view-property-expanded");
|
||||
let onExpand = view.inspector.once("computed-view-property-expanded");
|
||||
expandos[index].click();
|
||||
return onExpand;
|
||||
}
|
||||
|
@ -147,13 +147,18 @@ const HISTORY_FORWARD = 1;
|
||||
const GROUP_INDENT = 12;
|
||||
|
||||
// The number of messages to display in a single display update. If we display
|
||||
// too many messages at once we slow the Firefox UI too much.
|
||||
// too many messages at once we slow down the Firefox UI too much.
|
||||
const MESSAGES_IN_INTERVAL = DEFAULT_LOG_LIMIT;
|
||||
|
||||
// The delay between display updates - tells how often we should *try* to push
|
||||
// new messages to screen. This value is optimistic, updates won't always
|
||||
// happen. Keep this low so the Web Console output feels live.
|
||||
const OUTPUT_INTERVAL = 50; // milliseconds
|
||||
const OUTPUT_INTERVAL = 20; // milliseconds
|
||||
|
||||
// The maximum amount of time that can be spent doing cleanup inside of the
|
||||
// flush output callback. If things don't get cleaned up in this time,
|
||||
// then it will start again the next time it is called.
|
||||
const MAX_CLEANUP_TIME = 10; // milliseconds
|
||||
|
||||
// When the output queue has more than MESSAGES_IN_INTERVAL items we throttle
|
||||
// output updates to this number of milliseconds. So during a lot of output we
|
||||
@ -190,6 +195,7 @@ function WebConsoleFrame(aWebConsoleOwner)
|
||||
|
||||
this._repeatNodes = {};
|
||||
this._outputQueue = [];
|
||||
this._itemDestroyQueue = [];
|
||||
this._pruneCategoriesQueue = {};
|
||||
this._networkRequests = {};
|
||||
this.filterPrefs = {};
|
||||
@ -2048,9 +2054,7 @@ WebConsoleFrame.prototype = {
|
||||
|
||||
this._outputQueue.push([aCategory, aMethodOrNode, aArguments]);
|
||||
|
||||
if (!this._outputTimerInitialized) {
|
||||
this._initOutputTimer();
|
||||
}
|
||||
this._initOutputTimer();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2062,21 +2066,31 @@ WebConsoleFrame.prototype = {
|
||||
*/
|
||||
_flushMessageQueue: function WCF__flushMessageQueue()
|
||||
{
|
||||
this._outputTimerInitialized = false;
|
||||
if (!this._outputTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
let timeSinceFlush = Date.now() - this._lastOutputFlush;
|
||||
if (this._outputQueue.length > MESSAGES_IN_INTERVAL &&
|
||||
timeSinceFlush < THROTTLE_UPDATES) {
|
||||
this._initOutputTimer();
|
||||
return;
|
||||
}
|
||||
let startTime = Date.now();
|
||||
let timeSinceFlush = startTime - this._lastOutputFlush;
|
||||
let shouldThrottle = this._outputQueue.length > MESSAGES_IN_INTERVAL &&
|
||||
timeSinceFlush < THROTTLE_UPDATES;
|
||||
|
||||
// Determine how many messages we can display now.
|
||||
let toDisplay = Math.min(this._outputQueue.length, MESSAGES_IN_INTERVAL);
|
||||
if (toDisplay < 1) {
|
||||
this._outputTimerInitialized = false;
|
||||
|
||||
// If there aren't any messages to display (because of throttling or an
|
||||
// empty queue), then take care of some cleanup. Destroy items that were
|
||||
// pruned from the outputQueue before being displayed.
|
||||
if (shouldThrottle || toDisplay < 1) {
|
||||
while (this._itemDestroyQueue.length) {
|
||||
if ((Date.now() - startTime) > MAX_CLEANUP_TIME) {
|
||||
break;
|
||||
}
|
||||
this._destroyItem(this._itemDestroyQueue.pop());
|
||||
}
|
||||
|
||||
this._initOutputTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2088,21 +2102,22 @@ WebConsoleFrame.prototype = {
|
||||
}
|
||||
|
||||
let batch = this._outputQueue.splice(0, toDisplay);
|
||||
if (!batch.length) {
|
||||
this._outputTimerInitialized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let outputNode = this.outputNode;
|
||||
let lastVisibleNode = null;
|
||||
let scrollNode = outputNode.parentNode;
|
||||
let scrolledToBottom = Utils.isOutputScrolledToBottom(outputNode);
|
||||
let hudIdSupportsString = WebConsoleUtils.supportsString(this.hudId);
|
||||
|
||||
// We won't bother to try to restore scroll position if this is showing
|
||||
// a lot of messages at once (and there are still items in the queue).
|
||||
// It is going to purge whatever you were looking at anyway.
|
||||
let scrolledToBottom = shouldPrune ||
|
||||
Utils.isOutputScrolledToBottom(outputNode);
|
||||
|
||||
// Output the current batch of messages.
|
||||
let newMessages = new Set();
|
||||
let updatedMessages = new Set();
|
||||
for (let item of batch) {
|
||||
for (let i = 0; i < batch.length; i++) {
|
||||
let item = batch[i];
|
||||
let result = this._outputMessageFromQueue(hudIdSupportsString, item);
|
||||
if (result) {
|
||||
if (result.isRepeated) {
|
||||
@ -2118,12 +2133,15 @@ WebConsoleFrame.prototype = {
|
||||
}
|
||||
|
||||
let oldScrollHeight = 0;
|
||||
|
||||
// Prune messages if needed. We do not do this for every flush call to
|
||||
// improve performance.
|
||||
let removedNodes = 0;
|
||||
|
||||
// Prune messages from the DOM, but only if needed.
|
||||
if (shouldPrune || !this._outputQueue.length) {
|
||||
oldScrollHeight = scrollNode.scrollHeight;
|
||||
// Only bother measuring the scrollHeight if not scrolled to bottom,
|
||||
// since the oldScrollHeight will not be used if it is.
|
||||
if (!scrolledToBottom) {
|
||||
oldScrollHeight = scrollNode.scrollHeight;
|
||||
}
|
||||
|
||||
let categories = Object.keys(this._pruneCategoriesQueue);
|
||||
categories.forEach(function _pruneOutput(aCategory) {
|
||||
@ -2156,17 +2174,15 @@ WebConsoleFrame.prototype = {
|
||||
this.emit("messages-updated", updatedMessages);
|
||||
}
|
||||
|
||||
// If the queue is not empty, schedule another flush.
|
||||
if (this._outputQueue.length > 0) {
|
||||
this._initOutputTimer();
|
||||
}
|
||||
else {
|
||||
this._outputTimerInitialized = false;
|
||||
if (this._flushCallback && this._flushCallback() === false) {
|
||||
// If the output queue is empty, then run _flushCallback.
|
||||
if (this._outputQueue.length === 0 && this._flushCallback) {
|
||||
if (this._flushCallback() === false) {
|
||||
this._flushCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
this._initOutputTimer();
|
||||
|
||||
this._lastOutputFlush = Date.now();
|
||||
},
|
||||
|
||||
@ -2176,7 +2192,13 @@ WebConsoleFrame.prototype = {
|
||||
*/
|
||||
_initOutputTimer: function WCF__initOutputTimer()
|
||||
{
|
||||
if (!this._outputTimer) {
|
||||
let panelIsDestroyed = !this._outputTimer;
|
||||
let alreadyScheduled = this._outputTimerInitialized;
|
||||
let nothingToDo = !this._itemDestroyQueue.length &&
|
||||
!this._outputQueue.length;
|
||||
|
||||
// Don't schedule a callback in the following cases:
|
||||
if (panelIsDestroyed || alreadyScheduled || nothingToDo) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2274,7 +2296,7 @@ WebConsoleFrame.prototype = {
|
||||
let n = Math.max(0, indexes.length - limit);
|
||||
pruned += n;
|
||||
for (let i = n - 1; i >= 0; i--) {
|
||||
this._pruneItemFromQueue(this._outputQueue[indexes[i]]);
|
||||
this._itemDestroyQueue.push(this._outputQueue[indexes[i]]);
|
||||
this._outputQueue.splice(indexes[i], 1);
|
||||
}
|
||||
}
|
||||
@ -2284,17 +2306,18 @@ WebConsoleFrame.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Prune an item from the output queue.
|
||||
* Destroy an item that was once in the outputQueue but isn't needed
|
||||
* after all.
|
||||
*
|
||||
* @private
|
||||
* @param array aItem
|
||||
* The item you want to remove from the output queue.
|
||||
* The item you want to destroy. Does not remove it from the output
|
||||
* queue.
|
||||
*/
|
||||
_pruneItemFromQueue: function WCF__pruneItemFromQueue(aItem)
|
||||
_destroyItem: function WCF__destroyItem(aItem)
|
||||
{
|
||||
// TODO: handle object releasing in a more elegant way once all console
|
||||
// messages use the new API - bug 778766.
|
||||
|
||||
let [category, methodOrNode, args] = aItem;
|
||||
if (typeof methodOrNode != "function" && methodOrNode._objectActors) {
|
||||
for (let actor of methodOrNode._objectActors) {
|
||||
@ -2370,9 +2393,7 @@ WebConsoleFrame.prototype = {
|
||||
let messageNodes = this.outputNode.querySelectorAll(".message[category=" +
|
||||
CATEGORY_CLASS_FRAGMENTS[aCategory] + "]");
|
||||
let n = Math.max(0, messageNodes.length - logLimit);
|
||||
let toRemove = Array.prototype.slice.call(messageNodes, 0, n);
|
||||
toRemove.forEach(this.removeOutputMessage, this);
|
||||
|
||||
[...messageNodes].slice(0, n).forEach(this.removeOutputMessage, this);
|
||||
return n;
|
||||
},
|
||||
|
||||
@ -2415,9 +2436,7 @@ WebConsoleFrame.prototype = {
|
||||
aNode._variablesView = null;
|
||||
}
|
||||
|
||||
if (aNode.parentNode) {
|
||||
aNode.parentNode.removeChild(aNode);
|
||||
}
|
||||
aNode.remove();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2897,7 +2916,10 @@ WebConsoleFrame.prototype = {
|
||||
gDevTools.off("pref-changed", this._onToolboxPrefChanged);
|
||||
|
||||
this._repeatNodes = {};
|
||||
this._outputQueue.forEach(this._destroyItem, this);
|
||||
this._outputQueue = [];
|
||||
this._itemDestroyQueue.forEach(this._destroyItem, this);
|
||||
this._itemDestroyQueue = [];
|
||||
this._pruneCategoriesQueue = {};
|
||||
this._networkRequests = {};
|
||||
|
||||
@ -2906,7 +2928,6 @@ WebConsoleFrame.prototype = {
|
||||
this._outputTimer.cancel();
|
||||
}
|
||||
this._outputTimer = null;
|
||||
|
||||
if (this.jsterm) {
|
||||
this.jsterm.destroy();
|
||||
this.jsterm = null;
|
||||
@ -3787,7 +3808,7 @@ JSTerm.prototype = {
|
||||
}
|
||||
|
||||
hud.groupDepth = 0;
|
||||
hud._outputQueue.forEach(hud._pruneItemFromQueue, hud);
|
||||
hud._outputQueue.forEach(hud._destroyItem, hud);
|
||||
hud._outputQueue = [];
|
||||
hud._networkRequests = {};
|
||||
hud._repeatNodes = {};
|
||||
|
@ -89,6 +89,7 @@ SimulatorRuntime.prototype = {
|
||||
return promise.reject("Can't find simulator: " + this.getName());
|
||||
}
|
||||
return simulator.launch({port: port}).then(() => {
|
||||
connection.host = "localhost";
|
||||
connection.port = port;
|
||||
connection.keepConnecting = true;
|
||||
connection.once(Connection.Events.DISCONNECTED, simulator.close);
|
||||
@ -109,8 +110,8 @@ let gLocalRuntime = {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
connection.port = null;
|
||||
connection.host = null; // Force Pipe transport
|
||||
connection.port = null;
|
||||
connection.connect();
|
||||
return promise.resolve();
|
||||
},
|
||||
|
Before Width: | Height: | Size: 883 B After Width: | Height: | Size: 874 B |
Before Width: | Height: | Size: 811 B After Width: | Height: | Size: 742 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.2 KiB |
@ -1051,6 +1051,9 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
nsCOMPtr<EventTarget> otherChromeEventHandler =
|
||||
do_QueryInterface(otherWindow->GetChromeEventHandler());
|
||||
|
||||
nsCOMPtr<EventTarget> ourEventTarget = ourWindow->GetParentTarget();
|
||||
nsCOMPtr<EventTarget> otherEventTarget = otherWindow->GetParentTarget();
|
||||
|
||||
NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
|
||||
SameCOMIdentity(otherFrameElement, otherContent) &&
|
||||
SameCOMIdentity(ourChromeEventHandler, ourContent) &&
|
||||
@ -1100,25 +1103,25 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
// Fire pageshow events on still-loading pages, and then fire pagehide
|
||||
// events. Note that we do NOT fire these in the normal way, but just fire
|
||||
// them on the chrome event handlers.
|
||||
FirePageShowEvent(ourDocshell, ourChromeEventHandler, false);
|
||||
FirePageShowEvent(otherDocshell, otherChromeEventHandler, false);
|
||||
FirePageHideEvent(ourDocshell, ourChromeEventHandler);
|
||||
FirePageHideEvent(otherDocshell, otherChromeEventHandler);
|
||||
FirePageShowEvent(ourDocshell, ourEventTarget, false);
|
||||
FirePageShowEvent(otherDocshell, otherEventTarget, false);
|
||||
FirePageHideEvent(ourDocshell, ourEventTarget);
|
||||
FirePageHideEvent(otherDocshell, otherEventTarget);
|
||||
|
||||
nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
|
||||
nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
|
||||
if (!ourFrame || !otherFrame) {
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
|
||||
FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
|
||||
FirePageShowEvent(ourDocshell, ourEventTarget, true);
|
||||
FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
|
||||
if (!ourFrameFrame) {
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
|
||||
FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
|
||||
FirePageShowEvent(ourDocshell, ourEventTarget, true);
|
||||
FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@ -1126,8 +1129,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
|
||||
FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
|
||||
FirePageShowEvent(ourDocshell, ourEventTarget, true);
|
||||
FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1230,8 +1233,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
ourParentDocument->FlushPendingNotifications(Flush_Layout);
|
||||
otherParentDocument->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
FirePageShowEvent(ourDocshell, otherChromeEventHandler, true);
|
||||
FirePageShowEvent(otherDocshell, ourChromeEventHandler, true);
|
||||
FirePageShowEvent(ourDocshell, ourEventTarget, true);
|
||||
FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
return NS_OK;
|
||||
|
@ -7,3 +7,5 @@ skip-if = e10s # Bug ?????? - test e10s utils don't support load events from ifr
|
||||
[browser_state_notifications.js]
|
||||
# skip-if = e10s # Bug ?????? - content-document-* notifications come while document's URI is still about:blank, but test expects real URL.
|
||||
skip-if = true # Intermittent failures - bug 987493. Restore the skip-if above once fixed
|
||||
[browser_bug1058164.js]
|
||||
skip-if = e10s # We need bug 918634 to land before this can be tested with e10s.
|
||||
|
106
content/base/test/browser_bug1058164.js
Normal file
@ -0,0 +1,106 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const kTimeout = 5000; // ms
|
||||
|
||||
/**
|
||||
* Frame script injected in the test browser that sends
|
||||
* messages when it sees the pagehide and pageshow events
|
||||
* with the persisted property set to true.
|
||||
*/
|
||||
function frame_script() {
|
||||
addEventListener("pageshow", (event) => {
|
||||
if (event.persisted) {
|
||||
sendAsyncMessage("test:pageshow");
|
||||
}
|
||||
});
|
||||
addEventListener("pagehide", (event) => {
|
||||
if (event.persisted) {
|
||||
sendAsyncMessage("test:pagehide");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Promise that resolves when the browser's frame
|
||||
* script sees an event of type eventType. eventType can be
|
||||
* either "pagehide" or "pageshow". Times out after kTimeout
|
||||
* milliseconds if the event is never seen.
|
||||
*/
|
||||
function prepareForPageEvent(browser, eventType) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let mm = browser.messageManager;
|
||||
|
||||
let timeoutId = setTimeout(() => {
|
||||
ok(false, "Timed out waiting for " + eventType)
|
||||
reject();
|
||||
}, kTimeout);
|
||||
|
||||
mm.addMessageListener("test:" + eventType, function onSawEvent(message) {
|
||||
mm.removeMessageListener("test:" + eventType, onSawEvent);
|
||||
ok(true, "Saw " + eventType + " event in frame script.");
|
||||
clearTimeout(timeoutId);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves when both the pagehide
|
||||
* and pageshow events have been seen from the frame script.
|
||||
*/
|
||||
function prepareForPageHideAndShow(browser) {
|
||||
return Promise.all([prepareForPageEvent(browser, "pagehide"),
|
||||
prepareForPageEvent(browser, "pageshow")]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves when the load event for
|
||||
* aWindow fires during the capture phase.
|
||||
*/
|
||||
function waitForLoad(aWindow) {
|
||||
return new Promise((resolve, reject) => {
|
||||
aWindow.addEventListener("load", function onLoad(aEvent) {
|
||||
aWindow.removeEventListener("load", onLoad, true);
|
||||
resolve();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that frame scripts get pageshow / pagehide events when
|
||||
* swapping browser frameloaders (which occurs when moving a tab
|
||||
* into a different window).
|
||||
*/
|
||||
add_task(function* test_swap_frameloader_pagevisibility_events() {
|
||||
// Inject our frame script into a new browser.
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let mm = window.getGroupMessageManager("browsers");
|
||||
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
// Swap the browser out to a new window
|
||||
let newWindow = gBrowser.replaceTabWithWindow(tab);
|
||||
// We have to wait for the window to load so we can get the selected browser
|
||||
// to listen to.
|
||||
yield waitForLoad(newWindow);
|
||||
let pageHideAndShowPromise = prepareForPageHideAndShow(newWindow.gBrowser.selectedBrowser);
|
||||
// Yield waiting for the pagehide and pageshow events.
|
||||
yield pageHideAndShowPromise;
|
||||
|
||||
// Send the browser back to its original window
|
||||
let newTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = newTab;
|
||||
browser = newWindow.gBrowser.selectedBrowser;
|
||||
pageHideAndShowPromise = prepareForPageHideAndShow(gBrowser.selectedBrowser);
|
||||
gBrowser.swapBrowsersAndCloseOther(newTab, newWindow.gBrowser.selectedTab);
|
||||
|
||||
// Yield waiting for the pagehide and pageshow events.
|
||||
yield pageHideAndShowPromise;
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
});
|
@ -5,12 +5,15 @@
|
||||
|
||||
#include "domstubs.idl"
|
||||
interface nsIContentFrameMessageManager;
|
||||
interface nsIWebBrowserChrome3;
|
||||
|
||||
[scriptable, uuid(2eb3bc54-78bf-40f2-b301-a5b5b70f7da0)]
|
||||
interface nsITabChild : nsISupports
|
||||
{
|
||||
readonly attribute nsIContentFrameMessageManager messageManager;
|
||||
|
||||
attribute nsIWebBrowserChrome3 webBrowserChrome;
|
||||
|
||||
[notxpcom] void sendRequestFocus(in boolean canFocus);
|
||||
};
|
||||
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "UnitTransforms.h"
|
||||
#include "ClientLayerManager.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "nsIWebBrowserChrome3.h"
|
||||
|
||||
#include "nsColorPickerProxy.h"
|
||||
|
||||
@ -205,12 +206,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TabChildBase)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChildGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousGlobalScopes)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebBrowserChrome)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TabChildBase)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChildGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebBrowserChrome)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TabChildBase)
|
||||
@ -1314,6 +1317,11 @@ TabChild::FocusPrevElement()
|
||||
NS_IMETHODIMP
|
||||
TabChild::GetInterface(const nsIID & aIID, void **aSink)
|
||||
{
|
||||
if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome3))) {
|
||||
NS_IF_ADDREF(((nsISupports *) (*aSink = mWebBrowserChrome)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXXbz should we restrict the set of interfaces we hand out here?
|
||||
// See bug 537429
|
||||
return QueryInterface(aIID, aSink);
|
||||
@ -2840,6 +2848,20 @@ TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabChild::GetWebBrowserChrome(nsIWebBrowserChrome3** aWebBrowserChrome)
|
||||
{
|
||||
NS_IF_ADDREF(*aWebBrowserChrome = mWebBrowserChrome);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabChild::SetWebBrowserChrome(nsIWebBrowserChrome3* aWebBrowserChrome)
|
||||
{
|
||||
mWebBrowserChrome = aWebBrowserChrome;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::SendRequestFocus(bool aCanFocus)
|
||||
{
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "nsIWebBrowserChrome3.h"
|
||||
|
||||
class nsICachedFileDescriptorListener;
|
||||
class nsIDOMWindowUtils;
|
||||
@ -224,6 +225,7 @@ protected:
|
||||
ScreenIntSize mInnerSize;
|
||||
mozilla::layers::FrameMetrics mLastRootMetrics;
|
||||
mozilla::layout::ScrollingBehavior mScrolling;
|
||||
nsCOMPtr<nsIWebBrowserChrome3> mWebBrowserChrome;
|
||||
};
|
||||
|
||||
class TabChild MOZ_FINAL : public TabChildBase,
|
||||
|
@ -9,7 +9,7 @@ random != boxshadow-blur-2.html boxshadow-blur-2-notref.html # fixedpoint divisi
|
||||
== tableboxshadow-trshadow.html tableboxshadow-trshadow-ref.html
|
||||
== tableboxshadow-tdshadow.html tableboxshadow-tdshadow-ref.html
|
||||
== boxshadow-rounding.html boxshadow-rounding-ref.html
|
||||
fails-if(Android||B2G) == boxshadow-button.html boxshadow-button-ref.html
|
||||
fails-if(B2G) == boxshadow-button.html boxshadow-button-ref.html
|
||||
fails-if(Android||B2G) == boxshadow-fileupload.html boxshadow-fileupload-ref.html
|
||||
== boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
|
||||
random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
|
||||
@ -25,7 +25,7 @@ random-if(d2d) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
|
||||
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
|
||||
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
|
||||
== overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
|
||||
fails-if(Android||B2G) == 611574-1.html 611574-1-ref.html
|
||||
fails-if(Android||B2G) == 611574-2.html 611574-2-ref.html
|
||||
fails-if(B2G) == 611574-1.html 611574-1-ref.html
|
||||
fails-if(B2G) == 611574-2.html 611574-2-ref.html
|
||||
fuzzy-if(winWidget,5,30) == fieldset.html fieldset-ref.html # minor anti-aliasing problem on Windows
|
||||
fuzzy-if(winWidget,5,30) == fieldset-inset.html fieldset-inset-ref.html # minor anti-aliasing problem on Windows
|
||||
|
@ -1305,9 +1305,9 @@ skip-if(B2G) == 478811-1.html 478811-1-ref.html
|
||||
== 480880-2a.html about:blank
|
||||
== 480880-2b.html about:blank
|
||||
== 480880-2c.html about:blank
|
||||
skip-if(B2G) fails-if(Android) == 481024-1a.html 481024-1-ref.html
|
||||
skip-if(B2G) fails-if(Android) == 481024-1b.html 481024-1-ref.html
|
||||
skip-if(B2G) fails-if(Android) == 481024-1c.html 481024-1-ref.html
|
||||
skip-if(B2G) == 481024-1a.html 481024-1-ref.html
|
||||
skip-if(B2G) == 481024-1b.html 481024-1-ref.html
|
||||
skip-if(B2G) == 481024-1c.html 481024-1-ref.html
|
||||
== 481024-1d.html 481024-1-ref.html
|
||||
== 481024-1e.html 481024-1-ref.html
|
||||
!= 481948-1.html 481948-1-ref.html
|
||||
@ -1501,7 +1501,7 @@ skip-if(B2G) fails-if(Android) == 557087-2.html 557087-ref.html
|
||||
== 557736-1.html 557736-1-ref.html
|
||||
skip-if(B2G&&browserIsRemote) != 558011-1.xul 558011-1-ref.xul # bug 974780
|
||||
== 559284-1.html 559284-1-ref.html
|
||||
skip-if(B2G) fails-if(Android) == 560455-1.xul 560455-1-ref.xul
|
||||
skip-if(B2G) == 560455-1.xul 560455-1-ref.xul
|
||||
== 561981-1.html 561981-1-ref.html
|
||||
== 561981-2.html 561981-2-ref.html
|
||||
== 561981-3.html 561981-3-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== input-valid.html input-ref.html
|
||||
fuzzy(11,4) == input-customerror.html input-ref.html
|
||||
skip-if(B2G) fails-if(Android) == input-disabled.html input-ref.html
|
||||
skip-if(B2G) fails-if(Android) == input-dyn-disabled.html input-ref.html
|
||||
skip-if(B2G) == input-disabled.html input-ref.html
|
||||
skip-if(B2G) == input-dyn-disabled.html input-ref.html
|
||||
== input-dyn-not-disabled.html input-ref.html
|
||||
== input-readonly.html input-ref.html
|
||||
== input-dyn-readonly.html input-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== textarea-valid.html textarea-ref.html
|
||||
== textarea-customerror.html textarea-ref.html
|
||||
fails-if(Android||B2G) == textarea-disabled.html textarea-ref.html
|
||||
fails-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
fails-if(B2G) == textarea-disabled.html textarea-ref.html
|
||||
fails-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
== textarea-dyn-not-disabled.html textarea-ref.html
|
||||
== textarea-readonly.html textarea-ref.html
|
||||
== textarea-dyn-readonly.html textarea-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== input-valid.html input-ref.html
|
||||
fuzzy(64,4) == input-customerror.html input-ref.html
|
||||
skip-if(B2G) fails-if(Android) == input-disabled.html input-ref.html
|
||||
skip-if(B2G) fails-if(Android) == input-dyn-disabled.html input-ref.html
|
||||
skip-if(B2G) == input-disabled.html input-ref.html
|
||||
skip-if(B2G) == input-dyn-disabled.html input-ref.html
|
||||
== input-dyn-not-disabled.html input-ref.html
|
||||
== input-readonly.html input-ref.html
|
||||
== input-dyn-readonly.html input-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== textarea-valid.html textarea-ref.html
|
||||
== textarea-customerror.html textarea-ref.html
|
||||
skip-if(B2G) fails-if(Android) == textarea-disabled.html textarea-ref.html
|
||||
fails-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
skip-if(B2G) == textarea-disabled.html textarea-ref.html
|
||||
fails-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
== textarea-dyn-not-disabled.html textarea-ref.html
|
||||
== textarea-readonly.html textarea-ref.html
|
||||
== textarea-dyn-readonly.html textarea-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== input-valid.html input-ref.html
|
||||
fuzzy(11,4) == input-customerror.html input-ref.html
|
||||
fails-if(Android||B2G) == input-disabled.html input-ref.html
|
||||
fails-if(Android||B2G) == input-dyn-disabled.html input-ref.html
|
||||
fails-if(B2G) == input-disabled.html input-ref.html
|
||||
fails-if(B2G) == input-dyn-disabled.html input-ref.html
|
||||
== input-dyn-not-disabled.html input-ref.html
|
||||
== input-dyn-not-disabled-changed.html input-ref.html
|
||||
== input-readonly.html input-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== textarea-valid.html textarea-ref.html
|
||||
== textarea-customerror.html textarea-ref.html
|
||||
fails-if(Android||B2G) == textarea-disabled.html textarea-ref.html
|
||||
random-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
fails-if(B2G) == textarea-disabled.html textarea-ref.html
|
||||
random-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
== textarea-dyn-not-disabled.html textarea-ref.html
|
||||
== textarea-dyn-not-disabled-changed.html textarea-ref.html
|
||||
== textarea-readonly.html textarea-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== input-valid.html input-ref.html
|
||||
fuzzy(64,4) == input-customerror.html input-ref.html
|
||||
fails-if(Android||B2G) == input-disabled.html input-ref.html
|
||||
fails-if(Android||B2G) == input-dyn-disabled.html input-ref.html
|
||||
fails-if(B2G) == input-disabled.html input-ref.html
|
||||
fails-if(B2G) == input-dyn-disabled.html input-ref.html
|
||||
== input-dyn-not-disabled.html input-ref.html
|
||||
== input-readonly.html input-ref.html
|
||||
== input-dyn-readonly.html input-ref.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
== textarea-valid.html textarea-ref.html
|
||||
== textarea-customerror.html textarea-ref.html
|
||||
fails-if(Android||B2G) == textarea-disabled.html textarea-ref.html
|
||||
fails-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
fails-if(B2G) == textarea-disabled.html textarea-ref.html
|
||||
fails-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
|
||||
== textarea-dyn-not-disabled.html textarea-ref.html
|
||||
== textarea-readonly.html textarea-ref.html
|
||||
== textarea-dyn-readonly.html textarea-ref.html
|
||||
|
@ -3,6 +3,6 @@ fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,128) skip-if(B2G&&browserIsRemote) =
|
||||
fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,64) skip-if(B2G&&browserIsRemote) == rtl.html rtl-ref.xul # bug 974780
|
||||
fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,128) skip-if(B2G&&browserIsRemote) == size.html simple-ref.xul # bug 974780
|
||||
fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,64) skip-if(B2G&&browserIsRemote) == background.html background-ref.xul # bug 974780
|
||||
fails-if(B2G||Android) skip-if(B2G&&browserIsRemote) == style.html style-ref.xul # bug 974780
|
||||
fails-if(B2G) skip-if(B2G&&browserIsRemote) == style.html style-ref.xul # bug 974780
|
||||
!= width-clip.html width-clip-ref.html
|
||||
fails-if(B2G||Android) == color-inherit.html color-inherit-ref.html
|
||||
|
@ -1,6 +1,6 @@
|
||||
== bounds-1.html bounds-1-ref.html
|
||||
== size-1.html size-1-ref.html
|
||||
skip-if(B2G) fails-if(Android) == size-2.html size-2-ref.html
|
||||
skip-if(B2G) == size-2.html size-2-ref.html
|
||||
HTTP(..) == baseline-1.html baseline-1-ref.html
|
||||
skip-if(B2G&&browserIsRemote) HTTP(..) == centering-1.xul centering-1-ref.xul # bug 974780
|
||||
skip-if(B2G&&browserIsRemote) == dynamic-height-1.xul dynamic-height-1-ref.xul # bug 974780
|
||||
|
@ -1,4 +1,4 @@
|
||||
skip-if(B2G) fails-if(Android) HTTP(..) == text-control-baseline-1.html text-control-baseline-1-ref.html
|
||||
skip-if(B2G) HTTP(..) == text-control-baseline-1.html text-control-baseline-1-ref.html
|
||||
|
||||
# button element
|
||||
include button/reftest.list
|
||||
|
@ -25,7 +25,7 @@ fails-if(!nativeThemePref) != radio-native.html radio-nonnative.html
|
||||
== radio-still-native-when-styled.html radio-still-native-when-styled-ref.html
|
||||
fails-if(!nativeThemePref) != checkbox-native.html checkbox-nonnative.html
|
||||
== checkbox-still-native-when-styled.html checkbox-still-native-when-styled-ref.html
|
||||
fails-if(Android) == native-theme-disabled-cascade-levels.html native-theme-disabled-cascade-levels-ref.html
|
||||
== native-theme-disabled-cascade-levels.html native-theme-disabled-cascade-levels-ref.html
|
||||
|
||||
!= 427122-1.html 427122-1-ref.html
|
||||
|
||||
|
@ -444,6 +444,9 @@ pref("dom.max_script_run_time", 20);
|
||||
|
||||
// JS error console
|
||||
pref("devtools.errorconsole.enabled", false);
|
||||
// Absolute path to the devtools unix domain socket file used
|
||||
// to communicate with a usb cable via adb forward.
|
||||
pref("devtools.debugger.unix-domain-socket", "/data/data/@ANDROID_PACKAGE_NAME@/firefox-debugger-socket");
|
||||
|
||||
pref("font.size.inflation.minTwips", 120);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
for var in ('APP_NAME', 'APP_VERSION'):
|
||||
DEFINES[var] = CONFIG['MOZ_%s' % var]
|
||||
|
||||
for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME'):
|
||||
for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME', 'ANDROID_PACKAGE_NAME'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
if CONFIG['MOZ_PKG_SPECIAL']:
|
||||
|
@ -100,6 +100,7 @@ import android.nfc.NfcAdapter;
|
||||
import android.nfc.NfcEvent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.StrictMode;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
@ -279,10 +280,37 @@ public class BrowserApp extends GeckoApp
|
||||
loadFavicon(tab);
|
||||
}
|
||||
break;
|
||||
case BOOKMARK_ADDED:
|
||||
showBookmarkAddedToast();
|
||||
break;
|
||||
case BOOKMARK_REMOVED:
|
||||
showBookmarkRemovedToast();
|
||||
break;
|
||||
}
|
||||
super.onTabChanged(tab, msg, data);
|
||||
}
|
||||
|
||||
private void showBookmarkAddedToast() {
|
||||
getButtonToast().show(false,
|
||||
getResources().getString(R.string.bookmark_added),
|
||||
ButtonToast.LENGTH_SHORT,
|
||||
getResources().getString(R.string.bookmark_options),
|
||||
null,
|
||||
new ButtonToast.ToastListener() {
|
||||
@Override
|
||||
public void onButtonClicked() {
|
||||
showBookmarkDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToastHidden(ButtonToast.ReasonHidden reason) { }
|
||||
});
|
||||
}
|
||||
|
||||
private void showBookmarkRemovedToast() {
|
||||
Toast.makeText(this, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (AndroidGamepadManager.handleKeyEvent(event)) {
|
||||
@ -607,7 +635,7 @@ public class BrowserApp extends GeckoApp
|
||||
Method init = mediaManagerClass.getMethod("init", Context.class);
|
||||
init.invoke(null, this);
|
||||
} catch(Exception ex) {
|
||||
Log.i(LOGTAG, "Error initializing media manager", ex);
|
||||
Log.e(LOGTAG, "Error initializing media manager", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -637,7 +665,7 @@ public class BrowserApp extends GeckoApp
|
||||
return Class.forName("org.mozilla.gecko.MediaPlayerManager");
|
||||
} catch(Exception ex) {
|
||||
// Ignore failures
|
||||
Log.i(LOGTAG, "No native casting support", ex);
|
||||
Log.e(LOGTAG, "No native casting support", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -859,7 +887,7 @@ public class BrowserApp extends GeckoApp
|
||||
try {
|
||||
args.put("tabId", tab.getId());
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "error building json arguments");
|
||||
Log.e(LOGTAG, "error building json arguments", e);
|
||||
}
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Feeds:Subscribe", args.toString()));
|
||||
if (Versions.preHC) {
|
||||
@ -877,7 +905,7 @@ public class BrowserApp extends GeckoApp
|
||||
try {
|
||||
args.put("tabId", tab.getId());
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "error building json arguments");
|
||||
Log.e(LOGTAG, "error building json arguments", e);
|
||||
return true;
|
||||
}
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Add", args.toString()));
|
||||
@ -1003,7 +1031,7 @@ public class BrowserApp extends GeckoApp
|
||||
Method destroy = mediaManagerClass.getMethod("onDestroy", (Class[]) null);
|
||||
destroy.invoke(null);
|
||||
} catch(Exception ex) {
|
||||
Log.i(LOGTAG, "Error destroying media manager", ex);
|
||||
Log.e(LOGTAG, "Error destroying media manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1864,9 +1892,6 @@ public class BrowserApp extends GeckoApp
|
||||
* {@link BrowserHealthRecorder#SEARCH_LOCATIONS}.
|
||||
*/
|
||||
private static void recordSearch(SearchEngine engine, String where) {
|
||||
Log.i(LOGTAG, "Recording search: " +
|
||||
((engine == null) ? "null" : engine.name) +
|
||||
", " + where);
|
||||
try {
|
||||
String identifier = (engine == null) ? "other" : engine.getEngineIdentifier();
|
||||
JSONObject message = new JSONObject();
|
||||
@ -1875,7 +1900,7 @@ public class BrowserApp extends GeckoApp
|
||||
message.put("identifier", identifier);
|
||||
EventDispatcher.getInstance().dispatchEvent(message, null);
|
||||
} catch (Exception e) {
|
||||
Log.w(LOGTAG, "Error recording search.", e);
|
||||
Log.e(LOGTAG, "Error recording search.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2269,7 +2294,6 @@ public class BrowserApp extends GeckoApp
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
Log.i(LOGTAG, "Menu item clicked");
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Menu:Clicked", Integer.toString(info.id - ADDON_MENU_OFFSET)));
|
||||
return true;
|
||||
}
|
||||
@ -2620,25 +2644,10 @@ public class BrowserApp extends GeckoApp
|
||||
if (item.isChecked()) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.MENU, "bookmark");
|
||||
tab.removeBookmark();
|
||||
Toast.makeText(this, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
|
||||
item.setIcon(R.drawable.ic_menu_bookmark_add);
|
||||
} else {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, "bookmark");
|
||||
tab.addBookmark();
|
||||
getButtonToast().show(false,
|
||||
getResources().getString(R.string.bookmark_added),
|
||||
ButtonToast.LENGTH_SHORT,
|
||||
getResources().getString(R.string.bookmark_options),
|
||||
null,
|
||||
new ButtonToast.ToastListener() {
|
||||
@Override
|
||||
public void onButtonClicked() {
|
||||
showBookmarkDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToastHidden(ButtonToast.ReasonHidden reason) { }
|
||||
});
|
||||
item.setIcon(R.drawable.ic_menu_bookmark_remove);
|
||||
}
|
||||
}
|
||||
@ -2729,7 +2738,7 @@ public class BrowserApp extends GeckoApp
|
||||
args.put("desktopMode", !item.isChecked());
|
||||
args.put("tabId", selectedTab.getId());
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "error building json arguments");
|
||||
Log.e(LOGTAG, "error building json arguments", e);
|
||||
}
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("DesktopMode:Change", args.toString()));
|
||||
return true;
|
||||
@ -2859,30 +2868,27 @@ public class BrowserApp extends GeckoApp
|
||||
return;
|
||||
}
|
||||
|
||||
(new UIAsyncTask.WithoutParams<Boolean>(ThreadUtils.getBackgroundHandler()) {
|
||||
@Override
|
||||
public synchronized Boolean doInBackground() {
|
||||
// Check to see how many times the app has been launched.
|
||||
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
|
||||
String keyName = getPackageName() + ".feedback_launch_count";
|
||||
int launchCount = settings.getInt(keyName, 0);
|
||||
if (launchCount >= FEEDBACK_LAUNCH_COUNT)
|
||||
return false;
|
||||
// Check to see how many times the app has been launched.
|
||||
final String keyName = getPackageName() + ".feedback_launch_count";
|
||||
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
|
||||
|
||||
// Faster on main thread with an async apply().
|
||||
try {
|
||||
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
|
||||
int launchCount = settings.getInt(keyName, 0);
|
||||
if (launchCount < FEEDBACK_LAUNCH_COUNT) {
|
||||
// Increment the launch count and store the new value.
|
||||
launchCount++;
|
||||
settings.edit().putInt(keyName, launchCount).commit();
|
||||
settings.edit().putInt(keyName, launchCount).apply();
|
||||
|
||||
// If we've reached our magic number, show the feedback page.
|
||||
return launchCount == FEEDBACK_LAUNCH_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute(Boolean shouldShowFeedbackPage) {
|
||||
if (shouldShowFeedbackPage)
|
||||
if (launchCount == FEEDBACK_LAUNCH_COUNT) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Feedback:Show", null));
|
||||
}
|
||||
}
|
||||
}).execute();
|
||||
} finally {
|
||||
StrictMode.setThreadPolicy(savedPolicy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2893,13 +2899,8 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
private void resetFeedbackLaunchCount() {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
|
||||
settings.edit().putInt(getPackageName() + ".feedback_launch_count", 0).commit();
|
||||
}
|
||||
});
|
||||
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
|
||||
settings.edit().putInt(getPackageName() + ".feedback_launch_count", 0).apply();
|
||||
}
|
||||
|
||||
private void getLastUrl() {
|
||||
|
@ -282,7 +282,7 @@ public class BrowserLocaleManager implements LocaleManager {
|
||||
public void resetToSystemLocale(Context context) {
|
||||
// Wipe the pref.
|
||||
final SharedPreferences settings = getSharedPreferences(context);
|
||||
settings.edit().remove(PREF_LOCALE).commit();
|
||||
settings.edit().remove(PREF_LOCALE).apply();
|
||||
|
||||
// Apply the system locale.
|
||||
updateLocale(context, systemLocale);
|
||||
@ -324,7 +324,7 @@ public class BrowserLocaleManager implements LocaleManager {
|
||||
|
||||
private void persistLocale(Context context, String localeCode) {
|
||||
final SharedPreferences settings = getSharedPreferences(context);
|
||||
settings.edit().putString(PREF_LOCALE, localeCode).commit();
|
||||
settings.edit().putString(PREF_LOCALE, localeCode).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,7 +137,7 @@ public class CrashReporter extends Activity
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, true);
|
||||
editor.putBoolean(GeckoApp.PREFS_CRASHED, true);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
|
||||
final CheckBox allowContactCheckBox = (CheckBox) findViewById(R.id.allow_contact);
|
||||
final CheckBox includeUrlCheckBox = (CheckBox) findViewById(R.id.include_url);
|
||||
|
@ -44,7 +44,7 @@ public class DataReportingNotification {
|
||||
if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
|
||||
SharedPreferences.Editor editor = dataPrefs.edit();
|
||||
editor.putBoolean(GeckoPreferences.PREFS_HEALTHREPORT_UPLOAD_ENABLED, true);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -57,7 +57,7 @@ public class DataReportingNotification {
|
||||
// Silently update the version.
|
||||
SharedPreferences.Editor editor = dataPrefs.edit();
|
||||
editor.putInt(PREFS_POLICY_VERSION, DATA_REPORTING_VERSION);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -123,7 +123,7 @@ public class DataReportingNotification {
|
||||
long now = System.currentTimeMillis();
|
||||
editor.putLong(PREFS_POLICY_NOTIFIED_TIME, now);
|
||||
editor.putInt(PREFS_POLICY_VERSION, DATA_REPORTING_VERSION);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
result = true;
|
||||
} finally {
|
||||
// We want to track any errors, so record notification outcome.
|
||||
|
@ -27,7 +27,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
public final class EventDispatcher {
|
||||
private static final String LOGTAG = "GeckoEventDispatcher";
|
||||
private static final String GUID = "__guid__";
|
||||
private static final String STATUS_CANCEL = "cancel";
|
||||
private static final String STATUS_ERROR = "error";
|
||||
private static final String STATUS_SUCCESS = "success";
|
||||
|
||||
@ -200,10 +199,9 @@ public final class EventDispatcher {
|
||||
if (listeners == null || listeners.size() == 0) {
|
||||
Log.w(LOGTAG, "No listeners for " + type);
|
||||
|
||||
// If there are no listeners, cancel the callback to prevent Gecko-side observers
|
||||
// from being leaked.
|
||||
// If there are no listeners, dispatch an error.
|
||||
if (callback != null) {
|
||||
callback.sendCancel();
|
||||
callback.sendError("No listeners for request");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -258,10 +256,6 @@ public final class EventDispatcher {
|
||||
sendResponse(STATUS_ERROR, response);
|
||||
}
|
||||
|
||||
public void sendCancel() {
|
||||
sendResponse(STATUS_CANCEL, null);
|
||||
}
|
||||
|
||||
private void sendResponse(final String status, final Object response) {
|
||||
if (sent) {
|
||||
throw new IllegalStateException("Callback has already been executed for type=" +
|
||||
|
@ -1222,8 +1222,7 @@ public abstract class GeckoApp
|
||||
// injecting states.
|
||||
final SharedPreferences prefs = getSharedPreferences();
|
||||
if (prefs.getBoolean(PREFS_ALLOW_STATE_BUNDLE, false)) {
|
||||
Log.i(LOGTAG, "Restoring state from intent bundle");
|
||||
prefs.edit().remove(PREFS_ALLOW_STATE_BUNDLE).commit();
|
||||
prefs.edit().remove(PREFS_ALLOW_STATE_BUNDLE).apply();
|
||||
savedInstanceState = stateBundle;
|
||||
}
|
||||
} else if (savedInstanceState != null) {
|
||||
@ -1279,14 +1278,13 @@ public abstract class GeckoApp
|
||||
// on exit, or if we were suddenly killed (crash or native OOM).
|
||||
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
|
||||
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
|
||||
// The lifecycle of mHealthRecorder is "shortly after onCreate"
|
||||
// through "onDestroy" -- essentially the same as the lifecycle
|
||||
// of the activity itself.
|
||||
final String profilePath = getProfile().getDir().getAbsolutePath();
|
||||
final EventDispatcher dispatcher = EventDispatcher.getInstance();
|
||||
Log.i(LOGTAG, "Creating HealthRecorder.");
|
||||
|
||||
final String osLocale = Locale.getDefault().toString();
|
||||
String appLocale = localeManager.getAndApplyPersistedLocale(GeckoApp.this);
|
||||
@ -1691,15 +1689,7 @@ public abstract class GeckoApp
|
||||
if (prefs.getInt(PREFS_VERSION_CODE, 0) != versionCode) {
|
||||
// If the version has changed, the user has done an upgrade, so restore
|
||||
// previous tabs.
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
prefs.edit()
|
||||
.putInt(PREFS_VERSION_CODE, versionCode)
|
||||
.commit();
|
||||
}
|
||||
});
|
||||
|
||||
prefs.edit().putInt(PREFS_VERSION_CODE, versionCode).apply();
|
||||
shouldRestore = true;
|
||||
} else if (savedInstanceState != null ||
|
||||
getSessionRestorePreference().equals("always") ||
|
||||
@ -1708,12 +1698,7 @@ public abstract class GeckoApp
|
||||
// has chosen to always restore, or we restarted.
|
||||
shouldRestore = true;
|
||||
} else if (prefs.getBoolean(GeckoApp.PREFS_CRASHED, false)) {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
prefs.edit().putBoolean(PREFS_CRASHED, false).commit();
|
||||
}
|
||||
});
|
||||
prefs.edit().putBoolean(PREFS_CRASHED, false).apply();
|
||||
shouldRestore = true;
|
||||
}
|
||||
|
||||
@ -1959,7 +1944,7 @@ public abstract class GeckoApp
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
|
||||
currentSession.recordBegin(editor);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
|
||||
final HealthRecorder rec = mHealthRecorder;
|
||||
if (rec != null) {
|
||||
@ -2008,7 +1993,7 @@ public abstract class GeckoApp
|
||||
editor.putBoolean(GeckoApp.PREFS_CLEANUP_TEMP_FILES, false);
|
||||
}
|
||||
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
|
||||
// In theory, the first browser session will not run long enough that we need to
|
||||
// prune during it and we'd rather run it when the browser is inactive so we wait
|
||||
@ -2027,24 +2012,22 @@ public abstract class GeckoApp
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestart()
|
||||
{
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SharedPreferences prefs = GeckoApp.this.getSharedPreferences();
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
|
||||
editor.commit();
|
||||
}
|
||||
});
|
||||
public void onRestart() {
|
||||
// Faster on main thread with an async apply().
|
||||
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
|
||||
try {
|
||||
SharedPreferences.Editor editor = GeckoApp.this.getSharedPreferences().edit();
|
||||
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
|
||||
editor.apply();
|
||||
} finally {
|
||||
StrictMode.setThreadPolicy(savedPolicy);
|
||||
}
|
||||
|
||||
super.onRestart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
public void onDestroy() {
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this,
|
||||
"Gecko:Ready",
|
||||
"Gecko:DelayedStartup",
|
||||
@ -2094,6 +2077,7 @@ public abstract class GeckoApp
|
||||
mTextSelection.destroy();
|
||||
NotificationHelper.destroy();
|
||||
IntentHelper.destroy();
|
||||
GeckoNetworkManager.destroy();
|
||||
|
||||
if (SmsManager.getInstance() != null) {
|
||||
SmsManager.getInstance().stop();
|
||||
@ -2250,14 +2234,11 @@ public abstract class GeckoApp
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
for (File file : dir.listFiles()) {
|
||||
if (file.isFile() && file.getName().endsWith(".ttf")) {
|
||||
Log.i(LOGTAG, "deleting " + file.toString());
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
if (!dir.delete()) {
|
||||
Log.w(LOGTAG, "unable to delete res/fonts directory (not empty?)");
|
||||
} else {
|
||||
Log.i(LOGTAG, "res/fonts directory deleted");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2267,7 +2248,7 @@ public abstract class GeckoApp
|
||||
if (cleanupVersion != CURRENT_CLEANUP_VERSION) {
|
||||
SharedPreferences.Editor editor = GeckoApp.this.getSharedPreferences().edit();
|
||||
editor.putInt(CLEANUP_VERSION, CURRENT_CLEANUP_VERSION);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2592,7 +2573,6 @@ public abstract class GeckoApp
|
||||
* and poke HealthRecorder to tell it of our changed state.
|
||||
*/
|
||||
protected void setLocale(final String locale) {
|
||||
Log.d(LOGTAG, "setLocale: " + locale);
|
||||
if (locale == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -485,6 +485,9 @@ public class GeckoAppShell
|
||||
SharedPreferences prefs = getSharedPreferences();
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, true);
|
||||
|
||||
// Synchronously write to disk so we know it's done before we
|
||||
// shutdown
|
||||
editor.commit();
|
||||
}
|
||||
} finally {
|
||||
|
@ -39,6 +39,12 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
|
||||
|
||||
static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
|
||||
|
||||
public static void destroy() {
|
||||
if (sInstance != null) {
|
||||
sInstance.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
// Connection Type defined in Network Information API v3.
|
||||
private enum ConnectionType {
|
||||
CELLULAR(0),
|
||||
@ -60,6 +66,14 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
|
||||
MNC
|
||||
}
|
||||
|
||||
private GeckoNetworkManager() {
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener(this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
private void onDestroy() {
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
private ConnectionType mConnectionType = ConnectionType.NONE;
|
||||
private final IntentFilter mNetworkFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
|
||||
@ -96,8 +110,6 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
|
||||
if (mShouldNotify) {
|
||||
startListening();
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
private void startListening() {
|
||||
@ -117,8 +129,6 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
|
||||
if (mShouldNotify) {
|
||||
stopListening();
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -186,7 +186,7 @@ public final class GeckoProfile {
|
||||
if (success) {
|
||||
// Clear all shared prefs for the given profile.
|
||||
GeckoSharedPrefs.forProfileName(context, profileName)
|
||||
.edit().clear().commit();
|
||||
.edit().clear().apply();
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -270,7 +270,7 @@ public final class GeckoProfile {
|
||||
if (success) {
|
||||
// Clear all shared prefs for the guest profile.
|
||||
GeckoSharedPrefs.forProfileName(context, GUEST_PROFILE)
|
||||
.edit().clear().commit();
|
||||
.edit().clear().apply();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,10 +204,10 @@ public final class GeckoSharedPrefs {
|
||||
// Update prefs version accordingly.
|
||||
appEditor.putInt(PREFS_VERSION_KEY, PREFS_VERSION);
|
||||
|
||||
appEditor.commit();
|
||||
profileEditor.commit();
|
||||
appEditor.apply();
|
||||
profileEditor.apply();
|
||||
if (pmEditor != null) {
|
||||
pmEditor.commit();
|
||||
pmEditor.apply();
|
||||
}
|
||||
|
||||
Log.d(LOGTAG, "All keys have been migrated");
|
||||
|
@ -151,7 +151,7 @@ public final class SharedPreferencesHelper
|
||||
} else {
|
||||
Log.w(LOGTAG, "Unknown pref value type [" + type + "] for pref [" + name + "]");
|
||||
}
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -459,6 +459,7 @@ public class Tab {
|
||||
return;
|
||||
|
||||
BrowserDB.addBookmark(getContentResolver(), mTitle, url);
|
||||
Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.BOOKMARK_ADDED);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -472,6 +473,7 @@ public class Tab {
|
||||
return;
|
||||
|
||||
BrowserDB.removeBookmarksWithURL(getContentResolver(), url);
|
||||
Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.BOOKMARK_REMOVED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -597,7 +597,9 @@ public class Tabs implements GeckoEventListener {
|
||||
READER_ENABLED,
|
||||
DESKTOP_MODE_CHANGE,
|
||||
VIEWPORT_CHANGE,
|
||||
RECORDING_CHANGE
|
||||
RECORDING_CHANGE,
|
||||
BOOKMARK_ADDED,
|
||||
BOOKMARK_REMOVED
|
||||
}
|
||||
|
||||
public void notifyListeners(Tab tab, TabEvents msg) {
|
||||
|
@ -385,7 +385,7 @@ public class SuggestedSites {
|
||||
private static void updateSuggestedSitesLocale(Context context) {
|
||||
final Editor editor = GeckoSharedPrefs.forProfile(context).edit();
|
||||
editor.putString(PREF_SUGGESTED_SITES_LOCALE, Locale.getDefault().toString());
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private boolean isEnabled() {
|
||||
@ -582,6 +582,6 @@ public class SuggestedSites {
|
||||
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
|
||||
final String prefString = prefs.getString(PREF_SUGGESTED_SITES_HIDDEN, "");
|
||||
final String siteString = prefString.concat(" " + Uri.encode(url));
|
||||
prefs.edit().putString(PREF_SUGGESTED_SITES_HIDDEN, siteString).commit();
|
||||
prefs.edit().putString(PREF_SUGGESTED_SITES_HIDDEN, siteString).apply();
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ public class Distribution {
|
||||
checkSystemDistribution();
|
||||
|
||||
this.state = distributionSet ? STATE_SET : STATE_NONE;
|
||||
settings.edit().putInt(keyName, this.state).commit();
|
||||
settings.edit().putInt(keyName, this.state).apply();
|
||||
|
||||
runReadyQueue();
|
||||
return distributionSet;
|
||||
|
@ -8,6 +8,10 @@ package org.mozilla.gecko.home;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
@ -25,6 +29,7 @@ import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -123,13 +128,16 @@ public class HistoryPanel extends HomeFragment {
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
dialog.dismiss();
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
BrowserDB.clearHistory(cr);
|
||||
}
|
||||
});
|
||||
|
||||
// Send message to Java to clear history.
|
||||
final JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("history", true);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "JSON error", e);
|
||||
}
|
||||
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Sanitize:ClearData", json.toString()));
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SANITIZE, TelemetryContract.Method.BUTTON, "history");
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
||||
newJson.put(JSON_KEY_VERSION, VERSION);
|
||||
|
||||
prefsEditor.putString(PREFS_CONFIG_KEY, newJson.toString());
|
||||
prefsEditor.commit();
|
||||
prefsEditor.apply();
|
||||
|
||||
return newJsonPanels;
|
||||
}
|
||||
@ -278,7 +278,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
||||
}
|
||||
|
||||
editor.putString(PREFS_LOCALE_KEY, Locale.getDefault().toString());
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
|
||||
// Trigger reload listeners on all live backend instances
|
||||
sendReloadBroadcast();
|
||||
@ -295,7 +295,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
||||
|
||||
final SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(PREFS_LOCALE_KEY, currentLocale);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
|
||||
// If the user has saved HomeConfig before, return null this
|
||||
// one time to trigger a refresh and ensure we use the
|
||||
|
@ -355,7 +355,7 @@ public class HomePanelsManager implements GeckoEventListener {
|
||||
public void run() {
|
||||
final HomeConfig.Editor editor = mHomeConfig.load().edit();
|
||||
executePendingChanges(editor);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -28,17 +28,6 @@ public class MenuPanel extends LinearLayout {
|
||||
setLayoutParams(new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
// Restrict the height to 75% of the screen-height. heightPixels changes during rotation.
|
||||
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||
int restrictedHeightSpec = MeasureSpec.makeMeasureSpec((int) (0.75 * metrics.heightPixels), MeasureSpec.AT_MOST);
|
||||
|
||||
super.onMeasure(widthMeasureSpec, restrictedHeightSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPopulateAccessibilityEvent (AccessibilityEvent event) {
|
||||
if (Versions.feature14Plus) {
|
||||
|
@ -267,7 +267,6 @@ gbjar.sources += [
|
||||
'home/BookmarksPanel.java',
|
||||
'home/BrowserSearch.java',
|
||||
'home/DynamicPanel.java',
|
||||
'home/FadedTextView.java',
|
||||
'home/FramePanelLayout.java',
|
||||
'home/HistoryPanel.java',
|
||||
'home/HomeAdapter.java',
|
||||
@ -443,6 +442,7 @@ gbjar.sources += [
|
||||
'widget/Divider.java',
|
||||
'widget/DoorHanger.java',
|
||||
'widget/EllipsisTextView.java',
|
||||
'widget/FadedTextView.java',
|
||||
'widget/FaviconView.java',
|
||||
'widget/FloatingHintEditText.java',
|
||||
'widget/FlowLayout.java',
|
||||
|
@ -36,8 +36,8 @@ public class SendTabDeviceListArrayAdapter extends ArrayAdapter<ParcelableClient
|
||||
// This will show the user a prompt to select a device from a longer list of devices.
|
||||
private AlertDialog dialog;
|
||||
|
||||
public SendTabDeviceListArrayAdapter(Context context, SendTabTargetSelectedListener aListener, int textViewResourceId) {
|
||||
super(context, textViewResourceId);
|
||||
public SendTabDeviceListArrayAdapter(Context context, SendTabTargetSelectedListener aListener) {
|
||||
super(context, R.layout.overlay_share_send_tab_item);
|
||||
|
||||
listener = aListener;
|
||||
|
||||
|
@ -103,6 +103,7 @@ public class ShareDialog extends LocaleAware.LocaleAwareActivity implements Send
|
||||
// trying to send a share intent).
|
||||
Toast toast = Toast.makeText(this, getResources().getText(R.string.overlay_share_no_url), Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
finish();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -162,7 +163,7 @@ public class ShareDialog extends LocaleAware.LocaleAwareActivity implements Send
|
||||
SendTabList sendTabList = (SendTabList) findViewById(R.id.overlay_send_tab_btn);
|
||||
|
||||
// Register ourselves as both the listener and the context for the Adapter.
|
||||
SendTabDeviceListArrayAdapter adapter = new SendTabDeviceListArrayAdapter(this, this, R.layout.sync_list_item);
|
||||
SendTabDeviceListArrayAdapter adapter = new SendTabDeviceListArrayAdapter(this, this);
|
||||
sendTabList.setAdapter(adapter);
|
||||
sendTabList.setSendTabTargetSelectedListener(this);
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
<?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/.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="true" android:drawable="@color/overlay_share_selected" />
|
||||
<item android:drawable="@color/overlay_share_background"/>
|
||||
|
||||
</selector>
|
@ -30,7 +30,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="0dp"
|
||||
android:background="@color/background_light"
|
||||
android:background="@color/overlay_share_header_background"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="15dp"
|
||||
@ -63,7 +63,7 @@
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/overlay_share_background_colour"
|
||||
android:background="@color/overlay_share_background"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- TODO: Once API 11 is available, stick "showDividers=middle" into the parent and get rid
|
||||
@ -73,7 +73,6 @@
|
||||
<org.mozilla.gecko.overlays.ui.SendTabList
|
||||
style="@style/ShareOverlayButton"
|
||||
android:id="@+id/overlay_send_tab_btn"
|
||||
android:background="@color/overlay_share_background_colour"
|
||||
android:padding="0dp"/>
|
||||
|
||||
<!-- Evil separator -->
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/client_name"
|
||||
style="@style/ShareOverlayButton.Text"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="0.5"
|
||||
|
@ -12,7 +12,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"/>
|
||||
|
||||
<org.mozilla.gecko.home.FadedTextView
|
||||
<org.mozilla.gecko.widget.FadedTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/Widget.TopSitesGridItemTitle"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -17,7 +17,7 @@
|
||||
android:layout_marginRight="10dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.mozilla.gecko.home.FadedTextView
|
||||
<org.mozilla.gecko.widget.FadedTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/Widget.TwoLinePageRow.Title"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -51,8 +51,11 @@
|
||||
<!-- Colour used for share overlay button labels -->
|
||||
<color name="text_color_overlaybtn">#666666</color>
|
||||
|
||||
<!-- Colour used for share overlay button background -->
|
||||
<color name="overlay_share_background_colour">#FFD0CECB</color>
|
||||
<color name="overlay_share_header_background">#FFFFFFFF</color>
|
||||
|
||||
<!-- Colours used for share overlay button background -->
|
||||
<color name="overlay_share_background">#FFEBEBF0</color>
|
||||
<color name="overlay_share_selected">#FFF5F5F5</color>
|
||||
|
||||
<!-- Disabled colors -->
|
||||
<color name="text_color_primary_disable_only">#999999</color>
|
||||
|