Merge fx-team to m-c

This commit is contained in:
Wes Kocher 2013-09-24 20:06:37 -07:00
commit 9f40060dc3
88 changed files with 1096 additions and 600 deletions

View File

@ -4904,17 +4904,16 @@
<method name="_calcMouseTargetRect">
<body><![CDATA[
let alignRight = false;
let container = this.parentNode;
let alignRight = (getComputedStyle(container).direction == "rtl");
let panelRect = this.getBoundingClientRect();
let containerRect = container.getBoundingClientRect();
if (getComputedStyle(document.documentElement).direction == "rtl")
alignRight = !alignRight;
let rect = this.getBoundingClientRect();
this._mouseTargetRect = {
top: rect.top,
bottom: rect.bottom,
left: alignRight ? window.innerWidth - rect.width : 0,
right: alignRight ? window.innerWidth : rect.width
top: panelRect.top,
bottom: panelRect.bottom,
left: alignRight ? containerRect.right - panelRect.width : containerRect.left,
right: alignRight ? containerRect.right : containerRect.left + panelRect.width
};
]]></body>
</method>

View File

@ -1127,7 +1127,7 @@ var ViewMenu = {
* Set up the content of the view menu.
*/
populateSortMenu: function VM_populateSortMenu(event) {
this.fillWithColumns(event, "viewUnsorted", "directionSeparator", "radio", "view.sortBy.");
this.fillWithColumns(event, "viewUnsorted", "directionSeparator", "radio", "view.sortBy.1.");
var sortColumn = this._getSortColumn();
var viewSortAscending = document.getElementById("viewSortAscending");

View File

@ -384,7 +384,7 @@
<treecol label="&col.url.label;" id="placesContentUrl" anonid="url" flex="5"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.lastvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
<treecol label="&col.mostrecentvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"

View File

@ -2585,7 +2585,6 @@ let SessionStoreInternal = {
restoreHistory:
function ssi_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
aRestoreImmediately) {
var _this = this;
// if the tab got removed before being completely restored, then skip it
while (aTabs.length > 0 && !(this._canRestoreTabHistory(aTabs[0]))) {
aTabs.shift();
@ -2654,9 +2653,11 @@ let SessionStoreInternal = {
tab.dispatchEvent(event);
// Restore the history in the next tab
aWindow.setTimeout(function(){
_this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
aRestoreImmediately);
aWindow.setTimeout(() => {
if (!aWindow.closed) {
this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
aRestoreImmediately);
}
}, 0);
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but

View File

@ -61,6 +61,9 @@ let UI = {
this.template = new Template(document.body, this.store, Utils.l10n);
this.template.start();
this._onSimulatorConnected = this._onSimulatorConnected.bind(this);
this._onSimulatorDisconnected = this._onSimulatorDisconnected.bind(this);
},
useFloatingScrollbarsIfNeeded: function() {
@ -136,16 +139,25 @@ let UI = {
this.connection.log("Simulator ready. Connecting.");
this.connection.port = port;
this.connection.host = "localhost";
this.connection.once("connected", () => {
this.connection.log("Connected to simulator.");
this.connection.keepConnecting = false;
});
this.connection.once("connected",
this._onSimulatorConnected);
this.connection.once("disconnected",
this._onSimulatorDisconnected);
this.connection.keepConnecting = true;
this.connection.connect();
});
document.body.classList.remove("show-simulators");
},
_onSimulatorConnected: function() {
this.connection.log("Connected to simulator.");
this.connection.keepConnecting = false;
},
_onSimulatorDisconnected: function() {
this.connection.off("connected", this._onSimulatorConnected);
},
connectToAdbDevice: function(name) {
let device = Devices.getByName(name);
device.connect().then((port) => {

View File

@ -46,7 +46,7 @@ function testSetBreakpoint() {
let deferred = promise.defer();
gDebugger.gThreadClient.interrupt(aResponse => {
gDebugger.gThreadClient.setBreakpoint({ url: JS_URL, line: 30, column: 10 }, aResponse => {
gDebugger.gThreadClient.setBreakpoint({ url: JS_URL, line: 30, column: 21 }, aResponse => {
ok(!aResponse.error,
"Should be able to set a breakpoint in a js file.");
ok(!aResponse.actualLocation,

View File

@ -0,0 +1,40 @@
/* 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/. */
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function devtoolsCommandlineHandler() {
}
devtoolsCommandlineHandler.prototype = {
handle: function(cmdLine) {
if (!cmdLine.handleFlag("jsconsole", false)) {
return;
}
Cu.import("resource://gre/modules/Services.jsm");
let window = Services.wm.getMostRecentWindow("devtools:webconsole");
if (!window) {
let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
// Load the browser devtools main module as the loader's main module.
devtools.main("main");
let hudservice = devtools.require("devtools/webconsole/hudservice");
let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
hudservice.toggleBrowserConsole().then(null, console.error);
} else {
window.focus(); // the Browser Console was already open
}
if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
cmdLine.preventDefault = true;
}
},
helpInfo : " -jsconsole Open the Browser Console.\n",
classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([devtoolsCommandlineHandler]);

View File

@ -0,0 +1,2 @@
component {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32} devtools-clhandler.js
contract @mozilla.org/toolkit/console-clh;1 {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}

View File

@ -168,7 +168,7 @@ InspectorPanel.prototype = {
// as default selected, else set documentElement
return walker.getRootNode().then(aRootNode => {
rootNode = aRootNode;
return walker.querySelector(aRootNode, this.selectionCssSelector);
return walker.querySelector(rootNode, this.selectionCssSelector);
}).then(front => {
if (front) {
return front;

View File

@ -43,5 +43,7 @@ MOCHITEST_BROWSER_FILES := \
browser_inspector_select_last_selected.html \
browser_inspector_select_last_selected2.html \
browser_inspector_basic_highlighter.js \
browser_inspector_dead_node_exception.html \
browser_inspector_dead_node_exception.js \
head.js \
$(NULL)

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe creation/deletion test</title>
</head>
<body>
<div id="yay"></div>
<script type="text/javascript">
var yay = document.querySelector("#yay");
yay.textContent = "nothing";
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
yay.textContent = "before events";
document.addEventListener("DOMContentLoaded", function() {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
yay.textContent = "DOMContentLoaded";
});
window.addEventListener("load", function() {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
yay.textContent = "load";
});
</script>
</body>
</html>

View File

@ -0,0 +1,56 @@
/* Any copyright", " is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let contentTab, contentDoc, inspector;
waitForExplicitFinish();
// Create a tab
contentTab = gBrowser.selectedTab = gBrowser.addTab();
// Open the toolbox's inspector first
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
inspector = toolbox.getCurrentPanel();
inspector.selection.setNode(content.document.querySelector("body"));
inspector.once("inspector-updated", () => {
is(inspector.selection.node.tagName, "BODY", "Inspector displayed");
// Then load our test page
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
contentDoc = content.document;
// The content doc contains a script that creates an iframe and deletes
// it immediately after. This is what used to make the inspector go
// blank when navigating to that page.
var iframe = contentDoc.createElement("iframe");
contentDoc.body.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
is(contentDoc.querySelector("iframe"), null, "Iframe has been removed");
inspector.once("markuploaded", () => {
// Assert that the markup-view is displayed and works
is(contentDoc.querySelector("iframe"), null, "Iframe has been removed");
is(contentDoc.getElementById("yay").textContent, "load", "Load event fired");
inspector.selection.setNode(contentDoc.getElementById("yay"));
inspector.once("inspector-updated", () => {
ok(inspector.selection.node, "Inspector still displayed");
// Clean up and go
contentTab, contentDoc, inspector = null;
gBrowser.removeTab(contentTab);
finish();
});
});
}, true);
content.location = "http://mochi.test:8888/browser/browser/devtools/" +
"inspector/test/browser_inspector_dead_node_exception.html";
});
});
}

View File

@ -24,3 +24,8 @@ DIRS += [
'fontinspector',
'app-manager',
]
EXTRA_COMPONENTS += [
'devtools-clhandler.js',
'devtools-clhandler.manifest',
]

View File

@ -254,13 +254,14 @@ HUD_SERVICE.prototype =
return deferred.promise;
}
connect().then(getTarget).then(openWindow).then((aWindow) =>
connect().then(getTarget).then(openWindow).then((aWindow) => {
this.openBrowserConsole(target, aWindow, aWindow)
.then((aBrowserConsole) => {
this._browserConsoleID = aBrowserConsole.hudId;
this._browserConsoleDefer.resolve(aBrowserConsole);
this._browserConsoleDefer = null;
}));
})
}, console.error);
return this._browserConsoleDefer.promise;
},

View File

@ -62,7 +62,7 @@ function consoleOpened(hud)
let text = output.textContent;
chromeConsole = text.indexOf("bug587757a");
contentConsole = text.indexOf("bug587757b");
execValue = text.indexOf("browser.xul");
execValue = text.indexOf("webconsole.xul");
exception = text.indexOf("foobarExceptionBug587757");
xhrRequest = text.indexOf("test-console.html");
}

View File

@ -24,7 +24,10 @@ function test()
ok(hud, "browser console opened");
hud.jsterm.clearOutput();
hud.jsterm.execute("foobarzTezt = content.document", onAddVariable);
hud.jsterm.execute("Cu = Components.utils;" +
"Cu.import('resource://gre/modules/Services.jsm');" +
"chromeWindow = Services.wm.getMostRecentWindow('navigator:browser');" +
"foobarzTezt = chromeWindow.content.document", onAddVariable);
}
function onAddVariable()

View File

@ -81,7 +81,7 @@
<!ENTITY col.name.label "Name">
<!ENTITY col.tags.label "Tags">
<!ENTITY col.url.label "Location">
<!ENTITY col.lastvisit.label "Visit Date">
<!ENTITY col.mostrecentvisit.label "Most Recent Visit">
<!ENTITY col.visitcount.label "Visit Count">
<!ENTITY col.keyword.label "Keyword">
<!ENTITY col.description.label "Description">

View File

@ -25,24 +25,28 @@ menuOpenLivemarkOrigin.label=Open "%S"
sortByName=Sort '%S' by Name
sortByNameGeneric=Sort by Name
view.sortBy.name.label=Sort by Name
view.sortBy.name.accesskey=N
view.sortBy.url.label=Sort by Location
view.sortBy.url.accesskey=L
view.sortBy.date.label=Sort by Visit Date
view.sortBy.date.accesskey=V
view.sortBy.visitCount.label=Sort by Visit Count
view.sortBy.visitCount.accesskey=C
view.sortBy.keyword.label=Sort by Keyword
view.sortBy.keyword.accesskey=K
view.sortBy.description.label=Sort by Description
view.sortBy.description.accesskey=D
view.sortBy.dateAdded.label=Sort by Added
view.sortBy.dateAdded.accesskey=e
view.sortBy.lastModified.label=Sort by Last Modified
view.sortBy.lastModified.accesskey=M
view.sortBy.tags.label=Sort by Tags
view.sortBy.tags.accesskey=T
# LOCALIZATION NOTE (view.sortBy.1.name.label): sortBy properties are versioned.
# When any of these changes, all of the properties must be bumped, and the
# change must be annotated here. Both label and accesskey must be updated.
# - version 1: changed view.sortBy.1.date.
view.sortBy.1.name.label=Sort by Name
view.sortBy.1.name.accesskey=N
view.sortBy.1.url.label=Sort by Location
view.sortBy.1.url.accesskey=L
view.sortBy.1.date.label=Sort by Most Recent Visit
view.sortBy.1.date.accesskey=V
view.sortBy.1.visitCount.label=Sort by Visit Count
view.sortBy.1.visitCount.accesskey=C
view.sortBy.1.keyword.label=Sort by Keyword
view.sortBy.1.keyword.accesskey=K
view.sortBy.1.description.label=Sort by Description
view.sortBy.1.description.accesskey=D
view.sortBy.1.dateAdded.label=Sort by Added
view.sortBy.1.dateAdded.accesskey=e
view.sortBy.1.lastModified.label=Sort by Last Modified
view.sortBy.1.lastModified.accesskey=M
view.sortBy.1.tags.label=Sort by Tags
view.sortBy.1.tags.accesskey=T
searchBookmarks=Search Bookmarks
searchHistory=Search History

View File

@ -77,6 +77,13 @@ var ContentAreaObserver = {
return this._deckTransitioning;
},
get viewstate() {
if (this.width < Services.prefs.getIntPref("browser.ui.snapped.maxWidth")) {
return "snapped";
}
return (this.height > this.width) ? "portrait" : "landscape";
},
/*
* Public apis
*/
@ -122,6 +129,8 @@ var ContentAreaObserver = {
this.styles["window-height"].height = newHeight + "px";
this.styles["window-height"].maxHeight = newHeight + "px";
this._updateViewState();
this.updateContentArea(newWidth, this._getContentHeightForWindow(newHeight));
this._disatchBrowserEvent("SizeChanged");
},
@ -280,6 +289,15 @@ var ContentAreaObserver = {
* Internal helpers
*/
_updateViewState: function (aState) {
let oldViewstate = Elements.windowState.getAttribute("viewstate");
let viewstate = aState || this.viewstate;
if (viewstate != oldViewstate) {
Elements.windowState.setAttribute("viewstate", viewstate);
Services.obs.notifyObservers(null, "metro_viewstate_changed", viewstate);
}
},
_shiftBrowserDeck: function _shiftBrowserDeck(aAmount) {
if (aAmount == 0) {
this._deckTransitioning = false;

View File

@ -102,7 +102,6 @@ var BrowserUI = {
window.addEventListener("MozImprecisePointer", this, true);
Services.prefs.addObserver("browser.cache.disk_cache_ssl", this, false);
Services.obs.addObserver(this, "metro_viewstate_changed", false);
// Init core UI modules
ContextUI.init();
@ -112,9 +111,6 @@ var BrowserUI = {
SettingsCharm.init();
NavButtonSlider.init();
// show the right toolbars, awesomescreen, etc for the os viewstate
BrowserUI._adjustDOMforViewState();
// We can delay some initialization until after startup. We wait until
// the first page is shown, then dispatch a UIReadyDelayed event.
messageManager.addMessageListener("pageshow", function onPageShow() {
@ -178,6 +174,7 @@ var BrowserUI = {
messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps);
PanelUI.uninit();
FlyoutPanelsUI.uninit();
Downloads.uninit();
SettingsCharm.uninit();
messageManager.removeMessageListener("Content:StateChange", this);
@ -592,13 +589,6 @@ var BrowserUI = {
this.changeDebugPort(Services.prefs.getIntPref(aData));
break;
}
break;
case "metro_viewstate_changed":
this._adjustDOMforViewState(aData);
if (aData == "snapped") {
FlyoutPanelsUI.hide();
}
break;
}
},
@ -638,28 +628,6 @@ var BrowserUI = {
pullDesktopControlledPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref");
},
_adjustDOMforViewState: function(aState) {
let currViewState = aState;
if (!currViewState && Services.metro.immersive) {
switch (Services.metro.snappedState) {
case Ci.nsIWinMetroUtils.fullScreenLandscape:
currViewState = "landscape";
break;
case Ci.nsIWinMetroUtils.fullScreenPortrait:
currViewState = "portrait";
break;
case Ci.nsIWinMetroUtils.filled:
currViewState = "filled";
break;
case Ci.nsIWinMetroUtils.snapped:
currViewState = "snapped";
break;
}
}
Elements.windowState.setAttribute("viewstate", currViewState);
},
_titleChanged: function(aBrowser) {
let url = this.getDisplayURI(aBrowser);

View File

@ -130,14 +130,7 @@ var Browser = {
window.controllers.appendController(this);
window.controllers.appendController(BrowserUI);
let os = Services.obs;
os.addObserver(SessionHistoryObserver, "browser:purge-session-history", false);
os.addObserver(ActivityObserver, "application-background", false);
os.addObserver(ActivityObserver, "application-foreground", false);
os.addObserver(ActivityObserver, "system-active", false);
os.addObserver(ActivityObserver, "system-idle", false);
os.addObserver(ActivityObserver, "system-display-on", false);
os.addObserver(ActivityObserver, "system-display-off", false);
Services.obs.addObserver(SessionHistoryObserver, "browser:purge-session-history", false);
window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess();
@ -247,14 +240,7 @@ var Browser = {
messageManager.removeMessageListener("Browser:PluginClickToPlayClicked", this);
messageManager.removeMessageListener("Browser:TapOnSelection", this);
var os = Services.obs;
os.removeObserver(SessionHistoryObserver, "browser:purge-session-history");
os.removeObserver(ActivityObserver, "application-background");
os.removeObserver(ActivityObserver, "application-foreground");
os.removeObserver(ActivityObserver, "system-active");
os.removeObserver(ActivityObserver, "system-idle");
os.removeObserver(ActivityObserver, "system-display-on");
os.removeObserver(ActivityObserver, "system-display-off");
Services.obs.removeObserver(SessionHistoryObserver, "browser:purge-session-history");
window.controllers.removeController(this);
window.controllers.removeController(BrowserUI);
@ -1394,37 +1380,6 @@ var SessionHistoryObserver = {
}
};
var ActivityObserver = {
_inBackground : false,
_notActive : false,
_isDisplayOff : false,
_timeoutID: 0,
observe: function ao_observe(aSubject, aTopic, aData) {
if (aTopic == "application-background") {
this._inBackground = true;
} else if (aTopic == "application-foreground") {
this._inBackground = false;
} else if (aTopic == "system-idle") {
this._notActive = true;
} else if (aTopic == "system-active") {
this._notActive = false;
} else if (aTopic == "system-display-on") {
this._isDisplayOff = false;
} else if (aTopic == "system-display-off") {
this._isDisplayOff = true;
}
let activeTabState = !this._inBackground && !this._notActive && !this._isDisplayOff;
if (this._timeoutID)
clearTimeout(this._timeoutID);
if (Browser.selectedTab.active != activeTabState) {
// On Maemo all backgrounded applications getting portrait orientation
// so if browser had landscape mode then we need timeout in order
// to finish last rotate/paint operation and have nice lookine browser in TS
this._timeoutID = setTimeout(function() { Browser.selectedTab.active = activeTabState; }, activeTabState ? 0 : kSetInactiveStateTimeout);
}
}
};
function getNotificationBox(aBrowser) {
return Browser.getNotificationBox(aBrowser);
}

View File

@ -172,6 +172,7 @@
<stack id="stack" flex="1">
<observes element="bcast_urlbarState" attribute="*"/>
<observes element="bcast_windowState" attribute="*"/>
<!-- Page Area -->
<vbox id="page">
<vbox id="tray" class="tray-toolbar" observes="bcast_windowState" >

View File

@ -36,6 +36,12 @@ let FlyoutPanelsUI = {
return sandbox[name];
});
});
Services.obs.addObserver(this, "metro_viewstate_changed", false);
},
uninit: function () {
Services.obs.removeObserver(this, "metro_viewstate_changed");
},
show: function(aToShow) {
@ -73,6 +79,16 @@ let FlyoutPanelsUI = {
return this._currentFlyout ? true : false;
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "metro_viewstate_changed":
if (aData == "snapped") {
this.hide();
}
break;
}
},
dispatchEvent: function(aEvent) {
if (this._currentFlyout) {
this._currentFlyout._topmostElement.dispatchEvent(aEvent);

View File

@ -13,8 +13,8 @@
* @param aRoot Bookmark root to show in the view.
*/
function BookmarksView(aSet, aLimit, aRoot, aFilterUnpinned) {
this._set = aSet;
this._set.controller = this;
View.call(this, aSet);
this._inBatch = false; // batch up grid updates to avoid redundant arrangeItems calls
this._limit = aLimit;
@ -25,12 +25,10 @@ function BookmarksView(aSet, aLimit, aRoot, aFilterUnpinned) {
this._changes = new BookmarkChangeListener(this);
this._pinHelper = new ItemPinHelper("metro.bookmarks.unpinned");
this._bookmarkService.addObserver(this._changes, false);
Services.obs.addObserver(this, "metro_viewstate_changed", false);
StartUI.chromeWin.addEventListener('MozAppbarDismissing', this, false);
StartUI.chromeWin.addEventListener('BookmarksNeedsRefresh', this, false);
window.addEventListener("TabClose", this, true);
this._adjustDOMforViewState();
this.root = aRoot;
}
@ -62,11 +60,11 @@ BookmarksView.prototype = Util.extend(Object.create(View.prototype), {
destruct: function bv_destruct() {
this._bookmarkService.removeObserver(this._changes);
Services.obs.removeObserver(this, "metro_viewstate_changed");
if (StartUI.chromeWin) {
StartUI.chromeWin.removeEventListener('MozAppbarDismissing', this, false);
StartUI.chromeWin.removeEventListener('BookmarksNeedsRefresh', this, false);
}
View.prototype.destruct.call(this);
},
handleItemClick: function bv_handleItemClick(aItem) {
@ -275,15 +273,6 @@ BookmarksView.prototype = Util.extend(Object.create(View.prototype), {
this._sendNeedsRefresh();
},
// nsIObservers
observe: function (aSubject, aTopic, aState) {
switch(aTopic) {
case "metro_viewstate_changed":
this.onViewStateChange(aState);
break;
}
},
handleEvent: function bv_handleEvent(aEvent) {
switch (aEvent.type){
case "MozAppbarDismissing":

View File

@ -5,8 +5,8 @@
'use strict';
function HistoryView(aSet, aLimit, aFilterUnpinned) {
this._set = aSet;
this._set.controller = this;
View.call(this, aSet);
this._inBatch = 0;
this._limit = aLimit;
@ -16,12 +16,9 @@ function HistoryView(aSet, aLimit, aFilterUnpinned) {
this._pinHelper = new ItemPinHelper("metro.history.unpinned");
this._historyService.addObserver(this, false);
Services.obs.addObserver(this, "metro_viewstate_changed", false);
StartUI.chromeWin.addEventListener('MozAppbarDismissing', this, false);
StartUI.chromeWin.addEventListener('HistoryNeedsRefresh', this, false);
window.addEventListener("TabClose", this, true);
this._adjustDOMforViewState();
}
HistoryView.prototype = Util.extend(Object.create(View.prototype), {
@ -30,11 +27,11 @@ HistoryView.prototype = Util.extend(Object.create(View.prototype), {
destruct: function destruct() {
this._historyService.removeObserver(this);
Services.obs.removeObserver(this, "metro_viewstate_changed");
if (StartUI.chromeWin) {
StartUI.chromeWin.removeEventListener('MozAppbarDismissing', this, false);
StartUI.chromeWin.removeEventListener('HistoryNeedsRefresh', this, false);
}
View.prototype.destruct.call(this);
},
handleItemClick: function tabview_handleItemClick(aItem) {
@ -223,15 +220,6 @@ HistoryView.prototype = Util.extend(Object.create(View.prototype), {
}
},
// nsIObservers
observe: function (aSubject, aTopic, aState) {
switch(aTopic) {
case "metro_viewstate_changed":
this.onViewStateChange(aState);
break;
}
},
// nsINavHistoryObserver & helpers
onBeginUpdateBatch: function() {

View File

@ -20,8 +20,8 @@ Components.utils.import("resource://services-sync/main.js");
* You may only have one UI access point at this time.
*/
function RemoteTabsView(aSet, aSetUIAccessList) {
this._set = aSet;
this._set.controller = this;
View.call(this, aSet);
this._uiAccessElements = aSetUIAccessList;
// Sync uses special voodoo observers.
@ -29,15 +29,12 @@ function RemoteTabsView(aSet, aSetUIAccessList) {
Weave.Svc.Obs.add("weave:service:sync:finish", this);
Weave.Svc.Obs.add("weave:service:start-over", this);
Services.obs.addObserver(this, "metro_viewstate_changed", false);
if (this.isSyncEnabled() ) {
this.populateGrid();
}
else {
this.setUIAccessVisible(false);
}
this._adjustDOMforViewState();
}
RemoteTabsView.prototype = Util.extend(Object.create(View.prototype), {
@ -51,9 +48,6 @@ RemoteTabsView.prototype = Util.extend(Object.create(View.prototype), {
observe: function(subject, topic, data) {
switch (topic) {
case "metro_viewstate_changed":
this.onViewStateChange(data);
break;
case "weave:service:sync:finish":
this.populateGrid();
break;
@ -102,9 +96,9 @@ RemoteTabsView.prototype = Util.extend(Object.create(View.prototype), {
},
destruct: function destruct() {
Services.obs.removeObserver(this, "metro_viewstate_changed");
Weave.Svc.Obs.remove("weave:engine:sync:finish", this);
Weave.Svc.Obs.remove("weave:service:logout:start-over", this);
View.prototype.destruct.call(this);
},
isSyncEnabled: function isSyncEnabled() {

View File

@ -26,7 +26,7 @@ var StartUI = {
document.getElementById("bcast_preciseInput").setAttribute("input",
this.chromeWin.InputSourceHelper.isPrecise ? "precise" : "imprecise");
this._adjustDOMforViewState();
this._adjustDOMforViewState(this.chromeWin.ContentAreaObserver.viewstate);
TopSitesStartView.init();
BookmarksStartView.init();
@ -81,6 +81,10 @@ var StartUI = {
section.setAttribute("expanded", "true");
},
_adjustDOMforViewState: function(aState) {
document.getElementById("bcast_windowState").setAttribute("viewstate", aState);
},
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "MozPrecisePointer":
@ -106,33 +110,6 @@ var StartUI = {
}
},
_adjustDOMforViewState: function(aState) {
let currViewState = aState;
if (!currViewState && Services.metro.immersive) {
switch (Services.metro.snappedState) {
case Ci.nsIWinMetroUtils.fullScreenLandscape:
currViewState = "landscape";
break;
case Ci.nsIWinMetroUtils.fullScreenPortrait:
currViewState = "portrait";
break;
case Ci.nsIWinMetroUtils.filled:
currViewState = "filled";
break;
case Ci.nsIWinMetroUtils.snapped:
currViewState = "snapped";
break;
}
}
document.getElementById("bcast_windowState").setAttribute("viewstate", currViewState);
if (currViewState == "snapped") {
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
} else {
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
}
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "metro_viewstate_changed":

View File

@ -11,8 +11,8 @@ Cu.import("resource://gre/modules/PageThumbs.jsm");
Cu.import("resource:///modules/colorUtils.jsm");
function TopSitesView(aGrid, aMaxSites) {
this._set = aGrid;
this._set.controller = this;
View.call(this, aGrid);
this._topSitesMax = aMaxSites;
// clean up state when the appbar closes
@ -23,9 +23,6 @@ function TopSitesView(aGrid, aMaxSites) {
PageThumbs.addExpirationFilter(this);
Services.obs.addObserver(this, "Metro:RefreshTopsiteThumbnail", false);
Services.obs.addObserver(this, "metro_viewstate_changed", false);
this._adjustDOMforViewState();
NewTabUtils.allPages.register(this);
TopSites.prepareCache().then(function(){
@ -43,12 +40,12 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
destruct: function destruct() {
Services.obs.removeObserver(this, "Metro:RefreshTopsiteThumbnail");
Services.obs.removeObserver(this, "metro_viewstate_changed");
PageThumbs.removeExpirationFilter(this);
NewTabUtils.allPages.unregister(this);
if (StartUI.chromeWin) {
StartUI.chromeWin.removeEventListener('MozAppbarDismissing', this, false);
}
View.prototype.destruct.call(this);
},
handleItemClick: function tabview_handleItemClick(aItem) {
@ -137,6 +134,7 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
case "MozAppbarDismissing":
// clean up when the context appbar is dismissed - we don't remember selections
this._lastSelectedSites = null;
break;
}
},
@ -234,6 +232,13 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
View.prototype._adjustDOMforViewState.call(this, aState);
// Don't show thumbnails in snapped view.
if (aState == "snapped") {
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
} else {
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
}
// propogate tiletype changes down to tile children
let tileType = this._set.getAttribute("tiletype");
for (let item of this._set.children) {
@ -251,9 +256,6 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
case "Metro:RefreshTopsiteThumbnail":
this.forceReloadOfThumbnail(aState);
break;
case "metro_viewstate_changed":
this.onViewStateChange(aState);
break;
}
},

View File

@ -111,7 +111,7 @@ gTests.push({
},
tearDown: function() {
BookmarksTestHelper.restore();
restoreViewstate();
yield restoreViewstate();
}
});
@ -160,6 +160,6 @@ gTests.push({
tearDown: function() {
BookmarksTestHelper.restore();
HistoryTestHelper.restore();
restoreViewstate();
yield restoreViewstate();
}
});

View File

@ -47,7 +47,7 @@ const mochitestPath = splitPath.join('/') + '/';
function isLandscapeMode()
{
return (Services.metro.snappedState == Ci.nsIWinMetroUtils.fullScreenLandscape);
return Elements.windowState.getAttribute("viewstate") == "landscape";
}
function setDevPixelEqualToPx()

View File

@ -20,7 +20,7 @@ function setSnappedViewstate() {
browser.style.borderRight = padding + "px solid gray";
// Communicate viewstate change
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'snapped');
ContentAreaObserver._updateViewState("snapped");
// Make sure it renders the new mode properly
yield waitForMs(0);
@ -36,16 +36,15 @@ function setPortraitViewstate() {
browser.style.borderRight = padding + "px solid gray";
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'portrait');
ContentAreaObserver._updateViewState("portrait");
// Make sure it renders the new mode properly
yield waitForMs(0);
}
function restoreViewstate() {
ok(isLandscapeMode(), "restoreViewstate expects landscape mode to work.");
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'landscape');
ContentAreaObserver._updateViewState("landscape");
ok(isLandscapeMode(), "restoreViewstate should restore landscape mode.");
Browser.selectedBrowser.style.removeProperty("border-right");

View File

@ -6,10 +6,7 @@
{"index":1,"title":"@firefox_about@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/about/",
"iconUri":"chrome://branding/content/favicon32.png"
},
{"index":2,"title":"@getting_started@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/firefox/central/",
"iconUri":"chrome://branding/content/favicon32.png"
},
{"index":3,"title":"@firefox_community@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/contribute/",
{"index":2,"title":"@firefox_community@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/contribute/",
"iconUri":"chrome://branding/content/favicon32.png"
}
]

View File

@ -23,10 +23,23 @@ function makeURI(aURL, aOriginCharset, aBaseURI) {
// --------------------------------
// View prototype for shared functionality
function View() {
function View(aSet) {
this._set = aSet;
this._set.controller = this;
this.viewStateObserver = {
observe: (aSubject, aTopic, aData) => this._adjustDOMforViewState(aData)
};
Services.obs.addObserver(this.viewStateObserver, "metro_viewstate_changed", false);
this._adjustDOMforViewState();
}
View.prototype = {
destruct: function () {
Services.obs.removeObserver(this.viewStateObserver, "metro_viewstate_changed");
},
_adjustDOMforViewState: function _adjustDOMforViewState(aState) {
if (this._set) {
if (undefined == aState)
@ -44,10 +57,6 @@ View.prototype = {
}
},
onViewStateChange: function (aState) {
this._adjustDOMforViewState(aState);
},
_updateFavicon: function pv__updateFavicon(aItem, aUri) {
if ("string" == typeof aUri) {
aUri = makeURI(aUri);

View File

@ -377,6 +377,9 @@ pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%G
// JS error console
pref("devtools.errorconsole.enabled", false);
// snapped view
pref("browser.ui.snapped.maxWidth", 600);
// kinetic tweakables
pref("browser.ui.kinetic.updateInterval", 16);
pref("browser.ui.kinetic.exponentialC", 1400);

View File

@ -375,6 +375,7 @@ documenttab[selected] .documenttab-selection {
background-position: left 6px center;
}
#stack[viewstate="snapped"] > .overlay-button,
#stack[keyboardVisible] > .overlay-button,
#stack[autocomplete] > .overlay-button,
#stack[fullscreen] > .overlay-button,

View File

@ -181,9 +181,6 @@ abstract public class GeckoApp
protected TabsPanel mTabsPanel;
protected ButtonToast mToast;
// Handles notification messages from javascript
protected NotificationHelper mNotificationHelper;
protected LayerView mLayerView;
private AbsoluteLayout mPluginContainer;
@ -1235,7 +1232,6 @@ abstract public class GeckoApp
// Set up tabs panel.
mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel);
mNotificationHelper = new NotificationHelper(this);
mToast = new ButtonToast(findViewById(R.id.toast));
// Determine whether we should restore tabs.
@ -1796,11 +1792,6 @@ abstract public class GeckoApp
alertCookie = "";
}
handleNotification(ACTION_ALERT_CALLBACK, alertName, alertCookie);
if (intent.hasExtra(NotificationHelper.NOTIFICATION_ID)) {
String id = intent.getStringExtra(NotificationHelper.NOTIFICATION_ID);
mNotificationHelper.hideNotification(id);
}
}
@Override
@ -2045,8 +2036,6 @@ abstract public class GeckoApp
mPromptService.destroy();
if (mTextSelection != null)
mTextSelection.destroy();
if (mNotificationHelper != null)
mNotificationHelper.destroy();
if (SmsManager.getInstance() != null) {
SmsManager.getInstance().stop();

View File

@ -1330,12 +1330,6 @@ public class GeckoAppShell
return;
}
}
// Also send a notification to the observer service
// New listeners should register for these notifications since they will be called even if
// Gecko has been killed and restared between when your notification was shown and when the
// user clicked on it.
sendEventToGecko(GeckoEvent.createBroadcastEvent("Notification:Clicked", aAlertCookie));
closeNotification(aAlertName);
}

View File

@ -98,6 +98,7 @@ public class GeckoApplication extends Application {
public void onCreate() {
HardwareUtils.init(getApplicationContext());
Clipboard.init(getApplicationContext());
NotificationHelper.init(getApplicationContext());
GeckoLoader.loadMozGlue();
super.onCreate();
}

View File

@ -649,7 +649,7 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/ic_menu_bookmark_add.png \
res/drawable-mdpi/ic_menu_bookmark_remove.png \
res/drawable-mdpi/ic_menu_character_encoding.png \
res/drawable-mdpi/ic_menu_close_all_tabs.png \
res/drawable-mdpi/close.png \
res/drawable-mdpi/ic_menu_forward.png \
res/drawable-mdpi/ic_menu_guest.png \
res/drawable-mdpi/ic_menu_new_private_tab.png \
@ -671,6 +671,8 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/icon_pageaction.png \
res/drawable-mdpi/icon_reading_list_empty.png \
res/drawable-mdpi/progress_spinner.png \
res/drawable-mdpi/play.png \
res/drawable-mdpi/pause.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 \
@ -763,7 +765,7 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/ic_menu_bookmark_add.png \
res/drawable-hdpi/ic_menu_bookmark_remove.png \
res/drawable-hdpi/ic_menu_character_encoding.png \
res/drawable-hdpi/ic_menu_close_all_tabs.png \
res/drawable-hdpi/close.png \
res/drawable-hdpi/ic_menu_forward.png \
res/drawable-hdpi/ic_menu_guest.png \
res/drawable-hdpi/ic_menu_new_private_tab.png \
@ -818,6 +820,8 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/menu_item_more.png \
res/drawable-hdpi/menu_item_uncheck.png \
res/drawable-hdpi/pin.png \
res/drawable-hdpi/play.png \
res/drawable-hdpi/pause.png \
res/drawable-hdpi/shield.png \
res/drawable-hdpi/shield_doorhanger.png \
res/drawable-hdpi/tabs_normal.png \
@ -862,7 +866,7 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/ic_menu_addons_filler.png \
res/drawable-xhdpi/ic_menu_bookmark_add.png \
res/drawable-xhdpi/ic_menu_bookmark_remove.png \
res/drawable-xhdpi/ic_menu_close_all_tabs.png \
res/drawable-xhdpi/close.png \
res/drawable-xhdpi/ic_menu_character_encoding.png \
res/drawable-xhdpi/ic_menu_forward.png \
res/drawable-xhdpi/ic_menu_guest.png \
@ -917,6 +921,8 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/menu_item_more.png \
res/drawable-xhdpi/menu_item_uncheck.png \
res/drawable-xhdpi/pin.png \
res/drawable-xhdpi/play.png \
res/drawable-xhdpi/pause.png \
res/drawable-xhdpi/shield.png \
res/drawable-xhdpi/shield_doorhanger.png \
res/drawable-xhdpi/tab_indicator_divider.9.png \

View File

@ -14,6 +14,8 @@ import org.json.JSONObject;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@ -24,21 +26,59 @@ import android.util.Log;
import java.util.Set;
import java.util.HashSet;
public class NotificationHelper implements GeckoEventListener {
public final class NotificationHelper implements GeckoEventListener {
public static final String NOTIFICATION_ID = "NotificationHelper_ID";
private static final String LOGTAG = "GeckoNotificationManager";
private Context mContext;
private Set<String> mShowing;
private static final String HELPER_NOTIFICATION = "helperNotif";
private static final String HELPER_BROADCAST_ACTION = "helperBroadcastAction";
public NotificationHelper(Context context) {
// Attributes mandatory to be used while sending a notification from js.
private static final String TITLE_ATTR = "title";
private static final String TEXT_ATTR = "text";
private static final String ID_ATTR = "id";
private static final String SMALLICON_ATTR = "smallIcon";
// Attributes that can be used while sending a notification from js.
private static final String PROGRESS_VALUE_ATTR = "progress_value";
private static final String PROGRESS_MAX_ATTR = "progress_max";
private static final String LIGHT_ATTR = "light";
private static final String ONGOING_ATTR = "ongoing";
private static final String WHEN_ATTR = "when";
private static final String LARGE_ICON_ATTR = "largeIcon";
private static final String COOKIE_ATTR = "cookie";
private static final String EVENT_TYPE_ATTR = "eventType";
private static final String ACTIONS_ATTR = "actions";
private static final String ACTION_ATTR = "actionKind";
private static final String ACTION_TITLE_ATTR = "title";
private static final String ACTION_ICON_ATTR = "icon";
private static final String NOTIFICATION_SCHEME = "moz-notification";
private static final String CLICK_EVENT = "notification-clicked";
private static final String CLEARED_EVENT = "notification-cleared";
private static Context mContext;
private static Set<String> mShowing;
private static BroadcastReceiver mReceiver;
private static NotificationHelper mInstance;
private NotificationHelper() {
}
public static void init(Context context) {
if (mInstance != null) {
Log.w(LOGTAG, "NotificationHelper.init() called twice!");
}
mInstance = new NotificationHelper();
mContext = context;
mShowing = new HashSet<String>();
registerEventListener("Notification:Show");
registerEventListener("Notification:Hide");
registerReceiver(context);
}
private void registerEventListener(String event) {
GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
private static void registerEventListener(String event) {
GeckoAppShell.getEventDispatcher().registerEventListener(event, mInstance);
}
@Override
@ -50,24 +90,107 @@ public class NotificationHelper implements GeckoEventListener {
}
}
public boolean isHelperIntent(Intent i) {
return i.getBooleanExtra(HELPER_NOTIFICATION, false);
}
private static void registerReceiver(Context context) {
IntentFilter filter = new IntentFilter(HELPER_BROADCAST_ACTION);
// Scheme is needed, otherwise only broadcast with no data will be catched.
filter.addDataScheme(NOTIFICATION_SCHEME);
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mInstance.handleNotificationIntent(intent);
}
};
context.registerReceiver(mReceiver, filter);
}
private void handleNotificationIntent(Intent i) {
final Uri data = i.getData();
if (data == null) {
Log.w(LOGTAG, "handleNotificationEvent: empty data");
return;
}
final String id = data.getQueryParameter(ID_ATTR);
final String notificationType = data.getQueryParameter(EVENT_TYPE_ATTR);
if (id == null || notificationType == null) {
Log.w(LOGTAG, "handleNotificationEvent: invalid intent parameters");
return;
}
// In case the user swiped out the notification, we empty the id
// set.
if (CLEARED_EVENT.equals(notificationType)) {
mShowing.remove(id);
}
// If the notification was clicked, we are closing it.
if (CLICK_EVENT.equals(notificationType) && !i.getBooleanExtra(ONGOING_ATTR, false)) {
hideNotification(id);
}
String cookie = data.getQueryParameter(COOKIE_ATTR);
if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
JSONObject args = new JSONObject();
try {
args.put(NOTIFICATION_ID, id);
if (cookie != null) {
args.put(COOKIE_ATTR, cookie);
}
args.put(EVENT_TYPE_ATTR, notificationType);
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Notification:Event", args.toString()));
} catch (JSONException e) {
Log.w(LOGTAG, "Error building JSON notification arguments.", e);
}
}
}
private PendingIntent buildNotificationPendingIntent(JSONObject message, String type) {
Intent notificationIntent = new Intent(HELPER_BROADCAST_ACTION);
final boolean ongoing = message.optBoolean(ONGOING_ATTR);
notificationIntent.putExtra(ONGOING_ATTR, ongoing);
Uri.Builder b = new Uri.Builder();
b.scheme(NOTIFICATION_SCHEME).appendQueryParameter(EVENT_TYPE_ATTR, type);
try {
final String id = message.getString(ID_ATTR);
b.appendQueryParameter(ID_ATTR, id);
if (message.has(COOKIE_ATTR)) {
b.appendQueryParameter(COOKIE_ATTR,
message.getString(COOKIE_ATTR));
}
} catch (JSONException ex) {
Log.i(LOGTAG, "buildNotificationPendingIntent, error parsing", ex);
}
final Uri dataUri = b.build();
notificationIntent.setData(dataUri);
notificationIntent.putExtra(HELPER_NOTIFICATION, true);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return pi;
}
private void showNotification(JSONObject message) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
// These attributes are required
final String id;
try {
builder.setContentTitle(message.getString("title"));
builder.setContentText(message.getString("text"));
id = message.getString("id");
builder.setContentTitle(message.getString(TITLE_ATTR));
builder.setContentText(message.getString(TEXT_ATTR));
id = message.getString(ID_ATTR);
} catch (JSONException ex) {
Log.i(LOGTAG, "Error parsing", ex);
return;
}
Uri imageUri = Uri.parse(message.optString("smallicon"));
Uri imageUri = Uri.parse(message.optString(SMALLICON_ATTR));
builder.setSmallIcon(BitmapUtils.getResource(imageUri, R.drawable.ic_status_logo));
JSONArray light = message.optJSONArray("light");
JSONArray light = message.optJSONArray(LIGHT_ATTR);
if (light != null && light.length() == 3) {
try {
builder.setLights(light.getInt(0),
@ -78,33 +201,51 @@ public class NotificationHelper implements GeckoEventListener {
}
}
boolean ongoing = message.optBoolean("ongoing");
boolean ongoing = message.optBoolean(ONGOING_ATTR);
builder.setOngoing(ongoing);
if (message.has("when")) {
int when = message.optInt("when");
if (message.has(WHEN_ATTR)) {
int when = message.optInt(WHEN_ATTR);
builder.setWhen(when);
}
if (message.has("largeicon")) {
Bitmap b = BitmapUtils.getBitmapFromDataURI(message.optString("largeicon"));
if (message.has(LARGE_ICON_ATTR)) {
Bitmap b = BitmapUtils.getBitmapFromDataURI(message.optString(LARGE_ICON_ATTR));
builder.setLargeIcon(b);
}
// We currently don't support a callback when these are clicked.
// Instead we just open fennec.
Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CALLBACK);
String app = mContext.getClass().getName();
notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, app);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// if this isn't an ongoing notification, add the id to the intent so that we
// can remove the notification from our list of active notifications if its clicked
if (!ongoing) {
notificationIntent.putExtra(NOTIFICATION_ID, id);
if (message.has(PROGRESS_VALUE_ATTR) &&
message.has(PROGRESS_MAX_ATTR)) {
try {
final int progress = message.getInt(PROGRESS_VALUE_ATTR);
final int progressMax = message.getInt(PROGRESS_MAX_ATTR);
builder.setProgress(progressMax, progress, false);
} catch (JSONException ex) {
Log.i(LOGTAG, "Error parsing", ex);
}
}
PendingIntent pi = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
JSONArray actions = message.optJSONArray(ACTIONS_ATTR);
if (actions != null) {
try {
for (int i = 0; i < actions.length(); i++) {
JSONObject action = actions.getJSONObject(i);
final PendingIntent pending = buildNotificationPendingIntent(message, action.getString(ACTION_ATTR));
final String actionTitle = action.getString(ACTION_TITLE_ATTR);
final Uri actionImage = Uri.parse(action.optString(ACTION_ICON_ATTR));
builder.addAction(BitmapUtils.getResource(actionImage, R.drawable.ic_status_logo),
actionTitle,
pending);
}
} catch (JSONException ex) {
Log.i(LOGTAG, "Error parsing", ex);
}
}
PendingIntent pi = buildNotificationPendingIntent(message, CLICK_EVENT);
builder.setContentIntent(pi);
PendingIntent deletePendingIntent = buildNotificationPendingIntent(message, CLEARED_EVENT);
builder.setDeleteIntent(deletePendingIntent);
GeckoAppShell.sNotificationClient.add(id.hashCode(), builder.build());
if (!mShowing.contains(id)) {
@ -134,8 +275,4 @@ public class NotificationHelper implements GeckoEventListener {
hideNotification(id);
}
}
public void destroy() {
clearAll();
}
}

View File

Before

Width:  |  Height:  |  Size: 377 B

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

View File

Before

Width:  |  Height:  |  Size: 277 B

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

View File

Before

Width:  |  Height:  |  Size: 594 B

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

View File

@ -62,6 +62,11 @@
android:icon="@drawable/ic_menu_apps"
android:title="@string/apps"/>
<item android:id="@+id/new_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"
android:title="@string/new_guest_session"/>
</menu>
</item>
@ -75,11 +80,6 @@
android:icon="@drawable/ic_menu_settings"
android:title="@string/settings" />
<item android:id="@+id/new_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"
android:title="@string/new_guest_session"/>
<item android:id="@+id/exit_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"

View File

@ -63,6 +63,11 @@
android:icon="@drawable/ic_menu_apps"
android:title="@string/apps"/>
<item android:id="@+id/new_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"
android:title="@string/new_guest_session"/>
</menu>
</item>
@ -76,11 +81,6 @@
android:icon="@drawable/ic_menu_settings"
android:title="@string/settings" />
<item android:id="@+id/new_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"
android:title="@string/new_guest_session"/>
<item android:id="@+id/exit_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"

View File

@ -63,6 +63,11 @@
android:icon="@drawable/ic_menu_apps"
android:title="@string/apps"/>
<item android:id="@+id/new_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"
android:title="@string/new_guest_session"/>
</menu>
</item>
@ -76,11 +81,6 @@
android:icon="@drawable/ic_menu_settings"
android:title="@string/settings" />
<item android:id="@+id/new_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"
android:title="@string/new_guest_session"/>
<item android:id="@+id/exit_guest_session"
android:icon="@drawable/ic_menu_guest"
android:visible="false"

View File

@ -2,6 +2,7 @@
package @ANDROID_PACKAGE_NAME@.tests;
import @ANDROID_PACKAGE_NAME@.*;
import android.os.Build;
abstract class PixelTest extends BaseTest {
private static final long PAINT_CLEAR_DELAY = 10000; // milliseconds
@ -9,7 +10,11 @@ abstract class PixelTest extends BaseTest {
protected final PaintedSurface loadAndGetPainted(String url) {
Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
loadUrl(url);
verifyHomePagerHidden();
// Skip this on the Tegras (Android 2.2) since they are too slow,
// which results in too many intermittent failures.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
verifyHomePagerHidden();
}
paintExpecter.blockUntilClear(PAINT_CLEAR_DELAY);
paintExpecter.unregisterListener();
PaintedSurface p = mDriver.getPaintedSurface();

View File

@ -143,12 +143,18 @@ public class testSettingsMenuItems extends PixelTest {
ClassLoader classLoader = getActivity().getClassLoader();
Class appConstants = classLoader.loadClass("org.mozilla.gecko.AppConstants");
// Text reflow
Field textReflowField = appConstants.getField("RELEASE_BUILD");
boolean textReflow = textReflowField.getBoolean(appConstants);
if (textReflow) {
// Preferences dependent on RELEASE_BUILD
Field releaseBuildField = appConstants.getField("RELEASE_BUILD");
boolean releaseBuild = releaseBuildField.getBoolean(appConstants);
if (!releaseBuild) {
// Text reflow - only built if *not* release build
String[] textReflowUi = { "Text reflow" };
settingsMap.get("Display").add(textReflowUi);
// Anonymous cell tower/wifi collection - only built if *not* release build
String[] networkReportingUi = { "Mozilla location services", "Help improve geolocation services for the Open Web by letting " + BRAND_NAME + " collect and send anonymous cellular tower data" };
settingsMap.get("Mozilla").add(networkReportingUi);
}
// Automatic updates
@ -167,14 +173,6 @@ public class testSettingsMenuItems extends PixelTest {
settingsMap.get("Mozilla").add(crashReporterUi);
}
// Anonymous cell tower/wifi collection; built if *not* a RELEASE_BUILD
Field releaseBuildField = appConstants.getField("RELEASE_BUILD");
boolean releaseBuild = releaseBuildField.getBoolean(appConstants);
if (!releaseBuild) {
String[] networkReportingUi = { "Mozilla location services", "Help improve geolocation services for the Open Web by letting " + BRAND_NAME + " collect and send anonymous cellular tower data" };
settingsMap.get("Mozilla").add(networkReportingUi);
}
// Telemetry
Field telemetryField = appConstants.getField("MOZ_TELEMETRY_REPORTING");
boolean telemetry = telemetryField.getBoolean(appConstants);

View File

@ -5136,10 +5136,16 @@ var FormAssistant = {
// Reset invalid submit state on each pageshow
case "pageshow":
let target = aEvent.originalTarget;
let selectedDocument = BrowserApp.selectedBrowser.contentDocument;
if (target == selectedDocument || target.ownerDocument == selectedDocument)
this._invalidSubmit = false;
if (!this._invalidSubmit)
return;
let selectedBrowser = BrowserApp.selectedBrowser;
if (selectedBrowser) {
let selectedDocument = selectedBrowser.contentDocument;
let target = aEvent.originalTarget;
if (target == selectedDocument || target.ownerDocument == selectedDocument)
this._invalidSubmit = false;
}
}
},

View File

@ -10,6 +10,27 @@ function dump(a) {
}
const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download";
const URI_PAUSE_ICON = "drawable://pause";
const URI_CANCEL_ICON = "drawable://close";
const URI_RESUME_ICON = "drawable://play";
const PAUSE_ACTION = {
actionKind : "pause",
title : Strings.browser.GetStringFromName("alertDownloadsPause"),
icon : URI_PAUSE_ICON
};
const CANCEL_ACTION = {
actionKind : "cancel",
title : Strings.browser.GetStringFromName("alertDownloadsCancel"),
icon : URI_CANCEL_ICON
};
const RESUME_ACTION = {
actionKind : "resume",
title : Strings.browser.GetStringFromName("alertDownloadsResume"),
icon : URI_RESUME_ICON
};
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
@ -18,6 +39,7 @@ var Downloads = {
_dlmgr: null,
_progressAlert: null,
_privateDownloads: [],
_showingPrompt: false,
_getLocalFile: function dl__getLocalFile(aFileURI) {
// if this is a URL, get the file from that
@ -36,6 +58,7 @@ var Downloads = {
this._progressAlert = new AlertDownloadProgressListener();
this._dlmgr.addPrivacyAwareListener(this._progressAlert);
Services.obs.addObserver(this, "last-pb-context-exited", true);
Services.obs.addObserver(this, "Notification:Event", true);
},
openDownload: function dl_openDownload(aDownload) {
@ -60,61 +83,113 @@ var Downloads = {
OS.File.remove(f.path);
},
showAlert: function dl_showAlert(aDownload, aMessage, aTitle, aIcon) {
let self = this;
getNotificationIdFromDownload: function dl_getNotificationIdFromDownload(aDownload) {
return aDownload.target.spec.replace("file:", "download:");
},
// Use this flag to make sure we only show one prompt at a time
let cancelPrompt = false;
// Callback for tapping on the alert popup
let observer = {
observe: function (aSubject, aTopic, aData) {
if (aTopic == "alertclickcallback") {
if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED) {
// Only open the downloaded file if the download is complete
self.openDownload(aDownload);
} else if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING &&
!cancelPrompt) {
cancelPrompt = true;
// Open a prompt that offers a choice to cancel the download
let title = Strings.browser.GetStringFromName("downloadCancelPromptTitle");
let message = Strings.browser.GetStringFromName("downloadCancelPromptMessage");
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_YES +
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_NO;
let choice = Services.prompt.confirmEx(null, title, message, flags,
null, null, null, null, {});
if (choice == 0)
self.cancelDownload(aDownload);
cancelPrompt = false;
}
}
}
showNotification: function dl_showNotification(aDownload, aMessage, aTitle, aOptions) {
let msg = {
type: "Notification:Show",
id: this.getNotificationIdFromDownload(aDownload),
title: aTitle,
smallIcon: URI_GENERIC_ICON_DOWNLOAD,
text: aMessage,
ongoing: false,
cookie: aDownload.guid
};
if (!aIcon)
aIcon = URI_GENERIC_ICON_DOWNLOAD;
if (aDownload.isPrivate) {
this._privateDownloads.push(aDownload);
if (aOptions && aOptions.icon) {
msg.smallIcon = aOptions.icon;
}
var notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
notifier.showAlertNotification(aIcon, aTitle, aMessage, true, "", observer,
aDownload.target.spec.replace("file:", "download:"));
if (aOptions && aOptions.percentComplete) {
msg.progress_value = aOptions.percentComplete;
msg.progress_max = 100;
}
if (aOptions && aOptions.actions) {
msg.actions = aOptions.actions;
}
if (aOptions && aOptions.ongoing) {
msg.ongoing = aOptions.ongoing;
}
this._bridge.handleGeckoMessage(JSON.stringify(msg));
},
removeNotification: function dl_removeNotification(aDownload) {
let msg = {
type: "Notification:Hide",
id: this.getNotificationIdFromDownload(aDownload)
};
this._bridge.handleGeckoMessage(JSON.stringify(msg));
},
showCancelConfirmPrompt: function dl_showCancelConfirmPrompt(aDownload) {
if (this._showingPrompt)
return;
this._showingPrompt = true;
// Open a prompt that offers a choice to cancel the download
let title = Strings.browser.GetStringFromName("downloadCancelPromptTitle");
let message = Strings.browser.GetStringFromName("downloadCancelPromptMessage");
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_YES +
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_NO;
let choice = Services.prompt.confirmEx(null, title, message, flags,
null, null, null, null, {});
if (choice == 0)
this.cancelDownload(aDownload);
this._showingPrompt = false;
},
handleClickEvent: function dl_handleClickEvent(aDownload) {
// Only open the downloaded file if the download is complete
if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED)
this.openDownload(aDownload);
else if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING ||
aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_PAUSED)
this.showCancelConfirmPrompt(aDownload);
},
handleNotificationEvent: function dl_handleNotificationEvent(aNotifData, aDownload) {
switch (aNotifData.eventType) {
case "notification-clicked":
this.handleClickEvent(aDownload);
break;
case "cancel":
this.cancelDownload(aDownload);
break;
case "pause":
aDownload.pause();
break;
case "resume":
aDownload.resume();
break;
case "notification-cleared":
// notification cleared by the user
break;
}
},
// observer for last-pb-context-exited
observe: function dl_observe(aSubject, aTopic, aData) {
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
let download;
while ((download = this._privateDownloads.pop())) {
try {
let notificationName = download.target.spec.replace("file:", "download:");
progressListener.onCancel(notificationName);
} catch (e) {
dump("Error removing private download: " + e);
switch (aTopic) {
case "Notification:Event": {
let data = JSON.parse(aData);
let guid = data.cookie;
this._dlmgr.getDownloadByGUID(guid, (function(status, download) {
if (Components.isSuccessCode(status))
this.handleNotificationEvent(data, download);
}).bind(this));
break;
}
case "last-pb-context-exited": {
let download;
while ((download = this._privateDownloads.pop())) {
try {
Downloads.removeNotification(download);
} catch (e) {
dump("Error removing private download: " + e);
}
}
break;
}
}
},
@ -125,6 +200,12 @@ var Downloads = {
!aIID.equals(Ci.nsISupportsWeakReference))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
get _bridge() {
delete this._bridge;
return this._bridge = Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge);
}
};
@ -143,9 +224,8 @@ AlertDownloadProgressListener.prototype = {
} catch(ex) { }
let contentLength = aDownload.size;
if (availableSpace > 0 && contentLength > 0 && contentLength > availableSpace) {
Downloads.showAlert(aDownload, strings.GetStringFromName("alertDownloadsNoSpace"),
Downloads.showNotification(aDownload, strings.GetStringFromName("alertDownloadsNoSpace"),
strings.GetStringFromName("alertDownloadsSize"));
aDownload.cancel();
}
@ -153,10 +233,11 @@ AlertDownloadProgressListener.prototype = {
// Undetermined progress is not supported yet
return;
}
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
let notificationName = aDownload.target.spec.replace("file:", "download:");
progressListener.onProgress(notificationName, aDownload.percentComplete, 100);
Downloads.showNotification(aDownload, aDownload.percentComplete + "%",
aDownload.displayName, { percentComplete: aDownload.percentComplete,
ongoing: true,
actions: [PAUSE_ACTION, CANCEL_ACTION] });
},
onDownloadStateChange: function(aState, aDownload) {
@ -164,19 +245,21 @@ AlertDownloadProgressListener.prototype = {
switch (state) {
case Ci.nsIDownloadManager.DOWNLOAD_QUEUED:
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertDownloadsToast"), "long");
Downloads.showAlert(aDownload, Strings.browser.GetStringFromName("alertDownloadsStart2"),
Downloads.showNotification(aDownload, Strings.browser.GetStringFromName("alertDownloadsStart2"),
aDownload.displayName);
break;
case Ci.nsIDownloadManager.DOWNLOAD_PAUSED:
Downloads.showNotification(aDownload, aDownload.percentComplete + "%",
aDownload.displayName, { percentComplete: aDownload.percentComplete,
ongoing: true,
actions: [RESUME_ACTION, CANCEL_ACTION] });
break;
case Ci.nsIDownloadManager.DOWNLOAD_FAILED:
case Ci.nsIDownloadManager.DOWNLOAD_CANCELED:
case Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL:
case Ci.nsIDownloadManager.DOWNLOAD_DIRTY:
case Ci.nsIDownloadManager.DOWNLOAD_FINISHED: {
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
let notificationName = aDownload.target.spec.replace("file:", "download:");
progressListener.onCancel(notificationName);
Downloads.removeNotification(aDownload);
if (aDownload.isPrivate) {
let index = this._privateDownloads.indexOf(aDownload);
if (index != -1) {
@ -185,7 +268,7 @@ AlertDownloadProgressListener.prototype = {
}
if (state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED) {
Downloads.showAlert(aDownload, Strings.browser.GetStringFromName("alertDownloadsDone2"),
Downloads.showNotification(aDownload, Strings.browser.GetStringFromName("alertDownloadsDone2"),
aDownload.displayName);
}
break;

View File

@ -16,6 +16,9 @@ alertCantOpenDownload=Can't open file. Tap to save it.
alertDownloadsSize=Download too big
alertDownloadsNoSpace=Not enough storage space
alertDownloadsToast=Download started…
alertDownloadsPause=Pause
alertDownloadsResume=Resume
alertDownloadsCancel=Cancel
alertFullScreenToast=Press BACK to leave full-screen mode

View File

@ -9,9 +9,8 @@ let Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
"resource://gre/modules/FormHistory.jsm");
Cu.import("resource://gre/modules/LoadContextInfo.jsm");
Cu.import("resource://gre/modules/FormHistory.jsm");
function dump(a) {
Services.console.logStringMessage(a);

View File

@ -313,7 +313,7 @@ this.DownloadIntegration = {
* @return {Promise}
* @resolves The nsIFile of downloads directory.
*/
getUserDownloadsDirectory: function DI_getUserDownloadsDirectory() {
getPreferredDownloadsDirectory: function DI_getPreferredDownloadsDirectory() {
return Task.spawn(function() {
let directory = null;
let prefValue = 1;
@ -356,7 +356,7 @@ this.DownloadIntegration = {
return Task.spawn(function() {
let directory = null;
#ifdef XP_MACOSX
directory = yield this.getUserDownloadsDirectory();
directory = yield this.getPreferredDownloadsDirectory();
#elifdef ANDROID
directory = yield this.getSystemDownloadsDirectory();
#else

View File

@ -273,8 +273,8 @@ this.Downloads = {
* @return {Promise}
* @resolves The nsIFile of downloads directory.
*/
getUserDownloadsDirectory: function D_getUserDownloadsDirectory() {
return DownloadIntegration.getUserDownloadsDirectory();
getPreferredDownloadsDirectory: function D_getPreferredDownloadsDirectory() {
return DownloadIntegration.getPreferredDownloadsDirectory();
},
/**

View File

@ -116,10 +116,10 @@ add_task(function test_getSystemDownloadsDirectory()
});
/**
* Tests that the getUserDownloadsDirectory returns a valid nsFile
* Tests that the getPreferredDownloadsDirectory returns a valid nsFile
* download directory object.
*/
add_task(function test_getUserDownloadsDirectory()
add_task(function test_getPreferredDownloadsDirectory()
{
let folderListPrefName = "browser.download.folderList";
let dirPrefName = "browser.download.dir";
@ -132,20 +132,20 @@ add_task(function test_getUserDownloadsDirectory()
// Should return the system downloads directory.
Services.prefs.setIntPref(folderListPrefName, 1);
let systemDir = yield DownloadIntegration.getSystemDownloadsDirectory();
let downloadDir = yield DownloadIntegration.getUserDownloadsDirectory();
let downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
do_check_true(downloadDir instanceof Ci.nsIFile);
do_check_eq(downloadDir.path, systemDir.path);
// Should return the desktop directory.
Services.prefs.setIntPref(folderListPrefName, 0);
downloadDir = yield DownloadIntegration.getUserDownloadsDirectory();
downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
do_check_true(downloadDir instanceof Ci.nsIFile);
do_check_eq(downloadDir.path, Services.dirsvc.get("Desk", Ci.nsIFile).path);
// Should return the system downloads directory because the dir preference
// is not set.
Services.prefs.setIntPref(folderListPrefName, 2);
let downloadDir = yield DownloadIntegration.getUserDownloadsDirectory();
let downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
do_check_true(downloadDir instanceof Ci.nsIFile);
do_check_eq(downloadDir.path, systemDir.path);
@ -154,7 +154,7 @@ add_task(function test_getUserDownloadsDirectory()
let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
tempDir.append(time);
Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
downloadDir = yield DownloadIntegration.getUserDownloadsDirectory();
downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
do_check_true(downloadDir instanceof Ci.nsIFile);
do_check_eq(downloadDir.path, tempDir.path);
do_check_true(yield OS.File.exists(downloadDir.path));
@ -166,13 +166,13 @@ add_task(function test_getUserDownloadsDirectory()
tempDir.append("dir_not_exist");
tempDir.append(time);
Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
downloadDir = yield DownloadIntegration.getUserDownloadsDirectory();
downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
do_check_eq(downloadDir.path, systemDir.path);
// Should return the system downloads directory because the folderList
// preference is invalid
Services.prefs.setIntPref(folderListPrefName, 999);
let downloadDir = yield DownloadIntegration.getUserDownloadsDirectory();
let downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
do_check_eq(downloadDir.path, systemDir.path);
cleanup();
@ -188,8 +188,8 @@ add_task(function test_getTemporaryDownloadsDirectory()
do_check_true(downloadDir instanceof Ci.nsIFile);
if ("nsILocalFileMac" in Ci) {
let userDownloadDir = yield DownloadIntegration.getUserDownloadsDirectory();
do_check_eq(downloadDir.path, userDownloadDir.path);
let preferredDownloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
do_check_eq(downloadDir.path, preferredDownloadDir.path);
} else {
let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
do_check_eq(downloadDir.path, tempDir.path);

View File

@ -146,12 +146,12 @@ add_task(function test_getSystemDownloadsDirectory()
});
/**
* Tests that the getUserDownloadsDirectory returns a valid nsFile
* Tests that the getPreferredDownloadsDirectory returns a valid nsFile
* download directory object.
*/
add_task(function test_getUserDownloadsDirectory()
add_task(function test_getPreferredDownloadsDirectory()
{
let downloadDir = yield Downloads.getUserDownloadsDirectory();
let downloadDir = yield Downloads.getPreferredDownloadsDirectory();
do_check_true(downloadDir instanceof Ci.nsIFile);
});

View File

@ -214,6 +214,11 @@ exports.winIsAbsolute = winIsAbsolute;
let normalize = function(path) {
let stack = [];
if (!path.startsWith("\\\\")) {
// Normalize "/" to "\\"
path = path.replace(/\//g, "\\");
}
// Remove the drive (we will put it back at the end)
let root = this.winGetDrive(path);
if (root) {
@ -223,9 +228,6 @@ let normalize = function(path) {
// Remember whether we need to restore a leading "\\" or drive name.
let absolute = this.winIsAbsolute(path);
// Normalize "/" to "\\"
path = path.replace("/", "\\");
// And now, fill |stack| from the components,
// popping whenever there is a ".."
path.split("\\").forEach(function loop(v) {

View File

@ -88,6 +88,21 @@ function run_test()
do_check_eq(Win.winGetDrive("c:\\abc"), "c:");
do_check_eq(Win.winGetDrive("c:\\abc\\d\\e\\f\\g"), "c:");
do_print("Forwardslash-separated, no drive");
do_check_eq(Win.normalize("/a/b/c"), "\\a\\b\\c");
do_check_eq(Win.normalize("/a/b////c"), "\\a\\b\\c");
do_check_eq(Win.normalize("/a/b/c///"), "\\a\\b\\c");
do_check_eq(Win.normalize("/a/b/c/../../../d/e/f"), "\\d\\e\\f");
do_check_eq(Win.normalize("a/b/c/../../../d/e/f"), "d\\e\\f");
do_print("Forwardslash-separated, with a drive");
do_check_eq(Win.normalize("c:/a/b/c"), "c:\\a\\b\\c");
do_check_eq(Win.normalize("c:/a/b////c"), "c:\\a\\b\\c");
do_check_eq(Win.normalize("c:////a/b/c"), "c:\\a\\b\\c");
do_check_eq(Win.normalize("c:/a/b/c///"), "c:\\a\\b\\c");
do_check_eq(Win.normalize("c:/a/b/c/../../../d/e/f"), "c:\\d\\e\\f");
do_check_eq(Win.normalize("c:a/b/c/../../../d/e/f"), "c:d\\e\\f");
do_print("Backslash-separated, UNC-style");
do_check_eq(Win.basename("\\\\a\\b"), "b");
do_check_eq(Win.basename("\\\\a\\b\\"), "");

View File

@ -19,7 +19,7 @@ this.LayoutHelpers = LayoutHelpers = function(aTopLevelWindow) {
this._topDocShell = aTopLevelWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
}
};
LayoutHelpers.prototype = {
@ -366,18 +366,28 @@ LayoutHelpers.prototype = {
/**
* like win.frameElement, but goes through mozbrowsers and mozapps iframes.
*
* @param DOMWindow win The window to get the frame for
* @return DOMElement The element(only <iframe> for now) in which the window
* is embedded. A null return from this function does not imply that it is a
* top level window. Use isTopLevelWindow(win) if needed.
*/
getFrameElement: function LH_getFrameElement(win) {
if (this.isTopLevelWindow(win)) {
return null;
}
// Get the docShell for that window
let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
if (docShell.isBrowserOrApp) {
// Get the docShell's same-type parent ignoring mozBrowser and mozApp
// boundaries
let parentDocShell = docShell.getSameTypeParentIgnoreBrowserAndAppBoundaries();
// Once we have a parent, get all its iframes and loop through them
// to find `win`. If we do, it means win is a nested iframe
let parentDoc = parentDocShell.contentViewer.DOMDocument;
let allIframes = parentDoc.querySelectorAll("iframe");
for (let f of allIframes) {
@ -385,6 +395,7 @@ LayoutHelpers.prototype = {
return f;
}
}
return null;
} else {
return win.frameElement;

View File

@ -724,25 +724,26 @@ var ProgressListener = Class({
this.webProgress = null;
},
onStateChange: makeInfallible(function stateChange(progress, request, flag, status) {
onStateChange: makeInfallible(function stateChange(progress, request, flags, status) {
if (!this.webProgress) {
console.warn("got an onStateChange after destruction");
return;
}
let isWindow = flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
let isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
let isWindow = flags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
let isDocument = flags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
if (!(isWindow || isDocument)) {
return;
}
if (isDocument && (flag & Ci.nsIWebProgressListener.STATE_START)) {
if (isDocument && (flags & Ci.nsIWebProgressListener.STATE_START)) {
events.emit(this, "windowchange-start", progress.DOMWindow);
}
if (isWindow && (flag & Ci.nsIWebProgressListener.STATE_STOP)) {
if (isWindow && (flags & Ci.nsIWebProgressListener.STATE_STOP)) {
events.emit(this, "windowchange-stop", progress.DOMWindow);
}
}),
onProgressChange: function() {},
onSecurityChange: function() {},
onStatusChange: function() {},
@ -1736,7 +1737,8 @@ var WalkerActor = protocol.ActorClass({
onFrameLoad: function(window) {
let frame = this.layoutHelpers.getFrameElement(window);
if (!frame && !this.rootDoc) {
let isTopLevel = this.layoutHelpers.isTopLevelWindow(window);
if (!frame && !this.rootDoc && isTopLevel) {
this.rootDoc = window.document;
this.rootNode = this.document();
this.queueMutation({

View File

@ -2446,37 +2446,37 @@ SourceActor.prototype = {
* source map from b to a. We need to do this because the source map we get
* from _generatePrettyCodeAndMap goes the opposite way we want it to for
* debugging.
*
* Note that the source map is modified in place.
*/
_invertSourceMap: function SA__invertSourceMap({ code, map }) {
const smc = new SourceMapConsumer(map.toJSON());
const invertedMap = new SourceMapGenerator({
file: this._url
});
// XXX bug 918802: Monkey punch the source map consumer, because iterating
// over all mappings and inverting each of them, and then creating a new
// SourceMapConsumer is *way* too slow.
smc.eachMapping(m => {
if (!m.originalLine || !m.originalColumn) {
return;
}
const invertedMapping = {
source: m.source,
name: m.name,
original: {
line: m.generatedLine,
column: m.generatedColumn
},
generated: {
line: m.originalLine,
column: m.originalColumn
}
};
invertedMap.addMapping(invertedMapping);
});
map.setSourceContent(this._url, code);
const consumer = new SourceMapConsumer.fromSourceMap(map);
const getOrigPos = consumer.originalPositionFor.bind(consumer);
const getGenPos = consumer.generatedPositionFor.bind(consumer);
invertedMap.setSourceContent(this._url, code);
consumer.originalPositionFor = ({ line, column }) => {
const location = getGenPos({
line: line,
column: column,
source: this._url
});
location.source = this._url;
return location;
};
consumer.generatedPositionFor = ({ line, column }) => getOrigPos({
line: line,
column: column
});
return {
code: code,
map: new SourceMapConsumer(invertedMap.toJSON())
map: consumer
};
},
@ -2491,7 +2491,7 @@ SourceActor.prototype = {
// Compose the source maps
this._sourceMap = SourceMapGenerator.fromSourceMap(this._sourceMap);
this._sourceMap.applySourceMap(map, this._url);
this._sourceMap = new SourceMapConsumer(this._sourceMap.toJSON());
this._sourceMap = SourceMapConsumer.fromSourceMap(this._sourceMap);
this._threadActor.sources.saveSourceMap(this._sourceMap,
this._generatedSource);
} else {

View File

@ -622,13 +622,10 @@ StyleSheetActor.prototype = {
}
};
if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
let loadContext = this.window
.QueryInterface(Ci.nsIInterfaceRequestor)
channel.loadGroup = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext);
channel.setPrivate(loadContext.usePrivateBrowsing);
}
.QueryInterface(Ci.nsIDocumentLoader)
.loadGroup;
channel.loadFlags = channel.LOAD_FROM_CACHE;
channel.asyncOpen(streamListener, null);
},

View File

@ -185,8 +185,18 @@ function BrowserTabList(aConnection)
BrowserTabList.prototype.constructor = BrowserTabList;
/**
* Get the selected browser for the given navigator:browser window.
* @private
* @param aWindow nsIChromeWindow
* The navigator:browser window for which you want the selected browser.
* @return nsIDOMElement|null
* The currently selected xul:browser element, if any. Note that the
* browser window might not be loaded yet - the function will return
* |null| in such cases.
*/
BrowserTabList.prototype._getSelectedBrowser = function(aWindow) {
return aWindow.gBrowser.selectedBrowser;
return aWindow.gBrowser ? aWindow.gBrowser.selectedBrowser : null;
};
BrowserTabList.prototype._getChildren = function(aWindow) {
@ -209,6 +219,9 @@ BrowserTabList.prototype.getList = function() {
// Iterate over all navigator:browser XUL windows.
for (let win of allAppShellDOMWindows(DebuggerServer.chromeWindowType)) {
let selectedBrowser = this._getSelectedBrowser(win);
if (!selectedBrowser) {
continue;
}
// For each tab in this XUL window, ensure that we have an actor for
// it, reusing existing actors where possible. We actually iterate

View File

@ -118,10 +118,18 @@ WebConsoleActor.prototype =
conn: null,
/**
* The content window we work with.
* The window we work with.
* @type nsIDOMWindow
*/
get window() this.parentActor.window,
get window() {
if (this.parentActor.isRootActor) {
// Try to find the Browser Console window, otherwise use the window of
// the root actor.
let window = Services.wm.getMostRecentWindow("devtools:webconsole");
return window || this.parentActor.window;
}
return this.parentActor.window;
},
/**
* The ConsoleServiceListener instance.

View File

@ -117,6 +117,32 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
this._parseMappings(mappings, sourceRoot);
}
/**
* Create a SourceMapConsumer from a SourceMapGenerator.
*
* @param SourceMapGenerator aSourceMap
* The source map that will be consumed.
* @returns SourceMapConsumer
*/
SourceMapConsumer.fromSourceMap =
function SourceMapConsumer_fromSourceMap(aSourceMap) {
var smc = Object.create(SourceMapConsumer.prototype);
smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
smc.sourceRoot = aSourceMap._sourceRoot;
smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
smc.sourceRoot);
smc.file = aSourceMap._file;
smc._generatedMappings = aSourceMap._mappings.slice()
.sort(util.compareByGeneratedPositions);
smc._originalMappings = aSourceMap._mappings.slice()
.sort(util.compareByOriginalPositions);
return smc;
};
/**
* The version of the source mapping spec that we are consuming.
*/
@ -212,37 +238,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
}
}
this._originalMappings.sort(this._compareOriginalPositions);
};
/**
* Comparator between two mappings where the original positions are compared.
*/
SourceMapConsumer.prototype._compareOriginalPositions =
function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) {
if (mappingA.source > mappingB.source) {
return 1;
}
else if (mappingA.source < mappingB.source) {
return -1;
}
else {
var cmp = mappingA.originalLine - mappingB.originalLine;
return cmp === 0
? mappingA.originalColumn - mappingB.originalColumn
: cmp;
}
};
/**
* Comparator between two mappings where the generated positions are compared.
*/
SourceMapConsumer.prototype._compareGeneratedPositions =
function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) {
var cmp = mappingA.generatedLine - mappingB.generatedLine;
return cmp === 0
? mappingA.generatedColumn - mappingB.generatedColumn
: cmp;
this._originalMappings.sort(util.compareByOriginalPositions);
};
/**
@ -295,7 +291,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
this._generatedMappings,
"generatedLine",
"generatedColumn",
this._compareGeneratedPositions);
util.compareByGeneratedPositions);
if (mapping) {
var source = util.getArg(mapping, 'source', null);
@ -389,7 +385,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
this._originalMappings,
"originalLine",
"originalColumn",
this._compareOriginalPositions);
util.compareByOriginalPositions);
if (mapping) {
return {
@ -574,6 +570,93 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require,
}
exports.relative = relative;
function strcmp(aStr1, aStr2) {
var s1 = aStr1 || "";
var s2 = aStr2 || "";
return (s1 > s2) - (s1 < s2);
}
/**
* Comparator between two mappings where the original positions are compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same original source/line/column, but different generated
* line and column the same. Useful when searching for a mapping with a
* stubbed out mapping.
*/
function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
var cmp;
cmp = strcmp(mappingA.source, mappingB.source);
if (cmp) {
return cmp;
}
cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp) {
return cmp;
}
cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp || onlyCompareOriginal) {
return cmp;
}
cmp = strcmp(mappingA.name, mappingB.name);
if (cmp) {
return cmp;
}
cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp) {
return cmp;
}
return mappingA.generatedColumn - mappingB.generatedColumn;
};
exports.compareByOriginalPositions = compareByOriginalPositions;
/**
* Comparator between two mappings where the generated positions are
* compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same generated line and column, but different
* source/name/original line and column the same. Useful when searching for a
* mapping with a stubbed out mapping.
*/
function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) {
var cmp;
cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp) {
return cmp;
}
cmp = mappingA.generatedColumn - mappingB.generatedColumn;
if (cmp || onlyCompareGenerated) {
return cmp;
}
cmp = strcmp(mappingA.source, mappingB.source);
if (cmp) {
return cmp;
}
cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp) {
return cmp;
}
cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp) {
return cmp;
}
return strcmp(mappingA.name, mappingB.name);
};
exports.compareByGeneratedPositions = compareByGeneratedPositions;
});
/* -*- Mode: js; js-indent-level: 2; -*- */
/*
@ -604,7 +687,7 @@ define('source-map/binary-search', ['require', 'exports', 'module' , ], function
// element which is less than the one we are searching for, so we
// return null.
var mid = Math.floor((aHigh - aLow) / 2) + aLow;
var cmp = aCompare(aNeedle, aHaystack[mid]);
var cmp = aCompare(aNeedle, aHaystack[mid], true);
if (cmp === 0) {
// Found the element we are looking for.
return aHaystack[mid];
@ -1033,8 +1116,10 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
}
this._mappings.push({
generated: generated,
original: original,
generatedLine: generated.line,
generatedColumn: generated.column,
originalLine: original != null && original.line,
originalColumn: original != null && original.column,
source: source,
name: name
});
@ -1083,13 +1168,11 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
if (!aSourceFile) {
aSourceFile = aSourceMapConsumer.file;
}
var sourceRoot = this._sourceRoot;
// Make "aSourceFile" relative if an absolute Url is passed.
if (sourceRoot) {
aSourceFile = util.relative(sourceRoot, aSourceFile);
}
// Applying the SourceMap can add and remove items from the sources and
// the names array.
var newSources = new ArraySet();
@ -1097,13 +1180,12 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
// Find mappings for the "aSourceFile"
this._mappings.forEach(function (mapping) {
if (mapping.source === aSourceFile && mapping.original) {
if (mapping.source === aSourceFile && mapping.originalLine) {
// Check if it can be mapped by the source map, then update the mapping.
var original = aSourceMapConsumer.originalPositionFor({
line: mapping.original.line,
column: mapping.original.column
line: mapping.originalLine,
column: mapping.originalColumn
});
if (original.source !== null) {
// Copy mapping
if (sourceRoot) {
@ -1111,8 +1193,8 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
} else {
mapping.source = original.source;
}
mapping.original.line = original.line;
mapping.original.column = original.column;
mapping.originalLine = original.line;
mapping.originalColumn = original.column;
if (original.name !== null && mapping.name !== null) {
// Only use the identifier name if it's an identifier
// in both SourceMaps
@ -1180,24 +1262,6 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
}
};
function cmpLocation(loc1, loc2) {
var cmp = (loc1 && loc1.line) - (loc2 && loc2.line);
return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column);
}
function strcmp(str1, str2) {
str1 = str1 || '';
str2 = str2 || '';
return (str1 > str2) - (str1 < str2);
}
function cmpMapping(mappingA, mappingB) {
return cmpLocation(mappingA.generated, mappingB.generated) ||
cmpLocation(mappingA.original, mappingB.original) ||
strcmp(mappingA.source, mappingB.source) ||
strcmp(mappingA.name, mappingB.name);
}
/**
* Serialize the accumulated mappings in to the stream of base 64 VLQs
* specified by the source map format.
@ -1218,44 +1282,44 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
// via the ';' separators) will be all messed up. Note: it might be more
// performant to maintain the sorting as we insert them, rather than as we
// serialize them, but the big O is the same either way.
this._mappings.sort(cmpMapping);
this._mappings.sort(util.compareByGeneratedPositions);
for (var i = 0, len = this._mappings.length; i < len; i++) {
mapping = this._mappings[i];
if (mapping.generated.line !== previousGeneratedLine) {
if (mapping.generatedLine !== previousGeneratedLine) {
previousGeneratedColumn = 0;
while (mapping.generated.line !== previousGeneratedLine) {
while (mapping.generatedLine !== previousGeneratedLine) {
result += ';';
previousGeneratedLine++;
}
}
else {
if (i > 0) {
if (!cmpMapping(mapping, this._mappings[i - 1])) {
if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) {
continue;
}
result += ',';
}
}
result += base64VLQ.encode(mapping.generated.column
result += base64VLQ.encode(mapping.generatedColumn
- previousGeneratedColumn);
previousGeneratedColumn = mapping.generated.column;
previousGeneratedColumn = mapping.generatedColumn;
if (mapping.source && mapping.original) {
if (mapping.source) {
result += base64VLQ.encode(this._sources.indexOf(mapping.source)
- previousSource);
previousSource = this._sources.indexOf(mapping.source);
// lines are stored 0-based in SourceMap spec version 3
result += base64VLQ.encode(mapping.original.line - 1
result += base64VLQ.encode(mapping.originalLine - 1
- previousOriginalLine);
previousOriginalLine = mapping.original.line - 1;
previousOriginalLine = mapping.originalLine - 1;
result += base64VLQ.encode(mapping.original.column
result += base64VLQ.encode(mapping.originalColumn
- previousOriginalColumn);
previousOriginalColumn = mapping.original.column;
previousOriginalColumn = mapping.originalColumn;
if (mapping.name) {
result += base64VLQ.encode(this._names.indexOf(mapping.name)
@ -1268,6 +1332,20 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
return result;
};
SourceMapGenerator.prototype._generateSourcesContent =
function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
return aSources.map(function (source) {
if (aSourceRoot) {
source = util.relative(aSourceRoot, source);
}
var key = util.toSetString(source);
return Object.prototype.hasOwnProperty.call(this._sourcesContents,
key)
? this._sourcesContents[key]
: null;
}, this);
};
/**
* Externalize the source map.
*/
@ -1284,16 +1362,9 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
map.sourceRoot = this._sourceRoot;
}
if (this._sourcesContents) {
map.sourcesContent = map.sources.map(function (source) {
if (map.sourceRoot) {
source = util.relative(map.sourceRoot, source);
}
return Object.prototype.hasOwnProperty.call(
this._sourcesContents, util.toSetString(source))
? this._sourcesContents[util.toSetString(source)]
: null;
}, this);
map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
}
return map;
};
@ -1500,7 +1571,9 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
* @param aFn The traversal function.
*/
SourceNode.prototype.walk = function SourceNode_walk(aFn) {
this.children.forEach(function (chunk) {
var chunk;
for (var i = 0, len = this.children.length; i < len; i++) {
chunk = this.children[i];
if (chunk instanceof SourceNode) {
chunk.walk(aFn);
}
@ -1512,7 +1585,7 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
name: this.name });
}
}
}, this);
}
};
/**
@ -1578,14 +1651,16 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
*/
SourceNode.prototype.walkSourceContents =
function SourceNode_walkSourceContents(aFn) {
this.children.forEach(function (chunk) {
if (chunk instanceof SourceNode) {
chunk.walkSourceContents(aFn);
for (var i = 0, len = this.children.length; i < len; i++) {
if (this.children[i] instanceof SourceNode) {
this.children[i].walkSourceContents(aFn);
}
}, this);
Object.keys(this.sourceContents).forEach(function (sourceFileKey) {
aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]);
}, this);
}
var sources = Object.keys(this.sourceContents);
for (var i = 0, len = sources.length; i < len; i++) {
aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);
}
};
/**

View File

@ -214,7 +214,8 @@ define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-ma
expectedMap.sourceRoot,
"sourceRoot mismatch: " +
actualMap.sourceRoot + " != " + expectedMap.sourceRoot);
assert.equal(actualMap.mappings, expectedMap.mappings, "mappings mismatch");
assert.equal(actualMap.mappings, expectedMap.mappings,
"mappings mismatch:\nActual: " + actualMap.mappings + "\nExpected: " + expectedMap.mappings);
if (actualMap.sourcesContent) {
assert.equal(actualMap.sourcesContent.length,
expectedMap.sourcesContent.length,
@ -343,6 +344,93 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ
}
exports.relative = relative;
function strcmp(aStr1, aStr2) {
var s1 = aStr1 || "";
var s2 = aStr2 || "";
return (s1 > s2) - (s1 < s2);
}
/**
* Comparator between two mappings where the original positions are compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same original source/line/column, but different generated
* line and column the same. Useful when searching for a mapping with a
* stubbed out mapping.
*/
function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
var cmp;
cmp = strcmp(mappingA.source, mappingB.source);
if (cmp) {
return cmp;
}
cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp) {
return cmp;
}
cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp || onlyCompareOriginal) {
return cmp;
}
cmp = strcmp(mappingA.name, mappingB.name);
if (cmp) {
return cmp;
}
cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp) {
return cmp;
}
return mappingA.generatedColumn - mappingB.generatedColumn;
};
exports.compareByOriginalPositions = compareByOriginalPositions;
/**
* Comparator between two mappings where the generated positions are
* compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same generated line and column, but different
* source/name/original line and column the same. Useful when searching for a
* mapping with a stubbed out mapping.
*/
function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) {
var cmp;
cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp) {
return cmp;
}
cmp = mappingA.generatedColumn - mappingB.generatedColumn;
if (cmp || onlyCompareGenerated) {
return cmp;
}
cmp = strcmp(mappingA.source, mappingB.source);
if (cmp) {
return cmp;
}
cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp) {
return cmp;
}
cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp) {
return cmp;
}
return strcmp(mappingA.name, mappingB.name);
};
exports.compareByGeneratedPositions = compareByGeneratedPositions;
});
/* -*- Mode: js; js-indent-level: 2; -*- */
/*

View File

@ -393,6 +393,66 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
assert.equal(pos.column, 5);
};
exports['test SourceMapConsumer.fromSourceMap'] = function (assert, util) {
var smg = new SourceMapGenerator({
sourceRoot: 'http://example.com/',
file: 'foo.js'
});
smg.addMapping({
original: { line: 1, column: 1 },
generated: { line: 2, column: 2 },
source: 'bar.js'
});
smg.addMapping({
original: { line: 2, column: 2 },
generated: { line: 4, column: 4 },
source: 'baz.js',
name: 'dirtMcGirt'
});
smg.setSourceContent('baz.js', 'baz.js content');
var smc = SourceMapConsumer.fromSourceMap(smg);
assert.equal(smc.file, 'foo.js');
assert.equal(smc.sourceRoot, 'http://example.com/');
assert.equal(smc.sources.length, 2);
assert.equal(smc.sources[0], 'http://example.com/bar.js');
assert.equal(smc.sources[1], 'http://example.com/baz.js');
assert.equal(smc.sourceContentFor('baz.js'), 'baz.js content');
var pos = smc.originalPositionFor({
line: 2,
column: 2
});
assert.equal(pos.line, 1);
assert.equal(pos.column, 1);
assert.equal(pos.source, 'http://example.com/bar.js');
assert.equal(pos.name, null);
pos = smc.generatedPositionFor({
line: 1,
column: 1,
source: 'http://example.com/bar.js'
});
assert.equal(pos.line, 2);
assert.equal(pos.column, 2);
pos = smc.originalPositionFor({
line: 4,
column: 4
});
assert.equal(pos.line, 2);
assert.equal(pos.column, 2);
assert.equal(pos.source, 'http://example.com/baz.js');
assert.equal(pos.name, 'dirtMcGirt');
pos = smc.generatedPositionFor({
line: 2,
column: 2,
source: 'http://example.com/baz.js'
});
assert.equal(pos.line, 4);
assert.equal(pos.column, 4);
};
});
function run_test() {
runSourceMapTests('test/source-map/test-source-map-consumer', do_throw);

View File

@ -262,11 +262,17 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
exports['test .fromStringWithSourceMap() merging duplicate mappings'] = function (assert, util) {
var input = new SourceNode(null, null, null, [
new SourceNode(1, 0, "a.js", "(function"), new SourceNode(1, 0, "a.js", "() {\n"),
" ", new SourceNode(1, 0, "a.js", "var Test = "), new SourceNode(1, 0, "b.js", "{};\n"),
new SourceNode(2, 0, "b.js", "Test"), new SourceNode(2, 0, "b.js", ".A", "A"), new SourceNode(2, 20, "b.js", " = { value: 1234 };\n", "A"),
"}());\n",
"/* Generated Source */"]);
new SourceNode(1, 0, "a.js", "(function"),
new SourceNode(1, 0, "a.js", "() {\n"),
" ",
new SourceNode(1, 0, "a.js", "var Test = "),
new SourceNode(1, 0, "b.js", "{};\n"),
new SourceNode(2, 0, "b.js", "Test"),
new SourceNode(2, 0, "b.js", ".A", "A"),
new SourceNode(2, 20, "b.js", " = { value: 1234 };\n", "A"),
"}());\n",
"/* Generated Source */"
]);
input = input.toStringWithSourceMap({
file: 'foo.js'
});

View File

@ -52,7 +52,7 @@ WebappTabList.prototype = Object.create(BrowserTabList.prototype);
WebappTabList.prototype.constructor = WebappTabList;
WebappTabList.prototype.getList = function() {
let topXULWindow = windowMediator.getMostRecentWindow(this._windowType);
let topXULWindow = Services.wm.getMostRecentWindow(this._windowType);
// As a sanity check, make sure all the actors presently in our map get
// picked up when we iterate over all windows.

View File

@ -12,27 +12,13 @@
* implementation of this interface for non-Windows systems, for testing and
* development purposes only.
*/
[scriptable, uuid(c5a654c8-2443-47ce-9322-d150af3ca526)]
[scriptable, uuid(fa6750a2-f0fe-411c-af23-1cd6d2fdeceb)]
interface nsIWinMetroUtils : nsISupports
{
/* Fullscreen landscape orientation */
const long fullScreenLandscape = 0;
/* Larger snapped state */
const long filled = 1;
/* Smaller snapped state */
const long snapped = 2;
/* Fullscreen portrait orientation */
const long fullScreenPortrait = 3;
/* return constants for the handPreference property */
const long handPreferenceLeft = 0;
const long handPreferenceRight = 1;
/**
* Determines the current snapped state.
*/
readonly attribute long snappedState;
/**
* Determine if the current browser is running in the metro immersive
* environment.
@ -49,12 +35,6 @@ interface nsIWinMetroUtils : nsISupports
*/
readonly attribute AString activationURI;
/**
* Attempts to unsnap the application from snapped state to filled state
*/
void unsnap();
/**
* Show the settings flyout
*/

View File

@ -109,7 +109,6 @@ FrameworkView::ActivateView()
LogFunction();
UpdateWidgetSizeAndPosition();
MetroUtils::GetViewState(mViewState);
nsIntRegion region(nsIntRect(0, 0, mWindowBounds.width, mWindowBounds.height));
mWidget->Paint(region);
@ -386,36 +385,6 @@ FrameworkView::OnWindowClosed(ICoreWindow* aSender, ICoreWindowEventArgs* aArgs)
return S_OK;
}
void
FrameworkView::FireViewStateObservers()
{
ApplicationViewState state;
MetroUtils::GetViewState(state);
if (state == mViewState) {
return;
}
mViewState = state;
nsAutoString name;
switch (mViewState) {
case ApplicationViewState_FullScreenLandscape:
name.AssignLiteral("landscape");
break;
case ApplicationViewState_Filled:
name.AssignLiteral("filled");
break;
case ApplicationViewState_Snapped:
name.AssignLiteral("snapped");
break;
case ApplicationViewState_FullScreenPortrait:
name.AssignLiteral("portrait");
break;
default:
NS_WARNING("Unknown view state");
return;
};
MetroUtils::FireObserver("metro_viewstate_changed", name.get());
}
HRESULT
FrameworkView::OnWindowSizeChanged(ICoreWindow* aSender, IWindowSizeChangedEventArgs* aArgs)
{
@ -431,7 +400,6 @@ FrameworkView::OnWindowSizeChanged(ICoreWindow* aSender, IWindowSizeChangedEvent
mWindowBounds = MetroUtils::LogToPhys(logicalBounds);
UpdateWidgetSizeAndPosition();
FireViewStateObservers();
return S_OK;
}

View File

@ -195,7 +195,6 @@ private:
static Rect sKeyboardRect;
bool mWinVisible;
bool mWinActiveState;
ApplicationViewState mViewState;
};
} } }

View File

@ -363,32 +363,6 @@ nsWinMetroUtils::ShowNativeToast(const nsAString &aTitle,
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetSnappedState(int32_t *aSnappedState)
{
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
NS_WARNING("GetSnappedState can't be called on the desktop.");
return NS_ERROR_FAILURE;
}
NS_ENSURE_ARG_POINTER(aSnappedState);
ApplicationViewState viewState;
AssertRetHRESULT(MetroUtils::GetViewState(viewState), NS_ERROR_UNEXPECTED);
*aSnappedState = (int32_t) viewState;
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::Unsnap()
{
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
NS_WARNING("Unsnap can't be called on the desktop.");
return NS_ERROR_FAILURE;
}
HRESULT hr = MetroUtils::TryUnsnap();
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsWinMetroUtils::ShowSettingsFlyout()
{