Merge m-c to fx-team
|
@ -36,15 +36,15 @@ exports.testPlainTextConsole = function(test) {
|
|||
test.pass("PlainTextConsole instantiates");
|
||||
|
||||
con.log('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, 1, Array [2,3,4]\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing 1 Array [2,3,4]\n",
|
||||
"PlainTextConsole.log() must work.");
|
||||
|
||||
con.info('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "console.info: " + name + ": testing, 1, Array [2,3,4]\n",
|
||||
test.assertEqual(lastPrint(), "console.info: " + name + ": testing 1 Array [2,3,4]\n",
|
||||
"PlainTextConsole.info() must work.");
|
||||
|
||||
con.warn('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "console.warn: " + name + ": testing, 1, Array [2,3,4]\n",
|
||||
test.assertEqual(lastPrint(), "console.warn: " + name + ": testing 1 Array [2,3,4]\n",
|
||||
"PlainTextConsole.warn() must work.");
|
||||
|
||||
con.error('testing', 1, [2, 3, 4]);
|
||||
|
@ -64,20 +64,20 @@ exports.testPlainTextConsole = function(test) {
|
|||
prints = [];
|
||||
|
||||
con.log('testing', undefined);
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, undefined\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing undefined\n",
|
||||
"PlainTextConsole.log() must stringify undefined.");
|
||||
|
||||
con.log('testing', null);
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, null\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing null\n",
|
||||
"PlainTextConsole.log() must stringify null.");
|
||||
|
||||
// TODO: Fix console.jsm to detect custom toString.
|
||||
con.log("testing", { toString: function() "obj.toString()" });
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, {}\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing {}\n",
|
||||
"PlainTextConsole.log() doesn't printify custom toString.");
|
||||
|
||||
con.log("testing", { toString: function() { throw "fail!"; } });
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, {}\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing {}\n",
|
||||
"PlainTextConsole.log() must stringify custom bad toString.");
|
||||
|
||||
|
||||
|
|
|
@ -756,7 +756,6 @@ var gBrowserInit = {
|
|||
|
||||
// initialize observers and listeners
|
||||
// and give C++ access to gBrowser
|
||||
gBrowser.init();
|
||||
XULBrowserWindow.init();
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(nsIWebNavigation)
|
||||
|
|
|
@ -2956,7 +2956,17 @@
|
|||
filter.addProgressListener(tabListener, nsIWebProgress.NOTIFY_ALL);
|
||||
this.mTabListeners[0] = tabListener;
|
||||
this.mTabFilters[0] = filter;
|
||||
this.init();
|
||||
|
||||
try {
|
||||
// We assume this can only fail because mCurrentBrowser's docShell
|
||||
// hasn't been created, yet. This may be caused by code accessing
|
||||
// gBrowser before the window has finished loading.
|
||||
this._addProgressListenerForInitialTab();
|
||||
} catch (e) {
|
||||
// The binding was constructed too early, wait until the initial
|
||||
// tab's document is ready, then add the progress listener.
|
||||
this._waitForInitialContentDocument();
|
||||
}
|
||||
|
||||
this.style.backgroundColor =
|
||||
Services.prefs.getBoolPref("browser.display.use_system_colors") ?
|
||||
|
@ -2970,17 +2980,28 @@
|
|||
]]>
|
||||
</constructor>
|
||||
|
||||
<method name="init">
|
||||
<method name="_addProgressListenerForInitialTab">
|
||||
<body><![CDATA[
|
||||
if (!this._initialProgressListenerAdded) {
|
||||
this._initialProgressListenerAdded = true;
|
||||
try {
|
||||
this.webProgress.addProgressListener(this.mTabFilters[0], Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
} catch (e) {
|
||||
// The binding was constructed too early, need to try this again later. See bug 463384.
|
||||
this._initialProgressListenerAdded = false;
|
||||
}
|
||||
this.webProgress.addProgressListener(this.mTabFilters[0], Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_waitForInitialContentDocument">
|
||||
<body><![CDATA[
|
||||
let obs = (subject, topic) => {
|
||||
if (this.browsers[0].contentWindow == subject) {
|
||||
Services.obs.removeObserver(obs, topic);
|
||||
this._addProgressListenerForInitialTab();
|
||||
}
|
||||
};
|
||||
|
||||
// We use content-document-global-created as an approximation for
|
||||
// "docShell is initialized". We can do this because in the
|
||||
// mTabProgressListener we care most about the STATE_STOP notification
|
||||
// that will reset mBlank. That means it's important to at least add
|
||||
// the progress listener before the initial about:blank load stops
|
||||
// if we can't do it before the load starts.
|
||||
Services.obs.addObserver(obs, "content-document-global-created", false);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
|
|
@ -184,6 +184,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_bug822367.js \
|
||||
browser_bug832435.js \
|
||||
browser_bug839103.js \
|
||||
browser_bug880101.js \
|
||||
browser_bug882977.js \
|
||||
browser_bug887515.js \
|
||||
browser_canonizeURL.js \
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const URL = "about:robots";
|
||||
|
||||
function test() {
|
||||
let win;
|
||||
|
||||
let listener = {
|
||||
onLocationChange: (webProgress, request, uri, flags) => {
|
||||
ok(webProgress.isTopLevel, "Received onLocationChange from top frame");
|
||||
is(uri.spec, URL, "Received onLocationChange for correct URL");
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Remove the listener and window when we're done.
|
||||
registerCleanupFunction(() => {
|
||||
win.gBrowser.removeProgressListener(listener);
|
||||
win.close();
|
||||
});
|
||||
|
||||
// Wait for the newly opened window.
|
||||
whenNewWindowOpened(w => win = w);
|
||||
|
||||
// Open a link in a new window.
|
||||
openLinkIn(URL, "window", {});
|
||||
|
||||
// On the next tick, but before the window has finished loading, access the
|
||||
// window's gBrowser property to force the tabbrowser constructor early.
|
||||
(function tryAddProgressListener() {
|
||||
executeSoon(() => {
|
||||
try {
|
||||
win.gBrowser.addProgressListener(listener);
|
||||
} catch (e) {
|
||||
// win.gBrowser wasn't ready, yet. Try again in a tick.
|
||||
tryAddProgressListener();
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
function whenNewWindowOpened(cb) {
|
||||
Services.obs.addObserver(function obs(win) {
|
||||
Services.obs.removeObserver(obs, "domwindowopened");
|
||||
cb(win);
|
||||
}, "domwindowopened", false);
|
||||
}
|
|
@ -311,9 +311,6 @@ let SessionStoreInternal = {
|
|||
// states for all recently closed windows
|
||||
_closedWindows: [],
|
||||
|
||||
// not-"dirty" windows usually don't need to have their data updated
|
||||
_dirtyWindows: {},
|
||||
|
||||
// collection of session states yet to be restored
|
||||
_statesToRestore: {},
|
||||
|
||||
|
@ -488,8 +485,6 @@ let SessionStoreInternal = {
|
|||
this._prefBranch.getBoolPref("sessionstore.resume_session_once"))
|
||||
this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
|
||||
|
||||
this._initEncoding();
|
||||
|
||||
this._performUpgradeBackup();
|
||||
|
||||
this._sessionInitialized = true;
|
||||
|
@ -524,13 +519,6 @@ let SessionStoreInternal = {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
_initEncoding : function ssi_initEncoding() {
|
||||
// The (UTF-8) encoder used to write to files.
|
||||
XPCOMUtils.defineLazyGetter(this, "_writeFileEncoder", function () {
|
||||
return new TextEncoder();
|
||||
});
|
||||
},
|
||||
|
||||
_initPrefs : function() {
|
||||
this._prefBranch = Services.prefs.getBranch("browser.");
|
||||
|
||||
|
@ -1000,7 +988,7 @@ let SessionStoreInternal = {
|
|||
var activeWindow = this._getMostRecentBrowserWindow();
|
||||
if (activeWindow)
|
||||
this.activeWindowSSiCache = activeWindow.__SSi || "";
|
||||
this._dirtyWindows = [];
|
||||
DirtyWindows.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2544,14 +2532,14 @@ let SessionStoreInternal = {
|
|||
this._forEachBrowserWindow(function(aWindow) {
|
||||
if (!this._isWindowLoaded(aWindow)) // window data is still in _statesToRestore
|
||||
return;
|
||||
if (aUpdateAll || this._dirtyWindows[aWindow.__SSi] || aWindow == activeWindow) {
|
||||
if (aUpdateAll || DirtyWindows.has(aWindow) || aWindow == activeWindow) {
|
||||
this._collectWindowData(aWindow);
|
||||
}
|
||||
else { // always update the window features (whose change alone never triggers a save operation)
|
||||
this._updateWindowFeatures(aWindow);
|
||||
}
|
||||
});
|
||||
this._dirtyWindows = [];
|
||||
DirtyWindows.clear();
|
||||
}
|
||||
|
||||
// collect the data for all windows
|
||||
|
@ -2682,7 +2670,7 @@ let SessionStoreInternal = {
|
|||
this._windows[aWindow.__SSi].__lastSessionWindowID =
|
||||
aWindow.__SS_lastSessionWindowID;
|
||||
|
||||
this._dirtyWindows[aWindow.__SSi] = false;
|
||||
DirtyWindows.remove(aWindow);
|
||||
},
|
||||
|
||||
/* ........ Restoring Functionality .............. */
|
||||
|
@ -3010,7 +2998,7 @@ let SessionStoreInternal = {
|
|||
|
||||
// It's important to set the window state to dirty so that
|
||||
// we collect their data for the first time when saving state.
|
||||
this._dirtyWindows[aWindow.__SSi] = true;
|
||||
DirtyWindows.add(aWindow);
|
||||
}
|
||||
|
||||
if (aTabs.length == 0) {
|
||||
|
@ -3701,7 +3689,7 @@ let SessionStoreInternal = {
|
|||
*/
|
||||
saveStateDelayed: function ssi_saveStateDelayed(aWindow = null, aDelay = 2000) {
|
||||
if (aWindow) {
|
||||
this._dirtyWindows[aWindow.__SSi] = true;
|
||||
DirtyWindows.add(aWindow);
|
||||
}
|
||||
|
||||
if (!this._saveTimer) {
|
||||
|
@ -4689,6 +4677,28 @@ let DyingWindowCache = {
|
|||
}
|
||||
};
|
||||
|
||||
// A weak set of dirty windows. We use it to determine which windows we need to
|
||||
// recollect data for when _getCurrentState() is called.
|
||||
let DirtyWindows = {
|
||||
_data: new WeakMap(),
|
||||
|
||||
has: function (window) {
|
||||
return this._data.has(window);
|
||||
},
|
||||
|
||||
add: function (window) {
|
||||
return this._data.set(window, true);
|
||||
},
|
||||
|
||||
remove: function (window) {
|
||||
this._data.delete(window);
|
||||
},
|
||||
|
||||
clear: function (window) {
|
||||
this._data.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// A map storing the number of tabs last closed per windoow. This only
|
||||
// stores the most recent tab-close operation, and is used to undo
|
||||
// batch tab-closing operations.
|
||||
|
|
|
@ -1920,7 +1920,6 @@ let GroupItems = {
|
|||
minGroupHeight: 110,
|
||||
minGroupWidth: 125,
|
||||
_lastActiveList: null,
|
||||
_lastGroupToUpdateTabBar: null,
|
||||
|
||||
// ----------
|
||||
// Function: toString
|
||||
|
@ -2286,10 +2285,6 @@ let GroupItems = {
|
|||
});
|
||||
|
||||
this._lastActiveList.remove(groupItem);
|
||||
|
||||
if (this._lastGroupToUpdateTabBar == groupItem)
|
||||
this._lastGroupToUpdateTabBar = null;
|
||||
|
||||
UI.updateTabButton();
|
||||
},
|
||||
|
||||
|
@ -2423,13 +2418,8 @@ let GroupItems = {
|
|||
|
||||
Utils.assert(this._activeGroupItem, "There must be something to show in the tab bar!");
|
||||
|
||||
// Update list of visible tabs only once after switching to another group.
|
||||
if (this._activeGroupItem == this._lastGroupToUpdateTabBar)
|
||||
return;
|
||||
|
||||
let tabItems = this._activeGroupItem._children;
|
||||
gBrowser.showOnlyTheseTabs(tabItems.map(function(item) item.tab));
|
||||
this._lastGroupToUpdateTabBar = this._activeGroupItem;
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -2547,7 +2537,7 @@ let GroupItems = {
|
|||
if (tab._tabViewTabItem.parent && tab._tabViewTabItem.parent.id == groupItemId)
|
||||
return;
|
||||
|
||||
let shouldHideTab = false;
|
||||
let shouldUpdateTabBar = false;
|
||||
let shouldShowTabView = false;
|
||||
let groupItem;
|
||||
|
||||
|
@ -2555,12 +2545,12 @@ let GroupItems = {
|
|||
if (tab.selected) {
|
||||
if (gBrowser.visibleTabs.length > 1) {
|
||||
gBrowser._blurTab(tab);
|
||||
shouldHideTab = true;
|
||||
shouldUpdateTabBar = true;
|
||||
} else {
|
||||
shouldShowTabView = true;
|
||||
}
|
||||
} else {
|
||||
shouldHideTab = true;
|
||||
shouldUpdateTabBar = true
|
||||
}
|
||||
|
||||
// remove tab item from a groupItem
|
||||
|
@ -2583,8 +2573,8 @@ let GroupItems = {
|
|||
new GroupItem([ tab._tabViewTabItem ], { bounds: box, immediately: true });
|
||||
}
|
||||
|
||||
if (shouldHideTab)
|
||||
gBrowser.hideTab(tab);
|
||||
if (shouldUpdateTabBar)
|
||||
this._updateTabBar();
|
||||
else if (shouldShowTabView)
|
||||
UI.showTabView();
|
||||
},
|
||||
|
|
|
@ -99,14 +99,47 @@ function test() {
|
|||
}, aWindow);
|
||||
}
|
||||
|
||||
function testOnWindow(aCallback) {
|
||||
let win = OpenBrowserWindow({private: false});
|
||||
// [624102] check state after return from private browsing
|
||||
let testPrivateBrowsing = function (aWindow) {
|
||||
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#1', {inBackground: true});
|
||||
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#2', {inBackground: true});
|
||||
|
||||
let cw = getContentWindow(aWindow);
|
||||
let box = new cw.Rect(20, 20, 250, 200);
|
||||
let groupItem = new cw.GroupItem([], {bounds: box, immediately: true});
|
||||
cw.UI.setActive(groupItem);
|
||||
|
||||
aWindow.gBrowser.selectedTab = aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#3', {inBackground: true});
|
||||
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#4', {inBackground: true});
|
||||
|
||||
afterAllTabsLoaded(function () {
|
||||
assertNumberOfVisibleTabs(aWindow, 2);
|
||||
|
||||
enterAndLeavePrivateBrowsing(function () {
|
||||
assertNumberOfVisibleTabs(aWindow, 2);
|
||||
aWindow.gBrowser.selectedTab = aWindow.gBrowser.tabs[0];
|
||||
closeGroupItem(cw.GroupItems.groupItems[1], function() {
|
||||
next(aWindow);
|
||||
});
|
||||
});
|
||||
}, aWindow);
|
||||
}
|
||||
|
||||
function testOnWindow(aIsPrivate, aCallback) {
|
||||
let win = OpenBrowserWindow({private: aIsPrivate});
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
executeSoon(function() { aCallback(win) });
|
||||
}, false);
|
||||
}
|
||||
|
||||
function enterAndLeavePrivateBrowsing(callback) {
|
||||
testOnWindow(true, function (aWindow) {
|
||||
aWindow.close();
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Tests for #624265
|
||||
|
@ -116,7 +149,10 @@ function test() {
|
|||
tests.push(testDuplicateTab);
|
||||
tests.push(testBackForwardDuplicateTab);
|
||||
|
||||
testOnWindow(function(aWindow) {
|
||||
// Tests for #624102
|
||||
tests.push(testPrivateBrowsing);
|
||||
|
||||
testOnWindow(false, function(aWindow) {
|
||||
loadTabView(function() {
|
||||
next(aWindow);
|
||||
}, aWindow);
|
||||
|
|
|
@ -134,7 +134,6 @@ const WebProgress = {
|
|||
browser.messageManager.removeMessageListener(aMessage.name, arguments.callee);
|
||||
aTab._firstPaint = true;
|
||||
aTab.scrolledAreaChanged(true);
|
||||
aTab.updateThumbnailSource();
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<binding id="documenttab">
|
||||
<content observes="bcast_urlbarState">
|
||||
<xul:stack class="documenttab-container">
|
||||
<xul:box anonid="thumbnail" class="documenttab-thumbnail" />
|
||||
<html:canvas anonid="thumbnail-canvas" class="documenttab-thumbnail" />
|
||||
<xul:image anonid="favicon" class="documenttab-favicon"
|
||||
observes="bcast_urlbarState" width="26" height="26"/>
|
||||
|
||||
|
@ -36,12 +36,19 @@
|
|||
</handlers>
|
||||
|
||||
<implementation>
|
||||
<field name="_thumbnail" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
|
||||
<field name="thumbnailCanvas" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail-canvas");</field>
|
||||
<field name="_close" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "close");</field>
|
||||
<field name="_title" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "title");</field>
|
||||
<field name="_favicon" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "favicon");</field>
|
||||
<field name="_container" readonly="true">this.parentNode;</field>
|
||||
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this.thumbnailCanvas.mozOpaque = true;
|
||||
this.thumbnailCanvas.mozImageSmoothingEnabled = true;
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<method name="_onClick">
|
||||
<body>
|
||||
<![CDATA[
|
||||
|
@ -90,14 +97,6 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<method name="updateThumbnailSource">
|
||||
<parameter name="browser"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._thumbnail.style.backgroundImage = "-moz-element(#" + browser.id + ")";
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ let Ci = Components.interfaces;
|
|||
let Cu = Components.utils;
|
||||
let Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/PageThumbs.jsm");
|
||||
|
||||
const kBrowserViewZoomLevelPrecision = 10000;
|
||||
|
||||
// allow panning after this timeout on pages with registered touch listeners
|
||||
|
@ -16,6 +18,8 @@ const kSetInactiveStateTimeout = 100;
|
|||
|
||||
const kDefaultMetadata = { autoSize: false, allowZoom: true, autoScale: true };
|
||||
|
||||
const kTabThumbnailDelayCapture = 500;
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
// Override sizeToContent in the main window. It breaks things (bug 565887)
|
||||
|
@ -1454,6 +1458,7 @@ function Tab(aURI, aParams, aOwner) {
|
|||
this._chromeTab = null;
|
||||
this._metadata = null;
|
||||
this._eventDeferred = null;
|
||||
this._updateThumbnailTimeout = null;
|
||||
|
||||
this.owner = aOwner || null;
|
||||
|
||||
|
@ -1603,13 +1608,45 @@ Tab.prototype = {
|
|||
self._eventDeferred = null;
|
||||
}
|
||||
browser.addEventListener("pageshow", onPageShowEvent, true);
|
||||
browser.messageManager.addMessageListener("Content:StateChange", this);
|
||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||
|
||||
if (aOwner)
|
||||
this._copyHistoryFrom(aOwner);
|
||||
this._loadUsingParams(browser, aURI, aParams);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "Content:StateChange":
|
||||
// update the thumbnail now...
|
||||
this.updateThumbnail();
|
||||
// ...and in a little while to capture page after load.
|
||||
if (aMessage.json.stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
clearTimeout(this._updateThumbnailTimeout);
|
||||
this._updateThumbnailTimeout = setTimeout(() => {
|
||||
this.updateThumbnail();
|
||||
}, kTabThumbnailDelayCapture);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe: function BrowserUI_observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "metro_viewstate_changed":
|
||||
if (aData !== "snapped") {
|
||||
this.updateThumbnail();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function destroy() {
|
||||
this._browser.messageManager.removeMessageListener("Content:StateChange", this);
|
||||
Services.obs.removeObserver(this, "metro_viewstate_changed", false);
|
||||
clearTimeout(this._updateThumbnailTimeout);
|
||||
|
||||
Elements.tabList.removeTab(this._chromeTab);
|
||||
this._chromeTab = null;
|
||||
this._destroyBrowser();
|
||||
|
@ -1818,8 +1855,8 @@ Tab.prototype = {
|
|||
return this.metadata.allowZoom && !Util.isURLEmpty(this.browser.currentURI.spec);
|
||||
},
|
||||
|
||||
updateThumbnailSource: function updateThumbnailSource() {
|
||||
this._chromeTab.updateThumbnailSource(this._browser);
|
||||
updateThumbnail: function updateThumbnail() {
|
||||
PageThumbs.captureToCanvas(this.browser.contentWindow, this._chromeTab.thumbnailCanvas);
|
||||
},
|
||||
|
||||
updateFavicon: function updateFavicon() {
|
||||
|
|
|
@ -228,10 +228,7 @@
|
|||
<richgrid id="start-remotetabs-grid" set-name="remoteTabs" seltype="multiple" flex="1"/>
|
||||
</vbox>
|
||||
|
||||
<!-- Spacer to take extra space in snapped mode. -->
|
||||
<spacer flex="999"/>
|
||||
</scrollbox>
|
||||
|
||||
</hbox>
|
||||
</vbox> <!-- end tray -->
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ var AutofillMenuUI = {
|
|||
|
||||
get _panel() { return document.getElementById("autofill-container"); },
|
||||
get _popup() { return document.getElementById("autofill-popup"); },
|
||||
get _commands() { return this._popup.childNodes[0]; },
|
||||
get commands() { return this._popup.childNodes[0]; },
|
||||
|
||||
get _menuPopup() {
|
||||
if (!this.__menuPopup) {
|
||||
|
@ -32,8 +32,8 @@ var AutofillMenuUI = {
|
|||
},
|
||||
|
||||
_emptyCommands: function _emptyCommands() {
|
||||
while (this._commands.firstChild)
|
||||
this._commands.removeChild(this._commands.firstChild);
|
||||
while (this.commands.firstChild)
|
||||
this.commands.removeChild(this.commands.firstChild);
|
||||
},
|
||||
|
||||
_positionOptions: function _positionOptions() {
|
||||
|
@ -57,7 +57,7 @@ var AutofillMenuUI = {
|
|||
label.setAttribute("value", aSuggestionsList[idx].label);
|
||||
item.setAttribute("data", aSuggestionsList[idx].value);
|
||||
item.appendChild(label);
|
||||
this._commands.appendChild(item);
|
||||
this.commands.appendChild(item);
|
||||
}
|
||||
|
||||
this._menuPopup.show(this._positionOptions());
|
||||
|
@ -65,7 +65,7 @@ var AutofillMenuUI = {
|
|||
|
||||
selectByIndex: function mn_selectByIndex(aIndex) {
|
||||
this._menuPopup.hide();
|
||||
FormHelperUI.doAutoComplete(this._commands.childNodes[aIndex].getAttribute("data"));
|
||||
FormHelperUI.doAutoComplete(this.commands.childNodes[aIndex].getAttribute("data"));
|
||||
},
|
||||
|
||||
hide: function hide () {
|
||||
|
@ -85,7 +85,7 @@ var ContextMenuUI = {
|
|||
|
||||
get _panel() { return document.getElementById("context-container"); },
|
||||
get _popup() { return document.getElementById("context-popup"); },
|
||||
get _commands() { return this._popup.childNodes[0]; },
|
||||
get commands() { return this._popup.childNodes[0]; },
|
||||
|
||||
get _menuPopup() {
|
||||
if (!this.__menuPopup) {
|
||||
|
@ -153,12 +153,12 @@ var ContextMenuUI = {
|
|||
contentTypes.indexOf("selected-text") != -1))
|
||||
multipleMediaTypes = true;
|
||||
|
||||
for (let command of Array.slice(this._commands.childNodes)) {
|
||||
for (let command of Array.slice(this.commands.childNodes)) {
|
||||
command.hidden = true;
|
||||
}
|
||||
|
||||
let optionsAvailable = false;
|
||||
for (let command of Array.slice(this._commands.childNodes)) {
|
||||
for (let command of Array.slice(this.commands.childNodes)) {
|
||||
let types = command.getAttribute("type").split(",");
|
||||
let lowPriority = (command.hasAttribute("priority") &&
|
||||
command.getAttribute("priority") == "low");
|
||||
|
@ -221,7 +221,7 @@ var MenuControlUI = {
|
|||
|
||||
get _panel() { return document.getElementById("menucontrol-container"); },
|
||||
get _popup() { return document.getElementById("menucontrol-popup"); },
|
||||
get _commands() { return this._popup.childNodes[0]; },
|
||||
get commands() { return this._popup.childNodes[0]; },
|
||||
|
||||
get _menuPopup() {
|
||||
if (!this.__menuPopup) {
|
||||
|
@ -240,8 +240,8 @@ var MenuControlUI = {
|
|||
},
|
||||
|
||||
_emptyCommands: function _emptyCommands() {
|
||||
while (this._commands.firstChild)
|
||||
this._commands.removeChild(this._commands.firstChild);
|
||||
while (this.commands.firstChild)
|
||||
this.commands.removeChild(this.commands.firstChild);
|
||||
},
|
||||
|
||||
_positionOptions: function _positionOptions() {
|
||||
|
@ -314,7 +314,7 @@ var MenuControlUI = {
|
|||
label.setAttribute("value", child.label);
|
||||
item.appendChild(label);
|
||||
|
||||
this._commands.appendChild(item);
|
||||
this.commands.appendChild(item);
|
||||
}
|
||||
|
||||
this._menuPopup.show(this._positionOptions());
|
||||
|
@ -338,84 +338,25 @@ function MenuPopup(aPanel, aPopup) {
|
|||
this._panel = aPanel;
|
||||
this._popup = aPopup;
|
||||
this._wantTypeBehind = false;
|
||||
this._willReshowPopup = false;
|
||||
|
||||
window.addEventListener('MozAppbarShowing', this, false);
|
||||
}
|
||||
MenuPopup.prototype = {
|
||||
get _visible() { return !this._panel.hidden; },
|
||||
get _commands() { return this._popup.childNodes[0]; },
|
||||
get visible() { return !this._panel.hidden; },
|
||||
get commands() { return this._popup.childNodes[0]; },
|
||||
|
||||
show: function (aPositionOptions) {
|
||||
if (this._visible) {
|
||||
this._willReshowPopup = true;
|
||||
let self = this;
|
||||
this._panel.addEventListener("transitionend", function () {
|
||||
self._show(aPositionOptions);
|
||||
self._panel.removeEventListener("transitionend", arguments.callee);
|
||||
});
|
||||
if (this.visible) {
|
||||
this._animateHide().then(() => this._animateShow(aPositionOptions));
|
||||
} else {
|
||||
this._show(aPositionOptions);
|
||||
this._animateShow(aPositionOptions);
|
||||
}
|
||||
},
|
||||
|
||||
_show: function (aPositionOptions) {
|
||||
window.addEventListener("keypress", this, true);
|
||||
window.addEventListener("mousedown", this, true);
|
||||
Elements.stack.addEventListener("PopupChanged", this, false);
|
||||
Elements.browsers.addEventListener("PanBegin", this, false);
|
||||
|
||||
this._panel.hidden = false;
|
||||
this._position(aPositionOptions || {});
|
||||
|
||||
let self = this;
|
||||
this._panel.addEventListener("transitionend", function () {
|
||||
self._panel.removeEventListener("transitionend", arguments.callee);
|
||||
self._panel.removeAttribute("showingfrom");
|
||||
|
||||
let eventName = self._willReshowPopup ? "popupmoved" : "popupshown";
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent(eventName, true, false);
|
||||
self._panel.dispatchEvent(event);
|
||||
|
||||
self._willReshowPopup = false;
|
||||
});
|
||||
|
||||
let popupFrom = !aPositionOptions.bottomAligned ? "above" : "below";
|
||||
this._panel.setAttribute("showingfrom", popupFrom);
|
||||
|
||||
// Ensure the panel actually gets shifted before getting animated
|
||||
setTimeout(function () {
|
||||
self._panel.setAttribute("showing", "true");
|
||||
}, 0);
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
if (!this._visible)
|
||||
return;
|
||||
|
||||
window.removeEventListener("keypress", this, true);
|
||||
window.removeEventListener("mousedown", this, true);
|
||||
Elements.stack.removeEventListener("PopupChanged", this, false);
|
||||
Elements.browsers.removeEventListener("PanBegin", this, false);
|
||||
|
||||
let self = this;
|
||||
this._panel.addEventListener("transitionend", function () {
|
||||
self._panel.removeEventListener("transitionend", arguments.callee);
|
||||
self._panel.removeAttribute("hiding");
|
||||
self._panel.hidden = true;
|
||||
self._popup.style.maxWidth = "none";
|
||||
self._popup.style.maxHeight = "none";
|
||||
|
||||
if (!self._willReshowPopup) {
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("popuphidden", true, false);
|
||||
self._panel.dispatchEvent(event);
|
||||
if (this.visible) {
|
||||
this._animateHide();
|
||||
}
|
||||
});
|
||||
|
||||
this._panel.setAttribute("hiding", "true");
|
||||
setTimeout(()=>this._panel.removeAttribute("showing"), 0);
|
||||
},
|
||||
|
||||
_position: function _position(aPositionOptions) {
|
||||
|
@ -440,7 +381,7 @@ MenuPopup.prototype = {
|
|||
// Add padding on the side of the menu per the user's hand preference
|
||||
let leftHand = MetroUtils.handPreference == MetroUtils.handPreferenceLeft;
|
||||
if (aSource && aSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
|
||||
this._commands.setAttribute("left-hand", leftHand);
|
||||
this.commands.setAttribute("left-hand", leftHand);
|
||||
}
|
||||
|
||||
if (aPositionOptions.rightAligned)
|
||||
|
@ -486,6 +427,66 @@ MenuPopup.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_animateShow: function (aPositionOptions) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
window.addEventListener("keypress", this, true);
|
||||
window.addEventListener("click", this, true);
|
||||
Elements.stack.addEventListener("PopupChanged", this, false);
|
||||
Elements.browsers.addEventListener("PanBegin", this, false);
|
||||
|
||||
this._panel.hidden = false;
|
||||
let popupFrom = !aPositionOptions.bottomAligned ? "above" : "below";
|
||||
this._panel.setAttribute("showingfrom", popupFrom);
|
||||
|
||||
// This triggers a reflow, which sets transitionability.
|
||||
// All animation/transition setup must happen before here.
|
||||
this._position(aPositionOptions || {});
|
||||
|
||||
let self = this;
|
||||
this._panel.addEventListener("transitionend", function popupshown () {
|
||||
self._panel.removeEventListener("transitionend", popupshown);
|
||||
self._panel.removeAttribute("showingfrom");
|
||||
|
||||
self._dispatch("popupshown");
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
this._panel.setAttribute("showing", "true");
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
_animateHide: function () {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
window.removeEventListener("keypress", this, true);
|
||||
window.removeEventListener("click", this, true);
|
||||
Elements.stack.removeEventListener("PopupChanged", this, false);
|
||||
Elements.browsers.removeEventListener("PanBegin", this, false);
|
||||
|
||||
let self = this;
|
||||
this._panel.addEventListener("transitionend", function popuphidden() {
|
||||
self._panel.removeEventListener("transitionend", popuphidden);
|
||||
self._panel.removeAttribute("hiding");
|
||||
self._panel.hidden = true;
|
||||
self._popup.style.maxWidth = "none";
|
||||
self._popup.style.maxHeight = "none";
|
||||
|
||||
self._dispatch("popuphidden");
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
this._panel.setAttribute("hiding", "true");
|
||||
this._panel.removeAttribute("showing");
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
_dispatch: function _dispatch(aName) {
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent(aName, true, false);
|
||||
this._panel.dispatchEvent(event);
|
||||
},
|
||||
|
||||
handleEvent: function handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "keypress":
|
||||
|
@ -497,7 +498,7 @@ MenuPopup.prototype = {
|
|||
this.hide();
|
||||
}
|
||||
break;
|
||||
case "mousedown":
|
||||
case "click":
|
||||
if (!this._popup.contains(aEvent.target)) {
|
||||
aEvent.stopPropagation();
|
||||
this.hide();
|
||||
|
|
|
@ -10,19 +10,17 @@ relativesrcdir = @relativesrcdir@
|
|||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
# Disabled for intermittent failures
|
||||
# Bug 880739
|
||||
# browser_context_menu_tests.js \
|
||||
# browser_context_menu_tests_01.html \
|
||||
# browser_context_menu_tests_02.html \
|
||||
# browser_context_menu_tests_03.html \
|
||||
|
||||
MOCHITEST_METRO_FILES = \
|
||||
head.js \
|
||||
browser_urlbar.js \
|
||||
browser_bookmarks.js \
|
||||
browser_canonizeURL.js \
|
||||
browser_circular_progress_indicator.js \
|
||||
browser_context_menu_tests.js \
|
||||
browser_context_menu_tests_01.html \
|
||||
browser_context_menu_tests_02.html \
|
||||
browser_context_menu_tests_03.html \
|
||||
browser_context_menu_tests_04.html \
|
||||
browser_context_ui.js \
|
||||
browser_downloads.js \
|
||||
browser_findbar.js \
|
||||
|
|
|
@ -58,7 +58,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-copy",
|
||||
|
@ -91,7 +91,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-copy",
|
||||
|
@ -113,7 +113,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-open-in-new-tab",
|
||||
|
@ -135,7 +135,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
"context-select-all"]);
|
||||
|
@ -159,7 +159,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
"context-copy"]);
|
||||
|
@ -191,7 +191,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
|
@ -212,7 +212,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
|
@ -236,7 +236,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
"context-copy"]);
|
||||
|
@ -272,7 +272,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-paste"]);
|
||||
|
@ -295,7 +295,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should *not* be visible
|
||||
ok(!ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(!ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
// the test above will invoke the app bar
|
||||
yield hideContextUI();
|
||||
|
@ -336,7 +336,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible and at a specific position
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
let notificationBox = Browser.getNotificationBox();
|
||||
let notification = notificationBox.getNotificationWithValue("popup-blocked");
|
||||
|
@ -352,6 +352,9 @@ gTests.push({
|
|||
}
|
||||
});
|
||||
|
||||
/*
|
||||
XXX code used to diagnose bug 880739
|
||||
|
||||
var observeLogger = {
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
info("observeLogger: " + aTopic);
|
||||
|
@ -383,15 +386,18 @@ var observeLogger = {
|
|||
Services.obs.removeObserver(observeLogger, "dl-cancel");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Image context menu tests
|
||||
gTests.push({
|
||||
desc: "image context menu",
|
||||
setUp: function() {
|
||||
observeLogger.init();
|
||||
// XXX code used to diagnose bug 880739
|
||||
//observeLogger.init();
|
||||
},
|
||||
tearDown: function() {
|
||||
observeLogger.shutdown();
|
||||
// XXX code used to diagnose bug 880739
|
||||
//observeLogger.shutdown();
|
||||
},
|
||||
run: function test() {
|
||||
info(chromeRoot + "browser_context_menu_tests_01.html");
|
||||
|
@ -419,7 +425,7 @@ gTests.push({
|
|||
|
||||
purgeEventQueue();
|
||||
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-save-image-lib",
|
||||
"context-copy-image",
|
||||
|
@ -465,7 +471,7 @@ gTests.push({
|
|||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToWindow(win, 20, 20);
|
||||
yield promise;
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
let menuItem = document.getElementById("context-copy-image");
|
||||
ok(menuItem, "menu item exists");
|
||||
|
@ -486,7 +492,7 @@ gTests.push({
|
|||
promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToWindow(win, 30, 30);
|
||||
yield promise;
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
menuItem = document.getElementById("context-copy-image-loc");
|
||||
ok(menuItem, "menu item exists");
|
||||
|
@ -519,7 +525,7 @@ gTests.push({
|
|||
promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToWindow(win, 40, 40);
|
||||
yield promise;
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
menuItem = document.getElementById("context-open-image-tab");
|
||||
ok(menuItem, "menu item exists");
|
||||
|
@ -564,7 +570,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 175, 190);
|
||||
|
||||
|
@ -579,7 +585,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 95, 110);
|
||||
|
||||
|
@ -594,7 +600,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextMenuPositionRange(ContextMenuUI._panel, 295, 310, 540, 555);
|
||||
|
||||
|
@ -609,7 +615,7 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextMenuPositionRange(ContextMenuUI._panel, 295, 310, 340, 355);
|
||||
|
||||
|
@ -624,16 +630,87 @@ gTests.push({
|
|||
yield promise;
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 110, 125);
|
||||
|
||||
promise = waitForEvent(document, "popuphidden");
|
||||
ContextMenuUI.hide();
|
||||
yield promise;
|
||||
|
||||
Browser.closeTab(Browser.selectedTab, { forceClose: true });
|
||||
}
|
||||
});
|
||||
|
||||
function reopenSetUp() {
|
||||
info(chromeRoot + "browser_context_menu_tests_04.html");
|
||||
yield addTab(chromeRoot + "browser_context_menu_tests_04.html");
|
||||
|
||||
// Sometimes the context UI won't actually show up.
|
||||
// Since we're just normalizing, we don't want waitForCondition
|
||||
// to cause an orange, so we're putting a try/catch here.
|
||||
try {
|
||||
yield waitForCondition(() => ContextUI.isVisible);
|
||||
ContextUI.dismiss();
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function reopenTearDown() {
|
||||
let promise = waitForEvent(document, "popuphidden")
|
||||
ContextMenuUI.hide();
|
||||
yield promise;
|
||||
ok(!ContextMenuUI._menuPopup.visible, "popup is actually hidden");
|
||||
|
||||
Browser.closeTab(Browser.selectedTab, { forceClose: true });
|
||||
}
|
||||
|
||||
function getReopenTest(aElementInputFn, aWindowInputFn) {
|
||||
return function () {
|
||||
let win = Browser.selectedTab.browser.contentWindow;
|
||||
let panel = ContextMenuUI._menuPopup._panel;
|
||||
|
||||
let link1 = win.document.getElementById("text1-link");
|
||||
let link2 = win.document.getElementById("text2-link");
|
||||
|
||||
// Show the menu on link 1
|
||||
let showpromise = waitForEvent(panel, "popupshown");
|
||||
aElementInputFn(win, link1);
|
||||
|
||||
ok((yield showpromise), "popupshown event fired");
|
||||
ok(ContextMenuUI._menuPopup.visible, "initial popup is visible");
|
||||
|
||||
// Show the menu on link 2
|
||||
let hidepromise = waitForEvent(panel, "popuphidden");
|
||||
showpromise = waitForEvent(panel, "popupshown");
|
||||
aElementInputFn(win, link2);
|
||||
|
||||
ok((yield hidepromise), "popuphidden event fired");
|
||||
ok((yield showpromise), "popupshown event fired");
|
||||
ok(ContextMenuUI._menuPopup.visible, "popup is still visible");
|
||||
|
||||
// Hide the menu
|
||||
hidepromise = waitForEvent(panel, "popuphidden")
|
||||
aWindowInputFn(win, 10, 10);
|
||||
|
||||
ok((yield hidepromise), "popuphidden event fired");
|
||||
ok(!ContextMenuUI._menuPopup.visible, "popup is no longer visible");
|
||||
}
|
||||
}
|
||||
|
||||
gTests.push({
|
||||
desc: "bug 856264 - mouse - context menu should reopen on other links",
|
||||
setUp: reopenSetUp,
|
||||
tearDown: reopenTearDown,
|
||||
run: getReopenTest(sendContextMenuMouseClickToElement, sendMouseClick)
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "bug 856264 - touch - context menu should reopen on other links",
|
||||
setUp: reopenSetUp,
|
||||
tearDown: reopenTearDown,
|
||||
run: getReopenTest(sendContextMenuClickToElement, sendTap)
|
||||
});
|
||||
|
||||
function test() {
|
||||
runTests();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body style="padding: 10px; margin: 10px;">
|
||||
<div style="margin: 0; padding: 200px 0;">
|
||||
<span id="text1">hello, I'm sorry but I <a id="text1-link" href="#test">must be going</a>.</span>
|
||||
</div>
|
||||
<div style="margin: 0; padding: 200px 0;">
|
||||
<span id="text2"><a id="text2-link" href="#test">hello, I'm sorry but</a> I must be going.</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -29,8 +29,8 @@ function checkAutofillMenuItemContents(aItemList)
|
|||
{
|
||||
let errors = 0;
|
||||
let found = 0;
|
||||
for (let idx = 0; idx < AutofillMenuUI._commands.childNodes.length; idx++) {
|
||||
let item = AutofillMenuUI._commands.childNodes[idx];
|
||||
for (let idx = 0; idx < AutofillMenuUI.commands.childNodes.length; idx++) {
|
||||
let item = AutofillMenuUI.commands.childNodes[idx];
|
||||
let label = item.firstChild.getAttribute("value");
|
||||
let value = item.getAttribute("data");
|
||||
if (aItemList.indexOf(value) == -1) {
|
||||
|
|
|
@ -138,7 +138,7 @@ gTests.push({
|
|||
|
||||
yield promise;
|
||||
ok(promise && !(promise instanceof Error), "promise error");
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
|
||||
let menuItem = document.getElementById("context-copy");
|
||||
ok(menuItem, "menu item exists");
|
||||
|
|
|
@ -78,7 +78,7 @@ gTests.push({
|
|||
sendContextMenuClickToElement(window, edit);
|
||||
yield waitForEvent(document, "popupshown");
|
||||
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
ok(ContextMenuUI._menuPopup.visible, "is visible");
|
||||
let paste = document.getElementById("context-paste");
|
||||
ok(!paste.hidden, "paste item is visible");
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ function setDevPixelEqualToPx()
|
|||
function checkContextUIMenuItemCount(aCount)
|
||||
{
|
||||
let visibleCount = 0;
|
||||
for (let idx = 0; idx < ContextMenuUI._commands.childNodes.length; idx++) {
|
||||
if (!ContextMenuUI._commands.childNodes[idx].hidden)
|
||||
for (let idx = 0; idx < ContextMenuUI.commands.childNodes.length; idx++) {
|
||||
if (!ContextMenuUI.commands.childNodes[idx].hidden)
|
||||
visibleCount++;
|
||||
}
|
||||
is(visibleCount, aCount, "command list count");
|
||||
|
@ -49,8 +49,8 @@ function checkContextUIMenuItemCount(aCount)
|
|||
function checkContextUIMenuItemVisibility(aVisibleList)
|
||||
{
|
||||
let errors = 0;
|
||||
for (let idx = 0; idx < ContextMenuUI._commands.childNodes.length; idx++) {
|
||||
let item = ContextMenuUI._commands.childNodes[idx];
|
||||
for (let idx = 0; idx < ContextMenuUI.commands.childNodes.length; idx++) {
|
||||
let item = ContextMenuUI.commands.childNodes[idx];
|
||||
if (aVisibleList.indexOf(item.id) != -1 && item.hidden) {
|
||||
// item should be visible
|
||||
errors++;
|
||||
|
@ -551,6 +551,20 @@ function logicalCoordsForElement (aElement, aX, aY) {
|
|||
return coords;
|
||||
}
|
||||
|
||||
function sendContextMenuMouseClickToElement(aWindow, aElement, aX, aY) {
|
||||
let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let coords = logicalCoordsForElement(aElement, aX, aY);
|
||||
|
||||
utils.sendMouseEventToWindow("mousedown", coords.x, coords.y, 2, 1, 0);
|
||||
utils.sendMouseEventToWindow("mouseup", coords.x, coords.y, 2, 1, 0);
|
||||
utils.sendMouseEventToWindow("contextmenu", coords.x, coords.y, 2, 1, 0);
|
||||
}
|
||||
|
||||
function sendMouseClick(aWindow, aX, aY) {
|
||||
EventUtils.synthesizeMouseAtPoint(aX, aY, {}, aWindow);
|
||||
}
|
||||
|
||||
/*
|
||||
* sendContextMenuClick - simulates a press-hold touch input event. Event
|
||||
* is delivered to the main window of the application through the top-level
|
||||
|
|
|
@ -50,13 +50,65 @@ let ColorUtils = {
|
|||
return textColor;
|
||||
},
|
||||
|
||||
toCSSRgbColor: function toCSSRgbColor(r, g, b, a) {
|
||||
var values = [Math.round(r), Math.round(g), Math.round(b)];
|
||||
if(undefined !== a && a < 1) {
|
||||
values.push(a);
|
||||
return 'rgba('+values.join(',')+')';
|
||||
}
|
||||
return 'rgb('+values.join(',')+')';
|
||||
},
|
||||
|
||||
/**
|
||||
* converts a decimal(base10) number into rgb string
|
||||
* converts a decimal(base10) number into CSS rgb color value string
|
||||
*/
|
||||
convertDecimalToRgbColor: function convertDecimalToRgbColor(aColor) {
|
||||
let r = (aColor & 0xff0000) >> 16;
|
||||
let g = (aColor & 0x00ff00) >> 8;
|
||||
let b = (aColor & 0x0000ff);
|
||||
return "rgb("+r+","+g+","+b+")";
|
||||
let [r,g,b,a] = this.unpackDecimalColorWord(aColor);
|
||||
return this.toCSSRgbColor(r,g,b,a);
|
||||
},
|
||||
|
||||
/**
|
||||
* unpack a decimal(base10) word for r,g,b,a values
|
||||
*/
|
||||
unpackDecimalColorWord: function unpackDecimalColorWord(aColor) {
|
||||
let a = (aColor & 0xff000000) >> 24;
|
||||
let r = (aColor & 0x00ff0000) >> 16;
|
||||
let g = (aColor & 0x0000ff00) >> 8;
|
||||
let b = (aColor & 0x000000ff);
|
||||
// NB: falsy alpha treated as undefined, fully opaque
|
||||
return a ? [r,g,b,a/255] : [r,g,b];
|
||||
},
|
||||
|
||||
/**
|
||||
* create a decimal(base10) word for r,g,b values
|
||||
*/
|
||||
createDecimalColorWord: function createDecimalColorWord(r, g, b, a) {
|
||||
let rgb = 0;
|
||||
rgb |= b;
|
||||
rgb |= (g << 8);
|
||||
rgb |= (r << 16);
|
||||
// pack alpha value if one is given
|
||||
if(undefined !== a && a < 1)
|
||||
rgb |= (Math.round(a*255) << 24);
|
||||
return rgb;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add 2 rgb(a) colors to get a flat color
|
||||
*/
|
||||
addRgbColors: function addRgbColors(color1, color2) {
|
||||
let [r1, g1, b1] = this.unpackDecimalColorWord(color1);
|
||||
let [r2, g2, b2, alpha] = this.unpackDecimalColorWord(color2);
|
||||
|
||||
let color = {};
|
||||
// early return if 2nd color is opaque
|
||||
if (!alpha || alpha >= 1)
|
||||
return color2;
|
||||
|
||||
return this.createDecimalColorWord(
|
||||
Math.min(255, alpha * r2 + (1 - alpha) * r1),
|
||||
Math.min(255, alpha * g2 + (1 - alpha) * g1),
|
||||
Math.min(255, alpha * b2 + (1 - alpha) * b1)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -127,6 +127,7 @@ documenttab[closing] > .documenttab-container {
|
|||
margin: @metro_spacing_normal@ @metro_spacing_snormal@;
|
||||
background: white none center top no-repeat;
|
||||
background-size: cover;
|
||||
min-width: @thumbnail_width@;
|
||||
width: @thumbnail_width@;
|
||||
height: @thumbnail_height@;
|
||||
}
|
||||
|
@ -234,17 +235,18 @@ documenttab[selected] .documenttab-selection {
|
|||
#start-autocomplete[viewstate="snapped"] .richgrid-item-content {
|
||||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
#start-container,
|
||||
#start-autocomplete {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#start-container[viewstate="snapped"] #start-scrollbox > .meta-section {
|
||||
margin: 0;
|
||||
margin: 0 @metro_spacing_xnormal@;
|
||||
min-width: @grid_double_column_width@;
|
||||
-moz-box-flex: 1;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
#start-container[viewstate="snapped"] richgrid {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
|
|
@ -581,6 +581,16 @@ arrowbox {
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
#start-container[viewstate="snapped"] {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#start-container[viewstate="snapped"] .meta-section-title,
|
||||
#start-container[viewstate="snapped"] richgrid {
|
||||
margin-top: @metro_spacing_xnormal@;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#start-container[viewstate="snapped"] .meta-section-title.narrow-title,
|
||||
#start-container:not([viewstate="snapped"]) .meta-section-title.wide-title {
|
||||
display: block;
|
||||
|
|
|
@ -282,4 +282,13 @@ richgriditem[bending] > .tile-content {
|
|||
background: #fff;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.tile-content {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
richgriditem {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,14 +290,7 @@ let HiddenBrowsers = {
|
|||
|
||||
function HiddenBrowser(width, height) {
|
||||
this.resize(width, height);
|
||||
|
||||
HostFrame.get().then(aFrame => {
|
||||
let doc = aFrame.document;
|
||||
this._browser = doc.createElementNS(XUL_NS, "browser");
|
||||
this._browser.setAttribute("type", "content");
|
||||
this._browser.setAttribute("src", NEWTAB_URL);
|
||||
doc.getElementById("win").appendChild(this._browser);
|
||||
});
|
||||
this._createBrowser();
|
||||
}
|
||||
|
||||
HiddenBrowser.prototype = {
|
||||
|
@ -317,7 +310,9 @@ HiddenBrowser.prototype = {
|
|||
return false;
|
||||
}
|
||||
|
||||
let tabbrowser = aTab.ownerDocument.defaultView.gBrowser;
|
||||
let win = aTab.ownerDocument.defaultView;
|
||||
let tabbrowser = win.gBrowser;
|
||||
|
||||
if (!tabbrowser) {
|
||||
return false;
|
||||
}
|
||||
|
@ -325,6 +320,14 @@ HiddenBrowser.prototype = {
|
|||
// Swap docShells.
|
||||
tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
|
||||
|
||||
// Load all default frame scripts attached to the target window.
|
||||
let mm = aTab.linkedBrowser.messageManager;
|
||||
let scripts = win.messageManager.getDelayedFrameScripts();
|
||||
Array.forEach(scripts, script => mm.loadFrameScript(script, true));
|
||||
|
||||
// Remove the browser, it will be recreated by a timer.
|
||||
this._removeBrowser();
|
||||
|
||||
// Start a timer that will kick off preloading the next newtab page.
|
||||
this._timer = createTimer(this, PRELOADER_INTERVAL_MS);
|
||||
|
||||
|
@ -336,7 +339,7 @@ HiddenBrowser.prototype = {
|
|||
this._timer = null;
|
||||
|
||||
// Start pre-loading the new tab page.
|
||||
this._browser.loadURI(NEWTAB_URL);
|
||||
this._createBrowser();
|
||||
},
|
||||
|
||||
resize: function (width, height) {
|
||||
|
@ -350,12 +353,25 @@ HiddenBrowser.prototype = {
|
|||
},
|
||||
|
||||
destroy: function () {
|
||||
this._removeBrowser();
|
||||
this._timer = clearTimer(this._timer);
|
||||
},
|
||||
|
||||
_createBrowser: function () {
|
||||
HostFrame.get().then(aFrame => {
|
||||
let doc = aFrame.document;
|
||||
this._browser = doc.createElementNS(XUL_NS, "browser");
|
||||
this._browser.setAttribute("type", "content");
|
||||
this._browser.setAttribute("src", NEWTAB_URL);
|
||||
doc.getElementById("win").appendChild(this._browser);
|
||||
});
|
||||
},
|
||||
|
||||
_removeBrowser: function () {
|
||||
if (this._browser) {
|
||||
this._browser.remove();
|
||||
this._browser = null;
|
||||
}
|
||||
|
||||
this._timer = clearTimer(this._timer);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMDOMStringList;
|
||||
interface nsIDOMWindow;
|
||||
interface nsIDocShell;
|
||||
interface nsIContent;
|
||||
|
@ -320,7 +321,7 @@ interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
|
|||
[notxpcom] nsIContent getOwnerContent();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(a54acd34-4141-46f5-b71b-e2ca32879b08)]
|
||||
[scriptable, builtinclass, uuid(ecebfb8c-ff51-11e2-9d65-7af553959281)]
|
||||
interface nsIFrameScriptLoader : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -336,6 +337,12 @@ interface nsIFrameScriptLoader : nsISupports
|
|||
* Removes aURL from the list of scripts which support delayed load.
|
||||
*/
|
||||
void removeDelayedFrameScript(in AString aURL);
|
||||
|
||||
/**
|
||||
* Returns a list of all delayed scripts that will be loaded once
|
||||
* a (remote) frame becomes available.
|
||||
*/
|
||||
nsIDOMDOMStringList getDelayedFrameScripts();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(b37821ff-df79-44d4-821c-6d6ec4dfe1e9)]
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "mozilla/dom/StructuredCloneUtils.h"
|
||||
#include "JavaScriptChild.h"
|
||||
#include "JavaScriptParent.h"
|
||||
#include "nsDOMLists.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef ANDROID
|
||||
|
@ -316,6 +317,28 @@ nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::GetDelayedFrameScripts(nsIDOMDOMStringList** aList)
|
||||
{
|
||||
// Frame message managers may return an incomplete list because scripts
|
||||
// that were loaded after it was connected are not added to the list.
|
||||
if (!IsGlobal() && !IsWindowLevel()) {
|
||||
NS_WARNING("Cannot retrieve list of pending frame scripts for frame"
|
||||
"message managers as it may be incomplete");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMStringList> scripts = new nsDOMStringList();
|
||||
|
||||
for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
|
||||
scripts->Add(mPendingScripts[i]);
|
||||
}
|
||||
|
||||
scripts.forget(aList);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
|
||||
{
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
"set": [
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["browser.pagethumbnails.capturing_disabled", false]
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
|
|
|
@ -181,7 +181,7 @@
|
|||
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["browser.pagethumbnails.capturing_disabled", false]
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
|
|
|
@ -206,7 +206,7 @@ function expectMozbrowserEvent(iframe, eventName) {
|
|||
|
||||
// Set some prefs:
|
||||
//
|
||||
// * browser.pagethumbnails.capturing_disabled: false
|
||||
// * browser.pagethumbnails.capturing_disabled: true
|
||||
//
|
||||
// Disable tab view; it seriously messes us up.
|
||||
//
|
||||
|
@ -244,7 +244,7 @@ function expectMozbrowserEvent(iframe, eventName) {
|
|||
|
||||
browserElementTestHelpers.lockTestReady();
|
||||
SpecialPowers.setBoolPref("network.disable.ipc.security", true);
|
||||
SpecialPowers.pushPrefEnv({set: [["browser.pagethumbnails.capturing_disabled", false],
|
||||
SpecialPowers.pushPrefEnv({set: [["browser.pagethumbnails.capturing_disabled", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", oop],
|
||||
["dom.ipc.tabs.disabled", false],
|
||||
["security.mixed_content.block_active_content", false]]},
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["browser.pagethumbnails.capturing_disabled", false]
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
|
|
|
@ -106,7 +106,7 @@ RefTestCmdLineHandler.prototype =
|
|||
// Setting this pref makes tests run much faster there.
|
||||
branch.setBoolPref("security.fileuri.strict_origin_policy", false);
|
||||
// Disable the thumbnailing service
|
||||
branch.setBoolPref("browser.pagethumbnails.capturing_disabled", false);
|
||||
branch.setBoolPref("browser.pagethumbnails.capturing_disabled", true);
|
||||
|
||||
var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(nsIWindowWatcher);
|
||||
|
|
3
mach
|
@ -33,8 +33,7 @@ for dir_path in ancestors(os.getcwd()):
|
|||
# to look for a config file at the path in $MOZCONFIG rather than
|
||||
# its default locations.
|
||||
#
|
||||
# Note: subprocess requires native strings in os.environ Python
|
||||
# 2.7.2 and earlier on Windows.
|
||||
# Note: subprocess requires native strings in os.environ on Windows
|
||||
os.environ[b"MOZCONFIG"] = str(info["mozconfig"])
|
||||
|
||||
if "topsrcdir" in info:
|
||||
|
|
|
@ -478,10 +478,8 @@ pref("security.alternate_certificate_error_page", "certerror");
|
|||
|
||||
pref("security.warn_viewing_mixed", false); // Warning is disabled. See Bug 616712.
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Block insecure active content on https pages
|
||||
pref("security.mixed_content.block_active_content", true);
|
||||
#endif
|
||||
|
||||
// Override some named colors to avoid inverse OS themes
|
||||
pref("ui.-moz-dialog", "#efebe7");
|
||||
|
|
|
@ -136,4 +136,13 @@ public class AppConstants {
|
|||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
// See this wiki page for more details about channel specific build defines:
|
||||
// https://wiki.mozilla.org/Platform/Channel-specific_build_defines
|
||||
public static final boolean RELEASE_BUILD =
|
||||
#ifdef RELEASE_BUILD
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1988,8 +1988,7 @@ abstract public class BrowserApp extends GeckoApp
|
|||
* @return true if update UI was launched.
|
||||
*/
|
||||
protected boolean handleUpdaterLaunch() {
|
||||
if ("release".equals(AppConstants.MOZ_UPDATE_CHANNEL) ||
|
||||
"beta".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
|
||||
if (AppConstants.RELEASE_BUILD) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse("market://details?id=" + getPackageName()));
|
||||
startActivity(intent);
|
||||
|
|
|
@ -50,6 +50,7 @@ import android.view.Window;
|
|||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
|
@ -89,7 +90,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
|||
public ImageButton mStop;
|
||||
public ImageButton mSiteSecurity;
|
||||
public PageActionLayout mPageActionLayout;
|
||||
private AnimationDrawable mProgressSpinner;
|
||||
private Animation mProgressSpinner;
|
||||
private TabCounter mTabsCounter;
|
||||
private ImageView mShadow;
|
||||
private GeckoImageButton mMenu;
|
||||
|
@ -103,6 +104,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
|||
|
||||
private boolean mShowSiteSecurity;
|
||||
private boolean mShowReader;
|
||||
private boolean mSpinnerVisible;
|
||||
|
||||
private boolean mAnimatingEntry;
|
||||
|
||||
|
@ -221,7 +223,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
|||
mSiteSecurityVisible = (mSiteSecurity.getVisibility() == View.VISIBLE);
|
||||
mActivity.getSiteIdentityPopup().setAnchor(mSiteSecurity);
|
||||
|
||||
mProgressSpinner = (AnimationDrawable) res.getDrawable(R.drawable.progress_spinner);
|
||||
mProgressSpinner = AnimationUtils.loadAnimation(mActivity, R.anim.progress_spinner);
|
||||
|
||||
mStop = (ImageButton) findViewById(R.id.stop);
|
||||
mShadow = (ImageView) findViewById(R.id.shadow);
|
||||
|
@ -787,16 +789,26 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
|||
// are needed by S1/S2 tests (http://mrcote.info/phonedash/#).
|
||||
// See discussion in Bug 804457. Bug 805124 tracks paring these down.
|
||||
if (visible) {
|
||||
mFavicon.setImageDrawable(mProgressSpinner);
|
||||
mProgressSpinner.start();
|
||||
mFavicon.setImageResource(R.drawable.progress_spinner);
|
||||
//To stop the glitch caused by mutiple start() calls.
|
||||
if (!mSpinnerVisible) {
|
||||
setPageActionVisibility(true);
|
||||
mFavicon.setAnimation(mProgressSpinner);
|
||||
mProgressSpinner.start();
|
||||
mSpinnerVisible = true;
|
||||
}
|
||||
Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - Throbber start");
|
||||
} else {
|
||||
mProgressSpinner.stop();
|
||||
setPageActionVisibility(false);
|
||||
Tab selectedTab = Tabs.getInstance().getSelectedTab();
|
||||
if (selectedTab != null)
|
||||
setFavicon(selectedTab.getFavicon());
|
||||
|
||||
if (mSpinnerVisible) {
|
||||
setPageActionVisibility(false);
|
||||
mFavicon.setAnimation(null);
|
||||
mProgressSpinner.cancel();
|
||||
mSpinnerVisible = false;
|
||||
}
|
||||
Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - Throbber stop");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -721,6 +721,21 @@ abstract public class GeckoApp
|
|||
// something went wrong.
|
||||
Log.e(LOGTAG, "Received Contact:Add message with no email nor phone number");
|
||||
}
|
||||
} else if (event.equals("Intent:GetHandlers")) {
|
||||
Intent intent = GeckoAppShell.getOpenURIIntent(sAppContext, message.optString("url"),
|
||||
message.optString("mime"), message.optString("action"), message.optString("title"));
|
||||
String[] handlers = GeckoAppShell.getHandlersForIntent(intent);
|
||||
ArrayList<String> appList = new ArrayList<String>(handlers.length);
|
||||
for (int i = 0; i < handlers.length; i++) {
|
||||
appList.add(handlers[i]);
|
||||
}
|
||||
JSONObject handlersJSON = new JSONObject();
|
||||
handlersJSON.put("apps", new JSONArray(appList));
|
||||
mCurrentResponse = handlersJSON.toString();
|
||||
} else if (event.equals("Intent:Open")) {
|
||||
GeckoAppShell.openUriExternal(message.optString("url"),
|
||||
message.optString("mime"), message.optString("packageName"),
|
||||
message.optString("className"), message.optString("action"), message.optString("title"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
|
||||
|
@ -1507,6 +1522,8 @@ abstract public class GeckoApp
|
|||
registerEventListener("Update:Install");
|
||||
registerEventListener("PrivateBrowsing:Data");
|
||||
registerEventListener("Contact:Add");
|
||||
registerEventListener("Intent:Open");
|
||||
registerEventListener("Intent:GetHandlers");
|
||||
|
||||
if (SmsManager.getInstance() != null) {
|
||||
SmsManager.getInstance().start();
|
||||
|
@ -2061,6 +2078,8 @@ abstract public class GeckoApp
|
|||
unregisterEventListener("Update:Install");
|
||||
unregisterEventListener("PrivateBrowsing:Data");
|
||||
unregisterEventListener("Contact:Add");
|
||||
unregisterEventListener("Intent:Open");
|
||||
unregisterEventListener("Intent:GetHandlers");
|
||||
|
||||
deleteTempFiles();
|
||||
|
||||
|
|
|
@ -597,6 +597,7 @@ RES_ANIM = \
|
|||
res/anim/awesomebar_hold_still.xml \
|
||||
res/anim/grow_fade_in.xml \
|
||||
res/anim/grow_fade_in_center.xml \
|
||||
res/anim/progress_spinner.xml \
|
||||
res/anim/shrink_fade_out.xml \
|
||||
$(NULL)
|
||||
|
||||
|
@ -647,18 +648,7 @@ RES_DRAWABLE_MDPI = \
|
|||
res/drawable-mdpi/ic_menu_reload.png \
|
||||
res/drawable-mdpi/ic_status_logo.png \
|
||||
res/drawable-mdpi/icon_pageaction.png \
|
||||
res/drawable-mdpi/progress_spinner_1.png \
|
||||
res/drawable-mdpi/progress_spinner_2.png \
|
||||
res/drawable-mdpi/progress_spinner_3.png \
|
||||
res/drawable-mdpi/progress_spinner_4.png \
|
||||
res/drawable-mdpi/progress_spinner_5.png \
|
||||
res/drawable-mdpi/progress_spinner_6.png \
|
||||
res/drawable-mdpi/progress_spinner_7.png \
|
||||
res/drawable-mdpi/progress_spinner_8.png \
|
||||
res/drawable-mdpi/progress_spinner_9.png \
|
||||
res/drawable-mdpi/progress_spinner_10.png \
|
||||
res/drawable-mdpi/progress_spinner_11.png \
|
||||
res/drawable-mdpi/progress_spinner_12.png \
|
||||
res/drawable-mdpi/progress_spinner.png \
|
||||
res/drawable-mdpi/tab_indicator_divider.9.png \
|
||||
res/drawable-mdpi/tab_indicator_selected.9.png \
|
||||
res/drawable-mdpi/tab_indicator_selected_focused.9.png \
|
||||
|
@ -1118,7 +1108,6 @@ RES_DRAWABLE += \
|
|||
res/drawable/ic_menu_quit.xml \
|
||||
res/drawable/menu_item_state.xml \
|
||||
res/drawable/menu_level.xml \
|
||||
res/drawable/progress_spinner.xml \
|
||||
res/drawable/remote_tabs_child_divider.xml \
|
||||
res/drawable/shaped_button.xml \
|
||||
res/drawable/site_security_level.xml \
|
||||
|
|
|
@ -138,8 +138,7 @@ public class UpdateService extends IntentService {
|
|||
int interval;
|
||||
if (isRetry) {
|
||||
interval = INTERVAL_RETRY;
|
||||
} else if (AppConstants.MOZ_UPDATE_CHANNEL.equals("nightly") ||
|
||||
AppConstants.MOZ_UPDATE_CHANNEL.equals("aurora")) {
|
||||
} else if (!AppConstants.RELEASE_BUILD) {
|
||||
interval = INTERVAL_SHORT;
|
||||
} else {
|
||||
interval = INTERVAL_LONG;
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.content.Context;
|
|||
import android.content.ContextWrapper;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteConstraintException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Build;
|
||||
|
@ -186,7 +187,7 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
protected final HealthReportSQLiteOpenHelper helper;
|
||||
|
||||
public static class HealthReportSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
public static final int CURRENT_VERSION = 4;
|
||||
public static final int CURRENT_VERSION = 5;
|
||||
public static final String LOG_TAG = "HealthReportSQL";
|
||||
|
||||
/**
|
||||
|
@ -227,11 +228,16 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
|
||||
public static boolean CAN_USE_ABSOLUTE_DB_PATH = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO);
|
||||
public HealthReportSQLiteOpenHelper(Context context, File profileDirectory, String name) {
|
||||
this(context, profileDirectory, name, CURRENT_VERSION);
|
||||
}
|
||||
|
||||
// For testing DBs of different versions.
|
||||
public HealthReportSQLiteOpenHelper(Context context, File profileDirectory, String name, int version) {
|
||||
super(
|
||||
(CAN_USE_ABSOLUTE_DB_PATH ? context : new AbsolutePathContext(context, profileDirectory)),
|
||||
(CAN_USE_ABSOLUTE_DB_PATH ? getAbsolutePath(profileDirectory, name) : name),
|
||||
null,
|
||||
CURRENT_VERSION);
|
||||
version);
|
||||
|
||||
if (CAN_USE_ABSOLUTE_DB_PATH) {
|
||||
Logger.pii(LOG_TAG, "Opening: " + getAbsolutePath(profileDirectory, name));
|
||||
|
@ -347,6 +353,13 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(SQLiteDatabase db) {
|
||||
if (!db.isReadOnly()) {
|
||||
db.execSQL("PRAGMA foreign_keys=ON;");
|
||||
}
|
||||
}
|
||||
|
||||
private void createAddonsEnvironmentsView(SQLiteDatabase db) {
|
||||
db.execSQL("CREATE VIEW environments_with_addons AS " +
|
||||
"SELECT e.id AS id, " +
|
||||
|
@ -394,6 +407,22 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
" WHERE measurement IN (SELECT id FROM measurements WHERE name = 'org.mozilla.searches.counts')");
|
||||
}
|
||||
|
||||
private void upgradeDatabaseFrom4to5(SQLiteDatabase db) {
|
||||
// Delete NULL in addons.body, which appeared as a result of Bug 886156. Note that the
|
||||
// foreign key constraint, "ON DELETE RESTRICT", may be violated, but since onOpen() is
|
||||
// called after this method, foreign keys are not yet enabled and constraints can be broken.
|
||||
db.delete("addons", "body IS NULL", null);
|
||||
|
||||
// Purge any data inconsistent with foreign key references (which may have appeared before
|
||||
// foreign keys were enabled in Bug 900289).
|
||||
db.delete("fields", "measurement NOT IN (SELECT id FROM measurements)", null);
|
||||
db.delete("environments", "addonsID NOT IN (SELECT id from addons)", null);
|
||||
db.delete(EVENTS_INTEGER, "env NOT IN (SELECT id FROM environments)", null);
|
||||
db.delete(EVENTS_TEXTUAL, "env NOT IN (SELECT id FROM environments)", null);
|
||||
db.delete(EVENTS_INTEGER, "field NOT IN (SELECT id FROM fields)", null);
|
||||
db.delete(EVENTS_TEXTUAL, "field NOT IN (SELECT id FROM fields)", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion >= newVersion) {
|
||||
|
@ -408,6 +437,8 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
upgradeDatabaseFrom2To3(db);
|
||||
case 3:
|
||||
upgradeDatabaseFrom3To4(db);
|
||||
case 4:
|
||||
upgradeDatabaseFrom4to5(db);
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} catch (Exception e) {
|
||||
|
@ -1031,7 +1062,11 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
v.put("env", env);
|
||||
v.put("field", field);
|
||||
v.put("date", day);
|
||||
db.insert(table, null, v);
|
||||
try {
|
||||
db.insertOrThrow(table, null, v);
|
||||
} catch (SQLiteConstraintException e) {
|
||||
throw new IllegalStateException("Event did not reference existing an environment or field.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1063,7 +1098,11 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
|
||||
final SQLiteDatabase db = this.helper.getWritableDatabase();
|
||||
putValue(v, value);
|
||||
db.insert(table, null, v);
|
||||
try {
|
||||
db.insertOrThrow(table, null, v);
|
||||
} catch (SQLiteConstraintException e) {
|
||||
throw new IllegalStateException("Event did not reference existing an environment or field.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1133,7 +1172,11 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
|
|||
v.put("value", by);
|
||||
v.put("field", field);
|
||||
v.put("date", day);
|
||||
db.insert(EVENTS_INTEGER, null, v);
|
||||
try {
|
||||
db.insertOrThrow(EVENTS_INTEGER, null, v);
|
||||
} catch (SQLiteConstraintException e) {
|
||||
throw new IllegalStateException("Event did not reference existing an environment or field.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?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/. -->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/linear_interpolator">
|
||||
|
||||
<rotate android:duration="1200"
|
||||
android:fromDegrees="0"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:repeatCount="infinite"
|
||||
android:toDegrees="360"/>
|
||||
|
||||
</set>
|
До Ширина: | Высота: | Размер: 2.0 KiB После Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 1.9 KiB |
До Ширина: | Высота: | Размер: 1.9 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 1.9 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 1.9 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 1.9 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_1"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_2"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_3"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_4"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_5"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_6"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_7"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_8"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_9"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_10"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_11"/>
|
||||
<item android:duration="100" android:drawable="@drawable/progress_spinner_12"/>
|
||||
|
||||
</animation-list>
|
|
@ -75,8 +75,9 @@
|
|||
android:layout_width="@dimen/browser_toolbar_favicon_size"
|
||||
android:layout_height="fill_parent"
|
||||
android:scaleType="fitCenter"
|
||||
android:paddingLeft="8dip"
|
||||
android:layout_marginRight="4dip"
|
||||
android:layout_marginLeft="4dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/favicon"/>
|
||||
|
||||
|
|
|
@ -101,8 +101,9 @@
|
|||
android:layout_width="@dimen/browser_toolbar_favicon_size"
|
||||
android:layout_height="fill_parent"
|
||||
android:scaleType="fitCenter"
|
||||
android:paddingLeft="12dip"
|
||||
android:layout_marginRight="4dip"
|
||||
android:layout_marginLeft="8dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/favicon"/>
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<dimen name="browser_toolbar_button_padding">12dp</dimen>
|
||||
<dimen name="browser_toolbar_icon_width">48dp</dimen>
|
||||
<dimen name="browser_toolbar_lock_width">20dp</dimen>
|
||||
<dimen name="browser_toolbar_favicon_size">29.33dip</dimen>
|
||||
<dimen name="browser_toolbar_favicon_size">25.33dip</dimen>
|
||||
<dimen name="favicon_bg">32dp</dimen>
|
||||
<dimen name="favicon_bg_radius">1dp</dimen>
|
||||
|
||||
|
|
|
@ -3,6 +3,19 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "ContentAreaUtils", function() {
|
||||
let ContentAreaUtils = {};
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", ContentAreaUtils);
|
||||
return ContentAreaUtils;
|
||||
});
|
||||
|
||||
function getBridge() {
|
||||
return Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge);
|
||||
}
|
||||
|
||||
function sendMessageToJava(aMessage) {
|
||||
return getBridge().handleGeckoMessage(JSON.stringify(aMessage));
|
||||
}
|
||||
|
||||
var HelperApps = {
|
||||
get defaultHttpHandlers() {
|
||||
|
@ -37,25 +50,51 @@ var HelperApps = {
|
|||
|
||||
getAppsForUri: function getAppsFor(uri) {
|
||||
let found = [];
|
||||
let handlerInfoProto = this.urlHandlerService.getURLHandlerInfoFromOS(uri, {});
|
||||
let urlHandlers = handlerInfoProto.possibleApplicationHandlers;
|
||||
for (var i = 0; i < urlHandlers.length; i++) {
|
||||
let urlApp = urlHandlers.queryElementAt(i, Ci.nsIHandlerApp);
|
||||
if (!this.defaultHttpHandlers[urlApp.name]) {
|
||||
found.push(urlApp);
|
||||
}
|
||||
let mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
|
||||
// empty action string defaults to android.intent.action.VIEW
|
||||
let msg = {
|
||||
type: "Intent:GetHandlers",
|
||||
mime: mimeType,
|
||||
action: "",
|
||||
url: uri.spec,
|
||||
packageName: "",
|
||||
className: ""
|
||||
};
|
||||
let apps = this._parseApps(JSON.parse(sendMessageToJava(msg)));
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let appName = apps[i].name;
|
||||
if (appName.length > 0 && !this.defaultHttpHandlers[appName])
|
||||
found.push(apps[i]);
|
||||
}
|
||||
return found;
|
||||
},
|
||||
|
||||
openUriInApp: function openUriInApp(uri) {
|
||||
var possibleHandlers = this.getAppsForUri(uri);
|
||||
if (possibleHandlers.length == 1) {
|
||||
possibleHandlers[0].launchWithURI(uri);
|
||||
} else if (possibleHandlers.length > 0) {
|
||||
let handlerInfoProto = this.urlHandlerService.getURLHandlerInfoFromOS(uri, {});
|
||||
handlerInfoProto.preferredApplicationHandler.launchWithURI(uri);
|
||||
let mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
|
||||
let msg = {
|
||||
type: "Intent:Open",
|
||||
mime: mimeType,
|
||||
action: "",
|
||||
url: uri.spec,
|
||||
packageName: "",
|
||||
className: ""
|
||||
};
|
||||
sendMessageToJava(msg);
|
||||
},
|
||||
|
||||
_parseApps: function _parseApps(aJSON) {
|
||||
// aJSON -> {apps: [app1Label, app1Default, app1PackageName, app1ActivityName, app2Label, app2Defaut, ...]}
|
||||
// see GeckoAppShell.java getHandlersForIntent function for details
|
||||
let appInfo = aJSON.apps;
|
||||
const numAttr = 4; // 4 elements per ResolveInfo: label, default, package name, activity name.
|
||||
let apps = [];
|
||||
for (let i = 0; i < appInfo.length; i += numAttr) {
|
||||
apps.push({"name" : appInfo[i],
|
||||
"isDefault" : appInfo[i+1],
|
||||
"packageName" : appInfo[i+2],
|
||||
"activityName" : appInfo[i+3]});
|
||||
}
|
||||
return apps;
|
||||
},
|
||||
|
||||
showDoorhanger: function showDoorhanger(aUri, aCallback) {
|
||||
|
|
|
@ -41,7 +41,6 @@ var ContextMenus = {
|
|||
document.getElementById("contextmenu-enable").setAttribute("hidden", "true");
|
||||
document.getElementById("contextmenu-disable").setAttribute("hidden", "true");
|
||||
document.getElementById("contextmenu-uninstall").setAttribute("hidden", "true");
|
||||
document.getElementById("contextmenu-default").setAttribute("hidden", "true");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,8 +59,6 @@ var ContextMenus = {
|
|||
document.getElementById("contextmenu-enable").removeAttribute("hidden");
|
||||
document.getElementById("contextmenu-disable").setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
document.getElementById("contextmenu-default").setAttribute("hidden", "true");
|
||||
},
|
||||
|
||||
enable: function(event) {
|
||||
|
@ -253,37 +250,6 @@ var Addons = {
|
|||
list.appendChild(item);
|
||||
}
|
||||
|
||||
// Load the search engines
|
||||
let defaults = Services.search.getDefaultEngines({ }).map(function (e) e.name);
|
||||
function isDefault(aEngine)
|
||||
defaults.indexOf(aEngine.name) != -1
|
||||
|
||||
let defaultDescription = gStringBundle.GetStringFromName("addonsSearchEngine.description");
|
||||
|
||||
let engines = Services.search.getEngines({ });
|
||||
for (let e = 0; e < engines.length; e++) {
|
||||
let engine = engines[e];
|
||||
let addon = {};
|
||||
addon.id = engine.name;
|
||||
addon.type = "search";
|
||||
addon.name = engine.name;
|
||||
addon.version = "";
|
||||
addon.description = engine.description || defaultDescription;
|
||||
addon.iconURL = engine.iconURI ? engine.iconURI.spec : "";
|
||||
addon.optionsURL = "";
|
||||
addon.appDisabled = false;
|
||||
addon.scope = isDefault(engine) ? AddonManager.SCOPE_APPLICATION : AddonManager.SCOPE_PROFILE;
|
||||
addon.engine = engine;
|
||||
|
||||
let item = self._createItem(addon);
|
||||
item.setAttribute("isDisabled", engine.hidden);
|
||||
item.setAttribute("updateable", "false");
|
||||
item.setAttribute("opType", "");
|
||||
item.setAttribute("optionsURL", "");
|
||||
item.addon = addon;
|
||||
list.appendChild(item);
|
||||
}
|
||||
|
||||
// Add a "Browse all Firefox Add-ons" item to the bottom of the list.
|
||||
let browseItem = self._createBrowseItem();
|
||||
list.appendChild(browseItem);
|
||||
|
@ -348,9 +314,6 @@ var Addons = {
|
|||
else
|
||||
uninstallBtn.removeAttribute("disabled");
|
||||
|
||||
let defaultButton = document.getElementById("default-btn");
|
||||
defaultButton.setAttribute("hidden", "true");
|
||||
|
||||
let box = document.querySelector("#addons-details > .addon-item .options-box");
|
||||
box.innerHTML = "";
|
||||
|
||||
|
|
|
@ -7631,12 +7631,26 @@ let Reader = {
|
|||
var ExternalApps = {
|
||||
_contextMenuId: -1,
|
||||
|
||||
// extend _getLink to pickup html5 media links.
|
||||
_getMediaLink: function(aElement) {
|
||||
let uri = NativeWindow.contextmenus._getLink(aElement);
|
||||
if (uri == null) {
|
||||
if (aElement.nodeType == Ci.nsIDOMNode.ELEMENT_NODE && (aElement instanceof Ci.nsIDOMHTMLMediaElement && mediaSrc)) {
|
||||
try {
|
||||
let mediaSrc = aElement.currentSrc || aElement.src;
|
||||
uri = ContentAreaUtils.makeURI(mediaSrc, null, null);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
},
|
||||
|
||||
init: function helper_init() {
|
||||
this._contextMenuId = NativeWindow.contextmenus.add(function(aElement) {
|
||||
let uri = null;
|
||||
var node = aElement;
|
||||
while (node && !uri) {
|
||||
uri = NativeWindow.contextmenus._getLink(node);
|
||||
uri = ExternalApps._getMediaLink(node);
|
||||
node = node.parentNode;
|
||||
}
|
||||
let apps = [];
|
||||
|
@ -7654,7 +7668,7 @@ var ExternalApps = {
|
|||
|
||||
filter: {
|
||||
matches: function(aElement) {
|
||||
let uri = NativeWindow.contextmenus._getLink(aElement);
|
||||
let uri = ExternalApps._getMediaLink(aElement);
|
||||
let apps = [];
|
||||
if (uri) {
|
||||
apps = HelperApps.getAppsForUri(uri);
|
||||
|
@ -7664,7 +7678,7 @@ var ExternalApps = {
|
|||
},
|
||||
|
||||
openExternal: function(aElement) {
|
||||
let uri = NativeWindow.contextmenus._getLink(aElement);
|
||||
let uri = ExternalApps._getMediaLink(aElement);
|
||||
HelperApps.openUriInApp(uri);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -59,7 +59,8 @@ class MachCommands(MachCommandBase):
|
|||
return self.run_process([self.python_executable] + args,
|
||||
pass_thru=True, # Allow user to run Python interactively.
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
append_env={'PYTHONDONTWRITEBYTECODE': '1'})
|
||||
# Note: subprocess requires native strings in os.environ on Windows
|
||||
append_env={b'PYTHONDONTWRITEBYTECODE': str('1')})
|
||||
|
||||
@Command('python-test', category='testing',
|
||||
description='Run Python unit tests.')
|
||||
|
@ -109,7 +110,8 @@ class MachCommands(MachCommandBase):
|
|||
[self.python_executable, file],
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
log_name='python-test',
|
||||
append_env={'PYTHONDONTWRITEBYTECODE': '1'},
|
||||
# subprocess requires native strings in os.environ on Windows
|
||||
append_env={b'PYTHONDONTWRITEBYTECODE': str('1')},
|
||||
line_handler=_line_handler)
|
||||
return_code += inner_return_code
|
||||
|
||||
|
|
|
@ -149,7 +149,6 @@ class MochitestRunner(MozbuildObject):
|
|||
return 1
|
||||
|
||||
options.testPath = test_path
|
||||
env = {'TEST_PATH': test_path}
|
||||
|
||||
if rerun_failures:
|
||||
options.testManifest = failure_file_path
|
||||
|
|
|
@ -147,4 +147,4 @@ user_pref("geo.provider.testing", true);
|
|||
|
||||
// Background thumbnails in particular cause grief, and disabling thumbnails
|
||||
// in general can't hurt - we re-enable them when tests need them.
|
||||
user_pref("browser.pagethumbnails.capturing_disabled", false);
|
||||
user_pref("browser.pagethumbnails.capturing_disabled", true);
|
||||
|
|
|
@ -465,7 +465,7 @@ this.PageThumbs = {
|
|||
|
||||
_prefEnabled: function PageThumbs_prefEnabled() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
|
||||
return !Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
|
||||
}
|
||||
catch (e) {
|
||||
return true;
|
||||
|
|
|
@ -11,7 +11,7 @@ let {PageThumbs, PageThumbsStorage, SessionStore, FileUtils, OS} = tmp;
|
|||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
let oldEnabledPref = Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
|
||||
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", true);
|
||||
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", false);
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
while (gBrowser.tabs.length > 1)
|
||||
|
|
|
@ -111,11 +111,12 @@ function getCtorName(aObj) {
|
|||
*
|
||||
* @param {any} aThing
|
||||
* The object to be stringified
|
||||
* @param {boolean} aAllowNewLines
|
||||
* @return {string}
|
||||
* A single line representation of aThing, which will generally be at
|
||||
* most 80 chars long
|
||||
*/
|
||||
function stringify(aThing) {
|
||||
function stringify(aThing, aAllowNewLines) {
|
||||
if (aThing === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
|
@ -145,7 +146,10 @@ function stringify(aThing) {
|
|||
return aThing.toString().replace(/\s+/g, " ");
|
||||
}
|
||||
|
||||
let str = aThing.toString().replace(/\n/g, "|");
|
||||
let str = aThing.toString();
|
||||
if (!aAllowNewLines) {
|
||||
str = str.replace(/\n/g, "|");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -465,9 +469,9 @@ function createDumper(aLevel) {
|
|||
let frame = getStack(Components.stack.caller, 1)[0];
|
||||
sendConsoleAPIMessage(aLevel, frame, args);
|
||||
let data = args.map(function(arg) {
|
||||
return stringify(arg);
|
||||
return stringify(arg, true);
|
||||
});
|
||||
dumpMessage(this, aLevel, data.join(", "));
|
||||
dumpMessage(this, aLevel, data.join(" "));
|
||||
};
|
||||
}
|
||||
|
||||
|
|