diff --git a/browser/devtools/inspector/inspector-panel.js b/browser/devtools/inspector/inspector-panel.js
index dd4e0f98066..db742577381 100644
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -219,7 +219,9 @@ InspectorPanel.prototype = {
}
rootNode = aRootNode;
- return walker.querySelector(rootNode, this.selectionCssSelector);
+ if (this.selectionCssSelector) {
+ return walker.querySelector(rootNode, this.selectionCssSelector);
+ }
}).then(front => {
if (hasNavigated()) {
return promise.reject("navigated; resolution of _defaultNode aborted");
diff --git a/browser/devtools/inspector/test/browser.ini b/browser/devtools/inspector/test/browser.ini
index 72a41b6a518..59037ec56e7 100644
--- a/browser/devtools/inspector/test/browser.ini
+++ b/browser/devtools/inspector/test/browser.ini
@@ -51,8 +51,10 @@ support-files =
[browser_inspector_search-01.js]
[browser_inspector_search-02.js]
[browser_inspector_search-03.js]
+[browser_inspector_select-docshell.js]
[browser_inspector_select-last-selected.js]
[browser_inspector_search-navigation.js]
[browser_inspector_sidebarstate.js]
[browser_inspector_switch-to-inspector-on-pick.js]
[browser_inspector_update-on-navigation.js]
+
diff --git a/browser/devtools/inspector/test/browser_inspector_select-docshell.js b/browser/devtools/inspector/test/browser_inspector_select-docshell.js
new file mode 100644
index 00000000000..7810434f45e
--- /dev/null
+++ b/browser/devtools/inspector/test/browser_inspector_select-docshell.js
@@ -0,0 +1,81 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test frame selection switching at toolbox level
+// when using the inspector
+
+let test = asyncTest(function*() {
+ const FrameURL = "data:text/html;charset=UTF-8," + encodeURI("frame
");
+ const URL = "data:text/html;charset=UTF-8," + encodeURI("top
");
+
+ Services.prefs.setBoolPref("devtools.command-button-frames.enabled", true);
+
+ let {toolbox, inspector} = yield openInspectorForURL(URL);
+
+ // Verify we are on the top level document
+ let testNode = content.document.querySelector("#top");
+ ok(testNode, "We have the test node on the top level document");
+
+ assertMarkupViewIsLoaded();
+
+ // Verify that the frame list button is visible and populated
+ let btn = toolbox.doc.getElementById("command-button-frames");
+ ok(!btn.firstChild.getAttribute("hidden"), "The frame list button is visible");
+ let frameBtns = Array.slice(btn.firstChild.querySelectorAll("[data-window-id]"));
+ is(frameBtns.length, 2, "We have both frames in the list");
+ frameBtns.sort(function (a, b) {
+ return a.getAttribute("label").localeCompare(b.getAttribute("label"));
+ });
+ is(frameBtns[0].getAttribute("label"), FrameURL, "Got top level document in the list");
+ is(frameBtns[1].getAttribute("label"), URL, "Got iframe document in the list");
+
+ // Listen to will-navigate to check if the view is empty
+ let willNavigate = toolbox.target.on("will-navigate", () => {
+ info("Navigation to the iframe has started, the inspector should be empty");
+ assertMarkupViewIsEmpty();
+ });
+ let newRoot = inspector.once("new-root", () => {
+ info("Navigation to the iframe is done, the inspector should be back up");
+
+ // Verify we are on page one
+ //let testNode = content.frames[0].document.querySelector("#frame");
+ let testNode = getNode("#frame", { document: content.frames[0].document});
+ ok(testNode, "We have the test node on the iframe");
+
+ // On page 2 load, verify we have the right content
+ assertMarkupViewIsLoaded();
+
+ inspector.once("inspector-updated", () => {
+ deferred.resolve();
+ });
+ selectNode(testNode, inspector);
+ });
+
+ // select the iframe once we were able to select an element from the
+ // top level document
+ selectNode("#top", inspector);
+ inspector.once("inspector-updated", () => {
+ // Select the iframe
+ frameBtns[0].click();
+ });
+
+ yield willNavigate;
+ yield newRoot;
+
+// gBrowser.removeCurrentTab();
+ Services.prefs.clearUserPref("devtools.command-button-frames.enabled");
+
+ function assertMarkupViewIsLoaded() {
+ let markupViewBox = inspector.panelDoc.getElementById("markup-box");
+ is(markupViewBox.childNodes.length, 1, "The markup-view is loaded");
+ }
+
+ function assertMarkupViewIsEmpty() {
+ let markupViewBox = inspector.panelDoc.getElementById("markup-box");
+ is(markupViewBox.childNodes.length, 0, "The markup-view is unloaded");
+ }
+});
+
diff --git a/browser/devtools/markupview/test/browser.ini b/browser/devtools/markupview/test/browser.ini
index 75349fe611f..23b6d174284 100644
--- a/browser/devtools/markupview/test/browser.ini
+++ b/browser/devtools/markupview/test/browser.ini
@@ -3,6 +3,7 @@ subsuite = devtools
support-files =
doc_markup_edit.html
doc_markup_events.html
+ doc_markup_events-overflow.html
doc_markup_flashing.html
doc_markup_mutation.html
doc_markup_navigation.html
@@ -20,6 +21,8 @@ support-files =
[browser_markupview_css_completion_style_attribute.js]
[browser_markupview_events.js]
skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible
+[browser_markupview_events-overflow.js]
+skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible
[browser_markupview_highlight_hover_01.js]
skip-if = e10s # Bug 985597 - The XUL-based highlighter isn't e10s compatible
[browser_markupview_highlight_hover_02.js]
diff --git a/browser/devtools/markupview/test/browser_markupview_events-overflow.js b/browser/devtools/markupview/test/browser_markupview_events-overflow.js
new file mode 100644
index 00000000000..881a1d44da8
--- /dev/null
+++ b/browser/devtools/markupview/test/browser_markupview_events-overflow.js
@@ -0,0 +1,87 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const TEST_URL = TEST_URL_ROOT + "doc_markup_events-overflow.html";
+const TEST_DATA = [
+ {
+ desc: "editor overflows container",
+ initialScrollTop: -1, // scroll to bottom
+ headerToClick: 49, // last header
+ alignBottom: true,
+ alignTop: false,
+ },
+ {
+ desc: "header overflows the container",
+ initialScrollTop: 2,
+ headerToClick: 0,
+ alignBottom: false,
+ alignTop: true,
+ },
+ {
+ desc: "neither header nor editor overflows the container",
+ initialScrollTop: 2,
+ headerToClick: 5,
+ alignBottom: false,
+ alignTop: false,
+ },
+];
+
+let test = asyncTest(function*() {
+ let { inspector } = yield addTab(TEST_URL).then(openInspector);
+
+ let markupContainer = yield getContainerForSelector("#events", inspector);
+ let evHolder = markupContainer.elt.querySelector(".markupview-events");
+ let tooltip = inspector.markup.tooltip;
+
+ info("Clicking to open event tooltip.");
+ EventUtils.synthesizeMouseAtCenter(evHolder, {}, inspector.markup.doc.defaultView);
+ yield tooltip.once("shown");
+ info("EventTooltip visible.");
+
+ let container = tooltip.content;
+ let containerRect = container.getBoundingClientRect();
+ let headers = container.querySelectorAll(".event-header");
+
+ for (let data of TEST_DATA) {
+ info("Testing scrolling when " + data.desc);
+
+ if (data.initialScrollTop < 0) {
+ info("Scrolling container to the bottom.");
+ let newScrollTop = container.scrollHeight - container.clientHeight;
+ data.initialScrollTop = container.scrollTop = newScrollTop;
+ } else {
+ info("Scrolling container by " + data.initialScrollTop + "px");
+ container.scrollTop = data.initialScrollTop;
+ }
+
+ is(container.scrollTop, data.initialScrollTop, "Container scrolled.");
+
+ info("Clicking on header #" + data.headerToClick);
+ let header = headers[data.headerToClick];
+
+ let ready = tooltip.once("event-tooltip-ready");
+ EventUtils.synthesizeMouseAtCenter(header, {}, header.ownerGlobal);
+ yield ready;
+
+ info("Event handler expanded.");
+
+ if (data.alignTop) {
+ let headerRect = header.getBoundingClientRect();
+
+ is(headerRect.top, containerRect.top,
+ "Clicked header is aligned with the container top.");
+
+ } else if (data.alignBottom) {
+ let editorRect = header.nextElementSibling.getBoundingClientRect();
+
+ is(editorRect.bottom, containerRect.bottom,
+ "Clicked event handler code is aligned with the container bottom.");
+
+ } else {
+ is(container.scrollTop, data.initialScrollTop,
+ "Container did not scroll, as expected.");
+ }
+ }
+});
diff --git a/browser/devtools/markupview/test/doc_markup_events-overflow.html b/browser/devtools/markupview/test/doc_markup_events-overflow.html
new file mode 100644
index 00000000000..5c193bceb80
--- /dev/null
+++ b/browser/devtools/markupview/test/doc_markup_events-overflow.html
@@ -0,0 +1,18 @@
+
+
+
+ doc_markup_events-overflow.html
+
+
+ doc_markup_events-overflow.html
+ Inspect me!
+
+
+
diff --git a/browser/devtools/projecteditor/test/browser.ini b/browser/devtools/projecteditor/test/browser.ini
index fc55a7f865c..99b9ee3ced2 100644
--- a/browser/devtools/projecteditor/test/browser.ini
+++ b/browser/devtools/projecteditor/test/browser.ini
@@ -1,4 +1,5 @@
[DEFAULT]
+skip-if = e10s # Bug 1030357 - projecteditor tests disabled with e10s
subsuite = devtools
support-files =
head.js
diff --git a/browser/devtools/shared/frame-script-utils.js b/browser/devtools/shared/frame-script-utils.js
index aee6bd1ad80..51068b8ebfd 100644
--- a/browser/devtools/shared/frame-script-utils.js
+++ b/browser/devtools/shared/frame-script-utils.js
@@ -4,8 +4,6 @@
"use strict";
-let { utils: Cu, interfaces: Ci } = Components;
-
addMessageListener("devtools:test:history", function ({ data }) {
content.history[data.direction]();
});
@@ -18,11 +16,3 @@ addMessageListener("devtools:test:reload", function ({ data }) {
data = data || {};
content.location.reload(data.forceget);
});
-
-addMessageListener("devtools:test:forceCC", function () {
- let DOMWindowUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- DOMWindowUtils.cycleCollect();
- DOMWindowUtils.garbageCollect();
- DOMWindowUtils.garbageCollect();
-});
diff --git a/browser/devtools/shared/test/browser_tableWidget_basic.js b/browser/devtools/shared/test/browser_tableWidget_basic.js
index caed3de80e2..4e5218a4fe1 100644
--- a/browser/devtools/shared/test/browser_tableWidget_basic.js
+++ b/browser/devtools/shared/test/browser_tableWidget_basic.js
@@ -108,11 +108,15 @@ function populateTable() {
col3: "value27",
col4: "value34"
});
+
+ let span = doc.createElement("span");
+ span.textContent = "domnode";
+
table.push({
col1: "id9",
col2: "value11",
col3: "value23",
- col4: "value38"
+ col4: span
});
}
@@ -135,7 +139,7 @@ function testTreeItemInsertedCorrectly() {
}
/**
- * Tests if the API exposed by TreeWidget works properly
+ * Tests if the API exposed by TableWidget works properly
*/
function testAPI() {
info("Testing TableWidget API");
@@ -300,22 +304,48 @@ function testAPI() {
// Calling it on an unsorted column should sort by it in ascending manner
table.sortBy("col2");
let cell = table.tbody.children[2].firstChild.children[2];
- while(cell) {
- ok(cell.value >= cell.previousSibling.value, "Sorting is in ascending order");
- cell = cell.nextSibling;
- }
+ checkAscendingOrder(cell);
+
// Calling it again should sort by it in descending manner
table.sortBy("col2");
let cell = table.tbody.children[2].firstChild.lastChild.previousSibling;
- while(cell != cell.parentNode.firstChild) {
- ok(cell.value >= cell.nextSibling.value, "Sorting is in descending order");
- cell = cell.previousSibling;
- }
+ checkDescendingOrder(cell);
+
// Calling it again should sort by it in ascending manner
table.sortBy("col2");
let cell = table.tbody.children[2].firstChild.children[2];
+ checkAscendingOrder(cell);
+
+ table.clear();
+ populateTable();
+
+ // testing if sorting works should sort by ascending manner
+ table.sortBy("col4");
+ let cell = table.tbody.children[6].firstChild.children[1];
+ is(cell.textContent, "domnode", "DOMNode sorted correctly");
+ checkAscendingOrder(cell.nextSibling);
+
+ // Calling it again should sort it in descending order
+ table.sortBy("col4");
+ let cell = table.tbody.children[6].firstChild.children[9];
+ is(cell.textContent, "domnode", "DOMNode sorted correctly");
+ checkDescendingOrder(cell.previousSibling);
+}
+
+function checkAscendingOrder(cell) {
while(cell) {
- ok(cell.value >= cell.previousSibling.value, "Sorting is in ascending order");
+ let currentCell = cell.value || cell.textContent;
+ let prevCell = cell.previousSibling.value || cell.previousSibling.textContent;
+ ok(currentCell >= prevCell, "Sorting is in ascending order");
cell = cell.nextSibling;
}
}
+
+function checkDescendingOrder(cell) {
+ while(cell != cell.parentNode.firstChild) {
+ let currentCell = cell.value || cell.textContent;
+ let nextCell = cell.nextSibling.value || cell.nextSibling.textContent;
+ ok(currentCell >= nextCell, "Sorting is in descending order");
+ cell = cell.previousSibling;
+ }
+}
diff --git a/browser/devtools/shared/widgets/TableWidget.js b/browser/devtools/shared/widgets/TableWidget.js
index d5e8f6e2902..8363ce68ed7 100644
--- a/browser/devtools/shared/widgets/TableWidget.js
+++ b/browser/devtools/shared/widgets/TableWidget.js
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-const { Cu } = require("chrome");
+const {Cc, Ci, Cu} = require("chrome");
const EventEmitter = require("devtools/toolkit/event-emitter");
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
@@ -754,15 +754,22 @@ Column.prototype = {
* by this column.
*/
sort: function(items) {
-
// Only sort the array if we are sorting based on this column
if (this.sorted == 1) {
items.sort((a, b) => {
- return a[this.id] > b[this.id]
+ let val1 = (a[this.id] instanceof Ci.nsIDOMNode) ?
+ a[this.id].textContent : a[this.id];
+ let val2 = (b[this.id] instanceof Ci.nsIDOMNode) ?
+ b[this.id].textContent : b[this.id];
+ return val1 > val2;
});
} else if (this.sorted > 1) {
items.sort((a, b) => {
- return b[this.id] > a[this.id]
+ let val1 = (a[this.id] instanceof Ci.nsIDOMNode) ?
+ a[this.id].textContent : a[this.id];
+ let val2 = (b[this.id] instanceof Ci.nsIDOMNode) ?
+ b[this.id].textContent : b[this.id];
+ return val2 > val1;
});
}
@@ -806,8 +813,18 @@ Column.prototype = {
return;
}
if (event.button == 0) {
- this.table.emit(EVENTS.ROW_SELECTED,
- event.originalTarget.getAttribute("data-id"));
+ let target = event.originalTarget;
+ let dataid = null;
+
+ while (target) {
+ dataid = target.getAttribute("data-id");
+ if (dataid) {
+ break;
+ }
+ target = target.parentNode;
+ }
+
+ this.table.emit(EVENTS.ROW_SELECTED, dataid);
}
},
@@ -854,7 +871,9 @@ Column.prototype = {
* @param {Column} column
* The column object to which the cell belongs.
* @param {object} item
- * The object representing the row.
+ * The object representing the row. It contains a key value pair
+ * representing the column id and its associated value. The value
+ * can be a DOMNode that is appended or a string value.
* @param {Cell} nextCell
* The cell object which is next to this cell. null if this cell is last
* cell of the column
@@ -892,10 +911,23 @@ Cell.prototype = {
this.label.setAttribute("value", "");
return;
}
- if (value.length > MAX_VISIBLE_STRING_SIZE) {
+
+ if (!(value instanceof Ci.nsIDOMNode) &&
+ value.length > MAX_VISIBLE_STRING_SIZE) {
value = value .substr(0, MAX_VISIBLE_STRING_SIZE) + "\u2026"; // …
}
- this.label.setAttribute("value", value + "");
+
+ if (value instanceof Ci.nsIDOMNode) {
+ this.label.removeAttribute("value");
+
+ while (this.label.firstChild) {
+ this.label.removeChild(this.label.firstChild);
+ }
+
+ this.label.appendChild(value);
+ } else {
+ this.label.setAttribute("value", value + "");
+ }
},
get value() {
diff --git a/browser/devtools/shared/widgets/Tooltip.js b/browser/devtools/shared/widgets/Tooltip.js
index 35b74eac2fa..fac4648eacc 100644
--- a/browser/devtools/shared/widgets/Tooltip.js
+++ b/browser/devtools/shared/widgets/Tooltip.js
@@ -1265,6 +1265,14 @@ EventTooltip.prototype = {
editor.setText(tidied);
eventEditors.appended = true;
+
+ let container = header.parentElement.getBoundingClientRect();
+ if (header.getBoundingClientRect().top < container.top) {
+ header.scrollIntoView(true);
+ } else if (content.getBoundingClientRect().bottom > container.bottom) {
+ content.scrollIntoView(false);
+ }
+
this._tooltip.emit("event-tooltip-ready");
});
}
diff --git a/browser/devtools/styleeditor/test/browser_styleeditor_new.js b/browser/devtools/styleeditor/test/browser_styleeditor_new.js
index fda8846dd10..238e40acfa9 100644
--- a/browser/devtools/styleeditor/test/browser_styleeditor_new.js
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_new.js
@@ -4,85 +4,74 @@
const TESTCASE_URI = TEST_BASE + "simple.html";
-let TRANSITION_CLASS = "moz-styleeditor-transitioning";
let TESTCASE_CSS_SOURCE = "body{background-color:red;";
+let gOriginalHref;
let gUI;
-function test()
-{
- waitForExplicitFinish();
+waitForExplicitFinish();
- addTabAndCheckOnStyleEditorAdded(panel => gUI = panel.UI, testEditorAdded);
+let test = asyncTest(function*() {
+ let panel = yield addTabAndOpenStyleEditors(2, null, TESTCASE_URI);
+ gUI = panel.UI;
- content.location = TESTCASE_URI;
+ let editor = yield createNew();
+ testInitialState(editor);
+
+ let waitForPropertyChange = onPropertyChange(editor);
+
+ yield typeInEditor(editor);
+
+ yield waitForPropertyChange;
+
+ testUpdated(editor);
+
+ gUI = null;
+});
+
+function createNew() {
+ info("Creating a new stylesheet now");
+ let deferred = promise.defer();
+
+ gUI.once("editor-added", (ev, editor) => {
+ editor.getSourceEditor().then(deferred.resolve);
+ });
+
+ waitForFocus(function () {// create a new style sheet
+ let newButton = gPanelWindow.document.querySelector(".style-editor-newButton");
+ ok(newButton, "'new' button exists");
+
+ EventUtils.synthesizeMouseAtCenter(newButton, {}, gPanelWindow);
+ }, gPanelWindow);
+
+ return deferred.promise;
}
-let gAddedCount = 0; // to add new stylesheet after the 2 initial stylesheets
-let gNewEditor; // to make sure only one new stylesheet got created
-let gOriginalHref;
+function onPropertyChange(aEditor) {
+ let deferred = promise.defer();
-let checksCompleted = 0;
-
-function testEditorAdded(aEditor)
-{
- info("added " + gAddedCount + " editors");
- if (++gAddedCount == 2) {
- waitForFocus(function () {// create a new style sheet
- let newButton = gPanelWindow.document.querySelector(".style-editor-newButton");
- ok(newButton, "'new' button exists");
-
- EventUtils.synthesizeMouseAtCenter(newButton, {}, gPanelWindow);
- }, gPanelWindow);
- }
- if (gAddedCount < 3) {
- return;
- }
-
- ok(!gNewEditor, "creating a new stylesheet triggers one EditorAdded event");
- gNewEditor = aEditor; // above test will fail if we get a duplicate event
-
- is(gUI.editors.length, 3,
- "creating a new stylesheet added a new StyleEditor instance");
-
- aEditor.styleSheet.once("style-applied", function() {
- // when changes have been completely applied to live stylesheet after transisiton
- ok(!content.document.documentElement.classList.contains(TRANSITION_CLASS),
- "StyleEditor's transition class has been removed from content");
-
- if (++checksCompleted == 3) {
- cleanup();
+ aEditor.styleSheet.on("property-change", function onProp(property, value) {
+ // wait for text to be entered fully
+ let text = aEditor.sourceEditor.getText();
+ if (property == "ruleCount" && text == TESTCASE_CSS_SOURCE + "}") {
+ aEditor.styleSheet.off("property-change", onProp);
+ deferred.resolve();
}
});
- aEditor.styleSheet.on("property-change", function(property) {
- if (property == "ruleCount") {
- let ruleCount = aEditor.summary.querySelector(".stylesheet-rule-count").textContent;
- is(parseInt(ruleCount), 1,
- "new editor shows 1 rule after modification");
-
- if (++checksCompleted == 3) {
- cleanup();
- }
- }
- });
-
- aEditor.getSourceEditor().then(testEditor);
+ return deferred.promise;
}
-function testEditor(aEditor) {
- waitForFocus(function () {
+function testInitialState(aEditor) {
+ info("Testing the initial state of the new editor");
gOriginalHref = aEditor.styleSheet.href;
let summary = aEditor.summary;
- ok(aEditor.sourceLoaded,
- "new editor is loaded when attached");
- ok(aEditor.isNew,
- "new editor has isNew flag");
+ ok(aEditor.sourceLoaded, "new editor is loaded when attached");
+ ok(aEditor.isNew, "new editor has isNew flag");
- ok(aEditor.sourceEditor.hasFocus(),
- "new editor has focus");
+ ok(aEditor.sourceEditor.hasFocus(), "new editor has focus");
let summary = aEditor.summary;
let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
@@ -92,41 +81,33 @@ function testEditor(aEditor) {
let computedStyle = content.getComputedStyle(content.document.body, null);
is(computedStyle.backgroundColor, "rgb(255, 255, 255)",
"content's background color is initially white");
-
- for each (let c in TESTCASE_CSS_SOURCE) {
- EventUtils.synthesizeKey(c, {}, gPanelWindow);
- }
-
- ok(aEditor.unsaved,
- "new editor has unsaved flag");
-
- // we know that the testcase above will start a CSS transition
- content.addEventListener("transitionend", onTransitionEnd, false);
-}, gPanelWindow) ;
}
-function onTransitionEnd() {
- content.removeEventListener("transitionend", onTransitionEnd, false);
+function typeInEditor(aEditor) {
+ let deferred = promise.defer();
- is(gNewEditor.sourceEditor.getText(), TESTCASE_CSS_SOURCE + "}",
+ waitForFocus(function () {
+ for each (let c in TESTCASE_CSS_SOURCE) {
+ EventUtils.synthesizeKey(c, {}, gPanelWindow);
+ }
+ ok(aEditor.unsaved, "new editor has unsaved flag");
+
+ deferred.resolve();
+ }, gPanelWindow);
+
+ return deferred.promise;
+}
+
+function testUpdated(aEditor) {
+ info("Testing the state of the new editor after editing it");
+
+ is(aEditor.sourceEditor.getText(), TESTCASE_CSS_SOURCE + "}",
"rule bracket has been auto-closed");
- let computedStyle = content.getComputedStyle(content.document.body, null);
- is(computedStyle.backgroundColor, "rgb(255, 0, 0)",
- "content's background color has been updated to red");
+ let ruleCount = aEditor.summary.querySelector(".stylesheet-rule-count").textContent;
+ is(parseInt(ruleCount), 1,
+ "new editor shows 1 rule after modification");
- if (gNewEditor) {
- is(gNewEditor.styleSheet.href, gOriginalHref,
- "style sheet href did not change");
- }
-
- if (++checksCompleted == 3) {
- cleanup();
- }
-}
-
-function cleanup() {
- gNewEditor = null;
- gUI = null;
- finish();
+ is(aEditor.styleSheet.href, gOriginalHref,
+ "style sheet href did not change");
}
diff --git a/browser/devtools/webaudioeditor/test/browser.ini b/browser/devtools/webaudioeditor/test/browser.ini
index 349f1743b00..08a6b34e7f3 100644
--- a/browser/devtools/webaudioeditor/test/browser.ini
+++ b/browser/devtools/webaudioeditor/test/browser.ini
@@ -10,7 +10,6 @@ support-files =
doc_connect-toggle.html
doc_connect-param.html
doc_connect-multi-param.html
- doc_change-param.html
440hz_sine.ogg
head.js
@@ -20,10 +19,6 @@ support-files =
[browser_audionode-actor-get-set-param.js]
[browser_audionode-actor-get-type.js]
[browser_audionode-actor-is-source.js]
-
-[browser_webaudio-actor-change-params-01.js]
-[browser_webaudio-actor-change-params-02.js]
-[browser_webaudio-actor-change-params-03.js]
[browser_webaudio-actor-connect-param.js]
[browser_webaudio-actor-destroy-node.js]
[browser_webaudio-actor-simple.js]
@@ -36,11 +31,11 @@ support-files =
[browser_wa_reset-03.js]
[browser_wa_graph-click.js]
+[browser_wa_graph-markers.js]
[browser_wa_graph-render-01.js]
[browser_wa_graph-render-02.js]
[browser_wa_graph-render-03.js]
[browser_wa_graph-render-04.js]
-[browser_wa_graph-markers.js]
[browser_wa_graph-selected.js]
[browser_wa_graph-zoom.js]
@@ -48,10 +43,10 @@ support-files =
[browser_wa_inspector-toggle.js]
[browser_wa_properties-view.js]
+[browser_wa_properties-view-edit-01.js]
+skip-if = true # bug 1010423
+[browser_wa_properties-view-edit-02.js]
+skip-if = true # bug 1010423
[browser_wa_properties-view-media-nodes.js]
-# [browser_wa_properties-view-edit-01.js]
-# [browser_wa_properties-view-edit-02.js]
-# Disabled for too many intermittents bug 1010423
[browser_wa_properties-view-params.js]
-[browser_wa_properties-view-change-params.js]
[browser_wa_properties-view-params-objects.js]
diff --git a/browser/devtools/webaudioeditor/test/browser_wa_properties-view-change-params.js b/browser/devtools/webaudioeditor/test/browser_wa_properties-view-change-params.js
deleted file mode 100644
index 080f6a96da1..00000000000
--- a/browser/devtools/webaudioeditor/test/browser_wa_properties-view-change-params.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests that params view correctly updates changed parameters
- * when source code updates them, as well as CHANGE_PARAM events.
- */
-
-function spawnTest() {
- let [target, debuggee, panel] = yield initWebAudioEditor(CHANGE_PARAM_URL);
- let { panelWin } = panel;
- let { gFront, $, $$, EVENTS, WebAudioInspectorView } = panelWin;
- let gVars = WebAudioInspectorView._propsView;
-
- // Set parameter polling to 20ms for tests
- panelWin.PARAM_POLLING_FREQUENCY = 20;
-
- let started = once(gFront, "start-context");
-
- reload(target);
-
- let [actors] = yield Promise.all([
- getN(gFront, "create-node", 3),
- waitForGraphRendered(panelWin, 3, 0)
- ]);
-
- let oscId = actors[1].actorID;
-
- click(panelWin, findGraphNode(panelWin, oscId));
- yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
-
- // Yield twice so we get a diff
- yield once(panelWin, EVENTS.CHANGE_PARAM);
- let [[_, args]] = yield getSpread(panelWin, EVENTS.CHANGE_PARAM);
- is(args.actorID, oscId, "EVENTS.CHANGE_PARAM has correct `actorID`");
- ok(args.oldValue < args.newValue, "EVENTS.CHANGE_PARAM has correct `newValue` and `oldValue`");
- is(args.param, "detune", "EVENTS.CHANGE_PARAM has correct `param`");
-
- let [[_, args]] = yield getSpread(panelWin, EVENTS.CHANGE_PARAM);
- checkVariableView(gVars, 0, { "detune": args.newValue }, "`detune` parameter updated.");
- let [[_, args]] = yield getSpread(panelWin, EVENTS.CHANGE_PARAM);
- checkVariableView(gVars, 0, { "detune": args.newValue }, "`detune` parameter updated.");
-
- yield teardown(panel);
- finish();
-}
diff --git a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-01.js b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-01.js
deleted file mode 100644
index 072a17d6030..00000000000
--- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-01.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Test WebAudioActor `change-param` events and front.[en|dis]ableChangeParamEvents
- */
-
-function spawnTest () {
- let [target, debuggee, front] = yield initBackend(CHANGE_PARAM_URL);
- let [_, nodes] = yield Promise.all([
- front.setup({ reload: true }),
- getN(front, "create-node", 3)
- ]);
-
- let osc = nodes[1];
- let eventCount = 0;
-
- yield front.enableChangeParamEvents(osc, 20);
-
- front.on("change-param", onChangeParam);
-
- yield getN(front, "change-param", 3);
- yield front.disableChangeParamEvents();
-
- let currEventCount = eventCount;
-
- // Be flexible here incase we get an extra counter before the listener is turned off
- ok(eventCount >= 3, "Calling `enableChangeParamEvents` should allow front to emit `change-param`.");
-
- yield wait(100);
-
- ok((eventCount - currEventCount) <= 2, "Calling `disableChangeParamEvents` should turn off the listener.");
-
- front.off("change-param", onChangeParam);
-
- yield removeTab(target.tab);
- finish();
-
- function onChangeParam ({ newValue, oldValue, param, actorID }) {
- is(actorID, osc.actorID, "correct `actorID` in `change-param`.");
- is(param, "detune", "correct `param` property in `change-param`.");
- ok(newValue > oldValue,
- "correct `newValue` (" + newValue + ") and `oldValue` (" + oldValue + ") in `change-param`");
- eventCount++;
- }
-}
diff --git a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-02.js b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-02.js
deleted file mode 100644
index b650e5e73b1..00000000000
--- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-02.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Test that listening to param change polling does not break when the AudioNode is collected.
- */
-
-function spawnTest () {
- let [target, debuggee, front] = yield initBackend(DESTROY_NODES_URL);
- let waitUntilDestroyed = getN(front, "destroy-node", 10);
- let [_, nodes] = yield Promise.all([
- front.setup({ reload: true }),
- getN(front, "create-node", 13)
- ]);
-
- let bufferNode = nodes[6];
-
- yield front.enableChangeParamEvents(bufferNode, 20);
-
- front.on("change-param", onChangeParam);
-
- forceCC();
-
- yield waitUntilDestroyed;
- yield wait(50);
-
- front.off("change-param", onChangeParam);
-
- ok(true, "listening to `change-param` on a dead node doesn't throw.");
- yield removeTab(target.tab);
- finish();
-
- function onChangeParam (args) {
- ok(false, "`change-param` should not be emitted on a node that hasn't changed params or is dead.");
- }
-}
diff --git a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-03.js b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-03.js
deleted file mode 100644
index 43715cbd60e..00000000000
--- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-change-params-03.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Test WebAudioActor `change-param` events on special types.
- */
-
-function spawnTest () {
- let [target, debuggee, front] = yield initBackend(CHANGE_PARAM_URL);
- let [_, nodes] = yield Promise.all([
- front.setup({ reload: true }),
- getN(front, "create-node", 3)
- ]);
-
- let shaper = nodes[2];
- let eventCount = 0;
-
- yield front.enableChangeParamEvents(shaper, 20);
-
- let onChange = once(front, "change-param");
-
- shaper.setParam("curve", null);
-
- let { newValue, oldValue } = yield onChange;
-
- is(oldValue.type, "object", "`oldValue` should be an object.");
- is(oldValue.class, "Float32Array", "`oldValue` should be of class Float32Array.");
- is(newValue.type, "null", "`newValue` should be null.");
-
- yield removeTab(target.tab);
- finish();
-}
diff --git a/browser/devtools/webaudioeditor/test/doc_change-param.html b/browser/devtools/webaudioeditor/test/doc_change-param.html
deleted file mode 100644
index c8925d912fa..00000000000
--- a/browser/devtools/webaudioeditor/test/doc_change-param.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
- Web Audio Editor test page
-
-
-
-
-
-
-
-
diff --git a/browser/devtools/webaudioeditor/test/head.js b/browser/devtools/webaudioeditor/test/head.js
index 7a452d1bfbd..2a69ae1697b 100644
--- a/browser/devtools/webaudioeditor/test/head.js
+++ b/browser/devtools/webaudioeditor/test/head.js
@@ -19,9 +19,7 @@ let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.j
let { WebAudioFront } = devtools.require("devtools/server/actors/webaudio");
let TargetFactory = devtools.TargetFactory;
-let mm = null;
-const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js";
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/webaudioeditor/test/";
const SIMPLE_CONTEXT_URL = EXAMPLE_URL + "doc_simple-context.html";
const COMPLEX_CONTEXT_URL = EXAMPLE_URL + "doc_complex-context.html";
@@ -32,7 +30,6 @@ const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html";
const CONNECT_TOGGLE_URL = EXAMPLE_URL + "doc_connect-toggle.html";
const CONNECT_PARAM_URL = EXAMPLE_URL + "doc_connect-param.html";
const CONNECT_MULTI_PARAM_URL = EXAMPLE_URL + "doc_connect-multi-param.html";
-const CHANGE_PARAM_URL = EXAMPLE_URL + "doc_change-param.html";
// All tests are asynchronous.
waitForExplicitFinish();
@@ -136,8 +133,6 @@ function initBackend(aUrl) {
yield target.makeRemote();
let front = new WebAudioFront(target.client, target.form);
-
- loadFrameScripts();
return [target, debuggee, front];
});
}
@@ -155,8 +150,6 @@ function initWebAudioEditor(aUrl) {
Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true);
let toolbox = yield gDevTools.showToolbox(target, "webaudioeditor");
let panel = toolbox.getCurrentPanel();
-
- loadFrameScripts();
return [target, debuggee, panel];
});
}
@@ -394,12 +387,9 @@ function countGraphObjects (win) {
* Forces cycle collection and GC, used in AudioNode destruction tests.
*/
function forceCC () {
- mm.sendAsyncMessage("devtools:test:forceCC");
-}
-
-function loadFrameScripts () {
- mm = gBrowser.selectedBrowser.messageManager;
- mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false);
+ SpecialPowers.DOMWindowUtils.cycleCollect();
+ SpecialPowers.DOMWindowUtils.garbageCollect();
+ SpecialPowers.DOMWindowUtils.garbageCollect();
}
/**
diff --git a/browser/devtools/webaudioeditor/webaudioeditor-controller.js b/browser/devtools/webaudioeditor/webaudioeditor-controller.js
index 939d83773f5..7460e314c63 100644
--- a/browser/devtools/webaudioeditor/webaudioeditor-controller.js
+++ b/browser/devtools/webaudioeditor/webaudioeditor-controller.js
@@ -20,9 +20,8 @@ const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"
const L10N = new ViewHelpers.L10N(STRINGS_URI);
const Telemetry = require("devtools/shared/telemetry");
const telemetry = new Telemetry();
-let { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
-let PARAM_POLLING_FREQUENCY = 1000;
+let { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
// The panel's window global is an EventEmitter firing the following events:
const EVENTS = {
@@ -174,8 +173,6 @@ let WebAudioEditorController = {
telemetry.toolOpened("webaudioeditor");
this._onTabNavigated = this._onTabNavigated.bind(this);
this._onThemeChange = this._onThemeChange.bind(this);
- this._onSelectNode = this._onSelectNode.bind(this);
- this._onChangeParam = this._onChangeParam.bind(this);
gTarget.on("will-navigate", this._onTabNavigated);
gTarget.on("navigate", this._onTabNavigated);
gFront.on("start-context", this._onStartContext);
@@ -197,15 +194,12 @@ let WebAudioEditorController = {
window.on(EVENTS.DISCONNECT_NODE, this._onUpdatedContext);
window.on(EVENTS.DESTROY_NODE, this._onUpdatedContext);
window.on(EVENTS.CONNECT_PARAM, this._onUpdatedContext);
-
- // Set up a controller for managing parameter changes per audio node
- window.on(EVENTS.UI_SELECT_NODE, this._onSelectNode);
},
/**
* Remove events emitted by the current tab target.
*/
- destroy: Task.async(function* () {
+ destroy: function() {
telemetry.toolClosed("webaudioeditor");
gTarget.off("will-navigate", this._onTabNavigated);
gTarget.off("navigate", this._onTabNavigated);
@@ -221,11 +215,8 @@ let WebAudioEditorController = {
window.off(EVENTS.DISCONNECT_NODE, this._onUpdatedContext);
window.off(EVENTS.DESTROY_NODE, this._onUpdatedContext);
window.off(EVENTS.CONNECT_PARAM, this._onUpdatedContext);
- window.off(EVENTS.UI_SELECT_NODE, this._onSelectNode);
gDevTools.off("pref-changed", this._onThemeChange);
-
- yield gFront.disableChangeParamEvents();
- }),
+ },
/**
* Called when page is reloaded to show the reload notice and waiting
@@ -354,21 +345,9 @@ let WebAudioEditorController = {
/**
* Called when a node param is changed.
*/
- _onChangeParam: function (args) {
- window.emit(EVENTS.CHANGE_PARAM, args);
- },
-
- /**
- * Called on UI_SELECT_NODE, used to manage
- * `change-param` events on that node.
- */
- _onSelectNode: function (_, id) {
- let node = getViewNodeById(id);
-
- if (node && node.actor) {
- gFront.enableChangeParamEvents(node.actor, PARAM_POLLING_FREQUENCY);
- }
- },
+ _onChangeParam: function({ actor, param, value }) {
+ window.emit(EVENTS.CHANGE_PARAM, getViewNodeByActor(actor), param, value);
+ }
};
/**
diff --git a/browser/devtools/webaudioeditor/webaudioeditor-view.js b/browser/devtools/webaudioeditor/webaudioeditor-view.js
index 283a5347666..8bcf4b366ea 100644
--- a/browser/devtools/webaudioeditor/webaudioeditor-view.js
+++ b/browser/devtools/webaudioeditor/webaudioeditor-view.js
@@ -377,7 +377,6 @@ let WebAudioInspectorView = {
this._onNodeSelect = this._onNodeSelect.bind(this);
this._onTogglePaneClick = this._onTogglePaneClick.bind(this);
this._onDestroyNode = this._onDestroyNode.bind(this);
- this._onChangeParam = this._onChangeParam.bind(this);
this._inspectorPaneToggleButton.addEventListener("mousedown", this._onTogglePaneClick, false);
this._propsView = new VariablesView($("#properties-tabpanel-content"), GENERIC_VARIABLES_VIEW_SETTINGS);
@@ -385,7 +384,6 @@ let WebAudioInspectorView = {
window.on(EVENTS.UI_SELECT_NODE, this._onNodeSelect);
window.on(EVENTS.DESTROY_NODE, this._onDestroyNode);
- window.on(EVENTS.CHANGE_PARAM, this._onChangeParam);
},
/**
@@ -395,7 +393,6 @@ let WebAudioInspectorView = {
this._inspectorPaneToggleButton.removeEventListener("mousedown", this._onTogglePaneClick);
window.off(EVENTS.UI_SELECT_NODE, this._onNodeSelect);
window.off(EVENTS.DESTROY_NODE, this._onDestroyNode);
- window.off(EVENTS.CHANGE_PARAM, this._onChangeParam);
this._inspectorPane = null;
this._inspectorPaneToggleButton = null;
@@ -615,22 +612,7 @@ let WebAudioInspectorView = {
if (this._currentNode && this._currentNode.id === id) {
this.setCurrentAudioNode(null);
}
- },
-
- /**
- * Called when `CHANGE_PARAM` is fired. We should ensure that this event is
- * for the same node that is currently selected. We check the existence
- * of each part of the scope to make sure that if this event was fired
- * during a VariablesView rebuild, then we just ignore it.
- */
- _onChangeParam: function (_, { param, newValue, oldValue, actorID }) {
- if (!this._currentNode || this._currentNode.actor.actorID !== actorID) return;
- let scope = this._getAudioPropertiesScope();
- if (!scope) return;
- let property = scope.get(param);
- if (!property) return;
- property.setGrip(newValue);
- },
+ }
};
/**
diff --git a/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd b/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
index 5dec3427973..7abd9d35cf6 100644
--- a/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
@@ -18,6 +18,10 @@
+
+
diff --git a/browser/locales/en-US/chrome/browser/loop/loop.properties b/browser/locales/en-US/chrome/browser/loop/loop.properties
index 1dc5baa52e8..b9e41279046 100644
--- a/browser/locales/en-US/chrome/browser/loop/loop.properties
+++ b/browser/locales/en-US/chrome/browser/loop/loop.properties
@@ -22,6 +22,7 @@ incoming_call_decline_button=Decline
incoming_call_decline_and_block_button=Decline and Block
incoming_call_block_button=Block
hangup_button_title=Hang up
+hangup_button_caption=End Call
mute_local_audio_button_title=Mute your audio
unmute_local_audio_button_title=Unmute your audio
mute_local_video_button_title=Mute your video
diff --git a/browser/locales/en-US/chrome/browser/preferences/preferences.properties b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
index df2b3c7aa9a..00acacf1937 100644
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -94,6 +94,7 @@ cookiesAll=The following cookies are stored on your computer:
cookiesFiltered=The following cookies match your search:
#### Offline apps
+offlineAppsList.height=7em
offlineAppRemoveTitle=Remove offline website data
offlineAppRemovePrompt=After removing this data, %S will not be available offline. Are you sure you want to remove this offline website?
offlineAppRemoveConfirm=Remove offline data
diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn
index 58626678563..3cd2d6711f0 100644
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -217,6 +217,8 @@ browser.jar:
skin/classic/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png)
skin/classic/browser/devtools/command-pick.png (../shared/devtools/images/command-pick.png)
skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
+ skin/classic/browser/devtools/command-frames.png (../shared/devtools/images/command-frames.png)
+ skin/classic/browser/devtools/command-frames@2x.png (../shared/devtools/images/command-frames@2x.png)
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn
index 17402ac94ee..6099fdd74fd 100644
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -340,6 +340,8 @@ browser.jar:
skin/classic/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png)
skin/classic/browser/devtools/command-pick.png (../shared/devtools/images/command-pick.png)
skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
+ skin/classic/browser/devtools/command-frames.png (../shared/devtools/images/command-frames.png)
+ skin/classic/browser/devtools/command-frames@2x.png (../shared/devtools/images/command-frames@2x.png)
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
diff --git a/browser/themes/shared/devtools/images/command-frames.png b/browser/themes/shared/devtools/images/command-frames.png
new file mode 100755
index 00000000000..5c37ccb6bf8
Binary files /dev/null and b/browser/themes/shared/devtools/images/command-frames.png differ
diff --git a/browser/themes/shared/devtools/images/command-frames@2x.png b/browser/themes/shared/devtools/images/command-frames@2x.png
new file mode 100755
index 00000000000..84b37d33030
Binary files /dev/null and b/browser/themes/shared/devtools/images/command-frames@2x.png differ
diff --git a/browser/themes/shared/devtools/inspector.css b/browser/themes/shared/devtools/inspector.css
index 945ed108e74..298fb056093 100644
--- a/browser/themes/shared/devtools/inspector.css
+++ b/browser/themes/shared/devtools/inspector.css
@@ -44,6 +44,7 @@
#devtools-tooltip-events-container {
margin: -4px; /* Compensate for the .panel-arrowcontent padding. */
max-width: 390px;
+ overflow: auto;
}
.event-header {
diff --git a/browser/themes/shared/devtools/toolbars.inc.css b/browser/themes/shared/devtools/toolbars.inc.css
index cf9f8bd2d7b..b53225533ff 100644
--- a/browser/themes/shared/devtools/toolbars.inc.css
+++ b/browser/themes/shared/devtools/toolbars.inc.css
@@ -380,87 +380,84 @@
margin: 0;
min-width: 78px;
text-align: center;
+ background-color: transparent;
color: inherit;
-moz-box-flex: 1;
border-width: 0;
+ -moz-border-start-width: 1px;
+ border-style: solid;
border-radius: 0;
position: static;
- -moz-margin-start: -1px;
text-shadow: none;
}
-.devtools-sidebar-tabs > tabs > tab {
- background-size: calc(100% - 1px) 100%, 1px 100%;
- background-repeat: no-repeat;
- background-position: 1px, 0;
-}
-
-.devtools-sidebar-tabs > tabs > tab:not(:last-of-type) {
- background-size: calc(100% - 2px) 100%, 1px 100%;
-}
-
-.devtools-sidebar-tabs:-moz-locale-dir(rtl) > tabs > tab {
- background-position: calc(100% - 1px), 100%;
-}
-
-.devtools-sidebar-tabs > tabs > tab {
- background-color: transparent;
+.devtools-sidebar-tabs > tabs > tab:first-child {
+ -moz-border-start-width: 0;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab {
- background-image: linear-gradient(transparent, transparent), @smallSeparatorDark@;
+ border-image: @smallSeparatorDark@ 1 1;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab:hover {
- background-image: linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.2)), @smallSeparatorDark@;
+ background: hsla(206,37%,4%,.2);
+ border-image: @smallSeparatorDark@ 1 1;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab:hover:active {
- background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @smallSeparatorDark@;
+ background: hsla(206,37%,4%,.4);
+ border-image: @smallSeparatorDark@ 1 1;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab[selected] + tab {
- background-image: linear-gradient(transparent, transparent), @solidSeparatorDark@;
+ border-image: @solidSeparatorDark@ 1 1;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab[selected] + tab:hover {
- background-image: linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.2)), @solidSeparatorDark@;
+ background: hsla(206,37%,4%,.2);
+ border-image: @solidSeparatorDark@ 1 1;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab[selected] + tab:hover:active {
- background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @solidSeparatorDark@;
+ background: hsla(206,37%,4%,.4);
+ border-image: @solidSeparatorDark@ 1 1;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab[selected],
.theme-dark .devtools-sidebar-tabs > tabs > tab[selected]:hover:active {
color: #f5f7fa;
- background-image: linear-gradient(#1d4f73, #1d4f73), @solidSeparatorDark@;
+ background: #1d4f73;
+ border-image: @solidSeparatorDark@ 1 1;
}
.theme-light .devtools-sidebar-tabs > tabs > tab {
- background-image: linear-gradient(transparent, transparent), @smallSeparatorLight@;
+ border-image: @smallSeparatorLight@ 1 1;
}
.theme-light .devtools-sidebar-tabs > tabs > tab:hover {
- background-image: linear-gradient(#ddd, #ddd), @smallSeparatorLight@;
+ background: #ddd;
+ border-image: @smallSeparatorLight@ 1 1;
}
.theme-light .devtools-sidebar-tabs > tabs > tab:hover:active {
- background-image: linear-gradient(#ddd, #ddd), @smallSeparatorLight@;
+ background: #ddd;
+ border-image: @smallSeparatorLight@ 1 1;
}
.theme-light .devtools-sidebar-tabs > tabs > tab[selected] + tab {
- background-image: linear-gradient(transparent, transparent), @solidSeparatorLight@;
+ border-image: @solidSeparatorLight@;
}
.theme-light .devtools-sidebar-tabs > tabs > tab[selected] + tab:hover {
- background-image: linear-gradient(#ddd, #ddd), @solidSeparatorLight@;
+ background: #ddd;
+ border-image: @solidSeparatorLight@;
}
.theme-light .devtools-sidebar-tabs > tabs > tab[selected],
.theme-light .devtools-sidebar-tabs > tabs > tab[selected]:hover:active {
color: #f5f7fa;
- background-image: linear-gradient(#4c9ed9, #4c9ed9), @solidSeparatorLight@;
+ background: #4c9ed9;
+ border-image: @solidSeparatorLight@;
}
/* Toolbox - moved from toolbox.css.
@@ -596,6 +593,10 @@
background-image: url("chrome://browser/skin/devtools/command-pick.png");
}
+#command-button-frames > image {
+ background-image: url("chrome://browser/skin/devtools/command-frames.png");
+}
+
#command-button-splitconsole > image {
background-image: url("chrome://browser/skin/devtools/command-console.png");
}
@@ -629,6 +630,10 @@
background-image: url("chrome://browser/skin/devtools/command-pick@2x.png");
}
+ #command-button-frames > image {
+ background-image: url("chrome://browser/skin/devtools/command-frames@2x.png");
+ }
+
#command-button-splitconsole > image {
background-image: url("chrome://browser/skin/devtools/command-console@2x.png");
}
diff --git a/browser/themes/shared/incontentprefs/preferences.css b/browser/themes/shared/incontentprefs/preferences.css
index 34dd1c5bd04..832cea0e6b8 100644
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -131,6 +131,12 @@ prefpane {
height: 500px;
}
+#handlersView > listheader {
+ -moz-appearance: none;
+ border: 0;
+ padding: 0;
+}
+
#typeColumn,
#actionColumn {
-moz-appearance: none;
@@ -244,7 +250,8 @@ description > html|a {
#weavePrefsDeck > vbox > description,
#weavePrefsDeck > vbox > #pairDevice > label,
#weavePrefsDeck > #needsUpdate > hbox > #loginError,
-#weavePrefsDeck > #hasFxaAccount > hbox:not(#tosPP) > label {
+#weavePrefsDeck > #hasFxaAccount > hbox:not(#tosPP-normal) > label,
+#weavePrefsDeck > #hasFxaAccount > hbox:not(#tosPP-small) > label {
/* no margin-start for elements at the begin of a line */
-moz-margin-start: 0;
}
diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn
index f13ae8aeb44..701894a0736 100644
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -257,6 +257,8 @@ browser.jar:
skin/classic/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png)
skin/classic/browser/devtools/command-pick.png (../shared/devtools/images/command-pick.png)
skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
+ skin/classic/browser/devtools/command-frames.png (../shared/devtools/images/command-frames.png)
+ skin/classic/browser/devtools/command-frames@2x.png (../shared/devtools/images/command-frames@2x.png)
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
@@ -666,6 +668,8 @@ browser.jar:
skin/classic/aero/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png)
skin/classic/aero/browser/devtools/command-pick.png (../shared/devtools/images/command-pick.png)
skin/classic/aero/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
+ skin/classic/aero/browser/devtools/command-frames.png (../shared/devtools/images/command-frames.png)
+ skin/classic/aero/browser/devtools/command-frames@2x.png (../shared/devtools/images/command-frames@2x.png)
skin/classic/aero/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
skin/classic/aero/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/aero/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
diff --git a/configure.in b/configure.in
index 82c410bb92a..a50e70c744c 100644
--- a/configure.in
+++ b/configure.in
@@ -3905,6 +3905,11 @@ else
AC_MSG_RESULT([none])
AC_MSG_ERROR([--enable-application=mobile is no longer supported.])
fi
+ # Support comm-central.
+ if test -n "$EXTERNAL_SOURCE_DIR" ; then
+ MOZ_BUILD_APP="$EXTERNAL_SOURCE_DIR/$MOZ_BUILD_APP"
+ MOZ_BUILD_APP=`${PYTHON} -c "import os.path; print(os.path.relpath(\"${MOZ_BUILD_APP}\", \"${srcdir}\"))"`
+ fi
# We have a valid application only if it has a build.mk file in its top
# directory.
if test ! -f "${srcdir}/${MOZ_BUILD_APP}/build.mk" ; then
@@ -9046,7 +9051,7 @@ if test -n "$_subconfigure_subdir"; then
srcdir="$srcdir/.."
_save_ac_configure_args="$ac_configure_args"
ac_configure_args="$_subconfigure_config_args"
- AC_OUTPUT_SUBDIRS("$_subconfigure_subdir")
+ AC_OUTPUT_SUBDIRS("$_subconfigure_subdir",$cache_file)
ac_configure_args="$_save_ac_configure_args"
srcdir="$_save_srcdir"
fi
diff --git a/mobile/android/base/ChromeCast.java b/mobile/android/base/ChromeCast.java
index fe9bfb479ec..53be3a22921 100644
--- a/mobile/android/base/ChromeCast.java
+++ b/mobile/android/base/ChromeCast.java
@@ -78,11 +78,7 @@ class ChromeCast implements GeckoMediaPlayer {
}
@Override
- public void onMetadataUpdated() {
- MediaInfo mediaInfo = remoteMediaPlayer.getMediaInfo();
- MediaMetadata metadata = mediaInfo.getMetadata();
- debug("metadata updated " + metadata);
- }
+ public void onMetadataUpdated() { }
@Override
public void onResult(ApplicationConnectionResult result) {
diff --git a/mobile/android/base/background/fxa/FxAccountClient20.java b/mobile/android/base/background/fxa/FxAccountClient20.java
index 477fce1d83a..36f6cba9113 100644
--- a/mobile/android/base/background/fxa/FxAccountClient20.java
+++ b/mobile/android/base/background/fxa/FxAccountClient20.java
@@ -4,7 +4,10 @@
package org.mozilla.gecko.background.fxa;
+import java.io.UnsupportedEncodingException;
import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
import java.util.concurrent.Executor;
import org.json.simple.JSONObject;
@@ -94,13 +97,35 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
post(resource, body, delegate);
}
- public void createAccount(final byte[] emailUTF8, final byte[] quickStretchedPW, final boolean getKeys, final boolean preVerified,
+ /**
+ * Create account/create URI, encoding query parameters carefully.
+ *
+ * This is equivalent to android.net.Uri.Builder
, which is not
+ * present in our JUnit 4 tests.
+ */
+ protected URI getCreateAccountURI(final boolean getKeys, final String service) throws UnsupportedEncodingException, URISyntaxException {
+ if (service == null) {
+ throw new IllegalArgumentException("service must not be null");
+ }
+ final StringBuilder sb = new StringBuilder(serverURI); // serverURI always has a trailing slash.
+ sb.append("account/create?service=");
+ // Be very careful that query parameters are encoded correctly!
+ sb.append(URLEncoder.encode(service, "UTF-8"));
+ if (getKeys) {
+ sb.append("&keys=true");
+ }
+ return new URI(sb.toString());
+ }
+
+ public void createAccount(final byte[] emailUTF8, final byte[] quickStretchedPW,
+ final boolean getKeys,
+ final boolean preVerified,
+ final String service,
final RequestDelegate delegate) {
- BaseResource resource;
- JSONObject body;
- final String path = getKeys ? "account/create?keys=true" : "account/create";
+ final BaseResource resource;
+ final JSONObject body;
try {
- resource = new BaseResource(new URI(serverURI + path));
+ resource = new BaseResource(getCreateAccountURI(getKeys, service));
body = new FxAccount20CreateDelegate(emailUTF8, quickStretchedPW, preVerified).getCreateBody();
} catch (Exception e) {
invokeHandleError(delegate, e);
@@ -144,7 +169,7 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
public void createAccountAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, RequestDelegate delegate) {
try {
byte[] quickStretchedPW = passwordStretcher.getQuickStretchedPW(emailUTF8);
- createAccount(emailUTF8, quickStretchedPW, true, false, delegate);
+ createAccount(emailUTF8, quickStretchedPW, true, false, "sync", delegate);
} catch (Exception e) {
invokeHandleError(delegate, e);
return;
diff --git a/mobile/android/base/preferences/SearchEnginePreference.java b/mobile/android/base/preferences/SearchEnginePreference.java
index e3bb62cfa0a..ce0fab15fd1 100644
--- a/mobile/android/base/preferences/SearchEnginePreference.java
+++ b/mobile/android/base/preferences/SearchEnginePreference.java
@@ -37,7 +37,7 @@ public class SearchEnginePreference extends CustomListPreference {
private FaviconView mFaviconView;
- // Search engine identifier specified by the gecko search service. This will be null
+ // Search engine identifier specified by the gecko search service. This will be "other"
// for engines that are not shipped with the app.
private String mIdentifier;
@@ -123,7 +123,7 @@ public class SearchEnginePreference extends CustomListPreference {
* @return Identifier of built-in search engine, or "other" if engine is not built-in.
*/
public String getIdentifier() {
- return (mIdentifier == null) ? "other" : mIdentifier;
+ return mIdentifier;
}
/**
@@ -134,6 +134,11 @@ public class SearchEnginePreference extends CustomListPreference {
public void setSearchEngineFromJSON(JSONObject geckoEngineJSON) throws JSONException {
mIdentifier = geckoEngineJSON.getString("identifier");
+ // A null JS value gets converted into a string.
+ if (mIdentifier.equals("null")) {
+ mIdentifier = "other";
+ }
+
final String engineName = geckoEngineJSON.getString("name");
final SpannableString titleSpannable = new SpannableString(engineName);
diff --git a/mobile/android/base/resources/drawable-hdpi-v11/ic_menu_save_as_pdf.png b/mobile/android/base/resources/drawable-hdpi-v11/ic_menu_save_as_pdf.png
deleted file mode 100644
index 12246af15e9..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi-v11/ic_menu_save_as_pdf.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/folder.png b/mobile/android/base/resources/drawable-hdpi/folder.png
deleted file mode 100644
index 59d31033320..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/folder.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/fxaccount_ddarrow_active.png b/mobile/android/base/resources/drawable-hdpi/fxaccount_ddarrow_active.png
deleted file mode 100644
index 4abb71ee3cd..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/fxaccount_ddarrow_active.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/fxaccount_sync_icon.png b/mobile/android/base/resources/drawable-hdpi/fxaccount_sync_icon.png
deleted file mode 100644
index 1b6e67572fb..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/fxaccount_sync_icon.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/graphic_mail.png b/mobile/android/base/resources/drawable-hdpi/graphic_mail.png
deleted file mode 100644
index 02fe58a2e6a..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/graphic_mail.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/history_tabs_indicator_selected.9.png b/mobile/android/base/resources/drawable-hdpi/history_tabs_indicator_selected.9.png
deleted file mode 100644
index 369f0adbbb5..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/history_tabs_indicator_selected.9.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/ic_url_bar_reader.png b/mobile/android/base/resources/drawable-hdpi/ic_url_bar_reader.png
deleted file mode 100644
index 0e387cf6f4b..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/ic_url_bar_reader.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/icon_last_tabs.png b/mobile/android/base/resources/drawable-hdpi/icon_last_tabs.png
deleted file mode 100644
index 93b62554dae..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/icon_last_tabs.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/icon_most_recent.png b/mobile/android/base/resources/drawable-hdpi/icon_most_recent.png
deleted file mode 100644
index 268016aaa4b..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/icon_most_recent.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/icon_most_visited.png b/mobile/android/base/resources/drawable-hdpi/icon_most_visited.png
deleted file mode 100644
index c1ad8efe4f2..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/icon_most_visited.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/icon_new_home_panel.png b/mobile/android/base/resources/drawable-hdpi/icon_new_home_panel.png
deleted file mode 100644
index b2b61296f79..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/icon_new_home_panel.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/menu_popup_arrow_bottom.png b/mobile/android/base/resources/drawable-hdpi/menu_popup_arrow_bottom.png
deleted file mode 100644
index 329ffa9cd7d..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/menu_popup_arrow_bottom.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/reading_list.png b/mobile/android/base/resources/drawable-hdpi/reading_list.png
deleted file mode 100644
index c3af59952b5..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/reading_list.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-hdpi/tab_thumbnail_shadow.png b/mobile/android/base/resources/drawable-hdpi/tab_thumbnail_shadow.png
deleted file mode 100644
index cac50d60613..00000000000
Binary files a/mobile/android/base/resources/drawable-hdpi/tab_thumbnail_shadow.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi-v11/ic_menu_save_as_pdf.png b/mobile/android/base/resources/drawable-mdpi-v11/ic_menu_save_as_pdf.png
deleted file mode 100644
index 23d73d5adfd..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi-v11/ic_menu_save_as_pdf.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/desktop_notification.png b/mobile/android/base/resources/drawable-mdpi/desktop_notification.png
deleted file mode 100644
index 1e72d4598a3..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/desktop_notification.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/folder.png b/mobile/android/base/resources/drawable-mdpi/folder.png
deleted file mode 100644
index 2ffa6f35b72..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/folder.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/fxaccount_ddarrow_active.png b/mobile/android/base/resources/drawable-mdpi/fxaccount_ddarrow_active.png
deleted file mode 100644
index bb978372f0e..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/fxaccount_ddarrow_active.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/history_tabs_indicator_selected.9.png b/mobile/android/base/resources/drawable-mdpi/history_tabs_indicator_selected.9.png
deleted file mode 100644
index 0bfcc83d0ca..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/history_tabs_indicator_selected.9.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/ic_url_bar_reader.png b/mobile/android/base/resources/drawable-mdpi/ic_url_bar_reader.png
deleted file mode 100644
index 78429a44f06..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/ic_url_bar_reader.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/icon_last_tabs.png b/mobile/android/base/resources/drawable-mdpi/icon_last_tabs.png
deleted file mode 100644
index 8bac17e41af..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/icon_last_tabs.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/icon_most_recent.png b/mobile/android/base/resources/drawable-mdpi/icon_most_recent.png
deleted file mode 100644
index 9fa395e7072..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/icon_most_recent.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/icon_most_visited.png b/mobile/android/base/resources/drawable-mdpi/icon_most_visited.png
deleted file mode 100644
index a97eaf5859f..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/icon_most_visited.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/icon_new_home_panel.png b/mobile/android/base/resources/drawable-mdpi/icon_new_home_panel.png
deleted file mode 100644
index 3ec1557a47c..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/icon_new_home_panel.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/marketplace.png b/mobile/android/base/resources/drawable-mdpi/marketplace.png
deleted file mode 100644
index 35ae63c6d3a..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/marketplace.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/menu_popup_arrow_bottom.png b/mobile/android/base/resources/drawable-mdpi/menu_popup_arrow_bottom.png
deleted file mode 100644
index a759f628ac7..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/menu_popup_arrow_bottom.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/reading_list.png b/mobile/android/base/resources/drawable-mdpi/reading_list.png
deleted file mode 100644
index 6b4f9743a62..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/reading_list.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/start.png b/mobile/android/base/resources/drawable-mdpi/start.png
deleted file mode 100644
index fbef2c935f6..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/start.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-mdpi/tab_thumbnail_shadow.png b/mobile/android/base/resources/drawable-mdpi/tab_thumbnail_shadow.png
deleted file mode 100644
index 871e22da020..00000000000
Binary files a/mobile/android/base/resources/drawable-mdpi/tab_thumbnail_shadow.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_save_as_pdf.png b/mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_save_as_pdf.png
deleted file mode 100644
index dffcfa80c10..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_save_as_pdf.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/folder.png b/mobile/android/base/resources/drawable-xhdpi/folder.png
deleted file mode 100644
index 6e489a73dc8..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/folder.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/history_tabs_indicator_selected.9.png b/mobile/android/base/resources/drawable-xhdpi/history_tabs_indicator_selected.9.png
deleted file mode 100644
index 4ae6d8c1dd7..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/history_tabs_indicator_selected.9.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/ic_url_bar_reader.png b/mobile/android/base/resources/drawable-xhdpi/ic_url_bar_reader.png
deleted file mode 100644
index e7f684f3772..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/ic_url_bar_reader.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_last_tabs.png b/mobile/android/base/resources/drawable-xhdpi/icon_last_tabs.png
deleted file mode 100644
index 05fe2cee131..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/icon_last_tabs.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_most_recent.png b/mobile/android/base/resources/drawable-xhdpi/icon_most_recent.png
deleted file mode 100644
index 351d222bc62..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/icon_most_recent.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_most_visited.png b/mobile/android/base/resources/drawable-xhdpi/icon_most_visited.png
deleted file mode 100644
index 9c02a326c15..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/icon_most_visited.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_new_home_panel.png b/mobile/android/base/resources/drawable-xhdpi/icon_new_home_panel.png
deleted file mode 100644
index d92ce47b5d4..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/icon_new_home_panel.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/menu_popup_arrow_bottom.png b/mobile/android/base/resources/drawable-xhdpi/menu_popup_arrow_bottom.png
deleted file mode 100644
index 43f1158e452..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/menu_popup_arrow_bottom.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/reading_list.png b/mobile/android/base/resources/drawable-xhdpi/reading_list.png
deleted file mode 100644
index 7516d13a21f..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/reading_list.png and /dev/null differ
diff --git a/mobile/android/base/resources/drawable-xhdpi/tab_thumbnail_shadow.png b/mobile/android/base/resources/drawable-xhdpi/tab_thumbnail_shadow.png
deleted file mode 100644
index 12b24c58cc1..00000000000
Binary files a/mobile/android/base/resources/drawable-xhdpi/tab_thumbnail_shadow.png and /dev/null differ
diff --git a/mobile/android/base/resources/layout/fxaccount_status.xml b/mobile/android/base/resources/layout/fxaccount_status.xml
deleted file mode 100644
index 25284c416cd..00000000000
--- a/mobile/android/base/resources/layout/fxaccount_status.xml
+++ /dev/null
@@ -1,118 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/mobile/android/base/resources/layout/home_panel_picker.xml b/mobile/android/base/resources/layout/home_panel_picker.xml
deleted file mode 100644
index a4158c2cdaf..00000000000
--- a/mobile/android/base/resources/layout/home_panel_picker.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/mobile/android/base/resources/layout/home_panel_picker_empty.xml b/mobile/android/base/resources/layout/home_panel_picker_empty.xml
deleted file mode 100644
index 53ccecf679d..00000000000
--- a/mobile/android/base/resources/layout/home_panel_picker_empty.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/mobile/android/base/resources/layout/home_panel_picker_row.xml b/mobile/android/base/resources/layout/home_panel_picker_row.xml
deleted file mode 100644
index 7460d481a69..00000000000
--- a/mobile/android/base/resources/layout/home_panel_picker_row.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/mobile/android/base/resources/layout/launch_app_list.xml b/mobile/android/base/resources/layout/launch_app_list.xml
deleted file mode 100644
index 3567ce963a1..00000000000
--- a/mobile/android/base/resources/layout/launch_app_list.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/mobile/android/base/resources/layout/launch_app_listitem.xml b/mobile/android/base/resources/layout/launch_app_listitem.xml
deleted file mode 100644
index d34f7181460..00000000000
--- a/mobile/android/base/resources/layout/launch_app_listitem.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/mobile/android/base/resources/layout/videoplayer.xml b/mobile/android/base/resources/layout/videoplayer.xml
deleted file mode 100644
index 62292ee45ce..00000000000
--- a/mobile/android/base/resources/layout/videoplayer.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
diff --git a/testing/profiles/prefs_general.js b/testing/profiles/prefs_general.js
index 651c8696a26..d303b38da4e 100644
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -242,3 +242,7 @@ user_pref("browser.newtabpage.directory.ping", "");
// Enable Loop
user_pref("loop.enabled", true);
+
+// Ensure UITour won't hit the network
+user_pref("browser.uitour.pinnedTabUrl", "http://%(server)s/uitour-dummy/pinnedTab");
+user_pref("browser.uitour.url", "http://%(server)s/uitour-dummy/tour");
diff --git a/toolkit/components/places/PlacesDBUtils.jsm b/toolkit/components/places/PlacesDBUtils.jsm
index dfd52ab9eff..07b609bacd0 100644
--- a/toolkit/components/places/PlacesDBUtils.jsm
+++ b/toolkit/components/places/PlacesDBUtils.jsm
@@ -285,53 +285,53 @@ this.PlacesDBUtils = {
// The 'weave0' idiom exploits character ordering (0 follows /) to
// efficiently select all annos with a 'weave/' prefix.
let deleteObsoleteAnnos = DBConn.createAsyncStatement(
- "DELETE FROM moz_annos " +
- "WHERE anno_attribute_id IN ( " +
- " SELECT id FROM moz_anno_attributes " +
- " WHERE name BETWEEN 'weave/' AND 'weave0' " +
- ")");
+ `DELETE FROM moz_annos
+ WHERE anno_attribute_id IN (
+ SELECT id FROM moz_anno_attributes
+ WHERE name BETWEEN 'weave/' AND 'weave0'
+ )`);
cleanupStatements.push(deleteObsoleteAnnos);
// A.2 remove obsolete annotations from moz_items_annos.
let deleteObsoleteItemsAnnos = DBConn.createAsyncStatement(
- "DELETE FROM moz_items_annos " +
- "WHERE anno_attribute_id IN ( " +
- " SELECT id FROM moz_anno_attributes " +
- " WHERE name = 'sync/children' " +
- " OR name = 'placesInternal/GUID' " +
- " OR name BETWEEN 'weave/' AND 'weave0' " +
- ")");
+ `DELETE FROM moz_items_annos
+ WHERE anno_attribute_id IN (
+ SELECT id FROM moz_anno_attributes
+ WHERE name = 'sync/children'
+ OR name = 'placesInternal/GUID'
+ OR name BETWEEN 'weave/' AND 'weave0'
+ )`);
cleanupStatements.push(deleteObsoleteItemsAnnos);
// A.3 remove unused attributes.
let deleteUnusedAnnoAttributes = DBConn.createAsyncStatement(
- "DELETE FROM moz_anno_attributes WHERE id IN ( " +
- "SELECT id FROM moz_anno_attributes n " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_annos WHERE anno_attribute_id = n.id LIMIT 1) " +
- "AND NOT EXISTS " +
- "(SELECT id FROM moz_items_annos WHERE anno_attribute_id = n.id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_anno_attributes WHERE id IN (
+ SELECT id FROM moz_anno_attributes n
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_annos WHERE anno_attribute_id = n.id LIMIT 1)
+ AND NOT EXISTS
+ (SELECT id FROM moz_items_annos WHERE anno_attribute_id = n.id LIMIT 1)
+ )`);
cleanupStatements.push(deleteUnusedAnnoAttributes);
// MOZ_ANNOS
// B.1 remove annos with an invalid attribute
let deleteInvalidAttributeAnnos = DBConn.createAsyncStatement(
- "DELETE FROM moz_annos WHERE id IN ( " +
- "SELECT id FROM moz_annos a " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_anno_attributes " +
- "WHERE id = a.anno_attribute_id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_annos WHERE id IN (
+ SELECT id FROM moz_annos a
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_anno_attributes
+ WHERE id = a.anno_attribute_id LIMIT 1)
+ )`);
cleanupStatements.push(deleteInvalidAttributeAnnos);
// B.2 remove orphan annos
let deleteOrphanAnnos = DBConn.createAsyncStatement(
- "DELETE FROM moz_annos WHERE id IN ( " +
- "SELECT id FROM moz_annos a " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_places WHERE id = a.place_id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_annos WHERE id IN (
+ SELECT id FROM moz_annos a
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_places WHERE id = a.place_id LIMIT 1)
+ )`);
cleanupStatements.push(deleteOrphanAnnos);
// MOZ_BOOKMARKS_ROOTS
@@ -344,18 +344,18 @@ this.PlacesDBUtils = {
if (!selectPlacesRoot.executeStep()) {
// We are missing the root, try to recreate it.
let createPlacesRoot = DBConn.createAsyncStatement(
- "INSERT INTO moz_bookmarks (id, type, fk, parent, position, title, "
- + "guid) "
- + "VALUES (:places_root, 2, NULL, 0, 0, :title, GENERATE_GUID())");
+ `INSERT INTO moz_bookmarks (id, type, fk, parent, position, title,
+ guid)
+ VALUES (:places_root, 2, NULL, 0, 0, :title, GENERATE_GUID())`);
createPlacesRoot.params["places_root"] = PlacesUtils.placesRootId;
createPlacesRoot.params["title"] = "";
cleanupStatements.push(createPlacesRoot);
// Now ensure that other roots are children of Places root.
let fixPlacesRootChildren = DBConn.createAsyncStatement(
- "UPDATE moz_bookmarks SET parent = :places_root WHERE id IN " +
- "(SELECT folder_id FROM moz_bookmarks_roots " +
- "WHERE folder_id <> :places_root)");
+ `UPDATE moz_bookmarks SET parent = :places_root WHERE id IN
+ (SELECT folder_id FROM moz_bookmarks_roots
+ WHERE folder_id <> :places_root)`);
fixPlacesRootChildren.params["places_root"] = PlacesUtils.placesRootId;
cleanupStatements.push(fixPlacesRootChildren);
}
@@ -364,8 +364,8 @@ this.PlacesDBUtils = {
// C.2 fix roots titles
// some alpha version has wrong roots title, and this also fixes them if
// locale has changed.
- let updateRootTitleSql = "UPDATE moz_bookmarks SET title = :title " +
- "WHERE id = :root_id AND title <> :title";
+ let updateRootTitleSql = `UPDATE moz_bookmarks SET title = :title
+ WHERE id = :root_id AND title <> :title`;
// root
let fixPlacesRootTitle = DBConn.createAsyncStatement(updateRootTitleSql);
fixPlacesRootTitle.params["root_id"] = PlacesUtils.placesRootId;
@@ -400,67 +400,67 @@ this.PlacesDBUtils = {
// D.1 remove items without a valid place
// if fk IS NULL we fix them in D.7
let deleteNoPlaceItems = DBConn.createAsyncStatement(
- "DELETE FROM moz_bookmarks WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN (" +
- "SELECT b.id FROM moz_bookmarks b " +
- "WHERE fk NOT NULL AND b.type = :bookmark_type " +
- "AND NOT EXISTS (SELECT url FROM moz_places WHERE id = b.fk LIMIT 1) " +
- ")");
+ `DELETE FROM moz_bookmarks WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT b.id FROM moz_bookmarks b
+ WHERE fk NOT NULL AND b.type = :bookmark_type
+ AND NOT EXISTS (SELECT url FROM moz_places WHERE id = b.fk LIMIT 1)
+ )`);
deleteNoPlaceItems.params["bookmark_type"] = PlacesUtils.bookmarks.TYPE_BOOKMARK;
cleanupStatements.push(deleteNoPlaceItems);
// D.2 remove items that are not uri bookmarks from tag containers
let deleteBogusTagChildren = DBConn.createAsyncStatement(
- "DELETE FROM moz_bookmarks WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN (" +
- "SELECT b.id FROM moz_bookmarks b " +
- "WHERE b.parent IN " +
- "(SELECT id FROM moz_bookmarks WHERE parent = :tags_folder) " +
- "AND b.type <> :bookmark_type " +
- ")");
+ `DELETE FROM moz_bookmarks WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT b.id FROM moz_bookmarks b
+ WHERE b.parent IN
+ (SELECT id FROM moz_bookmarks WHERE parent = :tags_folder)
+ AND b.type <> :bookmark_type
+ )`);
deleteBogusTagChildren.params["tags_folder"] = PlacesUtils.tagsFolderId;
deleteBogusTagChildren.params["bookmark_type"] = PlacesUtils.bookmarks.TYPE_BOOKMARK;
cleanupStatements.push(deleteBogusTagChildren);
// D.3 remove empty tags
let deleteEmptyTags = DBConn.createAsyncStatement(
- "DELETE FROM moz_bookmarks WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN (" +
- "SELECT b.id FROM moz_bookmarks b " +
- "WHERE b.id IN " +
- "(SELECT id FROM moz_bookmarks WHERE parent = :tags_folder) " +
- "AND NOT EXISTS " +
- "(SELECT id from moz_bookmarks WHERE parent = b.id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_bookmarks WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT b.id FROM moz_bookmarks b
+ WHERE b.id IN
+ (SELECT id FROM moz_bookmarks WHERE parent = :tags_folder)
+ AND NOT EXISTS
+ (SELECT id from moz_bookmarks WHERE parent = b.id LIMIT 1)
+ )`);
deleteEmptyTags.params["tags_folder"] = PlacesUtils.tagsFolderId;
cleanupStatements.push(deleteEmptyTags);
// D.4 move orphan items to unsorted folder
let fixOrphanItems = DBConn.createAsyncStatement(
- "UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN (" +
- "SELECT b.id FROM moz_bookmarks b " +
- "WHERE b.parent <> 0 " + // exclude Places root
- "AND NOT EXISTS " +
- "(SELECT id FROM moz_bookmarks WHERE id = b.parent LIMIT 1) " +
- ")");
+ `UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT b.id FROM moz_bookmarks b
+ WHERE b.parent <> 0 /* exclude Places root */
+ AND NOT EXISTS
+ (SELECT id FROM moz_bookmarks WHERE id = b.parent LIMIT 1)
+ )`);
fixOrphanItems.params["unsorted_folder"] = PlacesUtils.unfiledBookmarksFolderId;
cleanupStatements.push(fixOrphanItems);
// D.5 fix wrong keywords
let fixInvalidKeywords = DBConn.createAsyncStatement(
- "UPDATE moz_bookmarks SET keyword_id = NULL WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN ( " +
- "SELECT id FROM moz_bookmarks b " +
- "WHERE keyword_id NOT NULL " +
- "AND NOT EXISTS " +
- "(SELECT id FROM moz_keywords WHERE id = b.keyword_id LIMIT 1) " +
- ")");
+ `UPDATE moz_bookmarks SET keyword_id = NULL WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT id FROM moz_bookmarks b
+ WHERE keyword_id NOT NULL
+ AND NOT EXISTS
+ (SELECT id FROM moz_keywords WHERE id = b.keyword_id LIMIT 1)
+ )`);
cleanupStatements.push(fixInvalidKeywords);
// D.6 fix wrong item types
@@ -468,13 +468,13 @@ this.PlacesDBUtils = {
// If they have a valid fk convert them to bookmarks. Later in D.9 we
// will move eventual children to unsorted bookmarks.
let fixBookmarksAsFolders = DBConn.createAsyncStatement(
- "UPDATE moz_bookmarks SET type = :bookmark_type WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN ( " +
- "SELECT id FROM moz_bookmarks b " +
- "WHERE type IN (:folder_type, :separator_type) " +
- "AND fk NOTNULL " +
- ")");
+ `UPDATE moz_bookmarks SET type = :bookmark_type WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT id FROM moz_bookmarks b
+ WHERE type IN (:folder_type, :separator_type)
+ AND fk NOTNULL
+ )`);
fixBookmarksAsFolders.params["bookmark_type"] = PlacesUtils.bookmarks.TYPE_BOOKMARK;
fixBookmarksAsFolders.params["folder_type"] = PlacesUtils.bookmarks.TYPE_FOLDER;
fixBookmarksAsFolders.params["separator_type"] = PlacesUtils.bookmarks.TYPE_SEPARATOR;
@@ -484,13 +484,13 @@ this.PlacesDBUtils = {
// Bookmarks should have an fk, if they don't have any, convert them to
// folders.
let fixFoldersAsBookmarks = DBConn.createAsyncStatement(
- "UPDATE moz_bookmarks SET type = :folder_type WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN ( " +
- "SELECT id FROM moz_bookmarks b " +
- "WHERE type = :bookmark_type " +
- "AND fk IS NULL " +
- ")");
+ `UPDATE moz_bookmarks SET type = :folder_type WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT id FROM moz_bookmarks b
+ WHERE type = :bookmark_type
+ AND fk IS NULL
+ )`);
fixFoldersAsBookmarks.params["bookmark_type"] = PlacesUtils.bookmarks.TYPE_BOOKMARK;
fixFoldersAsBookmarks.params["folder_type"] = PlacesUtils.bookmarks.TYPE_FOLDER;
cleanupStatements.push(fixFoldersAsBookmarks);
@@ -499,15 +499,15 @@ this.PlacesDBUtils = {
// Items cannot have separators or other bookmarks
// as parent, if they have bad parent move them to unsorted bookmarks.
let fixInvalidParents = DBConn.createAsyncStatement(
- "UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id NOT IN ( " +
- "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
- ") AND id IN ( " +
- "SELECT id FROM moz_bookmarks b " +
- "WHERE EXISTS " +
- "(SELECT id FROM moz_bookmarks WHERE id = b.parent " +
- "AND type IN (:bookmark_type, :separator_type) " +
- "LIMIT 1) " +
- ")");
+ `UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id NOT IN (
+ SELECT folder_id FROM moz_bookmarks_roots /* skip roots */
+ ) AND id IN (
+ SELECT id FROM moz_bookmarks b
+ WHERE EXISTS
+ (SELECT id FROM moz_bookmarks WHERE id = b.parent
+ AND type IN (:bookmark_type, :separator_type)
+ LIMIT 1)
+ )`);
fixInvalidParents.params["unsorted_folder"] = PlacesUtils.unfiledBookmarksFolderId;
fixInvalidParents.params["bookmark_type"] = PlacesUtils.bookmarks.TYPE_BOOKMARK;
fixInvalidParents.params["separator_type"] = PlacesUtils.bookmarks.TYPE_SEPARATOR;
@@ -520,41 +520,41 @@ this.PlacesDBUtils = {
// triangular numbers obtained by the number of children (n).
// SUM(DISTINCT position + 1) == (n * (n + 1) / 2).
cleanupStatements.push(DBConn.createAsyncStatement(
- "CREATE TEMP TABLE IF NOT EXISTS moz_bm_reindex_temp ( " +
- " id INTEGER PRIMARY_KEY " +
- ", parent INTEGER " +
- ", position INTEGER " +
- ") "
+ `CREATE TEMP TABLE IF NOT EXISTS moz_bm_reindex_temp (
+ id INTEGER PRIMARY_KEY
+ , parent INTEGER
+ , position INTEGER
+ )`
));
cleanupStatements.push(DBConn.createAsyncStatement(
- "INSERT INTO moz_bm_reindex_temp " +
- "SELECT id, parent, 0 " +
- "FROM moz_bookmarks b " +
- "WHERE parent IN ( " +
- "SELECT parent " +
- "FROM moz_bookmarks " +
- "GROUP BY parent " +
- "HAVING (SUM(DISTINCT position + 1) - (count(*) * (count(*) + 1) / 2)) <> 0 " +
- ") " +
- "ORDER BY parent ASC, position ASC, ROWID ASC "
+ `INSERT INTO moz_bm_reindex_temp
+ SELECT id, parent, 0
+ FROM moz_bookmarks b
+ WHERE parent IN (
+ SELECT parent
+ FROM moz_bookmarks
+ GROUP BY parent
+ HAVING (SUM(DISTINCT position + 1) - (count(*) * (count(*) + 1) / 2)) <> 0
+ )
+ ORDER BY parent ASC, position ASC, ROWID ASC`
));
cleanupStatements.push(DBConn.createAsyncStatement(
- "CREATE INDEX IF NOT EXISTS moz_bm_reindex_temp_index " +
- "ON moz_bm_reindex_temp(parent)"
+ `CREATE INDEX IF NOT EXISTS moz_bm_reindex_temp_index
+ ON moz_bm_reindex_temp(parent)`
));
cleanupStatements.push(DBConn.createAsyncStatement(
- "UPDATE moz_bm_reindex_temp SET position = ( " +
- "ROWID - (SELECT MIN(t.ROWID) FROM moz_bm_reindex_temp t " +
- "WHERE t.parent = moz_bm_reindex_temp.parent) " +
- ") "
+ `UPDATE moz_bm_reindex_temp SET position = (
+ ROWID - (SELECT MIN(t.ROWID) FROM moz_bm_reindex_temp t
+ WHERE t.parent = moz_bm_reindex_temp.parent)
+ )`
));
cleanupStatements.push(DBConn.createAsyncStatement(
- "CREATE TEMP TRIGGER IF NOT EXISTS moz_bm_reindex_temp_trigger " +
- "BEFORE DELETE ON moz_bm_reindex_temp " +
- "FOR EACH ROW " +
- "BEGIN " +
- "UPDATE moz_bookmarks SET position = OLD.position WHERE id = OLD.id; " +
- "END "
+ `CREATE TEMP TRIGGER IF NOT EXISTS moz_bm_reindex_temp_trigger
+ BEFORE DELETE ON moz_bm_reindex_temp
+ FOR EACH ROW
+ BEGIN
+ UPDATE moz_bookmarks SET position = OLD.position WHERE id = OLD.id;
+ END`
));
cleanupStatements.push(DBConn.createAsyncStatement(
"DELETE FROM moz_bm_reindex_temp "
@@ -573,9 +573,9 @@ this.PlacesDBUtils = {
// Tags were allowed to have empty names due to a UI bug. Fix them
// replacing their title with "(notitle)".
let fixEmptyNamedTags = DBConn.createAsyncStatement(
- "UPDATE moz_bookmarks SET title = :empty_title " +
- "WHERE length(title) = 0 AND type = :folder_type " +
- "AND parent = :tags_folder"
+ `UPDATE moz_bookmarks SET title = :empty_title
+ WHERE length(title) = 0 AND type = :folder_type
+ AND parent = :tags_folder`
);
fixEmptyNamedTags.params["empty_title"] = "(notitle)";
fixEmptyNamedTags.params["folder_type"] = PlacesUtils.bookmarks.TYPE_FOLDER;
@@ -585,107 +585,107 @@ this.PlacesDBUtils = {
// MOZ_FAVICONS
// E.1 remove orphan icons
let deleteOrphanIcons = DBConn.createAsyncStatement(
- "DELETE FROM moz_favicons WHERE id IN (" +
- "SELECT id FROM moz_favicons f " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_places WHERE favicon_id = f.id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_favicons WHERE id IN (
+ SELECT id FROM moz_favicons f
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_places WHERE favicon_id = f.id LIMIT 1)
+ )`);
cleanupStatements.push(deleteOrphanIcons);
// MOZ_HISTORYVISITS
// F.1 remove orphan visits
let deleteOrphanVisits = DBConn.createAsyncStatement(
- "DELETE FROM moz_historyvisits WHERE id IN (" +
- "SELECT id FROM moz_historyvisits v " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_places WHERE id = v.place_id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_historyvisits WHERE id IN (
+ SELECT id FROM moz_historyvisits v
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_places WHERE id = v.place_id LIMIT 1)
+ )`);
cleanupStatements.push(deleteOrphanVisits);
// MOZ_INPUTHISTORY
// G.1 remove orphan input history
let deleteOrphanInputHistory = DBConn.createAsyncStatement(
- "DELETE FROM moz_inputhistory WHERE place_id IN (" +
- "SELECT place_id FROM moz_inputhistory i " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_places WHERE id = i.place_id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_inputhistory WHERE place_id IN (
+ SELECT place_id FROM moz_inputhistory i
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_places WHERE id = i.place_id LIMIT 1)
+ )`);
cleanupStatements.push(deleteOrphanInputHistory);
// MOZ_ITEMS_ANNOS
// H.1 remove item annos with an invalid attribute
let deleteInvalidAttributeItemsAnnos = DBConn.createAsyncStatement(
- "DELETE FROM moz_items_annos WHERE id IN ( " +
- "SELECT id FROM moz_items_annos t " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_anno_attributes " +
- "WHERE id = t.anno_attribute_id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_items_annos WHERE id IN (
+ SELECT id FROM moz_items_annos t
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_anno_attributes
+ WHERE id = t.anno_attribute_id LIMIT 1)
+ )`);
cleanupStatements.push(deleteInvalidAttributeItemsAnnos);
// H.2 remove orphan item annos
let deleteOrphanItemsAnnos = DBConn.createAsyncStatement(
- "DELETE FROM moz_items_annos WHERE id IN ( " +
- "SELECT id FROM moz_items_annos t " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_bookmarks WHERE id = t.item_id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_items_annos WHERE id IN (
+ SELECT id FROM moz_items_annos t
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_bookmarks WHERE id = t.item_id LIMIT 1)
+ )`);
cleanupStatements.push(deleteOrphanItemsAnnos);
// MOZ_KEYWORDS
// I.1 remove unused keywords
let deleteUnusedKeywords = DBConn.createAsyncStatement(
- "DELETE FROM moz_keywords WHERE id IN ( " +
- "SELECT id FROM moz_keywords k " +
- "WHERE NOT EXISTS " +
- "(SELECT id FROM moz_bookmarks WHERE keyword_id = k.id LIMIT 1) " +
- ")");
+ `DELETE FROM moz_keywords WHERE id IN (
+ SELECT id FROM moz_keywords k
+ WHERE NOT EXISTS
+ (SELECT id FROM moz_bookmarks WHERE keyword_id = k.id LIMIT 1)
+ )`);
cleanupStatements.push(deleteUnusedKeywords);
// MOZ_PLACES
// L.1 fix wrong favicon ids
let fixInvalidFaviconIds = DBConn.createAsyncStatement(
- "UPDATE moz_places SET favicon_id = NULL WHERE id IN ( " +
- "SELECT id FROM moz_places h " +
- "WHERE favicon_id NOT NULL " +
- "AND NOT EXISTS " +
- "(SELECT id FROM moz_favicons WHERE id = h.favicon_id LIMIT 1) " +
- ")");
+ `UPDATE moz_places SET favicon_id = NULL WHERE id IN (
+ SELECT id FROM moz_places h
+ WHERE favicon_id NOT NULL
+ AND NOT EXISTS
+ (SELECT id FROM moz_favicons WHERE id = h.favicon_id LIMIT 1)
+ )`);
cleanupStatements.push(fixInvalidFaviconIds);
// L.2 recalculate visit_count and last_visit_date
let fixVisitStats = DBConn.createAsyncStatement(
- "UPDATE moz_places " +
- "SET visit_count = (SELECT count(*) FROM moz_historyvisits " +
- "WHERE place_id = moz_places.id AND visit_type NOT IN (0,4,7,8)), " +
- "last_visit_date = (SELECT MAX(visit_date) FROM moz_historyvisits " +
- "WHERE place_id = moz_places.id) " +
- "WHERE id IN ( " +
- "SELECT h.id FROM moz_places h " +
- "WHERE visit_count <> (SELECT count(*) FROM moz_historyvisits v " +
- "WHERE v.place_id = h.id AND visit_type NOT IN (0,4,7,8)) " +
- "OR last_visit_date <> (SELECT MAX(visit_date) FROM moz_historyvisits v " +
- "WHERE v.place_id = h.id) " +
- ")");
+ `UPDATE moz_places
+ SET visit_count = (SELECT count(*) FROM moz_historyvisits
+ WHERE place_id = moz_places.id AND visit_type NOT IN (0,4,7,8)),
+ last_visit_date = (SELECT MAX(visit_date) FROM moz_historyvisits
+ WHERE place_id = moz_places.id)
+ WHERE id IN (
+ SELECT h.id FROM moz_places h
+ WHERE visit_count <> (SELECT count(*) FROM moz_historyvisits v
+ WHERE v.place_id = h.id AND visit_type NOT IN (0,4,7,8))
+ OR last_visit_date <> (SELECT MAX(visit_date) FROM moz_historyvisits v
+ WHERE v.place_id = h.id)
+ )`);
cleanupStatements.push(fixVisitStats);
// L.3 recalculate hidden for redirects.
let fixRedirectsHidden = DBConn.createAsyncStatement(
- "UPDATE moz_places " +
- "SET hidden = 1 " +
- "WHERE id IN ( " +
- "SELECT h.id FROM moz_places h " +
- "JOIN moz_historyvisits src ON src.place_id = h.id " +
- "JOIN moz_historyvisits dst ON dst.from_visit = src.id AND dst.visit_type IN (5,6) " +
- "LEFT JOIN moz_bookmarks on fk = h.id AND fk ISNULL " +
- "GROUP BY src.place_id HAVING count(*) = visit_count " +
- ")");
+ `UPDATE moz_places
+ SET hidden = 1
+ WHERE id IN (
+ SELECT h.id FROM moz_places h
+ JOIN moz_historyvisits src ON src.place_id = h.id
+ JOIN moz_historyvisits dst ON dst.from_visit = src.id AND dst.visit_type IN (5,6)
+ LEFT JOIN moz_bookmarks on fk = h.id AND fk ISNULL
+ GROUP BY src.place_id HAVING count(*) = visit_count
+ )`);
cleanupStatements.push(fixRedirectsHidden);
// L.4 recalculate foreign_count.
let fixForeignCount = DBConn.createAsyncStatement(
- "UPDATE moz_places SET foreign_count = " +
- "(SELECT count(*) FROM moz_bookmarks WHERE fk = moz_places.id )");
+ `UPDATE moz_places SET foreign_count =
+ (SELECT count(*) FROM moz_bookmarks WHERE fk = moz_places.id )`);
cleanupStatements.push(fixForeignCount);
// MAINTENANCE STATEMENTS SHOULD GO ABOVE THIS POINT!
@@ -798,7 +798,7 @@ this.PlacesDBUtils = {
while (stmt.executeStep()) {
let tableName = stmt.getString(0);
let countStmt = DBConn.createStatement(
- "SELECT count(*) FROM " + tableName);
+ `SELECT count(*) FROM ${tableName}`);
countStmt.executeStep();
tasks.log("Table " + tableName + " has " + countStmt.getInt32(0) + " records");
countStmt.finalize();
@@ -871,47 +871,47 @@ this.PlacesDBUtils = {
{ histogram: "PLACES_BOOKMARKS_COUNT",
healthreport: true,
- query: "SELECT count(*) FROM moz_bookmarks b "
- + "JOIN moz_bookmarks t ON t.id = b.parent "
- + "AND t.parent <> :tags_folder "
- + "WHERE b.type = :type_bookmark " },
+ query: `SELECT count(*) FROM moz_bookmarks b
+ JOIN moz_bookmarks t ON t.id = b.parent
+ AND t.parent <> :tags_folder
+ WHERE b.type = :type_bookmark` },
{ histogram: "PLACES_TAGS_COUNT",
- query: "SELECT count(*) FROM moz_bookmarks "
- + "WHERE parent = :tags_folder " },
+ query: `SELECT count(*) FROM moz_bookmarks
+ WHERE parent = :tags_folder` },
{ histogram: "PLACES_FOLDERS_COUNT",
- query: "SELECT count(*) FROM moz_bookmarks "
- + "WHERE TYPE = :type_folder "
- + "AND parent NOT IN (0, :places_root, :tags_folder) " },
+ query: `SELECT count(*) FROM moz_bookmarks
+ WHERE TYPE = :type_folder
+ AND parent NOT IN (0, :places_root, :tags_folder)` },
{ histogram: "PLACES_KEYWORDS_COUNT",
- query: "SELECT count(*) FROM moz_keywords " },
+ query: "SELECT count(*) FROM moz_keywords" },
{ histogram: "PLACES_SORTED_BOOKMARKS_PERC",
- query: "SELECT IFNULL(ROUND(( "
- + "SELECT count(*) FROM moz_bookmarks b "
- + "JOIN moz_bookmarks t ON t.id = b.parent "
- + "AND t.parent <> :tags_folder AND t.parent > :places_root "
- + "WHERE b.type = :type_bookmark "
- + ") * 100 / ( "
- + "SELECT count(*) FROM moz_bookmarks b "
- + "JOIN moz_bookmarks t ON t.id = b.parent "
- + "AND t.parent <> :tags_folder "
- + "WHERE b.type = :type_bookmark "
- + ")), 0) " },
+ query: `SELECT IFNULL(ROUND((
+ SELECT count(*) FROM moz_bookmarks b
+ JOIN moz_bookmarks t ON t.id = b.parent
+ AND t.parent <> :tags_folder AND t.parent > :places_root
+ WHERE b.type = :type_bookmark
+ ) * 100 / (
+ SELECT count(*) FROM moz_bookmarks b
+ JOIN moz_bookmarks t ON t.id = b.parent
+ AND t.parent <> :tags_folder
+ WHERE b.type = :type_bookmark
+ )), 0)` },
{ histogram: "PLACES_TAGGED_BOOKMARKS_PERC",
- query: "SELECT IFNULL(ROUND(( "
- + "SELECT count(*) FROM moz_bookmarks b "
- + "JOIN moz_bookmarks t ON t.id = b.parent "
- + "AND t.parent = :tags_folder "
- + ") * 100 / ( "
- + "SELECT count(*) FROM moz_bookmarks b "
- + "JOIN moz_bookmarks t ON t.id = b.parent "
- + "AND t.parent <> :tags_folder "
- + "WHERE b.type = :type_bookmark "
- + ")), 0) " },
+ query: `SELECT IFNULL(ROUND((
+ SELECT count(*) FROM moz_bookmarks b
+ JOIN moz_bookmarks t ON t.id = b.parent
+ AND t.parent = :tags_folder
+ ) * 100 / (
+ SELECT count(*) FROM moz_bookmarks b
+ JOIN moz_bookmarks t ON t.id = b.parent
+ AND t.parent <> :tags_folder
+ WHERE b.type = :type_bookmark
+ )), 0)` },
{ histogram: "PLACES_DATABASE_FILESIZE_MB",
callback: function () {
diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm
index df3bb80b97d..ecb43815794 100644
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -1330,9 +1330,9 @@ this.PlacesUtils = {
let itemIds = [];
Task.spawn(function* () {
let conn = yield this.promiseDBConnection();
- const QUERY_STR = "SELECT b.id FROM moz_bookmarks b " +
- "JOIN moz_places h on h.id = b.fk " +
- "WHERE h.url = :url";
+ const QUERY_STR = `SELECT b.id FROM moz_bookmarks b
+ JOIN moz_places h on h.id = b.fk
+ WHERE h.url = :url`;
let spec = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
yield conn.executeCached(QUERY_STR, { url: spec }, aRow => {
if (abort)
@@ -1694,38 +1694,38 @@ this.PlacesUtils = {
};
const QUERY_STR =
- "WITH RECURSIVE " +
- "descendants(fk, level, type, id, guid, parent, parentGUID, position, " +
- " title, dateAdded, lastModified) AS (" +
- " SELECT b1.fk, 0, b1.type, b1.id, b1.guid, b1.parent, " +
- " (SELECT guid FROM moz_bookmarks WHERE id = b1.parent), " +
- " b1.position, b1.title, b1.dateAdded, b1.lastModified " +
- " FROM moz_bookmarks b1 WHERE b1.guid=:item_guid " +
- " UNION ALL " +
- " SELECT b2.fk, level + 1, b2.type, b2.id, b2.guid, b2.parent, " +
- " descendants.guid, b2.position, b2.title, b2.dateAdded, " +
- " b2.lastModified " +
- " FROM moz_bookmarks b2 " +
- " JOIN descendants ON b2.parent = descendants.id AND b2.id <> :tags_folder) " +
- "SELECT d.level, d.id, d.guid, d.parent, d.parentGUID, d.type, " +
- " d.position AS [index], d.title, d.dateAdded, d.lastModified, " +
- " h.url, f.url AS iconuri, " +
- " (SELECT GROUP_CONCAT(t.title, ',') " +
- " FROM moz_bookmarks b2 " +
- " JOIN moz_bookmarks t ON t.id = +b2.parent AND t.parent = :tags_folder " +
- " WHERE b2.fk = h.id " +
- " ) AS tags, " +
- " EXISTS (SELECT 1 FROM moz_items_annos " +
- " WHERE item_id = d.id LIMIT 1) AS has_annos, " +
- " (SELECT a.content FROM moz_annos a " +
- " JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id " +
- " WHERE place_id = h.id AND n.name = :charset_anno " +
- " ) AS charset " +
- "FROM descendants d " +
- "LEFT JOIN moz_bookmarks b3 ON b3.id = d.parent " +
- "LEFT JOIN moz_places h ON h.id = d.fk " +
- "LEFT JOIN moz_favicons f ON f.id = h.favicon_id " +
- "ORDER BY d.level, d.parent, d.position";
+ `WITH RECURSIVE
+ descendants(fk, level, type, id, guid, parent, parentGUID, position,
+ title, dateAdded, lastModified) AS (
+ SELECT b1.fk, 0, b1.type, b1.id, b1.guid, b1.parent,
+ (SELECT guid FROM moz_bookmarks WHERE id = b1.parent),
+ b1.position, b1.title, b1.dateAdded, b1.lastModified
+ FROM moz_bookmarks b1 WHERE b1.guid=:item_guid
+ UNION ALL
+ SELECT b2.fk, level + 1, b2.type, b2.id, b2.guid, b2.parent,
+ descendants.guid, b2.position, b2.title, b2.dateAdded,
+ b2.lastModified
+ FROM moz_bookmarks b2
+ JOIN descendants ON b2.parent = descendants.id AND b2.id <> :tags_folder)
+ SELECT d.level, d.id, d.guid, d.parent, d.parentGUID, d.type,
+ d.position AS [index], d.title, d.dateAdded, d.lastModified,
+ h.url, f.url AS iconuri,
+ (SELECT GROUP_CONCAT(t.title, ',')
+ FROM moz_bookmarks b2
+ JOIN moz_bookmarks t ON t.id = +b2.parent AND t.parent = :tags_folder
+ WHERE b2.fk = h.id
+ ) AS tags,
+ EXISTS (SELECT 1 FROM moz_items_annos
+ WHERE item_id = d.id LIMIT 1) AS has_annos,
+ (SELECT a.content FROM moz_annos a
+ JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id
+ WHERE place_id = h.id AND n.name = :charset_anno
+ ) AS charset
+ FROM descendants d
+ LEFT JOIN moz_bookmarks b3 ON b3.id = d.parent
+ LEFT JOIN moz_places h ON h.id = d.fk
+ LEFT JOIN moz_favicons f ON f.id = h.favicon_id
+ ORDER BY d.level, d.parent, d.position`;
if (!aItemGUID)
diff --git a/toolkit/components/places/nsLivemarkService.js b/toolkit/components/places/nsLivemarkService.js
index 885f3f5b571..3f3955d8be9 100644
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -73,21 +73,21 @@ LivemarkService.prototype = {
get _populateCacheSQL()
{
function getAnnoSQLFragment(aAnnoParam) {
- return "SELECT a.content "
- + "FROM moz_items_annos a "
- + "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
- + "WHERE a.item_id = b.id "
- + "AND n.name = " + aAnnoParam;
+ return `SELECT a.content
+ FROM moz_items_annos a
+ JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id
+ WHERE a.item_id = b.id
+ AND n.name = ${aAnnoParam}`;
}
- return "SELECT b.id, b.title, b.parent, b.position, b.guid, b.lastModified, "
- + "(" + getAnnoSQLFragment(":feedURI_anno") + ") AS feedURI, "
- + "(" + getAnnoSQLFragment(":siteURI_anno") + ") AS siteURI "
- + "FROM moz_bookmarks b "
- + "JOIN moz_items_annos a ON a.item_id = b.id "
- + "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
- + "WHERE b.type = :folder_type "
- + "AND n.name = :feedURI_anno ";
+ return `SELECT b.id, b.title, b.parent, b.position, b.guid, b.lastModified,
+ ( ${getAnnoSQLFragment(":feedURI_anno")} ) AS feedURI,
+ ( ${getAnnoSQLFragment(":siteURI_anno")} ) AS siteURI
+ FROM moz_bookmarks b
+ JOIN moz_items_annos a ON a.item_id = b.id
+ JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id
+ WHERE b.type = :folder_type
+ AND n.name = :feedURI_anno`;
},
_ensureAsynchronousCache: Task.async(function* () {
diff --git a/toolkit/components/places/nsPlacesAutoComplete.js b/toolkit/components/places/nsPlacesAutoComplete.js
index 745828df739..8b5e7fd2ba8 100644
--- a/toolkit/components/places/nsPlacesAutoComplete.js
+++ b/toolkit/components/places/nsPlacesAutoComplete.js
@@ -25,17 +25,17 @@ const Cr = Components.results;
// - the bookmark title, if it is a bookmark (kQueryIndexBookmarkTitle)
// - the tags associated with a bookmarked entry (kQueryIndexTags)
const kBookTagSQLFragment =
- "EXISTS(SELECT 1 FROM moz_bookmarks WHERE fk = h.id) AS bookmarked, "
-+ "( "
-+ "SELECT title FROM moz_bookmarks WHERE fk = h.id AND title NOTNULL "
-+ "ORDER BY lastModified DESC LIMIT 1 "
-+ ") AS btitle, "
-+ "( "
-+ "SELECT GROUP_CONCAT(t.title, ',') "
-+ "FROM moz_bookmarks b "
-+ "JOIN moz_bookmarks t ON t.id = +b.parent AND t.parent = :parent "
-+ "WHERE b.fk = h.id "
-+ ") AS tags";
+ `EXISTS(SELECT 1 FROM moz_bookmarks WHERE fk = h.id) AS bookmarked,
+ (
+ SELECT title FROM moz_bookmarks WHERE fk = h.id AND title NOTNULL
+ ORDER BY lastModified DESC LIMIT 1
+ ) AS btitle,
+ (
+ SELECT GROUP_CONCAT(t.title, ',')
+ FROM moz_bookmarks b
+ JOIN moz_bookmarks t ON t.id = +b.parent AND t.parent = :parent
+ WHERE b.fk = h.id
+ ) AS tags`;
// observer topics
const kTopicShutdown = "places-shutdown";
@@ -105,10 +105,10 @@ function initTempTable(aDatabase)
// Note: this should be kept up-to-date with the definition in
// nsPlacesTables.h.
let stmt = aDatabase.createAsyncStatement(
- "CREATE TEMP TABLE moz_openpages_temp ( "
- + " url TEXT PRIMARY KEY "
- + ", open_count INTEGER "
- + ") "
+ `CREATE TEMP TABLE moz_openpages_temp (
+ url TEXT PRIMARY KEY
+ , open_count INTEGER
+ )`
);
stmt.executeAsync();
stmt.finalize();
@@ -116,13 +116,13 @@ function initTempTable(aDatabase)
// Note: this should be kept up-to-date with the definition in
// nsPlacesTriggers.h.
stmt = aDatabase.createAsyncStatement(
- "CREATE TEMPORARY TRIGGER moz_openpages_temp_afterupdate_trigger "
- + "AFTER UPDATE OF open_count ON moz_openpages_temp FOR EACH ROW "
- + "WHEN NEW.open_count = 0 "
- + "BEGIN "
- + "DELETE FROM moz_openpages_temp "
- + "WHERE url = NEW.url; "
- + "END "
+ `CREATE TEMPORARY TRIGGER moz_openpages_temp_afterupdate_trigger
+ AFTER UPDATE OF open_count ON moz_openpages_temp FOR EACH ROW
+ WHEN NEW.open_count = 0
+ BEGIN
+ DELETE FROM moz_openpages_temp
+ WHERE url = NEW.url;
+ END`
);
stmt.executeAsync();
stmt.finalize();
@@ -286,21 +286,24 @@ function nsPlacesAutoComplete()
// TODO bug 412736 in case of a frecency tie, break it with h.typed and
// h.visit_count which is better than nothing. This is slow, so not doing it
// yet...
- const SQL_BASE = "SELECT h.url, h.title, f.url, " + kBookTagSQLFragment + ", "
- + "h.visit_count, h.typed, h.id, :query_type, "
- + "t.open_count "
- + "FROM moz_places h "
- + "LEFT JOIN moz_favicons f ON f.id = h.favicon_id "
- + "LEFT JOIN moz_openpages_temp t ON t.url = h.url "
- + "WHERE h.frecency <> 0 "
- + "AND AUTOCOMPLETE_MATCH(:searchString, h.url, "
- + "IFNULL(btitle, h.title), tags, "
- + "h.visit_count, h.typed, "
- + "bookmarked, t.open_count, "
- + ":matchBehavior, :searchBehavior) "
- + "{ADDITIONAL_CONDITIONS} "
- + "ORDER BY h.frecency DESC, h.id DESC "
- + "LIMIT :maxResults";
+ function baseQuery(conditions = "") {
+ let query = `SELECT h.url, h.title, f.url, ${kBookTagSQLFragment},
+ h.visit_count, h.typed, h.id, :query_type,
+ t.open_count
+ FROM moz_places h
+ LEFT JOIN moz_favicons f ON f.id = h.favicon_id
+ LEFT JOIN moz_openpages_temp t ON t.url = h.url
+ WHERE h.frecency <> 0
+ AND AUTOCOMPLETE_MATCH(:searchString, h.url,
+ IFNULL(btitle, h.title), tags,
+ h.visit_count, h.typed,
+ bookmarked, t.open_count,
+ :matchBehavior, :searchBehavior)
+ ${conditions}
+ ORDER BY h.frecency DESC, h.id DESC
+ LIMIT :maxResults`;
+ return query;
+ }
//////////////////////////////////////////////////////////////////////////////
//// Smart Getters
@@ -343,128 +346,113 @@ function nsPlacesAutoComplete()
});
XPCOMUtils.defineLazyGetter(this, "_defaultQuery", function() {
- let replacementText = "";
- return this._db.createAsyncStatement(
- SQL_BASE.replace("{ADDITIONAL_CONDITIONS}", replacementText, "g")
- );
+ return this._db.createAsyncStatement(baseQuery());
});
XPCOMUtils.defineLazyGetter(this, "_historyQuery", function() {
// Enforce ignoring the visit_count index, since the frecency one is much
// faster in this case. ANALYZE helps the query planner to figure out the
// faster path, but it may not have run yet.
- let replacementText = "AND +h.visit_count > 0";
- return this._db.createAsyncStatement(
- SQL_BASE.replace("{ADDITIONAL_CONDITIONS}", replacementText, "g")
- );
+ return this._db.createAsyncStatement(baseQuery("AND +h.visit_count > 0"));
});
XPCOMUtils.defineLazyGetter(this, "_bookmarkQuery", function() {
- let replacementText = "AND bookmarked";
- return this._db.createAsyncStatement(
- SQL_BASE.replace("{ADDITIONAL_CONDITIONS}", replacementText, "g")
- );
+ return this._db.createAsyncStatement(baseQuery("AND bookmarked"));
});
XPCOMUtils.defineLazyGetter(this, "_tagsQuery", function() {
- let replacementText = "AND tags IS NOT NULL";
- return this._db.createAsyncStatement(
- SQL_BASE.replace("{ADDITIONAL_CONDITIONS}", replacementText, "g")
- );
+ return this._db.createAsyncStatement(baseQuery("AND tags IS NOT NULL"));
});
XPCOMUtils.defineLazyGetter(this, "_openPagesQuery", function() {
return this._db.createAsyncStatement(
- "SELECT t.url, t.url, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "
- + ":query_type, t.open_count, NULL "
- + "FROM moz_openpages_temp t "
- + "LEFT JOIN moz_places h ON h.url = t.url "
- + "WHERE h.id IS NULL "
- + "AND AUTOCOMPLETE_MATCH(:searchString, t.url, t.url, NULL, "
- + "NULL, NULL, NULL, t.open_count, "
- + ":matchBehavior, :searchBehavior) "
- + "ORDER BY t.ROWID DESC "
- + "LIMIT :maxResults "
+ `SELECT t.url, t.url, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ :query_type, t.open_count, NULL
+ FROM moz_openpages_temp t
+ LEFT JOIN moz_places h ON h.url = t.url
+ WHERE h.id IS NULL
+ AND AUTOCOMPLETE_MATCH(:searchString, t.url, t.url, NULL,
+ NULL, NULL, NULL, t.open_count,
+ :matchBehavior, :searchBehavior)
+ ORDER BY t.ROWID DESC
+ LIMIT :maxResults`
);
});
XPCOMUtils.defineLazyGetter(this, "_typedQuery", function() {
- let replacementText = "AND h.typed = 1";
- return this._db.createAsyncStatement(
- SQL_BASE.replace("{ADDITIONAL_CONDITIONS}", replacementText, "g")
- );
+ return this._db.createAsyncStatement(baseQuery("AND h.typed = 1"));
});
XPCOMUtils.defineLazyGetter(this, "_adaptiveQuery", function() {
return this._db.createAsyncStatement(
- "/* do not warn (bug 487789) */ "
- + "SELECT h.url, h.title, f.url, " + kBookTagSQLFragment + ", "
- + "h.visit_count, h.typed, h.id, :query_type, t.open_count "
- + "FROM ( "
- + "SELECT ROUND( "
- + "MAX(use_count) * (1 + (input = :search_string)), 1 "
- + ") AS rank, place_id "
- + "FROM moz_inputhistory "
- + "WHERE input BETWEEN :search_string AND :search_string || X'FFFF' "
- + "GROUP BY place_id "
- + ") AS i "
- + "JOIN moz_places h ON h.id = i.place_id "
- + "LEFT JOIN moz_favicons f ON f.id = h.favicon_id "
- + "LEFT JOIN moz_openpages_temp t ON t.url = h.url "
- + "WHERE AUTOCOMPLETE_MATCH(NULL, h.url, "
- + "IFNULL(btitle, h.title), tags, "
- + "h.visit_count, h.typed, bookmarked, "
- + "t.open_count, "
- + ":matchBehavior, :searchBehavior) "
- + "ORDER BY rank DESC, h.frecency DESC "
+ `/* do not warn (bug 487789) */
+ SELECT h.url, h.title, f.url, ${kBookTagSQLFragment},
+ h.visit_count, h.typed, h.id, :query_type, t.open_count
+ FROM (
+ SELECT ROUND(
+ MAX(use_count) * (1 + (input = :search_string)), 1
+ ) AS rank, place_id
+ FROM moz_inputhistory
+ WHERE input BETWEEN :search_string AND :search_string || X'FFFF'
+ GROUP BY place_id
+ ) AS i
+ JOIN moz_places h ON h.id = i.place_id
+ LEFT JOIN moz_favicons f ON f.id = h.favicon_id
+ LEFT JOIN moz_openpages_temp t ON t.url = h.url
+ WHERE AUTOCOMPLETE_MATCH(NULL, h.url,
+ IFNULL(btitle, h.title), tags,
+ h.visit_count, h.typed, bookmarked,
+ t.open_count,
+ :matchBehavior, :searchBehavior)
+ ORDER BY rank DESC, h.frecency DESC`
);
});
XPCOMUtils.defineLazyGetter(this, "_keywordQuery", function() {
return this._db.createAsyncStatement(
- "/* do not warn (bug 487787) */ "
- + "SELECT "
- + "(SELECT REPLACE(url, '%s', :query_string) FROM moz_places WHERE id = b.fk) "
- + "AS search_url, h.title, "
- + "IFNULL(f.url, (SELECT f.url "
- + "FROM moz_places "
- + "JOIN moz_favicons f ON f.id = favicon_id "
- + "WHERE rev_host = (SELECT rev_host FROM moz_places WHERE id = b.fk) "
- + "ORDER BY frecency DESC "
- + "LIMIT 1) "
- + "), 1, b.title, NULL, h.visit_count, h.typed, IFNULL(h.id, b.fk), "
- + ":query_type, t.open_count "
- + "FROM moz_keywords k "
- + "JOIN moz_bookmarks b ON b.keyword_id = k.id "
- + "LEFT JOIN moz_places h ON h.url = search_url "
- + "LEFT JOIN moz_favicons f ON f.id = h.favicon_id "
- + "LEFT JOIN moz_openpages_temp t ON t.url = search_url "
- + "WHERE LOWER(k.keyword) = LOWER(:keyword) "
- + "ORDER BY h.frecency DESC "
+ `/* do not warn (bug 487787) */
+ SELECT
+ (SELECT REPLACE(url, '%s', :query_string) FROM moz_places WHERE id = b.fk)
+ AS search_url, h.title,
+ IFNULL(f.url, (SELECT f.url
+ FROM moz_places
+ JOIN moz_favicons f ON f.id = favicon_id
+ WHERE rev_host = (SELECT rev_host FROM moz_places WHERE id = b.fk)
+ ORDER BY frecency DESC
+ LIMIT 1)
+ ), 1, b.title, NULL, h.visit_count, h.typed, IFNULL(h.id, b.fk),
+ :query_type, t.open_count
+ FROM moz_keywords k
+ JOIN moz_bookmarks b ON b.keyword_id = k.id
+ LEFT JOIN moz_places h ON h.url = search_url
+ LEFT JOIN moz_favicons f ON f.id = h.favicon_id
+ LEFT JOIN moz_openpages_temp t ON t.url = search_url
+ WHERE LOWER(k.keyword) = LOWER(:keyword)
+ ORDER BY h.frecency DESC`
);
});
- this._registerOpenPageQuerySQL = "INSERT OR REPLACE INTO moz_openpages_temp "
- + "(url, open_count) "
- + "VALUES (:page_url, "
- + "IFNULL("
- + "("
- + "SELECT open_count + 1 "
- + "FROM moz_openpages_temp "
- + "WHERE url = :page_url "
- + "), "
- + "1"
- + ")"
- + ")";
+ this._registerOpenPageQuerySQL =
+ `INSERT OR REPLACE INTO moz_openpages_temp (url, open_count)
+ VALUES (:page_url,
+ IFNULL(
+ (
+ SELECT open_count + 1
+ FROM moz_openpages_temp
+ WHERE url = :page_url
+ ),
+ 1
+ )
+ )`;
XPCOMUtils.defineLazyGetter(this, "_registerOpenPageQuery", function() {
return this._db.createAsyncStatement(this._registerOpenPageQuerySQL);
});
XPCOMUtils.defineLazyGetter(this, "_unregisterOpenPageQuery", function() {
return this._db.createAsyncStatement(
- "UPDATE moz_openpages_temp "
- + "SET open_count = open_count - 1 "
- + "WHERE url = :page_url"
+ `UPDATE moz_openpages_temp
+ SET open_count = open_count - 1
+ WHERE url = :page_url`
);
});
@@ -1290,14 +1278,14 @@ urlInlineComplete.prototype = {
// Add a trailing slash at the end of the hostname, since we always
// want to complete up to and including a URL separator.
this.__hostQuery = this._db.createAsyncStatement(
- "/* do not warn (bug no): could index on (typed,frecency) but not worth it */ "
- + "SELECT host || '/', prefix || host || '/' "
- + "FROM moz_hosts "
- + "WHERE host BETWEEN :search_string AND :search_string || X'FFFF' "
- + "AND frecency <> 0 "
- + (this._autofillTyped ? "AND typed = 1 " : "")
- + "ORDER BY frecency DESC "
- + "LIMIT 1"
+ `/* do not warn (bug no): could index on (typed,frecency) but not worth it */
+ SELECT host || '/', prefix || host || '/'
+ FROM moz_hosts
+ WHERE host BETWEEN :search_string AND :search_string || X'FFFF'
+ AND frecency <> 0
+ ${this._autofillTyped ? "AND typed = 1" : ""}
+ ORDER BY frecency DESC
+ LIMIT 1`
);
}
return this.__hostQuery;
@@ -1309,17 +1297,17 @@ urlInlineComplete.prototype = {
{
if (!this.__urlQuery) {
this.__urlQuery = this._db.createAsyncStatement(
- "/* do not warn (bug no): can't use an index */ "
- + "SELECT h.url "
- + "FROM moz_places h "
- + "WHERE h.frecency <> 0 "
- + (this._autofillTyped ? "AND h.typed = 1 " : "")
- + "AND AUTOCOMPLETE_MATCH(:searchString, h.url, "
- + "h.title, '', "
- + "h.visit_count, h.typed, 0, 0, "
- + ":matchBehavior, :searchBehavior) "
- + "ORDER BY h.frecency DESC, h.id DESC "
- + "LIMIT 1"
+ `/* do not warn (bug no): can't use an index */
+ SELECT h.url
+ FROM moz_places h
+ WHERE h.frecency <> 0
+ ${this._autofillTyped ? "AND h.typed = 1 " : ""}
+ AND AUTOCOMPLETE_MATCH(:searchString, h.url,
+ h.title, '',
+ h.visit_count, h.typed, 0, 0,
+ :matchBehavior, :searchBehavior)
+ ORDER BY h.frecency DESC, h.id DESC
+ LIMIT 1`
);
}
return this.__urlQuery;
diff --git a/toolkit/components/places/nsPlacesExpiration.js b/toolkit/components/places/nsPlacesExpiration.js
index d118a835668..14438b40bd4 100644
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -171,24 +171,24 @@ const EXPIRATION_QUERIES = {
// This explicitly excludes any visits added in the last 7 days, to protect
// users with thousands of bookmarks from constantly losing history.
QUERY_FIND_VISITS_TO_EXPIRE: {
- sql: "INSERT INTO expiration_notify "
- + "(v_id, url, guid, visit_date, expected_results) "
- + "SELECT v.id, h.url, h.guid, v.visit_date, :limit_visits "
- + "FROM moz_historyvisits v "
- + "JOIN moz_places h ON h.id = v.place_id "
- + "WHERE (SELECT COUNT(*) FROM moz_places) > :max_uris "
- + "AND visit_date < strftime('%s','now','localtime','start of day','-7 days','utc') * 1000000 "
- + "ORDER BY v.visit_date ASC "
- + "LIMIT :limit_visits",
+ sql: `INSERT INTO expiration_notify
+ (v_id, url, guid, visit_date, expected_results)
+ SELECT v.id, h.url, h.guid, v.visit_date, :limit_visits
+ FROM moz_historyvisits v
+ JOIN moz_places h ON h.id = v.place_id
+ WHERE (SELECT COUNT(*) FROM moz_places) > :max_uris
+ AND visit_date < strftime('%s','now','localtime','start of day','-7 days','utc') * 1000000
+ ORDER BY v.visit_date ASC
+ LIMIT :limit_visits`,
actions: ACTION.TIMED_OVERLIMIT | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
},
// Removes the previously found visits.
QUERY_EXPIRE_VISITS: {
- sql: "DELETE FROM moz_historyvisits WHERE id IN ( "
- + "SELECT v_id FROM expiration_notify WHERE v_id NOTNULL "
- + ")",
+ sql: `DELETE FROM moz_historyvisits WHERE id IN (
+ SELECT v_id FROM expiration_notify WHERE v_id NOTNULL
+ )`,
actions: ACTION.TIMED_OVERLIMIT | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
},
@@ -201,51 +201,51 @@ const EXPIRATION_QUERIES = {
// before it actually gets the new visit or bookmark.
// Thus, since new pages get frecency -1, we filter on that.
QUERY_FIND_URIS_TO_EXPIRE: {
- sql: "INSERT INTO expiration_notify "
- + "(p_id, url, guid, visit_date, expected_results) "
- + "SELECT h.id, h.url, h.guid, h.last_visit_date, :limit_uris "
- + "FROM moz_places h "
- + "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
- + "WHERE h.last_visit_date IS NULL "
- + "AND h.foreign_count = 0 "
- + "AND v.id IS NULL "
- + "AND frecency <> -1 "
- + "LIMIT :limit_uris",
+ sql: `INSERT INTO expiration_notify
+ (p_id, url, guid, visit_date, expected_results)
+ SELECT h.id, h.url, h.guid, h.last_visit_date, :limit_uris
+ FROM moz_places h
+ LEFT JOIN moz_historyvisits v ON h.id = v.place_id
+ WHERE h.last_visit_date IS NULL
+ AND h.foreign_count = 0
+ AND v.id IS NULL
+ AND frecency <> -1
+ LIMIT :limit_uris`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
},
// Expire found URIs from the database.
QUERY_EXPIRE_URIS: {
- sql: "DELETE FROM moz_places WHERE id IN ( "
- + "SELECT p_id FROM expiration_notify WHERE p_id NOTNULL "
- + ")",
+ sql: `DELETE FROM moz_places WHERE id IN (
+ SELECT p_id FROM expiration_notify WHERE p_id NOTNULL
+ )`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
},
// Expire orphan URIs from the database.
QUERY_SILENT_EXPIRE_ORPHAN_URIS: {
- sql: "DELETE FROM moz_places WHERE id IN ( "
- + "SELECT h.id "
- + "FROM moz_places h "
- + "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
- + "WHERE h.last_visit_date IS NULL "
- + "AND h.foreign_count = 0 "
- + "AND v.id IS NULL "
- + "LIMIT :limit_uris "
- + ")",
+ sql: `DELETE FROM moz_places WHERE id IN (
+ SELECT h.id
+ FROM moz_places h
+ LEFT JOIN moz_historyvisits v ON h.id = v.place_id
+ WHERE h.last_visit_date IS NULL
+ AND h.foreign_count = 0
+ AND v.id IS NULL
+ LIMIT :limit_uris
+ )`,
actions: ACTION.CLEAR_HISTORY
},
// Expire orphan icons from the database.
QUERY_EXPIRE_FAVICONS: {
- sql: "DELETE FROM moz_favicons WHERE id IN ( "
- + "SELECT f.id FROM moz_favicons f "
- + "LEFT JOIN moz_places h ON f.id = h.favicon_id "
- + "WHERE h.favicon_id IS NULL "
- + "LIMIT :limit_favicons "
- + ")",
+ sql: `DELETE FROM moz_favicons WHERE id IN (
+ SELECT f.id FROM moz_favicons f
+ LEFT JOIN moz_places h ON f.id = h.favicon_id
+ WHERE h.favicon_id IS NULL
+ LIMIT :limit_favicons
+ )`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
@@ -253,12 +253,12 @@ const EXPIRATION_QUERIES = {
// Expire orphan page annotations from the database.
QUERY_EXPIRE_ANNOS: {
- sql: "DELETE FROM moz_annos WHERE id in ( "
- + "SELECT a.id FROM moz_annos a "
- + "LEFT JOIN moz_places h ON a.place_id = h.id "
- + "WHERE h.id IS NULL "
- + "LIMIT :limit_annos "
- + ")",
+ sql: `DELETE FROM moz_annos WHERE id in (
+ SELECT a.id FROM moz_annos a
+ LEFT JOIN moz_places h ON a.place_id = h.id
+ WHERE h.id IS NULL
+ LIMIT :limit_annos
+ )`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
@@ -266,13 +266,13 @@ const EXPIRATION_QUERIES = {
// Expire page annotations based on expiration policy.
QUERY_EXPIRE_ANNOS_WITH_POLICY: {
- sql: "DELETE FROM moz_annos "
- + "WHERE (expiration = :expire_days "
- + "AND :expire_days_time > MAX(lastModified, dateAdded)) "
- + "OR (expiration = :expire_weeks "
- + "AND :expire_weeks_time > MAX(lastModified, dateAdded)) "
- + "OR (expiration = :expire_months "
- + "AND :expire_months_time > MAX(lastModified, dateAdded))",
+ sql: `DELETE FROM moz_annos
+ WHERE (expiration = :expire_days
+ AND :expire_days_time > MAX(lastModified, dateAdded))
+ OR (expiration = :expire_weeks
+ AND :expire_weeks_time > MAX(lastModified, dateAdded))
+ OR (expiration = :expire_months
+ AND :expire_months_time > MAX(lastModified, dateAdded))`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
@@ -280,13 +280,13 @@ const EXPIRATION_QUERIES = {
// Expire items annotations based on expiration policy.
QUERY_EXPIRE_ITEMS_ANNOS_WITH_POLICY: {
- sql: "DELETE FROM moz_items_annos "
- + "WHERE (expiration = :expire_days "
- + "AND :expire_days_time > MAX(lastModified, dateAdded)) "
- + "OR (expiration = :expire_weeks "
- + "AND :expire_weeks_time > MAX(lastModified, dateAdded)) "
- + "OR (expiration = :expire_months "
- + "AND :expire_months_time > MAX(lastModified, dateAdded))",
+ sql: `DELETE FROM moz_items_annos
+ WHERE (expiration = :expire_days
+ AND :expire_days_time > MAX(lastModified, dateAdded))
+ OR (expiration = :expire_weeks
+ AND :expire_weeks_time > MAX(lastModified, dateAdded))
+ OR (expiration = :expire_months
+ AND :expire_months_time > MAX(lastModified, dateAdded))`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
@@ -294,10 +294,10 @@ const EXPIRATION_QUERIES = {
// Expire page annotations based on expiration policy.
QUERY_EXPIRE_ANNOS_WITH_HISTORY: {
- sql: "DELETE FROM moz_annos "
- + "WHERE expiration = :expire_with_history "
- + "AND NOT EXISTS (SELECT id FROM moz_historyvisits "
- + "WHERE place_id = moz_annos.place_id LIMIT 1)",
+ sql: `DELETE FROM moz_annos
+ WHERE expiration = :expire_with_history
+ AND NOT EXISTS (SELECT id FROM moz_historyvisits
+ WHERE place_id = moz_annos.place_id LIMIT 1)`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
@@ -305,37 +305,37 @@ const EXPIRATION_QUERIES = {
// Expire item annos without a corresponding item id.
QUERY_EXPIRE_ITEMS_ANNOS: {
- sql: "DELETE FROM moz_items_annos WHERE id IN ( "
- + "SELECT a.id FROM moz_items_annos a "
- + "LEFT JOIN moz_bookmarks b ON a.item_id = b.id "
- + "WHERE b.id IS NULL "
- + "LIMIT :limit_annos "
- + ")",
+ sql: `DELETE FROM moz_items_annos WHERE id IN (
+ SELECT a.id FROM moz_items_annos a
+ LEFT JOIN moz_bookmarks b ON a.item_id = b.id
+ WHERE b.id IS NULL
+ LIMIT :limit_annos
+ )`,
actions: ACTION.CLEAR_HISTORY | ACTION.IDLE_DAILY | ACTION.DEBUG
},
// Expire all annotation names without a corresponding annotation.
QUERY_EXPIRE_ANNO_ATTRIBUTES: {
- sql: "DELETE FROM moz_anno_attributes WHERE id IN ( "
- + "SELECT n.id FROM moz_anno_attributes n "
- + "LEFT JOIN moz_annos a ON n.id = a.anno_attribute_id "
- + "LEFT JOIN moz_items_annos t ON n.id = t.anno_attribute_id "
- + "WHERE a.anno_attribute_id IS NULL "
- + "AND t.anno_attribute_id IS NULL "
- + "LIMIT :limit_annos"
- + ")",
+ sql: `DELETE FROM moz_anno_attributes WHERE id IN (
+ SELECT n.id FROM moz_anno_attributes n
+ LEFT JOIN moz_annos a ON n.id = a.anno_attribute_id
+ LEFT JOIN moz_items_annos t ON n.id = t.anno_attribute_id
+ WHERE a.anno_attribute_id IS NULL
+ AND t.anno_attribute_id IS NULL
+ LIMIT :limit_annos
+ )`,
actions: ACTION.CLEAR_HISTORY | ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY |
ACTION.IDLE_DAILY | ACTION.DEBUG
},
// Expire orphan inputhistory.
QUERY_EXPIRE_INPUTHISTORY: {
- sql: "DELETE FROM moz_inputhistory WHERE place_id IN ( "
- + "SELECT i.place_id FROM moz_inputhistory i "
- + "LEFT JOIN moz_places h ON h.id = i.place_id "
- + "WHERE h.id IS NULL "
- + "LIMIT :limit_inputhistory "
- + ")",
+ sql: `DELETE FROM moz_inputhistory WHERE place_id IN (
+ SELECT i.place_id FROM moz_inputhistory i
+ LEFT JOIN moz_places h ON h.id = i.place_id
+ WHERE h.id IS NULL
+ LIMIT :limit_inputhistory
+ )`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
@@ -357,11 +357,11 @@ const EXPIRATION_QUERIES = {
// If p_id is set whole_entry = 1, then we have expired the full page.
// Either p_id or v_id are always set.
QUERY_SELECT_NOTIFICATIONS: {
- sql: "SELECT url, guid, MAX(visit_date) AS visit_date, "
- + "MAX(IFNULL(MIN(p_id, 1), MIN(v_id, 0))) AS whole_entry, "
- + "expected_results "
- + "FROM expiration_notify "
- + "GROUP BY url",
+ sql: `SELECT url, guid, MAX(visit_date) AS visit_date,
+ MAX(IFNULL(MIN(p_id, 1), MIN(v_id, 0))) AS whole_entry,
+ expected_results
+ FROM expiration_notify
+ GROUP BY url`,
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
},
@@ -415,15 +415,15 @@ function nsPlacesExpiration()
// Create the temporary notifications table.
let stmt = db.createAsyncStatement(
- "CREATE TEMP TABLE expiration_notify ( "
- + " id INTEGER PRIMARY KEY "
- + ", v_id INTEGER "
- + ", p_id INTEGER "
- + ", url TEXT NOT NULL "
- + ", guid TEXT NOT NULL "
- + ", visit_date INTEGER "
- + ", expected_results INTEGER NOT NULL "
- + ") ");
+ `CREATE TEMP TABLE expiration_notify (
+ id INTEGER PRIMARY KEY
+ , v_id INTEGER
+ , p_id INTEGER
+ , url TEXT NOT NULL
+ , guid TEXT NOT NULL
+ , visit_date INTEGER
+ , expected_results INTEGER NOT NULL
+ )`);
stmt.executeAsync();
stmt.finalize();
@@ -793,9 +793,9 @@ nsPlacesExpiration.prototype = {
_getPagesStats: function PEX__getPagesStats(aCallback) {
if (!this._cachedStatements["LIMIT_COUNT"]) {
this._cachedStatements["LIMIT_COUNT"] = this._db.createAsyncStatement(
- "SELECT (SELECT COUNT(*) FROM moz_places), "
- + "(SELECT SUBSTR(stat,1,LENGTH(stat)-2) FROM sqlite_stat1 "
- + "WHERE idx = 'moz_places_url_uniqueindex')"
+ `SELECT (SELECT COUNT(*) FROM moz_places),
+ (SELECT SUBSTR(stat,1,LENGTH(stat)-2) FROM sqlite_stat1
+ WHERE idx = 'moz_places_url_uniqueindex')`
);
}
this._cachedStatements["LIMIT_COUNT"].executeAsync({
diff --git a/toolkit/components/places/nsTaggingService.js b/toolkit/components/places/nsTaggingService.js
index 4b472c16e6b..398700adbc5 100644
--- a/toolkit/components/places/nsTaggingService.js
+++ b/toolkit/components/places/nsTaggingService.js
@@ -62,9 +62,9 @@ TaggingService.prototype = {
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
- "SELECT id FROM moz_bookmarks "
- + "WHERE parent = :tag_id "
- + "AND fk = (SELECT id FROM moz_places WHERE url = :page_url)"
+ `SELECT id FROM moz_bookmarks
+ WHERE parent = :tag_id
+ AND fk = (SELECT id FROM moz_places WHERE url = :page_url)`
);
stmt.params.tag_id = tagId;
stmt.params.page_url = aURI.spec;
@@ -181,8 +181,8 @@ TaggingService.prototype = {
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
- "SELECT count(*) AS count FROM moz_bookmarks "
- + "WHERE parent = :tag_id"
+ `SELECT count(*) AS count FROM moz_bookmarks
+ WHERE parent = :tag_id`
);
stmt.params.tag_id = aTagId;
try {
@@ -247,9 +247,9 @@ TaggingService.prototype = {
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
- "SELECT h.url FROM moz_places h "
- + "JOIN moz_bookmarks b ON b.fk = h.id "
- + "WHERE b.parent = :tag_id "
+ `SELECT h.url FROM moz_places h
+ JOIN moz_bookmarks b ON b.fk = h.id
+ WHERE b.parent = :tag_id`
);
stmt.params.tag_id = tagId;
try {
@@ -358,9 +358,9 @@ TaggingService.prototype = {
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
- "SELECT id, parent "
- + "FROM moz_bookmarks "
- + "WHERE fk = (SELECT id FROM moz_places WHERE url = :page_url)"
+ `SELECT id, parent
+ FROM moz_bookmarks
+ WHERE fk = (SELECT id FROM moz_places WHERE url = :page_url)`
);
stmt.params.page_url = aURI.spec;
try {
diff --git a/toolkit/content/widgets/autocomplete.xml b/toolkit/content/widgets/autocomplete.xml
index 86a9d626509..eaec31eb8ec 100644
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -5,11 +5,6 @@
# 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/.
-
-%actionsDTD;
-]>
-
+
+
+
+
null
@@ -1446,7 +1450,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
let [,action, param] = url.match(/^moz-action:([^,]+),(.*)$/);
this.setAttribute("actiontype", action);
url = param;
- let desc = "]]>&action.switchToTab.label;
if (!searchEngine) {
this._setUpDescription(this._url, url);
} else {
+ let desc = this._stringBundle.formatStringFromName("searchWithEngine", [searchEngine], 1);
+
// The search engine name, when present, is not emphasized.
- this._setUpDescription(this._url, searchEngine, true);
+ this._setUpDescription(this._url, desc, true);
}
// Set up overflow on a timeout because the contents of the box
diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml
index 2878fad347e..efdaa2e64d4 100644
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -447,7 +447,7 @@
readonly="true"/>
({ param: prop, value: this.getParam(prop), flags: this.getParamFlags(prop) }));
}, {
response: { params: RetVal("json") }
- }),
-
- /**
- * Returns a boolean indicating whether or not
- * the underlying AudioNode has been collected yet or not.
- *
- * @return Boolean
- */
- isAlive: function () {
- return !!this.node.get();
- }
+ })
});
/**
@@ -418,7 +407,6 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
this.tabActor = null;
this._initialized = false;
off(this._callWatcher._contentObserver, "global-destroyed", this._onGlobalDestroyed);
- this.disableChangeParamEvents();
this._nativeToActorID = null;
this._callWatcher.eraseRecording();
this._callWatcher.finalize();
@@ -427,59 +415,6 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
oneway: true
}),
- /**
- * Takes an AudioNodeActor and a duration specifying how often
- * should the node's parameters be polled to detect changes. Emits
- * `change-param` when a change is found.
- *
- * Currently, only one AudioNodeActor can be listened to at a time.
- *
- * `wait` is used in tests to specify the poll timer.
- */
- enableChangeParamEvents: method(function (nodeActor, wait) {
- // For now, only have one node being polled
- this.disableChangeParamEvents();
-
- // Ignore if node is dead
- if (!nodeActor.isAlive()) {
- return;
- }
-
- let previous = mapAudioParams(nodeActor);
-
- // Store the ID of the node being polled
- this._pollingID = nodeActor.actorID;
-
- this.poller = new Poller(() => {
- // If node has been collected, disable param polling
- if (!nodeActor.isAlive()) {
- this.disableChangeParamEvents();
- return;
- }
-
- let current = mapAudioParams(nodeActor);
- diffAudioParams(previous, current).forEach(changed => {
- this._onChangeParam(nodeActor, changed);
- });
- previous = current;
- }).on(wait || PARAM_POLLING_FREQUENCY);
- }, {
- request: {
- node: Arg(0, "audionode"),
- wait: Arg(1, "nullable:number"),
- },
- oneway: true
- }),
-
- disableChangeParamEvents: method(function () {
- if (this.poller) {
- this.poller.off();
- }
- this._pollingID = null;
- }, {
- oneway: true
- }),
-
/**
* Events emitted by this actor.
*/
@@ -502,6 +437,12 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
dest: Option(0, "audionode"),
param: Option(0, "string")
},
+ "change-param": {
+ type: "changeParam",
+ source: Option(0, "audionode"),
+ param: Option(0, "string"),
+ value: Option(0, "string")
+ },
"create-node": {
type: "createNode",
source: Arg(0, "audionode")
@@ -509,13 +450,6 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
"destroy-node": {
type: "destroyNode",
source: Arg(0, "audionode")
- },
- "change-param": {
- type: "changeParam",
- param: Option(0, "string"),
- newValue: Option(0, "json"),
- oldValue: Option(0, "json"),
- actorID: Option(0, "string")
}
},
@@ -539,7 +473,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
/**
* Takes an XrayWrapper node, and attaches the node's `nativeID`
* to the AudioParams as `_parentID`, as well as the the type of param
- * as a string on `_paramName`. Used to tag AudioParams for `connect-param` events.
+ * as a string on `_paramName`.
*/
_instrumentParams: function (node) {
let type = getConstructorName(node);
@@ -559,14 +493,6 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
* created), so make a new actor and store that.
*/
_getActorByNativeID: function (nativeID) {
- // If the WebAudioActor has already been finalized, the `_nativeToActorID`
- // map will already be destroyed -- the lingering destruction events
- // seem to only occur in e10s, so add an extra check here to disregard
- // these late events
- if (!this._nativeToActorID) {
- return null;
- }
-
// Ensure we have a Number, rather than a string
// return via notification.
nativeID = ~~nativeID;
@@ -618,12 +544,15 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
},
/**
- * Called when an AudioParam that's being listened to changes.
- * Takes an AudioNodeActor and an object with `newValue`, `oldValue`, and `param` name.
+ * Called when a parameter changes on an audio node
*/
- _onChangeParam: function (actor, changed) {
- changed.actorID = actor.actorID;
- emit(this, "change-param", changed);
+ _onParamChange: function (node, param, value) {
+ let actor = this._getActorByNativeID(node.id);
+ emit(this, "param-change", {
+ source: actor,
+ param: param,
+ value: value
+ });
},
/**
@@ -634,8 +563,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
emit(this, "create-node", actor);
},
- /**
- * Called when `webaudio-node-demise` is triggered,
+ /** Called when `webaudio-node-demise` is triggered,
* and emits the associated actor to the front if found.
*/
_onDestroyNode: function ({data}) {
@@ -648,10 +576,6 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
// notifications for a document that no longer exists,
// the mapping should not be found, so we do not emit an event.
if (actor) {
- // Turn off polling for changes if on for this node
- if (this._pollingID === actor.actorID) {
- this.disableChangeParamEvents();
- }
this._nativeToActorID.delete(nativeID);
emit(this, "destroy-node", actor);
}
@@ -739,109 +663,17 @@ function getConstructorName (obj) {
}
/**
- * Create a value grip for `value`, or fallback to a grip-like object
- * for renderable information for the front-end for things like Float32Arrays,
- * AudioBuffers, without tracking them in an actor pool.
+ * Create a grip-like object to pass in renderable information
+ * to the front-end for things like Float32Arrays, AudioBuffers,
+ * without tracking them in an actor pool.
*/
-function createGrip (value) {
- try {
- return ThreadActor.prototype.createValueGrip(value);
- }
- catch (e) {
- return {
- type: "object",
- preview: {
- kind: "ObjectWithText",
- text: ""
- },
- class: getConstructorName(value)
- };
- }
+function createObjectGrip (value) {
+ return {
+ type: "object",
+ preview: {
+ kind: "ObjectWithText",
+ text: ""
+ },
+ class: getConstructorName(value)
+ };
}
-
-/**
- * Takes an AudioNodeActor and maps its current parameter values
- * to a hash, where the property is the AudioParam name, and value
- * is the current value.
- */
-function mapAudioParams (node) {
- return node.getParams().reduce(function (obj, p) {
- obj[p.param] = p.value;
- return obj;
- }, {});
-}
-
-/**
- * Takes an object of previous and current values of audio parameters,
- * and compares them. If they differ, emit a `change-param` event.
- *
- * @param Object prev
- * Hash of previous set of AudioParam values.
- * @param Object current
- * Hash of current set of AudioParam values.
- */
-function diffAudioParams (prev, current) {
- return Object.keys(current).reduce((changed, param) => {
- if (!equalGrips(current[param], prev[param])) {
- changed.push({
- param: param,
- oldValue: prev[param],
- newValue: current[param]
- });
- }
- return changed;
- }, []);
-}
-
-/**
- * Compares two grip objects to determine if they're equal or not.
- *
- * @param Any a
- * @param Any a
- * @return Boolean
- */
-function equalGrips (a, b) {
- let aType = typeof a;
- let bType = typeof b;
- if (aType !== bType) {
- return false;
- } else if (aType === "object") {
- // In this case, we are comparing two objects, like an ArrayBuffer or Float32Array,
- // or even just plain "null"s (which grip's will have `type` property "null",
- // and we have no way of showing more information than its class, so assume
- // these are equal since nothing can be updated with information of value.
- if (a.type === b.type) {
- return true;
- }
- // Otherwise return false -- this could be a case of a property going from `null`
- // to having an ArrayBuffer or an object, in which case we should update it.
- return false;
- } else {
- return a === b;
- }
-}
-
-/**
- * Poller class -- takes a function, and call be turned on and off
- * via methods to execute `fn` on the interval specified during `on`.
- */
-function Poller (fn) {
- this.fn = fn;
-}
-
-Poller.prototype.on = function (wait) {
- let poller = this;
- poller.timer = setTimeout(poll, wait);
- function poll () {
- poller.fn();
- poller.timer = setTimeout(poll, wait);
- }
- return this;
-};
-
-Poller.prototype.off = function () {
- if (this.timer) {
- clearTimeout(this.timer);
- }
- return this;
-};
diff --git a/toolkit/devtools/server/actors/webbrowser.js b/toolkit/devtools/server/actors/webbrowser.js
index 41ed74ede21..d2c9e70b3f6 100644
--- a/toolkit/devtools/server/actors/webbrowser.js
+++ b/toolkit/devtools/server/actors/webbrowser.js
@@ -33,9 +33,11 @@ XPCOMUtils.defineLazyGetter(this, "StyleSheetActor", () => {
return require("devtools/server/actors/stylesheets").StyleSheetActor;
});
-// Also depends on following symbols, shared by common scope with main.js:
-// DebuggerServer, CommonCreateExtraActors, CommonAppendExtraActors, ActorPool,
-// ThreadActor
+function getWindowID(window) {
+ return window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .currentInnerWindowID;
+}
/**
* Browser-specific actors.
@@ -559,7 +561,7 @@ function TabActor(aConnection)
shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
});
- this.traits = { reconfigure: true };
+ this.traits = { reconfigure: true, frames: true };
}
// XXX (bug 710213): TabActor attach/detach/exit/disconnect is a
@@ -620,7 +622,10 @@ TabActor.prototype = {
let docShells = [];
while (docShellsEnum.hasMoreElements()) {
- docShells.push(docShellsEnum.getNext());
+ let docShell = docShellsEnum.getNext();
+ docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebProgress);
+ docShells.push(docShell);
}
return docShells;
@@ -807,11 +812,176 @@ TabActor.prototype = {
this._pushContext();
this._progressListener = new DebuggerProgressListener(this);
- this._progressListener.watch(this.docShell);
+
+ // Save references to the original document we attached to
+ this._originalWindow = this.window;
+
+ // Ensure replying to attach() request first
+ // before notifying about new docshells.
+ DevToolsUtils.executeSoon(() => this._watchDocshells());
this._attached = true;
},
+ _watchDocshells: function BTA_watchDocshells() {
+ // In child processes, we watch all docshells living in the process.
+ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
+ Services.obs.addObserver(this, "webnavigation-create", false);
+ }
+ Services.obs.addObserver(this, "webnavigation-destroy", false);
+
+ // We watch for all child docshells under the current document,
+ this._progressListener.watch(this.docShell);
+
+ // And list all already existing ones.
+ this._updateChildDocShells();
+ },
+
+ onSwitchToFrame: function BTA_onSwitchToFrame(aRequest) {
+ let windowId = aRequest.windowId;
+ let win;
+ try {
+ win = Services.wm.getOuterWindowWithId(windowId);
+ } catch(e) {}
+ if (!win) {
+ return { error: "noWindow",
+ message: "The related docshell is destroyed or not found" };
+ } else if (win == this.window) {
+ return {};
+ }
+
+ // Reply first before changing the document
+ DevToolsUtils.executeSoon(() => this._changeTopLevelDocument(win));
+
+ return {};
+ },
+
+ onListFrames: function BTA_onListFrames(aRequest) {
+ let windows = this._docShellsToWindows(this.docShells);
+ return { frames: windows };
+ },
+
+ observe: function (aSubject, aTopic, aData) {
+ // Ignore any event that comes before/after the tab actor is attached
+ // That typically happens during firefox shutdown.
+ if (!this.attached) {
+ return;
+ }
+ if (aTopic == "webnavigation-create") {
+ aSubject.QueryInterface(Ci.nsIDocShell);
+ // webnavigation-create is fired very early during docshell construction.
+ // In new root docshells within child processes, involving TabChild,
+ // this event is from within this call:
+ // http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l912
+ // whereas the chromeEventHandler (and most likely other stuff) is set later:
+ // http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l944
+ // So wait a tick before watching it:
+ DevToolsUtils.executeSoon(() => {
+ // In child processes, we have new root docshells,
+ // let's watch them and all their child docshells.
+ if (this._isRootDocShell(aSubject)) {
+ this._progressListener.watch(aSubject);
+ }
+ this._notifyDocShellsUpdate([aSubject]);
+ });
+ } else if (aTopic == "webnavigation-destroy") {
+ let webProgress = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebProgress);
+ this._notifyDocShellDestroy(webProgress);
+ }
+ },
+
+ _isRootDocShell: function (docShell) {
+ // Root docshells like top level xul windows don't have chromeEventHandler.
+ // Root docshells in child processes have one, it is TabChildGlobal,
+ // which isn't a DOM Element.
+ // Non-root docshell have a chromeEventHandler that is either
+ // xul:iframe, xul:browser or html:iframe.
+ return !docShell.chromeEventHandler ||
+ !(docShell.chromeEventHandler instanceof Ci.nsIDOMElement);
+ },
+
+ // Convert docShell list to windows objects list being sent to the client
+ _docShellsToWindows: function (docshells) {
+ return docshells.map(docShell => {
+ let window = docShell.DOMWindow;
+ let id = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .outerWindowID;
+ let parentID = undefined;
+ // Ignore the parent of the original document on non-e10s firefox,
+ // as we get the xul window as parent and don't care about it.
+ if (window.parent && window != this._originalWindow) {
+ parentID = window.parent
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .outerWindowID;
+ }
+ return {
+ id: id,
+ url: window.location.href,
+ title: window.title,
+ parentID: parentID
+ };
+ });
+ },
+
+ _notifyDocShellsUpdate: function (docshells) {
+ let windows = this._docShellsToWindows(docshells);
+ this.conn.send({ from: this.actorID,
+ type: "frameUpdate",
+ frames: windows
+ });
+ },
+
+ _updateChildDocShells: function () {
+ this._notifyDocShellsUpdate(this.docShells);
+ },
+
+ _notifyDocShellDestroy: function (webProgress) {
+ let id = webProgress.DOMWindow
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .outerWindowID;
+ this.conn.send({ from: this.actorID,
+ type: "frameUpdate",
+ frames: [{
+ id: id,
+ destroy: true
+ }]
+ });
+
+ // Stop watching this docshell if it's a root one.
+ // (child processes spawn new root docshells)
+ webProgress.QueryInterface(Ci.nsIDocShell);
+ if (this._isRootDocShell(webProgress)) {
+ this._progressListener.unwatch(webProgress);
+ }
+
+ if (webProgress.DOMWindow == this._originalWindow) {
+ // If for some reason (typically during Firefox shutdown), the original
+ // document is destroyed, we detach the tab actor to unregister all listeners
+ // and prevent any exception.
+ this.exit();
+ return;
+ }
+
+ // If the currently targeted context is destroyed,
+ // and we aren't on the top-level document,
+ // we have to switch to the top-level one.
+ if (webProgress.DOMWindow == this.window &&
+ this.window != this._originalWindow) {
+ this._changeTopLevelDocument(this._originalWindow);
+ }
+ },
+
+ _notifyDocShellDestroyAll: function () {
+ this.conn.send({ from: this.actorID,
+ type: "frameUpdate",
+ destroyAll: true
+ });
+ },
+
/**
* Creates a thread actor and a pool for context-lifetime actors. It then sets
* up the content window for debugging.
@@ -856,6 +1026,13 @@ TabActor.prototype = {
}
this._progressListener.destroy();
this._progressListener = null;
+ this._originalWindow = null;
+
+ // Removes the observers being set in _watchDocShells
+ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
+ Services.obs.removeObserver(this, "webnavigation-create", false);
+ }
+ Services.obs.removeObserver(this, "webnavigation-destroy", false);
this._popContext();
@@ -905,6 +1082,11 @@ TabActor.prototype = {
// Wait a tick so that the response packet can be dispatched before the
// subsequent navigation event packet.
Services.tm.currentThread.dispatch(DevToolsUtils.makeInfallible(() => {
+ // This won't work while the browser is shutting down and we don't really
+ // care.
+ if (Services.startup.shuttingDown) {
+ return;
+ }
this.webNavigation.reload(force ? Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE
: Ci.nsIWebNavigation.LOAD_FLAGS_NONE);
}, "TabActor.prototype.onReload's delayed body"), 0);
@@ -1043,17 +1225,64 @@ TabActor.prototype = {
}
},
+ _changeTopLevelDocument: function (window) {
+ // Fake a will-navigate on the previous document
+ // to let a chance to unregister it
+ this._willNavigate(this.window, window.location.href, null, true);
+
+ this._windowDestroyed(this.window);
+
+ DevToolsUtils.executeSoon(() => {
+ this._setWindow(window);
+
+ // Then fake window-ready and navigate on the given document
+ this._windowReady(window, true);
+ DevToolsUtils.executeSoon(() => {
+ this._navigate(window, true);
+ });
+ });
+ },
+
+ _setWindow: function (window) {
+ let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell);
+ // Here is the very important call where we switch the currently
+ // targeted context (it will indirectly update this.window and
+ // many other attributes defined from docShell).
+ Object.defineProperty(this, "docShell", {
+ value: docShell,
+ enumerable: true,
+ configurable: true
+ });
+ events.emit(this, "changed-toplevel-document");
+ let id = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .outerWindowID;
+ this.conn.send({ from: this.actorID,
+ type: "frameUpdate",
+ selected: id
+ });
+ },
+
/**
* Handle location changes, by clearing the previous debuggees and enabling
* debugging, which may have been disabled temporarily by the
* DebuggerProgressListener.
*/
- _windowReady: function (window) {
+ _windowReady: function (window, isFrameSwitching = false) {
let isTopLevel = window == this.window;
+ // We just reset iframe list on WillNavigate, so we now list all existing
+ // frames when we load a new document in the original window
+ if (window == this._originalWindow && !isFrameSwitching) {
+ this._updateChildDocShells();
+ }
+
events.emit(this, "window-ready", {
window: window,
- isTopLevel: isTopLevel
+ isTopLevel: isTopLevel,
+ id: getWindowID(window)
});
// TODO bug 997119: move that code to ThreadActor by listening to window-ready
@@ -1062,9 +1291,11 @@ TabActor.prototype = {
threadActor.clearDebuggees();
if (threadActor.dbg) {
threadActor.dbg.enabled = true;
- threadActor.global = window;
threadActor.maybePauseOnExceptions();
}
+ // Update the global no matter if the debugger is on or off,
+ // otherwise the global will be wrong when enabled later.
+ threadActor.global = window;
}
for (let sheetActor of this._styleSheetActors.values()) {
@@ -1080,19 +1311,37 @@ TabActor.prototype = {
}
},
- _windowDestroyed: function (window) {
+ _windowDestroyed: function (window, id = null) {
events.emit(this, "window-destroyed", {
window: window,
- isTopLevel: window == this.window
+ isTopLevel: window == this.window,
+ id: id || getWindowID(window)
});
},
/**
- * Start notifying server codebase and client about a new document
+ * Start notifying server and client about a new document
* being loaded in the currently targeted context.
*/
- _willNavigate: function (window, newURI, request) {
+ _willNavigate: function (window, newURI, request, isFrameSwitching = false) {
let isTopLevel = window == this.window;
+ let reset = false;
+
+ if (window == this._originalWindow && !isFrameSwitching) {
+ // Clear the iframe list if the original top-level document changes.
+ this._notifyDocShellDestroyAll();
+
+ // If the top level document changes and we are targeting
+ // an iframe, we need to reset to the upcoming new top level document.
+ // But for this will-navigate event, we will dispatch on the old window.
+ // (The inspector codebase expect to receive will-navigate for the currently
+ // displayed document in order to cleanup the markup view)
+ if (this.window != this._originalWindow) {
+ reset=true;
+ window = this.window;
+ isTopLevel = true;
+ }
+ }
// will-navigate event needs to be dispatched synchronously,
// by calling the listeners in the order or registration.
@@ -1128,15 +1377,20 @@ TabActor.prototype = {
type: "tabNavigated",
url: newURI,
nativeConsoleAPI: true,
- state: "start"
+ state: "start",
+ isFrameSwitching: isFrameSwitching
});
+
+ if (reset) {
+ this._setWindow(this._originalWindow);
+ }
},
/**
* Notify server and client about a new document done loading in the current
* targeted context.
*/
- _navigate: function (window) {
+ _navigate: function (window, isFrameSwitching = false) {
let isTopLevel = window == this.window;
// navigate event needs to be dispatched synchronously,
@@ -1166,7 +1420,8 @@ TabActor.prototype = {
url: this.url,
title: this.title,
nativeConsoleAPI: this.hasNativeConsoleAPI(this.window),
- state: "stop"
+ state: "stop",
+ isFrameSwitching: isFrameSwitching
});
},
@@ -1222,7 +1477,9 @@ TabActor.prototype.requestTypes = {
"detach": TabActor.prototype.onDetach,
"reload": TabActor.prototype.onReload,
"navigateTo": TabActor.prototype.onNavigateTo,
- "reconfigure": TabActor.prototype.onReconfigure
+ "reconfigure": TabActor.prototype.onReconfigure,
+ "switchToFrame": TabActor.prototype.onSwitchToFrame,
+ "listFrames": TabActor.prototype.onListFrames
};
exports.TabActor = TabActor;
@@ -1258,7 +1515,7 @@ Object.defineProperty(BrowserTabActor.prototype, "docShell", {
return null;
},
enumerable: true,
- configurable: false
+ configurable: true
});
Object.defineProperty(BrowserTabActor.prototype, "title", {
@@ -1637,14 +1894,17 @@ DebuggerProgressListener.prototype = {
// Dispatch the _windowReady event on the tabActor for pre-existing windows
for (let win of this._getWindowsInDocShell(docShell)) {
this._tabActor._windowReady(win);
- this._knownWindowIDs.set(this._getWindowID(win), win);
+ this._knownWindowIDs.set(getWindowID(win), win);
}
},
unwatch: function(docShell) {
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
- webProgress.removeProgressListener(this);
+ // During process shutdown, the docshell may already be cleaned up and throw
+ try {
+ webProgress.removeProgressListener(this);
+ } catch(e) {}
// TODO: fix docShell.chromeEventHandler in child processes!
let handler = docShell.chromeEventHandler ||
@@ -1656,7 +1916,7 @@ DebuggerProgressListener.prototype = {
handler.removeEventListener("pagehide", this._onWindowHidden, true);
for (let win of this._getWindowsInDocShell(docShell)) {
- this._knownWindowIDs.delete(this._getWindowID(win));
+ this._knownWindowIDs.delete(getWindowID(win));
}
},
@@ -1675,12 +1935,6 @@ DebuggerProgressListener.prototype = {
return windows;
},
- _getWindowID: function(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .currentInnerWindowID;
- },
-
onWindowCreated: DevToolsUtils.makeInfallible(function(evt) {
if (!this._tabActor.attached) {
return;
@@ -1697,7 +1951,7 @@ DebuggerProgressListener.prototype = {
this._tabActor._windowReady(window);
if (evt.type !== "pageshow") {
- this._knownWindowIDs.set(this._getWindowID(window), window);
+ this._knownWindowIDs.set(getWindowID(window), window);
}
}, "DebuggerProgressListener.prototype.onWindowCreated"),
@@ -1730,7 +1984,7 @@ DebuggerProgressListener.prototype = {
let window = this._knownWindowIDs.get(innerID);
if (window) {
this._knownWindowIDs.delete(innerID);
- this._tabActor._windowDestroyed(window);
+ this._tabActor._windowDestroyed(window, innerID);
}
}, "DebuggerProgressListener.prototype.observe"),
@@ -1745,12 +1999,23 @@ DebuggerProgressListener.prototype = {
let isDocument = aFlag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
let isWindow = aFlag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
+ // Catch any iframe location change
+ if (isDocument && isStop) {
+ // Watch document stop to ensure having the new iframe url.
+ aProgress.QueryInterface(Ci.nsIDocShell);
+ this._tabActor._notifyDocShellsUpdate([aProgress]);
+ }
+
let window = aProgress.DOMWindow;
if (isDocument && isStart) {
+ // One of the earliest events that tells us a new URI
+ // is being loaded in this window.
let newURI = aRequest instanceof Ci.nsIChannel ? aRequest.URI.spec : null;
this._tabActor._willNavigate(window, newURI, aRequest);
}
if (isWindow && isStop) {
+ // Somewhat equivalent of load event.
+ // (window.document.readyState == complete)
this._tabActor._navigate(window);
}
}, "DebuggerProgressListener.prototype.onStateChange")
diff --git a/toolkit/devtools/server/actors/webconsole.js b/toolkit/devtools/server/actors/webconsole.js
index caab05324cd..a42d502a785 100644
--- a/toolkit/devtools/server/actors/webconsole.js
+++ b/toolkit/devtools/server/actors/webconsole.js
@@ -70,8 +70,11 @@ function WebConsoleActor(aConnection, aParentActor)
this._netEvents = new Map();
this._gripDepth = 0;
+ this._listeners = new Set();
this._onWillNavigate = this._onWillNavigate.bind(this);
+ this._onChangedToplevelDocument = this._onChangedToplevelDocument.bind(this);
+ events.on(this.parentActor, "changed-toplevel-document", this._onChangedToplevelDocument);
this._onObserverNotification = this._onObserverNotification.bind(this);
if (this.parentActor.isRootActor) {
Services.obs.addObserver(this._onObserverNotification,
@@ -125,6 +128,14 @@ WebConsoleActor.prototype =
*/
_netEvents: null,
+ /**
+ * Holds a set of all currently registered listeners.
+ *
+ * @private
+ * @type Set
+ */
+ _listeners: null,
+
/**
* The debugger server connection instance.
* @type object
@@ -336,6 +347,7 @@ WebConsoleActor.prototype =
this.consoleReflowListener.destroy();
this.consoleReflowListener = null;
}
+ events.off(this.parentActor, "changed-toplevel-document", this._onChangedToplevelDocument);
this.conn.removeActorPool(this._actorPool);
if (this.parentActor.isRootActor) {
Services.obs.removeObserver(this._onObserverNotification,
@@ -564,6 +576,10 @@ WebConsoleActor.prototype =
break;
}
}
+
+ // Update the live list of running listeners
+ startedListeners.forEach(this._listeners.add, this._listeners);
+
return {
startedListeners: startedListeners,
nativeConsoleAPI: this.hasNativeConsoleAPI(this.window),
@@ -632,6 +648,9 @@ WebConsoleActor.prototype =
}
}
+ // Update the live list of running listeners
+ stoppedListeners.forEach(this._listeners.delete, this._listeners);
+
return { stoppedListeners: stoppedListeners };
},
@@ -1406,6 +1425,24 @@ WebConsoleActor.prototype =
this._progressListenerActive = false;
}
},
+
+ /**
+ * This listener is called when we switch to another frame,
+ * mostly to unregister previous listeners and start listening on the new document.
+ */
+ _onChangedToplevelDocument: function WCA__onChangedToplevelDocument()
+ {
+ // Convert the Set to an Array
+ let listeners = [...this._listeners];
+
+ // Unregister existing listener on the previous document
+ // (pass a copy of the array as it will shift from it)
+ this.onStopListeners({listeners: listeners.slice()});
+
+ // This method is called after this.window is changed,
+ // so we register new listener on this new window
+ this.onStartListeners({listeners: listeners});
+ },
};
WebConsoleActor.prototype.requestTypes =
diff --git a/toolkit/devtools/server/child.js b/toolkit/devtools/server/child.js
index 7d8cfaf1d59..ff37fd1b14d 100644
--- a/toolkit/devtools/server/child.js
+++ b/toolkit/devtools/server/child.js
@@ -13,6 +13,9 @@ let chromeGlobal = this;
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js");
const {DebuggerServer, ActorPool} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+ if (!DebuggerServer.childID) {
+ DebuggerServer.childID = 1;
+ }
if (!DebuggerServer.initialized) {
DebuggerServer.init();
@@ -24,21 +27,24 @@ let chromeGlobal = this;
// time we load child.js
DebuggerServer.addChildActors();
- let conn;
+ let connections = new Map();
let onConnect = DevToolsUtils.makeInfallible(function (msg) {
removeMessageListener("debug:connect", onConnect);
let mm = msg.target;
+ let prefix = msg.data.prefix;
+ let id = DebuggerServer.childID++;
- conn = DebuggerServer.connectToParent(msg.data.prefix, mm);
+ let conn = DebuggerServer.connectToParent(prefix, mm);
+ connections.set(id, conn);
let actor = new DebuggerServer.ContentActor(conn, chromeGlobal);
let actorPool = new ActorPool(conn);
actorPool.addActor(actor);
conn.addActorPool(actorPool);
- sendAsyncMessage("debug:actor", {actor: actor.grip()});
+ sendAsyncMessage("debug:actor", {actor: actor.grip(), childID: id});
});
addMessageListener("debug:connect", onConnect);
@@ -49,8 +55,12 @@ let chromeGlobal = this;
// Call DebuggerServerConnection.close to destroy all child actors
// (It should end up calling DebuggerServerConnection.onClosed
// that would actually cleanup all actor pools)
- conn.close();
- conn = null;
+ let childID = msg.data.childID;
+ let conn = connections.get(childID);
+ if (conn) {
+ conn.close();
+ connections.delete(childID);
+ }
});
addMessageListener("debug:disconnect", onDisconnect);
})();
diff --git a/toolkit/devtools/server/main.js b/toolkit/devtools/server/main.js
index 6ed958ce95f..13c6c857563 100644
--- a/toolkit/devtools/server/main.js
+++ b/toolkit/devtools/server/main.js
@@ -567,11 +567,14 @@ var DebuggerServer = {
let actor, childTransport;
let prefix = aConnection.allocID("child");
+ let childID = null;
let netMonitor = null;
let onActorCreated = DevToolsUtils.makeInfallible(function (msg) {
mm.removeMessageListener("debug:actor", onActorCreated);
+ childID = msg.json.childID;
+
// Pipe Debugger message from/to parent/child via the message manager
childTransport = new ChildDebuggerTransport(mm, prefix);
childTransport.hooks = {
@@ -604,7 +607,7 @@ var DebuggerServer = {
aConnection.cancelForwarding(prefix);
// ... and notify the child process to clean the tab actors.
- mm.sendAsyncMessage("debug:disconnect");
+ mm.sendAsyncMessage("debug:disconnect", { childID: childID });
} else {
// Otherwise, the app has been closed before the actor
// had a chance to be created, so we are not able to create
@@ -641,7 +644,12 @@ var DebuggerServer = {
aConnection.cancelForwarding(prefix);
// ... and notify the child process to clean the tab actors.
- mm.sendAsyncMessage("debug:disconnect");
+ mm.sendAsyncMessage("debug:disconnect", { childID: childID });
+
+ if (netMonitor) {
+ netMonitor.destroy();
+ netMonitor = null;
+ }
}
});
diff --git a/toolkit/devtools/webconsole/network-monitor.js b/toolkit/devtools/webconsole/network-monitor.js
index f6efd182a51..4ff49f31ec7 100644
--- a/toolkit/devtools/webconsole/network-monitor.js
+++ b/toolkit/devtools/webconsole/network-monitor.js
@@ -595,9 +595,17 @@ NetworkMonitor.prototype = {
}
if (this.window) {
+ // Since frames support, this.window may not be the top level content
+ // frame, so that we can't only compare with win.top.
let win = NetworkHelper.getWindowForRequest(aChannel);
- if (win && win.top === this.window) {
- return true;
+ while(win) {
+ if (win == this.window) {
+ return true;
+ }
+ if (win.parent == win) {
+ break;
+ }
+ win = win.parent;
}
}
@@ -1074,13 +1082,18 @@ NetworkMonitorChild.prototype = {
destroy: function() {
let mm = this._messageManager;
- mm.removeMessageListener("debug:netmonitor:" + this.connID + ":newEvent",
- this._onNewEvent);
- mm.removeMessageListener("debug:netmonitor:" + this.connID + ":updateEvent",
- this._onUpdateEvent);
- mm.sendAsyncMessage("debug:netmonitor:" + this.connID, {
- action: "disconnect",
- });
+ try {
+ mm.removeMessageListener("debug:netmonitor:" + this.connID + ":newEvent",
+ this._onNewEvent);
+ mm.removeMessageListener("debug:netmonitor:" + this.connID + ":updateEvent",
+ this._onUpdateEvent);
+ } catch(e) {
+ // On b2g, when registered to a new root docshell,
+ // all message manager functions throw when trying to call them during
+ // message-manager-disconnect event.
+ // As there is no attribute/method on message manager to know
+ // if they are still usable or not, we can only catch the exception...
+ }
this._netEvents.clear();
this._messageManager = null;
this.owner = null;
diff --git a/toolkit/locales/en-US/chrome/global/actions.dtd b/toolkit/locales/en-US/chrome/global/actions.dtd
deleted file mode 100644
index 457be04d6b0..00000000000
--- a/toolkit/locales/en-US/chrome/global/actions.dtd
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/toolkit/locales/en-US/chrome/global/autocomplete.properties b/toolkit/locales/en-US/chrome/global/autocomplete.properties
new file mode 100644
index 00000000000..cdf49b1659e
--- /dev/null
+++ b/toolkit/locales/en-US/chrome/global/autocomplete.properties
@@ -0,0 +1,9 @@
+# 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/.
+
+# LOCALIZATION NOTE (searchWithEngine): %S will be replaced with
+# the search engine provider's name. This format was chosen because
+# the provider can also end with "Search" (e.g.: MSN Search).
+searchWithEngine = Search with %S
+switchToTab = Switch to tab
\ No newline at end of file
diff --git a/toolkit/locales/jar.mn b/toolkit/locales/jar.mn
index 0b852f02c42..0d4377fb5dc 100644
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -14,7 +14,7 @@
locale/@AB_CD@/global/aboutSupport.properties (%chrome/global/aboutSupport.properties)
locale/@AB_CD@/global/aboutTelemetry.dtd (%chrome/global/aboutTelemetry.dtd)
locale/@AB_CD@/global/aboutTelemetry.properties (%chrome/global/aboutTelemetry.properties)
- locale/@AB_CD@/global/actions.dtd (%chrome/global/actions.dtd)
+ locale/@AB_CD@/global/autocomplete.properties (%chrome/global/autocomplete.properties)
locale/@AB_CD@/global/appPicker.dtd (%chrome/global/appPicker.dtd)
locale/@AB_CD@/global/brand.dtd (generic/chrome/global/brand.dtd)
locale/@AB_CD@/global/browser.properties (%chrome/global/browser.properties)