зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound, a=merge
--HG-- extra : commitid : KfjY9JJOq3w
This commit is contained in:
Коммит
2ed2b43c29
|
@ -4,9 +4,6 @@
|
|||
# Exclude expected objdirs.
|
||||
obj*/**
|
||||
|
||||
# Temporarily ignore HTML files that still need to be fixed.
|
||||
devtools/**/*.html
|
||||
|
||||
# We ignore all these directories by default, until we get them enabled.
|
||||
# If you are enabling a directory, please add directory specific exclusions
|
||||
# below.
|
||||
|
@ -17,7 +14,6 @@ caps/**
|
|||
chrome/**
|
||||
config/**
|
||||
db/**
|
||||
devtools/**
|
||||
docshell/**
|
||||
dom/**
|
||||
editor/**
|
||||
|
@ -91,24 +87,52 @@ browser/locales/**
|
|||
browser/extensions/loop/**
|
||||
|
||||
# devtools/ exclusions
|
||||
# Ignore d3
|
||||
devtools/client/shared/d3.js
|
||||
devtools/client/webaudioeditor/lib/dagre-d3.js
|
||||
devtools/*.js
|
||||
devtools/client/*.js
|
||||
devtools/client/aboutdebugging/**
|
||||
devtools/client/animationinspector/**
|
||||
devtools/client/canvasdebugger/**
|
||||
devtools/client/commandline/**
|
||||
devtools/client/debugger/**
|
||||
devtools/client/eyedropper/**
|
||||
devtools/client/framework/**
|
||||
# devtools/client/inspector/shared/*.js files are eslint-clean, so they aren't
|
||||
# included in the ignore list.
|
||||
devtools/client/inspector/computed/**
|
||||
devtools/client/inspector/fonts/**
|
||||
devtools/client/inspector/layout/**
|
||||
devtools/client/inspector/markup/**
|
||||
devtools/client/inspector/rules/**
|
||||
devtools/client/inspector/shared/test/**
|
||||
devtools/client/inspector/test/**
|
||||
devtools/client/inspector/*.js
|
||||
devtools/client/jsonview/**
|
||||
devtools/client/memory/**
|
||||
devtools/client/netmonitor/**
|
||||
devtools/client/performance/**
|
||||
devtools/client/projecteditor/**
|
||||
devtools/client/promisedebugger/**
|
||||
devtools/client/responsivedesign/**
|
||||
devtools/client/scratchpad/**
|
||||
devtools/client/shadereditor/**
|
||||
devtools/client/shared/**
|
||||
devtools/client/sourceeditor/**
|
||||
devtools/client/storage/**
|
||||
devtools/client/styleeditor/**
|
||||
devtools/client/tilt/**
|
||||
devtools/client/webaudioeditor/**
|
||||
devtools/client/webconsole/**
|
||||
devtools/client/webide/**
|
||||
devtools/server/**
|
||||
devtools/shared/**
|
||||
|
||||
# Ignore codemirror
|
||||
devtools/client/sourceeditor/codemirror/*.js
|
||||
devtools/client/sourceeditor/codemirror/**/*.js
|
||||
devtools/client/sourceeditor/test/codemirror/*
|
||||
|
||||
# Ignore jquery test libs
|
||||
devtools/client/markupview/test/lib_*
|
||||
|
||||
# Ignore pre-processed files
|
||||
# Ignore devtools pre-processed files
|
||||
devtools/client/framework/toolbox-process-window.js
|
||||
devtools/client/performance/system.js
|
||||
devtools/client/webide/webide-prefs.js
|
||||
devtools/client/preferences/**
|
||||
|
||||
# Ignore various libs
|
||||
# Ignore devtools third-party libs
|
||||
devtools/shared/jsbeautify/*
|
||||
devtools/shared/acorn/*
|
||||
devtools/client/sourceeditor/tern/*
|
||||
|
@ -117,6 +141,12 @@ devtools/shared/sourcemap/*
|
|||
devtools/shared/qrcode/decoder/*
|
||||
devtools/shared/qrcode/encoder/*
|
||||
devtools/client/shared/vendor/*
|
||||
devtools/client/shared/d3.js
|
||||
devtools/client/webaudioeditor/lib/dagre-d3.js
|
||||
devtools/client/sourceeditor/codemirror/*.js
|
||||
devtools/client/sourceeditor/codemirror/**/*.js
|
||||
devtools/client/sourceeditor/test/codemirror/*
|
||||
devtools/client/markupview/test/lib_*
|
||||
|
||||
# mobile/android/ exclusions
|
||||
mobile/android/chrome/content
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"rules": {
|
||||
"mozilla/components-imports": 1,
|
||||
"mozilla/import-globals-from": 1,
|
||||
"mozilla/this-top-level-scope": 1,
|
||||
},
|
||||
"env": {
|
||||
"es6": true
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee",
|
||||
"git_revision": "89602d6ae53ecf4129b35a84e49d25b9fd37bc39",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "d74e738cd626558fb9dc289500ad28ae29deab03",
|
||||
"revision": "ea9b9cc69315e86bf7198ec0d57a267e64345b32",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
|
|
@ -2275,16 +2275,22 @@ function BrowserViewSource(browser) {
|
|||
});
|
||||
}
|
||||
|
||||
// doc - document to use for source, or null for this window's document
|
||||
// documentURL - URL of the document to view, or null for this window's document
|
||||
// initialTab - name of the initial tab to display, or null for the first tab
|
||||
// imageElement - image to load in the Media Tab of the Page Info window; can be null/omitted
|
||||
// frameOuterWindowID - the id of the frame that the context menu opened in; can be null/omitted
|
||||
function BrowserPageInfo(doc, initialTab, imageElement, frameOuterWindowID) {
|
||||
var args = {doc: doc, initialTab: initialTab, imageElement: imageElement,
|
||||
frameOuterWindowID: frameOuterWindowID};
|
||||
function BrowserPageInfo(documentURL, initialTab, imageElement, frameOuterWindowID) {
|
||||
if (documentURL instanceof HTMLDocument) {
|
||||
Deprecated.warning("Please pass the location URL instead of the document " +
|
||||
"to BrowserPageInfo() as the first argument.",
|
||||
"https://bugzilla.mozilla.org/show_bug.cgi?id=1238180");
|
||||
documentURL = documentURL.location;
|
||||
}
|
||||
|
||||
let args = { initialTab, imageElement, frameOuterWindowID };
|
||||
var windows = Services.wm.getEnumerator("Browser:page-info");
|
||||
|
||||
var documentURL = doc ? doc.location : window.gBrowser.selectedBrowser.currentURI.spec;
|
||||
documentURL = documentURL || window.gBrowser.selectedBrowser.currentURI.spec;
|
||||
|
||||
// Check for windows matching the url
|
||||
while (windows.hasMoreElements()) {
|
||||
|
|
|
@ -1065,12 +1065,11 @@ nsContextMenu.prototype = {
|
|||
},
|
||||
|
||||
viewInfo: function() {
|
||||
BrowserPageInfo(this.target.ownerDocument.defaultView.top.document);
|
||||
BrowserPageInfo();
|
||||
},
|
||||
|
||||
viewImageInfo: function() {
|
||||
BrowserPageInfo(this.target.ownerDocument.defaultView.top.document,
|
||||
"mediaTab", this.target);
|
||||
BrowserPageInfo(null, "mediaTab", this.target);
|
||||
},
|
||||
|
||||
viewImageDesc: function(e) {
|
||||
|
@ -1082,7 +1081,7 @@ nsContextMenu.prototype = {
|
|||
},
|
||||
|
||||
viewFrameInfo: function() {
|
||||
BrowserPageInfo(this.target.ownerDocument, null, null,
|
||||
BrowserPageInfo(gContextMenuContentData.docLocation, null, null,
|
||||
this.frameOuterWindowID);
|
||||
},
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ function test() {
|
|||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
var doc = gBrowser.contentDocument;
|
||||
var pageInfo = BrowserPageInfo(doc, "mediaTab");
|
||||
var pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
|
||||
"mediaTab");
|
||||
|
||||
pageInfo.addEventListener("load", function () {
|
||||
pageInfo.removeEventListener("load", arguments.callee, true);
|
||||
|
|
|
@ -10,7 +10,8 @@ function test() {
|
|||
|
||||
var doc = gBrowser.contentDocument;
|
||||
var testImg = doc.getElementById("test-image");
|
||||
var pageInfo = BrowserPageInfo(doc, "mediaTab", testImg);
|
||||
var pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
|
||||
"mediaTab", testImg);
|
||||
|
||||
pageInfo.addEventListener("load", function () {
|
||||
pageInfo.removeEventListener("load", arguments.callee, true);
|
||||
|
|
|
@ -2,116 +2,19 @@
|
|||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* testTabSwitchContext() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"page_action": {
|
||||
"default_icon": "default.png",
|
||||
"default_popup": "default.html",
|
||||
"default_title": "Default Title \u263a",
|
||||
},
|
||||
"permissions": ["tabs"],
|
||||
},
|
||||
|
||||
background: function() {
|
||||
let details = [
|
||||
{ "icon": browser.runtime.getURL("default.png"),
|
||||
"popup": browser.runtime.getURL("default.html"),
|
||||
"title": "Default Title \u263a" },
|
||||
{ "icon": browser.runtime.getURL("1.png"),
|
||||
"popup": browser.runtime.getURL("default.html"),
|
||||
"title": "Default Title \u263a" },
|
||||
{ "icon": browser.runtime.getURL("2.png"),
|
||||
"popup": browser.runtime.getURL("2.html"),
|
||||
"title": "Title 2" },
|
||||
];
|
||||
|
||||
function* runTests(options) {
|
||||
function background(getTests) {
|
||||
let tabs;
|
||||
let tests;
|
||||
let allTests = [
|
||||
expect => {
|
||||
browser.test.log("Initial state. No icon visible.");
|
||||
expect(null);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Show the icon on the first tab, expect default properties.");
|
||||
browser.pageAction.show(tabs[0]);
|
||||
expect(details[0]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Change the icon. Expect default properties excluding the icon.");
|
||||
browser.pageAction.setIcon({ tabId: tabs[0], path: "1.png" });
|
||||
expect(details[1]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Create a new tab. No icon visible.");
|
||||
browser.tabs.create({ active: true, url: "about:blank?0" }, tab => {
|
||||
tabs.push(tab.id);
|
||||
expect(null);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Change properties. Expect new properties.");
|
||||
let tabId = tabs[1];
|
||||
browser.pageAction.show(tabId);
|
||||
browser.pageAction.setIcon({ tabId, path: "2.png" });
|
||||
browser.pageAction.setPopup({ tabId, popup: "2.html" });
|
||||
browser.pageAction.setTitle({ tabId, title: "Title 2" });
|
||||
|
||||
expect(details[2]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Navigate to a new page. Expect icon hidden.");
|
||||
|
||||
// TODO: This listener should not be necessary, but the |tabs.update|
|
||||
// callback currently fires too early in e10s windows.
|
||||
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
|
||||
if (tabId == tabs[1] && changed.url) {
|
||||
browser.tabs.onUpdated.removeListener(listener);
|
||||
expect(null);
|
||||
}
|
||||
});
|
||||
|
||||
browser.tabs.update(tabs[1], { url: "about:blank?1" });
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Show the icon. Expect default properties again.");
|
||||
browser.pageAction.show(tabs[1]);
|
||||
expect(details[0]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Switch back to the first tab. Expect previously set properties.");
|
||||
browser.tabs.update(tabs[0], { active: true }, () => {
|
||||
expect(details[1]);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Hide the icon on tab 2. Switch back, expect hidden.");
|
||||
browser.pageAction.hide(tabs[1]);
|
||||
browser.tabs.update(tabs[1], { active: true }, () => {
|
||||
expect(null);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Switch back to tab 1. Expect previous results again.");
|
||||
browser.tabs.remove(tabs[1], () => {
|
||||
expect(details[1]);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Hide the icon. Expect hidden.");
|
||||
browser.pageAction.hide(tabs[0]);
|
||||
expect(null);
|
||||
},
|
||||
];
|
||||
|
||||
// Gets the current details of the page action, and returns a
|
||||
// promise that resolves to an object containing them.
|
||||
function getDetails() {
|
||||
return new Promise(resolve => {
|
||||
return browser.tabs.query({ active: true, currentWindow: true }, resolve);
|
||||
}).then(tabs => {
|
||||
let tabId = tabs[0].id;
|
||||
}).then(([tab]) => {
|
||||
let tabId = tab.id;
|
||||
browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
|
||||
return Promise.all([
|
||||
new Promise(resolve => browser.pageAction.getTitle({tabId}, resolve)),
|
||||
new Promise(resolve => browser.pageAction.getPopup({tabId}, resolve))]);
|
||||
|
@ -154,7 +57,7 @@ add_task(function* testTabSwitchContext() {
|
|||
|
||||
function runTests() {
|
||||
tabs = [];
|
||||
tests = allTests.slice();
|
||||
tests = getTests(tabs);
|
||||
|
||||
browser.tabs.query({ active: true, currentWindow: true }, resultTabs => {
|
||||
tabs[0] = resultTabs[0].id;
|
||||
|
@ -174,7 +77,12 @@ add_task(function* testTabSwitchContext() {
|
|||
});
|
||||
|
||||
runTests();
|
||||
},
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: options.manifest,
|
||||
|
||||
background: `(${background})(${options.getTests})`,
|
||||
});
|
||||
|
||||
let pageActionId = makeWidgetId(extension.id) + "-page-action";
|
||||
|
@ -189,8 +97,10 @@ add_task(function* testTabSwitchContext() {
|
|||
ok(image, "image exists");
|
||||
|
||||
is(image.src, details.icon, "icon URL is correct");
|
||||
is(image.getAttribute("tooltiptext"), details.title, "image title is correct");
|
||||
is(image.getAttribute("aria-label"), details.title, "image aria-label is correct");
|
||||
|
||||
let title = details.title || options.manifest.name;
|
||||
is(image.getAttribute("tooltiptext"), title, "image title is correct");
|
||||
is(image.getAttribute("aria-label"), title, "image aria-label is correct");
|
||||
// TODO: Popup URL.
|
||||
}
|
||||
}
|
||||
|
@ -235,4 +145,183 @@ add_task(function* testTabSwitchContext() {
|
|||
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
}
|
||||
|
||||
add_task(function* testTabSwitchContext() {
|
||||
yield runTests({
|
||||
manifest: {
|
||||
"name": "Foo Extension",
|
||||
|
||||
"page_action": {
|
||||
"default_icon": "default.png",
|
||||
"default_popup": "default.html",
|
||||
"default_title": "Default Title \u263a",
|
||||
},
|
||||
|
||||
"permissions": ["tabs"],
|
||||
},
|
||||
|
||||
getTests(tabs) {
|
||||
let details = [
|
||||
{ "icon": browser.runtime.getURL("default.png"),
|
||||
"popup": browser.runtime.getURL("default.html"),
|
||||
"title": "Default Title \u263a" },
|
||||
{ "icon": browser.runtime.getURL("1.png"),
|
||||
"popup": browser.runtime.getURL("default.html"),
|
||||
"title": "Default Title \u263a" },
|
||||
{ "icon": browser.runtime.getURL("2.png"),
|
||||
"popup": browser.runtime.getURL("2.html"),
|
||||
"title": "Title 2" },
|
||||
{ "icon": browser.runtime.getURL("2.png"),
|
||||
"popup": browser.runtime.getURL("2.html"),
|
||||
"title": "Default Title \u263a" },
|
||||
];
|
||||
|
||||
let promiseTabLoad = details => {
|
||||
return new Promise(resolve => {
|
||||
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
|
||||
if (tabId == details.id && changed.url == details.url) {
|
||||
browser.tabs.onUpdated.removeListener(listener);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
let tabLoadPromise;
|
||||
|
||||
return [
|
||||
expect => {
|
||||
browser.test.log("Initial state. No icon visible.");
|
||||
expect(null);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Show the icon on the first tab, expect default properties.");
|
||||
browser.pageAction.show(tabs[0]);
|
||||
expect(details[0]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Change the icon. Expect default properties excluding the icon.");
|
||||
browser.pageAction.setIcon({ tabId: tabs[0], path: "1.png" });
|
||||
expect(details[1]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Create a new tab. No icon visible.");
|
||||
browser.tabs.create({ active: true, url: "about:blank?0" }, tab => {
|
||||
tabLoadPromise = promiseTabLoad({ url: "about:blank?0", id: tab.id });
|
||||
tabs.push(tab.id);
|
||||
expect(null);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Await tab load. No icon visible.");
|
||||
tabLoadPromise.then(() => {
|
||||
expect(null);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Change properties. Expect new properties.");
|
||||
let tabId = tabs[1];
|
||||
browser.pageAction.show(tabId);
|
||||
browser.pageAction.setIcon({ tabId, path: "2.png" });
|
||||
browser.pageAction.setPopup({ tabId, popup: "2.html" });
|
||||
browser.pageAction.setTitle({ tabId, title: "Title 2" });
|
||||
|
||||
expect(details[2]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Clear the title. Expect default title.");
|
||||
browser.pageAction.setTitle({ tabId: tabs[1], title: "" });
|
||||
|
||||
expect(details[3]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Navigate to a new page. Expect icon hidden.");
|
||||
|
||||
// TODO: This listener should not be necessary, but the |tabs.update|
|
||||
// callback currently fires too early in e10s windows.
|
||||
promiseTabLoad({ id: tabs[1], url: "about:blank?1" }).then(() => {
|
||||
expect(null);
|
||||
});
|
||||
|
||||
browser.tabs.update(tabs[1], { url: "about:blank?1" });
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Show the icon. Expect default properties again.");
|
||||
browser.pageAction.show(tabs[1]);
|
||||
expect(details[0]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Switch back to the first tab. Expect previously set properties.");
|
||||
browser.tabs.update(tabs[0], { active: true }, () => {
|
||||
expect(details[1]);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Hide the icon on tab 2. Switch back, expect hidden.");
|
||||
browser.pageAction.hide(tabs[1]);
|
||||
browser.tabs.update(tabs[1], { active: true }, () => {
|
||||
expect(null);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Switch back to tab 1. Expect previous results again.");
|
||||
browser.tabs.remove(tabs[1], () => {
|
||||
expect(details[1]);
|
||||
});
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Hide the icon. Expect hidden.");
|
||||
browser.pageAction.hide(tabs[0]);
|
||||
expect(null);
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* testDefaultTitle() {
|
||||
yield runTests({
|
||||
manifest: {
|
||||
"name": "Foo Extension",
|
||||
|
||||
"page_action": {
|
||||
"default_icon": "icon.png",
|
||||
},
|
||||
|
||||
"permissions": ["tabs"],
|
||||
},
|
||||
|
||||
getTests(tabs) {
|
||||
let details = [
|
||||
{ "title": "Foo Extension",
|
||||
"popup": "",
|
||||
"icon": browser.runtime.getURL("icon.png") },
|
||||
{ "title": "Foo Title",
|
||||
"popup": "",
|
||||
"icon": browser.runtime.getURL("icon.png") },
|
||||
];
|
||||
|
||||
return [
|
||||
expect => {
|
||||
browser.test.log("Initial state. No icon visible.");
|
||||
expect(null);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Show the icon on the first tab, expect extension title as default title.");
|
||||
browser.pageAction.show(tabs[0]);
|
||||
expect(details[0]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Change the title. Expect new title.");
|
||||
browser.pageAction.setTitle({ tabId: tabs[0], title: "Foo Title" });
|
||||
expect(details[1]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Clear the title. Expect extension title.");
|
||||
browser.pageAction.setTitle({ tabId: tabs[0], title: "" });
|
||||
expect(details[0]);
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -38,6 +38,15 @@ this.TestRunner = {
|
|||
_libDir: null,
|
||||
|
||||
init(extensionPath) {
|
||||
this._extensionPath = extensionPath;
|
||||
},
|
||||
|
||||
/**
|
||||
* Load specified sets, execute all combinations of them, and capture screenshots.
|
||||
*/
|
||||
start(setNames = null) {
|
||||
setNames = setNames || defaultSetNames;
|
||||
|
||||
let subDirs = ["mozscreenshots",
|
||||
(new Date()).toISOString().replace(/:/g, "-") + "_" + Services.appinfo.OS];
|
||||
let screenshotPath = FileUtils.getFile("TmpD", subDirs).path;
|
||||
|
@ -48,27 +57,14 @@ this.TestRunner = {
|
|||
}
|
||||
|
||||
log.info("Saving screenshots to:", screenshotPath);
|
||||
log.debug("TestRunner.init");
|
||||
|
||||
let screenshotPrefix = Services.appinfo.appBuildID + "_";
|
||||
Screenshot.init(screenshotPath, extensionPath, screenshotPrefix);
|
||||
this._libDir = extensionPath.QueryInterface(Ci.nsIFileURL).file.clone();
|
||||
Screenshot.init(screenshotPath, this._extensionPath, screenshotPrefix);
|
||||
this._libDir = this._extensionPath.QueryInterface(Ci.nsIFileURL).file.clone();
|
||||
this._libDir.append("chrome");
|
||||
this._libDir.append("mozscreenshots");
|
||||
this._libDir.append("lib");
|
||||
|
||||
// Setup some prefs
|
||||
Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl", "data:");
|
||||
Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
|
||||
// Don't let the caret blink since it causes false positives for image diffs
|
||||
Services.prefs.setIntPref("ui.caretBlinkTime", -1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Load specified sets, execute all combinations of them, and capture screenshots.
|
||||
*/
|
||||
start(setNames = null) {
|
||||
setNames = setNames || defaultSetNames;
|
||||
let sets = this.loadSets(setNames);
|
||||
|
||||
log.info(sets.length + " sets:", setNames);
|
||||
|
@ -78,6 +74,12 @@ this.TestRunner = {
|
|||
this.currentComboIndex = this.completedCombos = 0;
|
||||
this._lastCombo = null;
|
||||
|
||||
// Setup some prefs
|
||||
Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl", "data:");
|
||||
Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
|
||||
// Don't let the caret blink since it causes false positives for image diffs
|
||||
Services.prefs.setIntPref("ui.caretBlinkTime", -1);
|
||||
|
||||
return Task.spawn(function* doStart() {
|
||||
for (let i = 0; i < this.combos.length;
|
||||
i++){
|
||||
|
|
|
@ -3805,7 +3805,6 @@ MOZ_ANDROID_HISTORY=
|
|||
MOZ_WEBSMS_BACKEND=
|
||||
MOZ_ANDROID_BEAM=
|
||||
MOZ_LOCALE_SWITCHER=
|
||||
MOZ_ANDROID_READING_LIST_SERVICE=
|
||||
MOZ_ANDROID_SEARCH_ACTIVITY=
|
||||
MOZ_ANDROID_DOWNLOADS_INTEGRATION=
|
||||
MOZ_ANDROID_GCM=
|
||||
|
@ -4883,13 +4882,6 @@ if test -n "$MOZ_ANDROID_SEARCH_ACTIVITY"; then
|
|||
AC_DEFINE(MOZ_ANDROID_SEARCH_ACTIVITY)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Include Reading List service on Android
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_ANDROID_READING_LIST_SERVICE"; then
|
||||
AC_DEFINE(MOZ_ANDROID_READING_LIST_SERVICE)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Include Mozilla Location Service Stumbler on Android
|
||||
dnl ========================================================
|
||||
|
@ -8555,7 +8547,6 @@ AC_SUBST(MOZ_LOCALE_SWITCHER)
|
|||
AC_SUBST(MOZ_DISABLE_GECKOVIEW)
|
||||
AC_SUBST(MOZ_ANDROID_GCM)
|
||||
AC_SUBST(MOZ_ANDROID_GECKOLIBS_AAR)
|
||||
AC_SUBST(MOZ_ANDROID_READING_LIST_SERVICE)
|
||||
AC_SUBST(MOZ_ANDROID_SEARCH_ACTIVITY)
|
||||
AC_SUBST(MOZ_ANDROID_MLS_STUMBLER)
|
||||
AC_SUBST(MOZ_ANDROID_DOWNLOADS_INTEGRATION)
|
||||
|
|
|
@ -39,22 +39,34 @@ add_task(function *() {
|
|||
names = names.map(element => element.textContent);
|
||||
ok(names.includes(SERVICE_WORKER), "The service worker url appears in the list: " + names);
|
||||
|
||||
// Finally, unregister the service worker itself
|
||||
let aboutDebuggingUpdate = waitForWorkersUpdate(document);
|
||||
|
||||
// Use message manager to work with e10s
|
||||
let frameScript = function () {
|
||||
// Retrieve the `sw` promise created in the html page
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function (registration) {
|
||||
registration.unregister().then(function (success) {
|
||||
dump("SW unregistered: " + success + "\n");
|
||||
sendAsyncMessage("sw-unregistered");
|
||||
},
|
||||
function (e) {
|
||||
dump("SW not unregistered; " + e + "\n");
|
||||
});
|
||||
});
|
||||
};
|
||||
swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
let mm = swTab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
yield waitForWorkersUpdate(document);
|
||||
yield new Promise(done => {
|
||||
mm.addMessageListener("sw-unregistered", function listener() {
|
||||
mm.removeMessageListener("sw-unregistered", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
ok(true, "Service worker registration unregistered");
|
||||
|
||||
yield aboutDebuggingUpdate;
|
||||
|
||||
// Check that the service worker disappeared from the UI
|
||||
names = [...document.querySelectorAll("#service-workers .target-name")];
|
||||
|
|
|
@ -98,14 +98,23 @@ add_task(function *() {
|
|||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function (registration) {
|
||||
registration.unregister().then(function (success) {
|
||||
dump("SW unregistered: " + success + "\n");
|
||||
sendAsyncMessage("sw-unregistered");
|
||||
},
|
||||
function (e) {
|
||||
dump("SW not unregistered; " + e + "\n");
|
||||
});
|
||||
});
|
||||
};
|
||||
swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
let mm = swTab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
yield new Promise(done => {
|
||||
mm.addMessageListener("sw-unregistered", function listener() {
|
||||
mm.removeMessageListener("sw-unregistered", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
ok(true, "Service worker registration unregistered");
|
||||
|
||||
yield removeTab(swTab);
|
||||
yield closeAboutDebugging(tab);
|
||||
|
|
|
@ -93,7 +93,9 @@ var getServerTraits = Task.async(function*(target) {
|
|||
{ name: "hasSetCurrentTimes", actor: "animations",
|
||||
method: "setCurrentTimes" },
|
||||
{ name: "hasGetFrames", actor: "animationplayer",
|
||||
method: "getFrames" }
|
||||
method: "getFrames" },
|
||||
{ name: "hasSetWalkerActor", actor: "animations",
|
||||
method: "setWalkerActor" },
|
||||
];
|
||||
|
||||
let traits = {};
|
||||
|
@ -147,6 +149,12 @@ var AnimationsController = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Let the AnimationsActor know what WalkerActor we're using. This will
|
||||
// come in handy later to return references to DOM Nodes.
|
||||
if (this.traits.hasSetWalkerActor) {
|
||||
yield this.animationsFront.setWalkerActor(gInspector.walker);
|
||||
}
|
||||
|
||||
this.startListeners();
|
||||
yield this.onNewNodeFront();
|
||||
|
||||
|
|
|
@ -3,35 +3,22 @@
|
|||
const {Cu} = require("chrome");
|
||||
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const {
|
||||
createNode,
|
||||
TargetNodeHighlighter
|
||||
} = require("devtools/client/animationinspector/utils");
|
||||
const {DomNodePreview} = require(
|
||||
"devtools/client/inspector/shared/dom-node-preview");
|
||||
|
||||
const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
// Map dom node fronts by animation fronts so we don't have to get them from the
|
||||
// walker every time the timeline is refreshed.
|
||||
var nodeFronts = new WeakMap();
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying a preview of the target dom node of
|
||||
* a given animation.
|
||||
* @param {InspectorPanel} inspector Requires a reference to the inspector-panel
|
||||
* to highlight and select the node, as well as refresh it when there are
|
||||
* mutations.
|
||||
* @param {Object} options Supported properties are:
|
||||
* - compact {Boolean} Defaults to false. If true, nodes will be previewed like
|
||||
* tag#id.class instead of <tag id="id" class="class">
|
||||
* Accepts the same parameters as the DomNodePreview component. See
|
||||
* devtools/client/inspector/shared/dom-node-preview.js for documentation.
|
||||
*/
|
||||
function AnimationTargetNode(inspector, options = {}) {
|
||||
function AnimationTargetNode(inspector, options) {
|
||||
this.inspector = inspector;
|
||||
this.options = options;
|
||||
|
||||
this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
|
||||
this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
|
||||
this.onSelectNodeClick = this.onSelectNodeClick.bind(this);
|
||||
this.onMarkupMutations = this.onMarkupMutations.bind(this);
|
||||
this.onHighlightNodeClick = this.onHighlightNodeClick.bind(this);
|
||||
this.onTargetHighlighterLocked = this.onTargetHighlighterLocked.bind(this);
|
||||
|
||||
this.previewer = new DomNodePreview(inspector, options);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
|
@ -39,282 +26,51 @@ exports.AnimationTargetNode = AnimationTargetNode;
|
|||
|
||||
AnimationTargetNode.prototype = {
|
||||
init: function(containerEl) {
|
||||
let document = containerEl.ownerDocument;
|
||||
|
||||
// Init the markup for displaying the target node.
|
||||
this.el = createNode({
|
||||
parent: containerEl,
|
||||
attributes: {
|
||||
"class": "animation-target"
|
||||
}
|
||||
});
|
||||
|
||||
// Icon to select the node in the inspector.
|
||||
this.highlightNodeEl = createNode({
|
||||
parent: this.el,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "node-highlighter",
|
||||
"title": L10N.getStr("node.highlightNodeLabel")
|
||||
}
|
||||
});
|
||||
|
||||
// Wrapper used for mouseover/out event handling.
|
||||
this.previewEl = createNode({
|
||||
parent: this.el,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"title": L10N.getStr("node.selectNodeLabel")
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.previewEl.appendChild(document.createTextNode("<"));
|
||||
}
|
||||
|
||||
// Tag name.
|
||||
this.tagNameEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "tag-name theme-fg-color3"
|
||||
}
|
||||
});
|
||||
|
||||
// Id attribute container.
|
||||
this.idEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span"
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-name theme-fg-color2"
|
||||
},
|
||||
textContent: "id"
|
||||
});
|
||||
this.idEl.appendChild(document.createTextNode("=\""));
|
||||
} else {
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "theme-fg-color2"
|
||||
},
|
||||
textContent: "#"
|
||||
});
|
||||
}
|
||||
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-value theme-fg-color6"
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.idEl.appendChild(document.createTextNode("\""));
|
||||
}
|
||||
|
||||
// Class attribute container.
|
||||
this.classEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span"
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-name theme-fg-color2"
|
||||
},
|
||||
textContent: "class"
|
||||
});
|
||||
this.classEl.appendChild(document.createTextNode("=\""));
|
||||
} else {
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "theme-fg-color6"
|
||||
},
|
||||
textContent: "."
|
||||
});
|
||||
}
|
||||
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-value theme-fg-color6"
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.classEl.appendChild(document.createTextNode("\""));
|
||||
this.previewEl.appendChild(document.createTextNode(">"));
|
||||
}
|
||||
|
||||
this.startListeners();
|
||||
},
|
||||
|
||||
startListeners: function() {
|
||||
// Init events for highlighting and selecting the node.
|
||||
this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
|
||||
this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
|
||||
this.previewEl.addEventListener("click", this.onSelectNodeClick);
|
||||
this.highlightNodeEl.addEventListener("click", this.onHighlightNodeClick);
|
||||
|
||||
// Start to listen for markupmutation events.
|
||||
this.inspector.on("markupmutation", this.onMarkupMutations);
|
||||
|
||||
// Listen to the target node highlighter.
|
||||
TargetNodeHighlighter.on("highlighted", this.onTargetHighlighterLocked);
|
||||
},
|
||||
|
||||
stopListeners: function() {
|
||||
TargetNodeHighlighter.off("highlighted", this.onTargetHighlighterLocked);
|
||||
this.inspector.off("markupmutation", this.onMarkupMutations);
|
||||
this.previewEl.removeEventListener("mouseover", this.onPreviewMouseOver);
|
||||
this.previewEl.removeEventListener("mouseout", this.onPreviewMouseOut);
|
||||
this.previewEl.removeEventListener("click", this.onSelectNodeClick);
|
||||
this.highlightNodeEl.removeEventListener("click", this.onHighlightNodeClick);
|
||||
this.previewer.init(containerEl);
|
||||
this.isDestroyed = false;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
TargetNodeHighlighter.unhighlight().catch(e => console.error(e));
|
||||
|
||||
this.stopListeners();
|
||||
|
||||
this.el.remove();
|
||||
this.el = this.tagNameEl = this.idEl = this.classEl = null;
|
||||
this.highlightNodeEl = this.previewEl = null;
|
||||
this.nodeFront = this.inspector = this.playerFront = null;
|
||||
},
|
||||
|
||||
get highlighterUtils() {
|
||||
if (this.inspector && this.inspector.toolbox) {
|
||||
return this.inspector.toolbox.highlighterUtils;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
onPreviewMouseOver: function() {
|
||||
if (!this.nodeFront || !this.highlighterUtils) {
|
||||
return;
|
||||
}
|
||||
this.highlighterUtils.highlightNodeFront(this.nodeFront)
|
||||
.catch(e => console.error(e));
|
||||
},
|
||||
|
||||
onPreviewMouseOut: function() {
|
||||
if (!this.nodeFront || !this.highlighterUtils) {
|
||||
return;
|
||||
}
|
||||
this.highlighterUtils.unhighlight()
|
||||
.catch(e => console.error(e));
|
||||
},
|
||||
|
||||
onSelectNodeClick: function() {
|
||||
if (!this.nodeFront) {
|
||||
return;
|
||||
}
|
||||
this.inspector.selection.setNodeFront(this.nodeFront, "animationinspector");
|
||||
},
|
||||
|
||||
onHighlightNodeClick: function(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
let classList = this.highlightNodeEl.classList;
|
||||
|
||||
let isHighlighted = classList.contains("selected");
|
||||
if (isHighlighted) {
|
||||
classList.remove("selected");
|
||||
TargetNodeHighlighter.unhighlight().then(() => {
|
||||
this.emit("target-highlighter-unlocked");
|
||||
}, e => console.error(e));
|
||||
} else {
|
||||
classList.add("selected");
|
||||
TargetNodeHighlighter.highlight(this).then(() => {
|
||||
this.emit("target-highlighter-locked");
|
||||
}, e => console.error(e));
|
||||
}
|
||||
},
|
||||
|
||||
onTargetHighlighterLocked: function(e, animationTargetNode) {
|
||||
if (animationTargetNode !== this) {
|
||||
this.highlightNodeEl.classList.remove("selected");
|
||||
}
|
||||
},
|
||||
|
||||
onMarkupMutations: function(e, mutations) {
|
||||
if (!this.nodeFront || !this.playerFront) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let {target} of mutations) {
|
||||
if (target === this.nodeFront) {
|
||||
// Re-render with the same nodeFront to update the output.
|
||||
this.render(this.playerFront);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.previewer.destroy();
|
||||
this.inspector = null;
|
||||
this.isDestroyed = true;
|
||||
},
|
||||
|
||||
render: Task.async(function*(playerFront) {
|
||||
this.playerFront = playerFront;
|
||||
this.nodeFront = undefined;
|
||||
// Get the nodeFront from the cache if it was stored previously.
|
||||
let nodeFront = nodeFronts.get(playerFront);
|
||||
|
||||
// Try and get it from the playerFront directly next.
|
||||
if (!nodeFront) {
|
||||
nodeFront = playerFront.animationTargetNodeFront;
|
||||
}
|
||||
|
||||
// Finally, get it from the walkerActor if it wasn't found.
|
||||
if (!nodeFront) {
|
||||
try {
|
||||
this.nodeFront = yield this.inspector.walker.getNodeFromActor(
|
||||
nodeFront = yield this.inspector.walker.getNodeFromActor(
|
||||
playerFront.actorID, ["node"]);
|
||||
} catch (e) {
|
||||
if (!this.el) {
|
||||
// The panel was destroyed in the meantime. Just log a warning.
|
||||
console.warn("Cound't retrieve the animation target node, widget " +
|
||||
"destroyed");
|
||||
} else {
|
||||
// This was an unexpected error, log it.
|
||||
// If an error occured while getting the nodeFront and if it can't be
|
||||
// attributed to the panel having been destroyed in the meantime, this
|
||||
// error needs to be logged and render needs to stop.
|
||||
if (!this.isDestroyed) {
|
||||
console.error(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.nodeFront || !this.el) {
|
||||
// In all cases, if by now the panel doesn't exist anymore, we need to
|
||||
// stop rendering too.
|
||||
if (this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {tagName, attributes} = this.nodeFront;
|
||||
|
||||
this.tagNameEl.textContent = tagName.toLowerCase();
|
||||
|
||||
let idIndex = attributes.findIndex(({name}) => name === "id");
|
||||
if (idIndex > -1 && attributes[idIndex].value) {
|
||||
this.idEl.querySelector(".attribute-value").textContent =
|
||||
attributes[idIndex].value;
|
||||
this.idEl.style.display = "inline";
|
||||
} else {
|
||||
this.idEl.style.display = "none";
|
||||
}
|
||||
|
||||
let classIndex = attributes.findIndex(({name}) => name === "class");
|
||||
if (classIndex > -1 && attributes[classIndex].value) {
|
||||
let value = attributes[classIndex].value;
|
||||
if (this.options.compact) {
|
||||
value = value.split(" ").join(".");
|
||||
}
|
||||
|
||||
this.classEl.querySelector(".attribute-value").textContent = value;
|
||||
this.classEl.style.display = "inline";
|
||||
} else {
|
||||
this.classEl.style.display = "none";
|
||||
}
|
||||
// Add the nodeFront to the cache.
|
||||
nodeFronts.set(playerFront, nodeFront);
|
||||
|
||||
this.previewer.render(nodeFront);
|
||||
this.emit("target-retrieved");
|
||||
})
|
||||
};
|
||||
|
|
|
@ -25,7 +25,7 @@ add_task(function*() {
|
|||
|
||||
// Reduce the known nodeFronts to a set to make them unique.
|
||||
let nodeFronts = new Set(panel.animationsTimelineComponent
|
||||
.targetNodes.map(n => n.nodeFront));
|
||||
.targetNodes.map(n => n.previewer.nodeFront));
|
||||
is(nodeFronts.size, 3,
|
||||
"The animations are applied to 3 different node fronts");
|
||||
});
|
||||
|
|
|
@ -16,16 +16,18 @@ add_task(function*() {
|
|||
yield selectNode(".animated", inspector);
|
||||
|
||||
let targetNodeComponent = panel.animationsTimelineComponent.targetNodes[0];
|
||||
let {previewer} = targetNodeComponent;
|
||||
|
||||
// Make sure to wait for the target-retrieved event if the nodeFront hasn't
|
||||
// yet been retrieved by the TargetNodeComponent.
|
||||
if (!targetNodeComponent.nodeFront) {
|
||||
if (!previewer.nodeFront) {
|
||||
yield targetNodeComponent.once("target-retrieved");
|
||||
}
|
||||
|
||||
is(targetNodeComponent.el.textContent, "div#.ball.animated",
|
||||
is(previewer.el.textContent, "div#.ball.animated",
|
||||
"The target element's content is correct");
|
||||
|
||||
let highlighterEl = targetNodeComponent.el.querySelector(".node-highlighter");
|
||||
let highlighterEl = previewer.el.querySelector(".node-highlighter");
|
||||
ok(highlighterEl,
|
||||
"The icon to highlight the target element in the page exists");
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ add_task(function*() {
|
|||
let targetNodeComponent = targets[0];
|
||||
|
||||
info("Retrieve the part of the widget that highlights the node on hover");
|
||||
let highlightingEl = targetNodeComponent.previewEl;
|
||||
let highlightingEl = targetNodeComponent.previewer.previewEl;
|
||||
|
||||
info("Listen to node-highlight event and mouse over the widget");
|
||||
let onHighlight = toolbox.once("node-highlight");
|
||||
|
@ -39,7 +39,7 @@ add_task(function*() {
|
|||
highlightingEl.ownerDocument.defaultView);
|
||||
|
||||
ok(true, "The node-highlight event was fired");
|
||||
is(targetNodeComponent.nodeFront, nodeFront,
|
||||
is(targetNodeComponent.previewer.nodeFront, nodeFront,
|
||||
"The highlighted node is the one stored on the animation widget");
|
||||
is(nodeFront.tagName, "DIV",
|
||||
"The highlighted node has the correct tagName");
|
||||
|
@ -60,12 +60,12 @@ add_task(function*() {
|
|||
"selection to change");
|
||||
let onSelection = inspector.selection.once("new-node-front");
|
||||
onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
let nodeEl = targetNodeComponent.previewEl;
|
||||
let nodeEl = targetNodeComponent.previewer.previewEl;
|
||||
EventUtils.sendMouseEvent({type: "click"}, nodeEl,
|
||||
nodeEl.ownerDocument.defaultView);
|
||||
yield onSelection;
|
||||
|
||||
is(inspector.selection.nodeFront, targetNodeComponent.nodeFront,
|
||||
is(inspector.selection.nodeFront, targetNodeComponent.previewer.nodeFront,
|
||||
"The selected node is the one stored on the animation widget");
|
||||
|
||||
yield onPanelUpdated;
|
||||
|
|
|
@ -11,42 +11,44 @@ requestLongerTimeout(2);
|
|||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {toolbox, inspector, panel} = yield openAnimationInspector();
|
||||
let {panel} = yield openAnimationInspector();
|
||||
|
||||
let targets = panel.animationsTimelineComponent.targetNodes;
|
||||
|
||||
info("Click on the highlighter icon for the first animated node");
|
||||
yield lockHighlighterOn(targets[0]);
|
||||
ok(targets[0].highlightNodeEl.classList.contains("selected"),
|
||||
let domNodePreview1 = targets[0].previewer;
|
||||
yield lockHighlighterOn(domNodePreview1);
|
||||
ok(domNodePreview1.highlightNodeEl.classList.contains("selected"),
|
||||
"The highlighter icon is selected");
|
||||
|
||||
info("Click on the highlighter icon for the second animated node");
|
||||
yield lockHighlighterOn(targets[1]);
|
||||
ok(targets[1].highlightNodeEl.classList.contains("selected"),
|
||||
let domNodePreview2 = targets[1].previewer;
|
||||
yield lockHighlighterOn(domNodePreview2);
|
||||
ok(domNodePreview2.highlightNodeEl.classList.contains("selected"),
|
||||
"The highlighter icon is selected");
|
||||
ok(!targets[0].highlightNodeEl.classList.contains("selected"),
|
||||
ok(!domNodePreview1.highlightNodeEl.classList.contains("selected"),
|
||||
"The highlighter icon for the first node is unselected");
|
||||
|
||||
info("Click again to unhighlight");
|
||||
yield unlockHighlighterOn(targets[1]);
|
||||
ok(!targets[1].highlightNodeEl.classList.contains("selected"),
|
||||
yield unlockHighlighterOn(domNodePreview2);
|
||||
ok(!domNodePreview2.highlightNodeEl.classList.contains("selected"),
|
||||
"The highlighter icon for the second node is unselected");
|
||||
});
|
||||
|
||||
function* lockHighlighterOn(targetComponent) {
|
||||
let onLocked = targetComponent.once("target-highlighter-locked");
|
||||
clickOnHighlighterIcon(targetComponent);
|
||||
function* lockHighlighterOn(domNodePreview) {
|
||||
let onLocked = domNodePreview.once("target-highlighter-locked");
|
||||
clickOnHighlighterIcon(domNodePreview);
|
||||
yield onLocked;
|
||||
}
|
||||
|
||||
function* unlockHighlighterOn(targetComponent) {
|
||||
let onUnlocked = targetComponent.once("target-highlighter-unlocked");
|
||||
clickOnHighlighterIcon(targetComponent);
|
||||
function* unlockHighlighterOn(domNodePreview) {
|
||||
let onUnlocked = domNodePreview.once("target-highlighter-unlocked");
|
||||
clickOnHighlighterIcon(domNodePreview);
|
||||
yield onUnlocked;
|
||||
}
|
||||
|
||||
function clickOnHighlighterIcon(targetComponent) {
|
||||
let lockEl = targetComponent.highlightNodeEl;
|
||||
function clickOnHighlighterIcon(domNodePreview) {
|
||||
let lockEl = domNodePreview.highlightNodeEl;
|
||||
EventUtils.sendMouseEvent({type: "click"}, lockEl,
|
||||
lockEl.ownerDocument.defaultView);
|
||||
}
|
||||
|
|
|
@ -351,7 +351,7 @@ function isNodeVisible(node) {
|
|||
var waitForAllAnimationTargets = Task.async(function*(panel) {
|
||||
let targets = panel.animationsTimelineComponent.targetNodes;
|
||||
yield promise.all(targets.map(t => {
|
||||
if (!t.nodeFront) {
|
||||
if (!t.previewer.nodeFront) {
|
||||
return t.once("target-retrieved");
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -146,43 +146,6 @@ function findOptimalTimeInterval(timeScale,
|
|||
|
||||
exports.findOptimalTimeInterval = findOptimalTimeInterval;
|
||||
|
||||
/**
|
||||
* The TargetNodeHighlighter util is a helper for AnimationTargetNode components
|
||||
* that is used to lock the highlighter on animated nodes in the page.
|
||||
* It instantiates a new highlighter that is then shared amongst all instances
|
||||
* of AnimationTargetNode. This is useful because that means showing the
|
||||
* highlighter on one animated node will unhighlight the previously highlighted
|
||||
* one, but will not interfere with the default inspector highlighter.
|
||||
*/
|
||||
var TargetNodeHighlighter = {
|
||||
highlighter: null,
|
||||
isShown: false,
|
||||
|
||||
highlight: Task.async(function*(animationTargetNode) {
|
||||
if (!this.highlighter) {
|
||||
let hUtils = animationTargetNode.inspector.toolbox.highlighterUtils;
|
||||
this.highlighter = yield hUtils.getHighlighterByType("BoxModelHighlighter");
|
||||
}
|
||||
|
||||
yield this.highlighter.show(animationTargetNode.nodeFront);
|
||||
this.isShown = true;
|
||||
this.emit("highlighted", animationTargetNode);
|
||||
}),
|
||||
|
||||
unhighlight: Task.async(function*() {
|
||||
if (!this.highlighter || !this.isShown) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield this.highlighter.hide();
|
||||
this.isShown = false;
|
||||
this.emit("unhighlighted");
|
||||
})
|
||||
};
|
||||
|
||||
EventEmitter.decorate(TargetNodeHighlighter);
|
||||
exports.TargetNodeHighlighter = TargetNodeHighlighter;
|
||||
|
||||
/**
|
||||
* Format a timestamp (in ms) as a mm:ss.mmm string.
|
||||
* @param {Number} time
|
||||
|
|
|
@ -12,8 +12,10 @@ const TEST_URI = "<style>" +
|
|||
"#div1 { margin-top: 5px }" +
|
||||
"#div2 { border-bottom: 1em solid black; }" +
|
||||
"#div3 { padding: 2em; }" +
|
||||
"#div4 { margin: 1px; }" +
|
||||
"</style>" +
|
||||
"<div id='div1'></div><div id='div2'></div><div id='div3'></div>";
|
||||
"<div id='div1'></div><div id='div2'></div>" +
|
||||
"<div id='div3'></div><div id='div4'></div>";
|
||||
|
||||
function getStyle(node, property) {
|
||||
return node.style.getPropertyValue(property);
|
||||
|
@ -144,3 +146,34 @@ function*(inspector, view) {
|
|||
is(getStyle(node, "margin-right"), "", "Should be the right margin-top on the element.")
|
||||
is(span.textContent, 10, "Should have the right value in the box model.");
|
||||
});
|
||||
|
||||
addTest("Test that clicking in the editor input does not remove focus",
|
||||
function*(inspector, view) {
|
||||
let node = content.document.getElementById("div4");
|
||||
|
||||
yield selectNode("#div4", inspector);
|
||||
|
||||
let span = view.doc.querySelector(".margin.top > span");
|
||||
is(span.textContent, 1, "Should have the right value in the box model.");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
|
||||
let editor = view.doc.querySelector(".styleinspector-propertyeditor");
|
||||
ok(editor, "Should have opened the editor.");
|
||||
|
||||
info("Click in the already opened editor input");
|
||||
EventUtils.synthesizeMouseAtCenter(editor, {}, view.doc.defaultView);
|
||||
is(editor, view.doc.activeElement,
|
||||
"Inplace editor input should still have focus.");
|
||||
|
||||
info("Check the input can still be used as expected");
|
||||
EventUtils.synthesizeKey("VK_UP", {}, view.doc.defaultView);
|
||||
yield waitForUpdate(inspector);
|
||||
|
||||
is(editor.value, "2px", "Should have the right value in the editor.");
|
||||
is(getStyle(node, "margin-top"), "2px", "Should have updated the margin.");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
|
||||
|
||||
is(getStyle(node, "margin-top"), "2px",
|
||||
"Should be the right margin-top on the element.");
|
||||
is(span.textContent, 2, "Should have the right value in the box model.");
|
||||
});
|
||||
|
|
|
@ -39,6 +39,8 @@ XPCOMUtils.defineLazyGetter(this, "domUtils", function() {
|
|||
* inherited: An element this rule was inherited from. If omitted,
|
||||
* the rule applies directly to the current element.
|
||||
* isSystem: Is this a user agent style?
|
||||
* isUnmatched: True if the rule does not match the current selected
|
||||
* element, otherwise, false.
|
||||
*/
|
||||
function Rule(elementStyle, options) {
|
||||
this.elementStyle = elementStyle;
|
||||
|
@ -48,6 +50,7 @@ function Rule(elementStyle, options) {
|
|||
this.pseudoElement = options.pseudoElement || "";
|
||||
|
||||
this.isSystem = options.isSystem;
|
||||
this.isUnmatched = options.isUnmatched || false;
|
||||
this.inherited = options.inherited || null;
|
||||
this.keyframes = options.keyframes || null;
|
||||
this._modificationDepth = 0;
|
||||
|
|
|
@ -101,6 +101,7 @@ skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work wit
|
|||
[browser_rules_edit-selector_04.js]
|
||||
[browser_rules_edit-selector_05.js]
|
||||
[browser_rules_edit-selector_06.js]
|
||||
[browser_rules_edit-selector_07.js]
|
||||
[browser_rules_editable-field-focus_01.js]
|
||||
[browser_rules_editable-field-focus_02.js]
|
||||
[browser_rules_eyedropper.js]
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that the rule view overridden search filter does not appear for an
|
||||
// unmatched rule.
|
||||
|
||||
const TEST_URI = `
|
||||
<style type="text/css">
|
||||
div {
|
||||
height: 0px;
|
||||
}
|
||||
#testid {
|
||||
height: 1px;
|
||||
}
|
||||
.testclass {
|
||||
height: 10px;
|
||||
}
|
||||
</style>
|
||||
<div id="testid">Styled Node</div>
|
||||
<span class="testclass">This is a span</span>
|
||||
`;
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
|
||||
yield selectNode("#testid", inspector);
|
||||
yield testEditSelector(view, "span");
|
||||
});
|
||||
|
||||
function* testEditSelector(view, name) {
|
||||
info("Test editing existing selector fields");
|
||||
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
|
||||
info("Focusing an existing selector name in the rule-view");
|
||||
let editor = yield focusEditableField(view, ruleEditor.selectorText);
|
||||
|
||||
is(inplaceEditor(ruleEditor.selectorText), editor,
|
||||
"The selector editor got focused");
|
||||
|
||||
info("Entering a new selector name and committing");
|
||||
editor.input.value = name;
|
||||
|
||||
info("Entering the commit key");
|
||||
let onRuleViewChanged = once(view, "ruleview-changed");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
yield onRuleViewChanged;
|
||||
|
||||
// Get the new rule editor that replaced the original
|
||||
ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let rule = ruleEditor.rule;
|
||||
let textPropEditor = rule.textProps[0].editor;
|
||||
|
||||
is(view._elementStyle.rules.length, 3, "Should have 3 rules.");
|
||||
ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
|
||||
ok(ruleEditor.element.getAttribute("unmatched"),
|
||||
"Rule with " + name + " does not match the current element.");
|
||||
ok(textPropEditor.filterProperty.hidden, "Overridden search is hidden.");
|
||||
}
|
|
@ -48,6 +48,8 @@ const TEST_DATA = [
|
|||
numUserRules: 1,
|
||||
numUARules: 0
|
||||
},
|
||||
// Note that some tests below assume that the "a" selector is the
|
||||
// last test in TEST_DATA.
|
||||
{
|
||||
selector: "a",
|
||||
numUserRules: 3,
|
||||
|
@ -111,9 +113,11 @@ function* userAgentStylesVisible(inspector, view) {
|
|||
ok(userRules.some(rule=> rule.matchedSelectors.length === 1),
|
||||
"There is an inline style for element in user styles");
|
||||
|
||||
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf(":-moz-any-link")),
|
||||
// These tests rely on the "a" selector being the last test in
|
||||
// TEST_DATA.
|
||||
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf(":-moz-any-link") !== -1),
|
||||
"There is a rule for :-moz-any-link");
|
||||
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf("*|*:link")),
|
||||
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf("*|*:link") !== -1),
|
||||
"There is a rule for *|*:link");
|
||||
ok(uaRules.some(rule=> rule.matchedSelectors.length === 1),
|
||||
"Inline styles for ua styles");
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
<title>authored sheet test</title>
|
||||
|
||||
<style>
|
||||
#target {
|
||||
color: chartreuse;
|
||||
pre a {
|
||||
color: orange;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
var gIOService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService)
|
||||
|
||||
var style = "data:text/css,div { background-color: seagreen; }";
|
||||
var style = "data:text/css,a { background-color: seagreen; }";
|
||||
var uri = gIOService.newURI(style, null, null);
|
||||
var windowUtils = SpecialPowers.wrap(window)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
|
@ -25,8 +25,6 @@ windowUtils.loadSheet(uri, windowUtils.AUTHOR_SHEET);
|
|||
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"> the ocean </div>
|
||||
|
||||
<input type=text placeholder=test></input>
|
||||
<input type=color></input>
|
||||
<input type=range></input>
|
||||
|
|
|
@ -86,6 +86,7 @@ RuleEditor.prototype = {
|
|||
this.element = this.doc.createElementNS(HTML_NS, "div");
|
||||
this.element.className = "ruleview-rule theme-separator";
|
||||
this.element.setAttribute("uneditable", !this.isEditable);
|
||||
this.element.setAttribute("unmatched", this.rule.isUnmatched);
|
||||
this.element._ruleEditor = this;
|
||||
|
||||
// Give a relative position for the inplace editor's measurement
|
||||
|
@ -494,6 +495,7 @@ RuleEditor.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
ruleProps.isUnmatched = !isMatching;
|
||||
let newRule = new Rule(elementStyle, ruleProps);
|
||||
let editor = new RuleEditor(ruleView, newRule);
|
||||
let rules = elementStyle.rules;
|
||||
|
@ -503,7 +505,6 @@ RuleEditor.prototype = {
|
|||
elementStyle._changed();
|
||||
elementStyle.markOverriddenAll();
|
||||
|
||||
editor.element.setAttribute("unmatched", !isMatching);
|
||||
this.element.parentNode.replaceChild(editor.element, this.element);
|
||||
|
||||
// Remove highlight for modified selector
|
||||
|
|
|
@ -299,7 +299,8 @@ TextPropertyEditor.prototype = {
|
|||
this.warning.hidden = this.editing || this.isValid();
|
||||
this.filterProperty.hidden = this.editing ||
|
||||
!this.isValid() ||
|
||||
!this.prop.overridden;
|
||||
!this.prop.overridden ||
|
||||
this.ruleEditor.rule.isUnmatched;
|
||||
|
||||
if (!this.editing &&
|
||||
(this.prop.overridden || !this.prop.enabled ||
|
||||
|
|
|
@ -0,0 +1,333 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const {createNode} = require("devtools/client/animationinspector/utils");
|
||||
|
||||
const STRINGS_URI = "chrome://devtools/locale/inspector.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying a preview of a dom node.
|
||||
* @param {InspectorPanel} inspector Requires a reference to the inspector-panel
|
||||
* to highlight and select the node, as well as refresh it when there are
|
||||
* mutations.
|
||||
* @param {Object} options Supported properties are:
|
||||
* - compact {Boolean} Defaults to false.
|
||||
* By default, nodes are previewed like <tag id="id" class="class">
|
||||
* If true, nodes will be previewed like tag#id.class instead.
|
||||
*/
|
||||
function DomNodePreview(inspector, options = {}) {
|
||||
this.inspector = inspector;
|
||||
this.options = options;
|
||||
|
||||
this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
|
||||
this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
|
||||
this.onSelectElClick = this.onSelectElClick.bind(this);
|
||||
this.onMarkupMutations = this.onMarkupMutations.bind(this);
|
||||
this.onHighlightElClick = this.onHighlightElClick.bind(this);
|
||||
this.onHighlighterLocked = this.onHighlighterLocked.bind(this);
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.DomNodePreview = DomNodePreview;
|
||||
|
||||
DomNodePreview.prototype = {
|
||||
init: function(containerEl) {
|
||||
let document = containerEl.ownerDocument;
|
||||
|
||||
// Init the markup for displaying the target node.
|
||||
this.el = createNode({
|
||||
parent: containerEl,
|
||||
attributes: {
|
||||
"class": "animation-target"
|
||||
}
|
||||
});
|
||||
|
||||
// Icon to select the node in the inspector.
|
||||
this.highlightNodeEl = createNode({
|
||||
parent: this.el,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "node-highlighter",
|
||||
"title": L10N.getStr("inspector.nodePreview.highlightNodeLabel")
|
||||
}
|
||||
});
|
||||
|
||||
// Wrapper used for mouseover/out event handling.
|
||||
this.previewEl = createNode({
|
||||
parent: this.el,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"title": L10N.getStr("inspector.nodePreview.selectNodeLabel")
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.previewEl.appendChild(document.createTextNode("<"));
|
||||
}
|
||||
|
||||
// Tag name.
|
||||
this.tagNameEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "tag-name theme-fg-color3"
|
||||
}
|
||||
});
|
||||
|
||||
// Id attribute container.
|
||||
this.idEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span"
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-name theme-fg-color2"
|
||||
},
|
||||
textContent: "id"
|
||||
});
|
||||
this.idEl.appendChild(document.createTextNode("=\""));
|
||||
} else {
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "theme-fg-color6"
|
||||
},
|
||||
textContent: "#"
|
||||
});
|
||||
}
|
||||
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-value theme-fg-color6"
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.idEl.appendChild(document.createTextNode("\""));
|
||||
}
|
||||
|
||||
// Class attribute container.
|
||||
this.classEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span"
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-name theme-fg-color2"
|
||||
},
|
||||
textContent: "class"
|
||||
});
|
||||
this.classEl.appendChild(document.createTextNode("=\""));
|
||||
} else {
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "theme-fg-color6"
|
||||
},
|
||||
textContent: "."
|
||||
});
|
||||
}
|
||||
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-value theme-fg-color6"
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.classEl.appendChild(document.createTextNode("\""));
|
||||
this.previewEl.appendChild(document.createTextNode(">"));
|
||||
}
|
||||
|
||||
this.startListeners();
|
||||
},
|
||||
|
||||
startListeners: function() {
|
||||
// Init events for highlighting and selecting the node.
|
||||
this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
|
||||
this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
|
||||
this.previewEl.addEventListener("click", this.onSelectElClick);
|
||||
this.highlightNodeEl.addEventListener("click", this.onHighlightElClick);
|
||||
|
||||
// Start to listen for markupmutation events.
|
||||
this.inspector.on("markupmutation", this.onMarkupMutations);
|
||||
|
||||
// Listen to the target node highlighter.
|
||||
HighlighterLock.on("highlighted", this.onHighlighterLocked);
|
||||
},
|
||||
|
||||
stopListeners: function() {
|
||||
HighlighterLock.off("highlighted", this.onHighlighterLocked);
|
||||
this.inspector.off("markupmutation", this.onMarkupMutations);
|
||||
this.previewEl.removeEventListener("mouseover", this.onPreviewMouseOver);
|
||||
this.previewEl.removeEventListener("mouseout", this.onPreviewMouseOut);
|
||||
this.previewEl.removeEventListener("click", this.onSelectElClick);
|
||||
this.highlightNodeEl.removeEventListener("click", this.onHighlightElClick);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
HighlighterLock.unhighlight().catch(e => console.error(e));
|
||||
|
||||
this.stopListeners();
|
||||
|
||||
this.el.remove();
|
||||
this.el = this.tagNameEl = this.idEl = this.classEl = null;
|
||||
this.highlightNodeEl = this.previewEl = null;
|
||||
this.nodeFront = this.inspector = null;
|
||||
},
|
||||
|
||||
get highlighterUtils() {
|
||||
if (this.inspector && this.inspector.toolbox) {
|
||||
return this.inspector.toolbox.highlighterUtils;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
onPreviewMouseOver: function() {
|
||||
if (!this.nodeFront || !this.highlighterUtils) {
|
||||
return;
|
||||
}
|
||||
this.highlighterUtils.highlightNodeFront(this.nodeFront)
|
||||
.catch(e => console.error(e));
|
||||
},
|
||||
|
||||
onPreviewMouseOut: function() {
|
||||
if (!this.nodeFront || !this.highlighterUtils) {
|
||||
return;
|
||||
}
|
||||
this.highlighterUtils.unhighlight()
|
||||
.catch(e => console.error(e));
|
||||
},
|
||||
|
||||
onSelectElClick: function() {
|
||||
if (!this.nodeFront) {
|
||||
return;
|
||||
}
|
||||
this.inspector.selection.setNodeFront(this.nodeFront, "dom-node-preview");
|
||||
},
|
||||
|
||||
onHighlightElClick: function(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
let classList = this.highlightNodeEl.classList;
|
||||
let isHighlighted = classList.contains("selected");
|
||||
|
||||
if (isHighlighted) {
|
||||
classList.remove("selected");
|
||||
HighlighterLock.unhighlight().then(() => {
|
||||
this.emit("target-highlighter-unlocked");
|
||||
}, error => console.error(error));
|
||||
} else {
|
||||
classList.add("selected");
|
||||
HighlighterLock.highlight(this).then(() => {
|
||||
this.emit("target-highlighter-locked");
|
||||
}, error => console.error(error));
|
||||
}
|
||||
},
|
||||
|
||||
onHighlighterLocked: function(e, domNodePreview) {
|
||||
if (domNodePreview !== this) {
|
||||
this.highlightNodeEl.classList.remove("selected");
|
||||
}
|
||||
},
|
||||
|
||||
onMarkupMutations: function(e, mutations) {
|
||||
if (!this.nodeFront) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let {target} of mutations) {
|
||||
if (target === this.nodeFront) {
|
||||
// Re-render with the same nodeFront to update the output.
|
||||
this.render(this.nodeFront);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function(nodeFront) {
|
||||
this.nodeFront = nodeFront;
|
||||
let {tagName, attributes} = nodeFront;
|
||||
|
||||
this.tagNameEl.textContent = tagName.toLowerCase();
|
||||
|
||||
let idIndex = attributes.findIndex(({name}) => name === "id");
|
||||
if (idIndex > -1 && attributes[idIndex].value) {
|
||||
this.idEl.querySelector(".attribute-value").textContent =
|
||||
attributes[idIndex].value;
|
||||
this.idEl.style.display = "inline";
|
||||
} else {
|
||||
this.idEl.style.display = "none";
|
||||
}
|
||||
|
||||
let classIndex = attributes.findIndex(({name}) => name === "class");
|
||||
if (classIndex > -1 && attributes[classIndex].value) {
|
||||
let value = attributes[classIndex].value;
|
||||
if (this.options.compact) {
|
||||
value = value.split(" ").join(".");
|
||||
}
|
||||
|
||||
this.classEl.querySelector(".attribute-value").textContent = value;
|
||||
this.classEl.style.display = "inline";
|
||||
} else {
|
||||
this.classEl.style.display = "none";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HighlighterLock is a helper used to lock the highlighter on DOM nodes in the
|
||||
* page.
|
||||
* It instantiates a new highlighter that is then shared amongst all instances
|
||||
* of DomNodePreview. This is useful because that means showing the highlighter
|
||||
* on one node will unhighlight the previously highlighted one, but will not
|
||||
* interfere with the default inspector highlighter.
|
||||
*/
|
||||
var HighlighterLock = {
|
||||
highlighter: null,
|
||||
isShown: false,
|
||||
|
||||
highlight: Task.async(function*(animationTargetNode) {
|
||||
if (!this.highlighter) {
|
||||
let util = animationTargetNode.inspector.toolbox.highlighterUtils;
|
||||
this.highlighter = yield util.getHighlighterByType("BoxModelHighlighter");
|
||||
}
|
||||
|
||||
yield this.highlighter.show(animationTargetNode.nodeFront);
|
||||
this.isShown = true;
|
||||
this.emit("highlighted", animationTargetNode);
|
||||
}),
|
||||
|
||||
unhighlight: Task.async(function*() {
|
||||
if (!this.highlighter || !this.isShown) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield this.highlighter.hide();
|
||||
this.isShown = false;
|
||||
this.emit("unhighlighted");
|
||||
})
|
||||
};
|
||||
|
||||
EventEmitter.decorate(HighlighterLock);
|
|
@ -5,6 +5,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'dom-node-preview.js',
|
||||
'style-inspector-menu.js',
|
||||
'style-inspector-overlays.js',
|
||||
'utils.js'
|
||||
|
|
|
@ -32,11 +32,16 @@ const TOOLTIP_IMAGE_TYPE = "image";
|
|||
const TOOLTIP_FONTFAMILY_TYPE = "font-family";
|
||||
|
||||
// Types of nodes in the rule/computed-view
|
||||
const VIEW_NODE_SELECTOR_TYPE = exports.VIEW_NODE_SELECTOR_TYPE = 1;
|
||||
const VIEW_NODE_PROPERTY_TYPE = exports.VIEW_NODE_PROPERTY_TYPE = 2;
|
||||
const VIEW_NODE_VALUE_TYPE = exports.VIEW_NODE_VALUE_TYPE = 3;
|
||||
const VIEW_NODE_IMAGE_URL_TYPE = exports.VIEW_NODE_IMAGE_URL_TYPE = 4;
|
||||
const VIEW_NODE_LOCATION_TYPE = exports.VIEW_NODE_LOCATION_TYPE = 5;
|
||||
const VIEW_NODE_SELECTOR_TYPE = 1;
|
||||
exports.VIEW_NODE_SELECTOR_TYPE = VIEW_NODE_SELECTOR_TYPE;
|
||||
const VIEW_NODE_PROPERTY_TYPE = 2;
|
||||
exports.VIEW_NODE_PROPERTY_TYPE = VIEW_NODE_PROPERTY_TYPE;
|
||||
const VIEW_NODE_VALUE_TYPE = 3;
|
||||
exports.VIEW_NODE_VALUE_TYPE = VIEW_NODE_VALUE_TYPE;
|
||||
const VIEW_NODE_IMAGE_URL_TYPE = 4;
|
||||
exports.VIEW_NODE_IMAGE_URL_TYPE = VIEW_NODE_IMAGE_URL_TYPE;
|
||||
const VIEW_NODE_LOCATION_TYPE = 5;
|
||||
exports.VIEW_NODE_LOCATION_TYPE = VIEW_NODE_LOCATION_TYPE;
|
||||
|
||||
/**
|
||||
* Manages all highlighters in the style-inspector.
|
||||
|
@ -183,9 +188,9 @@ HighlightersOverlay.prototype = {
|
|||
// promise. This causes some tests to fail when trying to install a
|
||||
// rejection handler on the result of the call. To avoid this, check
|
||||
// whether the result is truthy before installing the handler.
|
||||
let promise = this.highlighters[this.highlighterShown].hide();
|
||||
if (promise) {
|
||||
promise.then(null, e => console.error(e));
|
||||
let onHidden = this.highlighters[this.highlighterShown].hide();
|
||||
if (onHidden) {
|
||||
onHidden.then(null, e => console.error(e));
|
||||
}
|
||||
|
||||
this.highlighterShown = null;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu} = require("chrome");
|
||||
const {Ci, Cu} = require("chrome");
|
||||
const {setTimeout, clearTimeout} =
|
||||
Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
const {parseDeclarations} =
|
||||
|
@ -28,7 +28,7 @@ const HTML_NS = "http://www.w3.org/1999/xhtml";
|
|||
* @param {object} attributes
|
||||
* A set of attributes to set on the node.
|
||||
*/
|
||||
function createChild(parent, tagName, attributes={}) {
|
||||
function createChild(parent, tagName, attributes = {}) {
|
||||
let elt = parent.ownerDocument.createElementNS(HTML_NS, tagName);
|
||||
for (let attr in attributes) {
|
||||
if (attributes.hasOwnProperty(attr)) {
|
||||
|
|
|
@ -93,17 +93,3 @@ timeline.csstransition.nameLabel=%S - CSS Transition
|
|||
# This can happen if devtools couldn't figure out the type of the animation.
|
||||
# %S will be replaced by the name of the transition at run-time.
|
||||
timeline.unknown.nameLabel=%S
|
||||
|
||||
# LOCALIZATION NOTE (node.selectNodeLabel):
|
||||
# This string is displayed in a tooltip of the animation panel that is shown
|
||||
# when hovering over an animated node (e.g. something like div.animated).
|
||||
# The tooltip invites the user to click on the node in order to select it in the
|
||||
# inspector panel.
|
||||
node.selectNodeLabel=Click to select this node in the Inspector
|
||||
|
||||
# LOCALIZATION NOTE (node.highlightNodeLabel):
|
||||
# This string is displayed in a tooltip of the animation panel that is shown
|
||||
# when hovering over the inspector icon displayed next to animated nodes.
|
||||
# The tooltip invites the user to click on the icon in order to show the node
|
||||
# highlighter.
|
||||
node.highlightNodeLabel=Click to highlight this node in the page
|
||||
|
|
|
@ -116,3 +116,22 @@ inspector.menu.editAttribute.label=Edit Attribute %S
|
|||
# when the user right-clicks on the attribute of a node in the inspector,
|
||||
# and that allows to remove this attribute.
|
||||
inspector.menu.removeAttribute.label=Remove Attribute %S
|
||||
|
||||
# LOCALIZATION NOTE (inspector.nodePreview.selectNodeLabel):
|
||||
# This string is displayed in a tooltip that is shown when hovering over a DOM
|
||||
# node preview (e.g. something like "div#foo.bar").
|
||||
# DOM node previews can be displayed in places like the animation-inspector, the
|
||||
# console or the object inspector.
|
||||
# The tooltip invites the user to click on the node in order to select it in the
|
||||
# inspector panel.
|
||||
inspector.nodePreview.selectNodeLabel=Click to select this node in the Inspector
|
||||
|
||||
# LOCALIZATION NOTE (inspector.nodePreview.highlightNodeLabel):
|
||||
# This string is displayed in a tooltip that is shown when hovering over a the
|
||||
# inspector icon displayed next to a DOM node preview (e.g. next to something
|
||||
# like "div#foo.bar").
|
||||
# DOM node previews can be displayed in places like the animation-inspector, the
|
||||
# console or the object inspector.
|
||||
# The tooltip invites the user to click on the icon in order to highlight the
|
||||
# node in the page.
|
||||
inspector.nodePreview.highlightNodeLabel=Click to highlight this node in the page
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
label="&performanceUI.enableMemory;"
|
||||
tooltiptext="&performanceUI.enableMemory.tooltiptext;"/>
|
||||
<menuitem id="option-enable-allocations"
|
||||
class="experimental-option"
|
||||
type="checkbox"
|
||||
data-pref="enable-allocations"
|
||||
label="&performanceUI.enableAllocations;"
|
||||
|
|
|
@ -126,14 +126,12 @@ body.theme-sidebar {
|
|||
#main > p {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#main > p {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#main > p > span {
|
||||
#main > p > span,
|
||||
#main > p > input {
|
||||
vertical-align: middle;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
|
|
@ -113,6 +113,6 @@ function* testNaviatingHistoryInUI(hud) {
|
|||
// restores this.
|
||||
for (let i = INPUT_HISTORY_COUNT - 1; i >= 0; i--) {
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(inputNode.value, i, "Pressing up restores last input");
|
||||
is(jsterm.getInputValue(), i, "Pressing up restores last input");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,23 +71,23 @@ function consoleOpened(HUD) {
|
|||
WebConsoleUtils.usageCount = 0;
|
||||
updateEditUIVisibility();
|
||||
|
||||
let oldVal = jsterm.inputNode.value;
|
||||
let oldVal = jsterm.getInputValue();
|
||||
goDoCommand("cmd_paste");
|
||||
let notificationbox = jsterm.hud.document.getElementById("webconsole-notificationbox");
|
||||
let notification = notificationbox.getNotificationWithValue("selfxss-notification");
|
||||
ok(notification, "Self-xss notification shown");
|
||||
is(oldVal, jsterm.inputNode.value, "Paste blocked by self-xss prevention");
|
||||
is(oldVal, jsterm.getInputValue(), "Paste blocked by self-xss prevention");
|
||||
|
||||
// Allow pasting
|
||||
jsterm.inputNode.value = "allow pasting";
|
||||
jsterm.setInputValue("allow pasting");
|
||||
let evt = document.createEvent("KeyboardEvent");
|
||||
evt.initKeyEvent("keyup", true, true, window,
|
||||
0, 0, 0, 0,
|
||||
0, " ".charCodeAt(0));
|
||||
jsterm.inputNode.dispatchEvent(evt);
|
||||
jsterm.inputNode.value = "";
|
||||
jsterm.setInputValue("");
|
||||
goDoCommand("cmd_paste");
|
||||
isnot("", jsterm.inputNode.value, "Paste works");
|
||||
isnot("", jsterm.getInputValue(), "Paste works");
|
||||
}
|
||||
function onClipboardPaste() {
|
||||
ok(!jsterm.completeNode.value, "no completion value after paste");
|
||||
|
|
|
@ -88,7 +88,7 @@ var consoleOpened = Task.async(function*(aHud) {
|
|||
"Index of the first item from bottom is selected.");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
|
||||
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
||||
|
||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||
is(popup.selectedItem.label, "watch", "watch is selected");
|
||||
|
@ -149,7 +149,7 @@ function popupHideAfterTab() {
|
|||
// At this point the completion suggestion should be accepted.
|
||||
ok(!popup.isOpen, "popup is not open");
|
||||
|
||||
is(inputNode.value, "window.foobarBug585991.watch",
|
||||
is(jsterm.getInputValue(), "window.foobarBug585991.watch",
|
||||
"completion was successful after VK_TAB");
|
||||
|
||||
ok(!completeNode.value, "completeNode is empty");
|
||||
|
@ -164,7 +164,7 @@ function popupHideAfterTab() {
|
|||
is(popup.selectedIndex, 18, "First index from bottom is selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
|
||||
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
||||
|
||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||
is(popup.selectedItem.label, "watch", "watch is selected");
|
||||
|
@ -176,7 +176,7 @@ function popupHideAfterTab() {
|
|||
|
||||
ok(!popup.isOpen, "popup is not open after VK_ESCAPE");
|
||||
|
||||
is(inputNode.value, "window.foobarBug585991.",
|
||||
is(jsterm.getInputValue(), "window.foobarBug585991.",
|
||||
"completion was cancelled");
|
||||
|
||||
ok(!completeNode.value, "completeNode is empty");
|
||||
|
@ -212,7 +212,7 @@ function testReturnKey() {
|
|||
is(popup.selectedIndex, 18, "First index from bottom is selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
|
||||
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
||||
|
||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||
is(popup.selectedItem.label, "watch", "watch is selected");
|
||||
|
@ -231,7 +231,7 @@ function testReturnKey() {
|
|||
|
||||
ok(!popup.isOpen, "popup is not open after VK_RETURN");
|
||||
|
||||
is(inputNode.value, "window.foobarBug585991.valueOf",
|
||||
is(jsterm.getInputValue(), "window.foobarBug585991.valueOf",
|
||||
"completion was successful after VK_RETURN");
|
||||
|
||||
ok(!completeNode.value, "completeNode is empty");
|
||||
|
@ -324,7 +324,7 @@ function testReturnWithNoSelection() {
|
|||
function popupHideAfterReturnWithNoSelection() {
|
||||
ok(!popup.isOpen, "popup is not open after VK_RETURN");
|
||||
|
||||
is(inputNode.value, "", "inputNode is empty after VK_RETURN");
|
||||
is(jsterm.getInputValue(), "", "inputNode is empty after VK_RETURN");
|
||||
is(completeNode.value, "", "completeNode is empty");
|
||||
is(jsterm.history[jsterm.history.length - 1], "window.testBug",
|
||||
"jsterm history is correct");
|
||||
|
@ -369,7 +369,7 @@ function testCompletionInText() {
|
|||
function popupHideAfterCompletionInText() {
|
||||
// At this point the completion suggestion should be accepted.
|
||||
ok(!popup.isOpen, "popup is not open");
|
||||
is(inputNode.value, "dump(window.testBug873250b)",
|
||||
is(jsterm.getInputValue(), "dump(window.testBug873250b)",
|
||||
"completion was successful after VK_TAB");
|
||||
is(inputNode.selectionStart, 26, "cursor location is correct");
|
||||
is(inputNode.selectionStart, inputNode.selectionEnd,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var inputNode, values;
|
||||
var jsterm, inputNode, values;
|
||||
|
||||
var TEST_URI = "data:text/html;charset=utf-8,Web Console test for " +
|
||||
"bug 594497 and bug 619598";
|
||||
|
@ -23,31 +23,33 @@ add_task(function* () {
|
|||
setup(hud);
|
||||
performTests();
|
||||
|
||||
inputNode = values = null;
|
||||
jsterm = inputNode = values = null;
|
||||
});
|
||||
|
||||
function setup(HUD) {
|
||||
inputNode = HUD.jsterm.inputNode;
|
||||
jsterm = HUD.jsterm;
|
||||
inputNode = jsterm.inputNode;
|
||||
|
||||
inputNode.focus();
|
||||
|
||||
ok(!inputNode.value, "inputNode.value is empty");
|
||||
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
|
||||
|
||||
values = ["document", "window", "document.body"];
|
||||
values.push(values.join(";\n"), "document.location");
|
||||
|
||||
// Execute each of the values;
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
HUD.jsterm.setInputValue(values[i]);
|
||||
HUD.jsterm.execute();
|
||||
jsterm.setInputValue(values[i]);
|
||||
jsterm.execute();
|
||||
}
|
||||
}
|
||||
|
||||
function performTests() {
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(inputNode.value, values[4],
|
||||
"VK_UP: inputNode.value #4 is correct");
|
||||
|
||||
is(jsterm.getInputValue(), values[4],
|
||||
"VK_UP: jsterm.getInputValue() #4 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == values[4].length &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
|
@ -55,8 +57,8 @@ function performTests() {
|
|||
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(inputNode.value, values[3],
|
||||
"VK_UP: inputNode.value #3 is correct");
|
||||
is(jsterm.getInputValue(), values[3],
|
||||
"VK_UP: jsterm.getInputValue() #3 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == values[3].length &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
|
@ -67,17 +69,17 @@ function performTests() {
|
|||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(inputNode.value, values[3],
|
||||
"VK_UP two times: inputNode.value #3 is correct");
|
||||
is(jsterm.getInputValue(), values[3],
|
||||
"VK_UP two times: jsterm.getInputValue() #3 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == inputNode.value.indexOf("\n") &&
|
||||
ok(inputNode.selectionStart == jsterm.getInputValue().indexOf("\n") &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
"caret location is correct");
|
||||
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(inputNode.value, values[3],
|
||||
"VK_UP again: inputNode.value #3 is correct");
|
||||
is(jsterm.getInputValue(), values[3],
|
||||
"VK_UP again: jsterm.getInputValue() #3 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == 0 &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
|
@ -85,18 +87,18 @@ function performTests() {
|
|||
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(inputNode.value, values[2],
|
||||
"VK_UP: inputNode.value #2 is correct");
|
||||
is(jsterm.getInputValue(), values[2],
|
||||
"VK_UP: jsterm.getInputValue() #2 is correct");
|
||||
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(inputNode.value, values[1],
|
||||
"VK_UP: inputNode.value #1 is correct");
|
||||
is(jsterm.getInputValue(), values[1],
|
||||
"VK_UP: jsterm.getInputValue() #1 is correct");
|
||||
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(inputNode.value, values[0],
|
||||
"VK_UP: inputNode.value #0 is correct");
|
||||
is(jsterm.getInputValue(), values[0],
|
||||
"VK_UP: jsterm.getInputValue() #0 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == values[0].length &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
|
@ -104,8 +106,8 @@ function performTests() {
|
|||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(inputNode.value, values[1],
|
||||
"VK_DOWN: inputNode.value #1 is correct");
|
||||
is(jsterm.getInputValue(), values[1],
|
||||
"VK_DOWN: jsterm.getInputValue() #1 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == values[1].length &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
|
@ -113,13 +115,13 @@ function performTests() {
|
|||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(inputNode.value, values[2],
|
||||
"VK_DOWN: inputNode.value #2 is correct");
|
||||
is(jsterm.getInputValue(), values[2],
|
||||
"VK_DOWN: jsterm.getInputValue() #2 is correct");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(inputNode.value, values[3],
|
||||
"VK_DOWN: inputNode.value #3 is correct");
|
||||
is(jsterm.getInputValue(), values[3],
|
||||
"VK_DOWN: jsterm.getInputValue() #3 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == values[3].length &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
|
@ -130,17 +132,17 @@ function performTests() {
|
|||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(inputNode.value, values[3],
|
||||
"VK_DOWN two times: inputNode.value #3 is correct");
|
||||
is(jsterm.getInputValue(), values[3],
|
||||
"VK_DOWN two times: jsterm.getInputValue() #3 is correct");
|
||||
|
||||
ok(inputNode.selectionStart > inputNode.value.lastIndexOf("\n") &&
|
||||
ok(inputNode.selectionStart > jsterm.getInputValue().lastIndexOf("\n") &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
"caret location is correct");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(inputNode.value, values[3],
|
||||
"VK_DOWN again: inputNode.value #3 is correct");
|
||||
is(jsterm.getInputValue(), values[3],
|
||||
"VK_DOWN again: jsterm.getInputValue() #3 is correct");
|
||||
|
||||
ok(inputNode.selectionStart == values[3].length &&
|
||||
inputNode.selectionStart == inputNode.selectionEnd,
|
||||
|
@ -148,11 +150,11 @@ function performTests() {
|
|||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(inputNode.value, values[4],
|
||||
"VK_DOWN: inputNode.value #4 is correct");
|
||||
is(jsterm.getInputValue(), values[4],
|
||||
"VK_DOWN: jsterm.getInputValue() #4 is correct");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
ok(!inputNode.value,
|
||||
"VK_DOWN: inputNode.value is empty");
|
||||
ok(!jsterm.getInputValue(),
|
||||
"VK_DOWN: jsterm.getInputValue() is empty");
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ add_task(function* () {
|
|||
// Test select all with Control + A.
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
let inputLength = inputNode.selectionEnd - inputNode.selectionStart;
|
||||
is(inputLength, inputNode.value.length, "Select all of input");
|
||||
is(inputLength, jsterm.getInputValue().length, "Select all of input");
|
||||
|
||||
// Test do nothing on Control + E.
|
||||
jsterm.setInputValue("Ignore These Four Words");
|
||||
|
|
|
@ -31,7 +31,7 @@ add_task(function* () {
|
|||
function doTests(HUD) {
|
||||
jsterm = HUD.jsterm;
|
||||
inputNode = jsterm.inputNode;
|
||||
ok(!jsterm.inputNode.value, "inputNode.value is empty");
|
||||
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
|
||||
is(jsterm.inputNode.selectionStart, 0);
|
||||
is(jsterm.inputNode.selectionEnd, 0);
|
||||
|
||||
|
@ -96,10 +96,10 @@ function testMultiLineInputNavNoHistory() {
|
|||
jsterm.setInputValue("");
|
||||
// simulate shift-return
|
||||
for (let i = 0; i < lineValues.length; i++) {
|
||||
jsterm.setInputValue(inputNode.value + lineValues[i]);
|
||||
jsterm.setInputValue(jsterm.getInputValue() + lineValues[i]);
|
||||
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
|
||||
}
|
||||
let inputValue = inputNode.value;
|
||||
let inputValue = jsterm.getInputValue();
|
||||
is(inputNode.selectionStart, inputNode.selectionEnd);
|
||||
is(inputNode.selectionStart, inputValue.length,
|
||||
"caret at end of multiline input");
|
||||
|
@ -111,36 +111,36 @@ function testMultiLineInputNavNoHistory() {
|
|||
// Ok, test navigating within the multi-line string!
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
let expectedStringAfterCarat = lineValues[5] + newlineString;
|
||||
is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
|
||||
is(jsterm.getInputValue().slice(inputNode.selectionStart), expectedStringAfterCarat,
|
||||
"up arrow from end of multiline");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(inputNode.value.slice(inputNode.selectionStart), "",
|
||||
is(jsterm.getInputValue().slice(inputNode.selectionStart), "",
|
||||
"down arrow from within multiline");
|
||||
|
||||
// navigate up through input lines
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
|
||||
is(jsterm.getInputValue().slice(inputNode.selectionStart), expectedStringAfterCarat,
|
||||
"ctrl-p from end of multiline");
|
||||
|
||||
for (let i = 4; i >= 0; i--) {
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
expectedStringAfterCarat = lineValues[i] + newlineString +
|
||||
expectedStringAfterCarat;
|
||||
is(inputNode.value.slice(inputNode.selectionStart),
|
||||
is(jsterm.getInputValue().slice(inputNode.selectionStart),
|
||||
expectedStringAfterCarat, "ctrl-p from within line " + i +
|
||||
" of multiline input");
|
||||
}
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0, "reached start of input");
|
||||
is(inputNode.value, inputValue,
|
||||
is(jsterm.getInputValue(), inputValue,
|
||||
"no change to multiline input on ctrl-p from beginning of multiline");
|
||||
|
||||
// navigate to end of first line
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
let caretPos = inputNode.selectionStart;
|
||||
let expectedStringBeforeCarat = lineValues[0];
|
||||
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
|
||||
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
|
||||
"ctrl-e into multiline input");
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, caretPos,
|
||||
|
@ -152,13 +152,13 @@ function testMultiLineInputNavNoHistory() {
|
|||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
caretPos = inputNode.selectionStart;
|
||||
expectedStringBeforeCarat += newlineString;
|
||||
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
|
||||
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
|
||||
"ctrl-a to beginning of line " + (i + 1) + " in multiline input");
|
||||
|
||||
EventUtils.synthesizeKey("e", { ctrlKey: true });
|
||||
caretPos = inputNode.selectionStart;
|
||||
expectedStringBeforeCarat += lineValues[i];
|
||||
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
|
||||
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
|
||||
"ctrl-e to end of line " + (i + 1) + "in multiline input");
|
||||
}
|
||||
}
|
||||
|
@ -195,27 +195,27 @@ function testNavWithHistory() {
|
|||
// single-line inputs will update from history from end of line
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
}
|
||||
is(inputNode.value, values[i - 1],
|
||||
is(jsterm.getInputValue(), values[i - 1],
|
||||
"ctrl-p updates inputNode from backwards history values[" + i - 1 + "]");
|
||||
}
|
||||
let inputValue = inputNode.value;
|
||||
let inputValue = jsterm.getInputValue();
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.selectionStart, 0,
|
||||
"ctrl-p at beginning of history moves caret location to beginning " +
|
||||
"of line");
|
||||
is(inputNode.value, inputValue,
|
||||
is(jsterm.getInputValue(), inputValue,
|
||||
"no change to input value on ctrl-p from beginning of line");
|
||||
|
||||
// Navigate forwards history with ctrl-n
|
||||
for (let i = 1; i < values.length; i++) {
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
is(inputNode.value, values[i],
|
||||
is(jsterm.getInputValue(), values[i],
|
||||
"ctrl-n updates inputNode from forwards history values[" + i + "]");
|
||||
is(inputNode.selectionStart, values[i].length,
|
||||
"caret location correct at end of history input for values[" + i + "]");
|
||||
}
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
ok(!inputNode.value, "ctrl-n at end of history updates to empty input");
|
||||
ok(!jsterm.getInputValue(), "ctrl-n at end of history updates to empty input");
|
||||
|
||||
// Simulate editing multi-line
|
||||
inputValue = "one\nlinebreak";
|
||||
|
@ -223,11 +223,11 @@ function testNavWithHistory() {
|
|||
|
||||
// Attempt nav within input
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.value, inputValue,
|
||||
is(jsterm.getInputValue(), inputValue,
|
||||
"ctrl-p from end of multi-line does not trigger history");
|
||||
|
||||
EventUtils.synthesizeKey("a", { ctrlKey: true });
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
is(inputNode.value, values[values.length - 1],
|
||||
is(jsterm.getInputValue(), values[values.length - 1],
|
||||
"ctrl-p from start of multi-line triggers history");
|
||||
}
|
||||
|
|
|
@ -28,36 +28,36 @@ add_task(function* () {
|
|||
function testEditedInputHistory(HUD) {
|
||||
let jsterm = HUD.jsterm;
|
||||
let inputNode = jsterm.inputNode;
|
||||
ok(!inputNode.value, "inputNode.value is empty");
|
||||
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
|
||||
is(inputNode.selectionStart, 0);
|
||||
is(inputNode.selectionEnd, 0);
|
||||
|
||||
jsterm.setInputValue('"first item"');
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(inputNode.value, '"first item"', "null test history up");
|
||||
is(jsterm.getInputValue(), '"first item"', "null test history up");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(inputNode.value, '"first item"', "null test history down");
|
||||
is(jsterm.getInputValue(), '"first item"', "null test history down");
|
||||
|
||||
jsterm.execute();
|
||||
is(inputNode.value, "", "cleared input line after submit");
|
||||
is(jsterm.getInputValue(), "", "cleared input line after submit");
|
||||
|
||||
jsterm.setInputValue('"editing input 1"');
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(inputNode.value, '"first item"', "test history up");
|
||||
is(jsterm.getInputValue(), '"first item"', "test history up");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(inputNode.value, '"editing input 1"',
|
||||
is(jsterm.getInputValue(), '"editing input 1"',
|
||||
"test history down restores in-progress input");
|
||||
|
||||
jsterm.setInputValue('"second item"');
|
||||
jsterm.execute();
|
||||
jsterm.setInputValue('"editing input 2"');
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(inputNode.value, '"second item"', "test history up");
|
||||
is(jsterm.getInputValue(), '"second item"', "test history up");
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(inputNode.value, '"first item"', "test history up");
|
||||
is(jsterm.getInputValue(), '"first item"', "test history up");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(inputNode.value, '"second item"', "test history down");
|
||||
is(jsterm.getInputValue(), '"second item"', "test history down");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(inputNode.value, '"editing input 2"',
|
||||
is(jsterm.getInputValue(), '"editing input 2"',
|
||||
"test history down restores new in-progress input again");
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ add_task(function*() {
|
|||
info("Waiting for input to be set");
|
||||
yield onceInputSet;
|
||||
|
||||
is(hud.jsterm.inputNode.value, "temp0", "Input was set");
|
||||
is(hud.jsterm.getInputValue(), "temp0", "Input was set");
|
||||
let executedResult = yield hud.jsterm.execute();
|
||||
|
||||
ok(executedResult.textContent.includes("{ baz: 1 }"),
|
||||
|
|
|
@ -3252,7 +3252,7 @@ JSTerm.prototype = {
|
|||
*
|
||||
* @param string [executeString]
|
||||
* The string you want to execute. If this is not provided, the current
|
||||
* user input is used - taken from |this.inputNode.value|.
|
||||
* user input is used - taken from |this.getInputValue()|.
|
||||
* @param function [callback]
|
||||
* Optional function to invoke when the result is displayed.
|
||||
* This is deprecated - please use the promise return value instead.
|
||||
|
@ -3270,7 +3270,7 @@ JSTerm.prototype = {
|
|||
}
|
||||
|
||||
// attempt to execute the content of the inputNode
|
||||
executeString = executeString || this.inputNode.value;
|
||||
executeString = executeString || this.getInputValue();
|
||||
if (!executeString) {
|
||||
return;
|
||||
}
|
||||
|
@ -3863,16 +3863,25 @@ JSTerm.prototype = {
|
|||
this.emit("set-input-value");
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the value from the input field
|
||||
* @returns string
|
||||
*/
|
||||
getInputValue: function()
|
||||
{
|
||||
return this.inputNode.value || "";
|
||||
},
|
||||
|
||||
/**
|
||||
* The inputNode "input" and "keyup" event handler.
|
||||
* @private
|
||||
*/
|
||||
_inputEventHandler: function JST__inputEventHandler()
|
||||
{
|
||||
if (this.lastInputValue != this.inputNode.value) {
|
||||
if (this.lastInputValue != this.getInputValue()) {
|
||||
this.resizeInput();
|
||||
this.complete(this.COMPLETE_HINT_ONLY);
|
||||
this.lastInputValue = this.inputNode.value;
|
||||
this.lastInputValue = this.getInputValue();
|
||||
this._inputChanged = true;
|
||||
}
|
||||
},
|
||||
|
@ -3897,6 +3906,7 @@ JSTerm.prototype = {
|
|||
_keyPress: function JST__keyPress(event)
|
||||
{
|
||||
let inputNode = this.inputNode;
|
||||
let inputValue = this.getInputValue();
|
||||
let inputUpdated = false;
|
||||
|
||||
if (event.ctrlKey) {
|
||||
|
@ -3906,12 +3916,12 @@ JSTerm.prototype = {
|
|||
if (Services.appinfo.OS == "WINNT") {
|
||||
break;
|
||||
}
|
||||
let lineEndPos = inputNode.value.length;
|
||||
let lineEndPos = inputValue.length;
|
||||
if (this.hasMultilineInput()) {
|
||||
// find index of closest newline >= cursor
|
||||
for (let i = inputNode.selectionEnd; i<lineEndPos; i++) {
|
||||
if (inputNode.value.charAt(i) == "\r" ||
|
||||
inputNode.value.charAt(i) == "\n") {
|
||||
if (inputValue.charAt(i) == "\r" ||
|
||||
inputValue.charAt(i) == "\n") {
|
||||
lineEndPos = i;
|
||||
break;
|
||||
}
|
||||
|
@ -4060,7 +4070,7 @@ JSTerm.prototype = {
|
|||
if (this.autocompletePopup.isOpen) {
|
||||
this.autocompletePopup.selectedIndex = 0;
|
||||
event.preventDefault();
|
||||
} else if (this.inputNode.value.length <= 0) {
|
||||
} else if (inputValue.length <= 0) {
|
||||
this.hud.outputNode.parentNode.scrollTop = 0;
|
||||
event.preventDefault();
|
||||
}
|
||||
|
@ -4070,7 +4080,7 @@ JSTerm.prototype = {
|
|||
if (this.autocompletePopup.isOpen) {
|
||||
this.autocompletePopup.selectedIndex = this.autocompletePopup.itemCount - 1;
|
||||
event.preventDefault();
|
||||
} else if (this.inputNode.value.length <= 0) {
|
||||
} else if (inputValue.length <= 0) {
|
||||
this.hud.outputNode.parentNode.scrollTop = this.hud.outputNode.parentNode.scrollHeight;
|
||||
event.preventDefault();
|
||||
}
|
||||
|
@ -4086,7 +4096,7 @@ JSTerm.prototype = {
|
|||
let cursorAtTheEnd = this.inputNode.selectionStart ==
|
||||
this.inputNode.selectionEnd &&
|
||||
this.inputNode.selectionStart ==
|
||||
this.inputNode.value.length;
|
||||
inputValue.length;
|
||||
let haveSuggestion = this.autocompletePopup.isOpen ||
|
||||
this.lastCompletion.value;
|
||||
let useCompletion = cursorAtTheEnd || this._autocompletePopupNavigated;
|
||||
|
@ -4154,7 +4164,7 @@ JSTerm.prototype = {
|
|||
// Note: this code does not store changes to items that are already in
|
||||
// history.
|
||||
if (this.historyPlaceHolder+1 == this.historyIndex) {
|
||||
this.history[this.historyIndex] = this.inputNode.value || "";
|
||||
this.history[this.historyIndex] = this.getInputValue() || "";
|
||||
}
|
||||
|
||||
this.setInputValue(inputVal);
|
||||
|
@ -4183,7 +4193,7 @@ JSTerm.prototype = {
|
|||
*/
|
||||
hasMultilineInput: function JST_hasMultilineInput()
|
||||
{
|
||||
return /[\r\n]/.test(this.inputNode.value);
|
||||
return /[\r\n]/.test(this.getInputValue());
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -4253,7 +4263,7 @@ JSTerm.prototype = {
|
|||
* completion and the input value stayed the same compared to the
|
||||
* last time this function was called, then the same completion is
|
||||
* used again. If there is only one possible completion, then
|
||||
* the inputNode.value is set to this value and the selection is set
|
||||
* the this.getInputValue() is set to this value and the selection is set
|
||||
* from the current cursor position to the end of the completed text.
|
||||
* @param function callback
|
||||
* Optional function invoked when the autocomplete properties are
|
||||
|
@ -4264,7 +4274,7 @@ JSTerm.prototype = {
|
|||
complete: function JSTF_complete(type, callback)
|
||||
{
|
||||
let inputNode = this.inputNode;
|
||||
let inputValue = inputNode.value;
|
||||
let inputValue = this.getInputValue();
|
||||
let frameActor = this.getFrameActor(this.SELECTED_FRAME);
|
||||
|
||||
// If the inputNode has no value, then don't try to complete on it.
|
||||
|
@ -4328,13 +4338,14 @@ JSTerm.prototype = {
|
|||
function JST__updateCompletionResult(type, callback)
|
||||
{
|
||||
let frameActor = this.getFrameActor(this.SELECTED_FRAME);
|
||||
if (this.lastCompletion.value == this.inputNode.value && frameActor == this._lastFrameActorId) {
|
||||
if (this.lastCompletion.value == this.getInputValue() &&
|
||||
frameActor == this._lastFrameActorId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let requestId = gSequenceId();
|
||||
let cursor = this.inputNode.selectionStart;
|
||||
let input = this.inputNode.value.substring(0, cursor);
|
||||
let input = this.getInputValue().substring(0, cursor);
|
||||
let cache = this._autocompleteCache;
|
||||
|
||||
// If the current input starts with the previous input, then we already
|
||||
|
@ -4404,7 +4415,7 @@ JSTerm.prototype = {
|
|||
function JST__receiveAutocompleteProperties(requestId, callback, message)
|
||||
{
|
||||
let inputNode = this.inputNode;
|
||||
let inputValue = inputNode.value;
|
||||
let inputValue = this.getInputValue();
|
||||
if (this.lastCompletion.value == inputValue ||
|
||||
requestId != this.lastCompletion.requestId) {
|
||||
return;
|
||||
|
@ -4441,7 +4452,7 @@ JSTerm.prototype = {
|
|||
};
|
||||
|
||||
if (items.length > 1 && !popup.isOpen) {
|
||||
let str = this.inputNode.value.substr(0, this.inputNode.selectionStart);
|
||||
let str = this.getInputValue().substr(0, this.inputNode.selectionStart);
|
||||
let offset = str.length - (str.lastIndexOf("\n") + 1) - lastPart.length;
|
||||
let x = offset * this.hud._inputCharWidth;
|
||||
popup.openPopup(inputNode, x + this.hud._chevronWidth);
|
||||
|
@ -4475,7 +4486,7 @@ JSTerm.prototype = {
|
|||
onAutocompleteSelect: function JSTF_onAutocompleteSelect()
|
||||
{
|
||||
// Render the suggestion only if the cursor is at the end of the input.
|
||||
if (this.inputNode.selectionStart != this.inputNode.value.length) {
|
||||
if (this.inputNode.selectionStart != this.getInputValue().length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4521,7 +4532,7 @@ JSTerm.prototype = {
|
|||
let suffix = currentItem.label.substring(this.lastCompletion.
|
||||
matchProp.length);
|
||||
let cursor = this.inputNode.selectionStart;
|
||||
let value = this.inputNode.value;
|
||||
let value = this.getInputValue();
|
||||
this.setInputValue(value.substr(0, cursor) + suffix + value.substr(cursor));
|
||||
let newCursor = cursor + suffix.length;
|
||||
this.inputNode.selectionStart = this.inputNode.selectionEnd = newCursor;
|
||||
|
@ -4542,7 +4553,7 @@ JSTerm.prototype = {
|
|||
updateCompleteNode: function JSTF_updateCompleteNode(suffix)
|
||||
{
|
||||
// completion prefix = input, with non-control chars replaced by spaces
|
||||
let prefix = suffix ? this.inputNode.value.replace(/[\S]/g, " ") : "";
|
||||
let prefix = suffix ? this.getInputValue().replace(/[\S]/g, " ") : "";
|
||||
this.completeNode.value = prefix + suffix;
|
||||
},
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ var AnimationPlayerActor = ActorClass({
|
|||
|
||||
this.onAnimationMutation = this.onAnimationMutation.bind(this);
|
||||
|
||||
this.walker = animationsActor.walker;
|
||||
this.tabActor = animationsActor.tabActor;
|
||||
this.player = player;
|
||||
this.node = player.effect.target;
|
||||
|
@ -89,7 +90,9 @@ var AnimationPlayerActor = ActorClass({
|
|||
if (this.observer && !Cu.isDeadWrapper(this.observer)) {
|
||||
this.observer.disconnect();
|
||||
}
|
||||
this.tabActor = this.player = this.node = this.styles = this.observer = null;
|
||||
this.tabActor = this.player = this.node = this.styles = null;
|
||||
this.observer = this.walker = null;
|
||||
|
||||
Actor.prototype.destroy.call(this);
|
||||
},
|
||||
|
||||
|
@ -107,6 +110,12 @@ var AnimationPlayerActor = ActorClass({
|
|||
let data = this.getCurrentState();
|
||||
data.actor = this.actorID;
|
||||
|
||||
// If we know the WalkerActor, and if the animated node is known by it, then
|
||||
// return its corresponding NodeActor ID too.
|
||||
if (this.walker && this.walker.hasNode(this.node)) {
|
||||
data.animationTargetNodeActorID = this.walker.getNode(this.node).actorID;
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
|
@ -381,6 +390,18 @@ var AnimationPlayerFront = FrontClass(AnimationPlayerActor, {
|
|||
Front.prototype.destroy.call(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* If the AnimationsActor was given a reference to the WalkerActor previously
|
||||
* then calling this getter will return the animation target NodeFront.
|
||||
*/
|
||||
get animationTargetNodeFront() {
|
||||
if (!this._form.animationTargetNodeActorID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.conn.getActor(this._form.animationTargetNodeActorID);
|
||||
},
|
||||
|
||||
/**
|
||||
* Getter for the initial state of the player. Up to date states can be
|
||||
* retrieved by calling the getCurrentState method.
|
||||
|
@ -495,7 +516,7 @@ var AnimationsActor = exports.AnimationsActor = ActorClass({
|
|||
events.off(this.tabActor, "navigate", this.onNavigate);
|
||||
|
||||
this.stopAnimationPlayerUpdates();
|
||||
this.tabActor = this.observer = this.actors = null;
|
||||
this.tabActor = this.observer = this.actors = this.walker = null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -506,6 +527,23 @@ var AnimationsActor = exports.AnimationsActor = ActorClass({
|
|||
this.destroy();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clients can optionally call this with a reference to their WalkerActor.
|
||||
* If they do, then AnimationPlayerActor's forms are going to also include
|
||||
* NodeActor IDs when the corresponding NodeActors do exist.
|
||||
* This, in turns, is helpful for clients to avoid having to go back once more
|
||||
* to the server to get a NodeActor for a particular animation.
|
||||
* @param {WalkerActor} walker
|
||||
*/
|
||||
setWalkerActor: method(function(walker) {
|
||||
this.walker = walker;
|
||||
}, {
|
||||
request: {
|
||||
walker: Arg(0, "domwalker")
|
||||
},
|
||||
response: {}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Retrieve the list of AnimationPlayerActor actors for currently running
|
||||
* animations on a node and its descendants.
|
||||
|
|
|
@ -1367,7 +1367,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
let target = current.target;
|
||||
|
||||
if (this._refMap.has(target)) {
|
||||
let actor = this._refMap.get(target);
|
||||
let actor = this.getNode(target);
|
||||
let mutation = {
|
||||
type: "events",
|
||||
target: actor.actorID,
|
||||
|
@ -1469,13 +1469,30 @@ var WalkerActor = protocol.ActorClass({
|
|||
protocol.Actor.prototype.unmanage.call(this, actor);
|
||||
},
|
||||
|
||||
hasNode: function(node) {
|
||||
return this._refMap.has(node);
|
||||
/**
|
||||
* Determine if the walker has come across this DOM node before.
|
||||
* @param {DOMNode} rawNode
|
||||
* @return {Boolean}
|
||||
*/
|
||||
hasNode: function(rawNode) {
|
||||
return this._refMap.has(rawNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* If the walker has come across this DOM node before, then get the
|
||||
* corresponding node actor.
|
||||
* @param {DOMNode} rawNode
|
||||
* @return {NodeActor}
|
||||
*/
|
||||
getNode: function(rawNode) {
|
||||
return this._refMap.get(rawNode);
|
||||
},
|
||||
|
||||
_ref: function(node) {
|
||||
let actor = this._refMap.get(node);
|
||||
if (actor) return actor;
|
||||
let actor = this.getNode(node);
|
||||
if (actor) {
|
||||
return actor;
|
||||
}
|
||||
|
||||
actor = new NodeActor(this, node);
|
||||
|
||||
|
@ -1763,7 +1780,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
|
||||
let child = walker.firstChild();
|
||||
while (child) {
|
||||
let childActor = this._refMap.get(child);
|
||||
let childActor = this.getNode(child);
|
||||
if (childActor) {
|
||||
this.releaseNode(childActor, options);
|
||||
}
|
||||
|
@ -1789,7 +1806,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
let walker = this.getDocumentWalker(node.rawNode);
|
||||
let cur;
|
||||
while ((cur = walker.parentNode())) {
|
||||
let parent = this._refMap.get(cur);
|
||||
let parent = this.getNode(cur);
|
||||
if (!parent) {
|
||||
// This parent didn't exist, so hasn't been seen by the client yet.
|
||||
newParents.add(this._ref(cur));
|
||||
|
@ -2942,7 +2959,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
events.emit(this, "any-mutation");
|
||||
|
||||
for (let change of mutations) {
|
||||
let targetActor = this._refMap.get(change.target);
|
||||
let targetActor = this.getNode(change.target);
|
||||
if (!targetActor) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2972,7 +2989,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
let removedActors = [];
|
||||
let addedActors = [];
|
||||
for (let removed of change.removedNodes) {
|
||||
let removedActor = this._refMap.get(removed);
|
||||
let removedActor = this.getNode(removed);
|
||||
if (!removedActor) {
|
||||
// If the client never encountered this actor we don't need to
|
||||
// mention that it was removed.
|
||||
|
@ -2983,7 +3000,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
removedActors.push(removedActor.actorID);
|
||||
}
|
||||
for (let added of change.addedNodes) {
|
||||
let addedActor = this._refMap.get(added);
|
||||
let addedActor = this.getNode(added);
|
||||
if (!addedActor) {
|
||||
// If the client never encounted this actor we don't need to tell
|
||||
// it about its addition for ownership tree purposes - if the
|
||||
|
@ -3021,7 +3038,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
return;
|
||||
}
|
||||
let frame = getFrameElement(window);
|
||||
let frameActor = this._refMap.get(frame);
|
||||
let frameActor = this.getNode(frame);
|
||||
if (!frameActor) {
|
||||
return;
|
||||
}
|
||||
|
@ -3076,7 +3093,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
}
|
||||
|
||||
let doc = window.document;
|
||||
let documentActor = this._refMap.get(doc);
|
||||
let documentActor = this.getNode(doc);
|
||||
if (!documentActor) {
|
||||
return;
|
||||
}
|
||||
|
@ -3098,7 +3115,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
// they should reread the children list.
|
||||
this.queueMutation({
|
||||
type: "childList",
|
||||
target: this._refMap.get(parentNode).actorID,
|
||||
target: this.getNode(parentNode).actorID,
|
||||
added: [],
|
||||
removed: []
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu} = require("chrome");
|
||||
const {Cc, Ci} = require("chrome");
|
||||
const promise = require("promise");
|
||||
const protocol = require("devtools/server/protocol");
|
||||
const {Arg, Option, method, RetVal, types} = protocol;
|
||||
|
@ -572,7 +572,8 @@ var PageStyleActor = protocol.ActorClass({
|
|||
|
||||
this.cssLogic.highlight(node.rawNode);
|
||||
let entries = [];
|
||||
entries = entries.concat(this._getAllElementRules(node, undefined, options));
|
||||
entries = entries.concat(this._getAllElementRules(node, undefined,
|
||||
options));
|
||||
|
||||
let result = this.getAppliedProps(node, entries, options);
|
||||
for (let rule of result.rules) {
|
||||
|
@ -611,7 +612,8 @@ var PageStyleActor = protocol.ActorClass({
|
|||
* - pseudoElement String
|
||||
*/
|
||||
_getAllElementRules: function(node, inherited, options) {
|
||||
let {bindingElement, pseudo} = CssLogic.getBindingElementAndPseudo(node.rawNode);
|
||||
let {bindingElement, pseudo} =
|
||||
CssLogic.getBindingElementAndPseudo(node.rawNode);
|
||||
let rules = [];
|
||||
|
||||
if (!bindingElement || !bindingElement.style) {
|
||||
|
@ -644,20 +646,23 @@ var PageStyleActor = protocol.ActorClass({
|
|||
// Add normal rules. Typically this is passing in the node passed into the
|
||||
// function, unless if that node was ::before/::after. In which case,
|
||||
// it will pass in the parentNode along with "::before"/"::after".
|
||||
this._getElementRules(bindingElement, pseudo, inherited, options).forEach(rule => {
|
||||
// The only case when there would be a pseudo here is ::before/::after,
|
||||
// and in this case we want to tell the view that it belongs to the
|
||||
// element (which is a _moz_generated_content native anonymous element).
|
||||
rule.pseudoElement = null;
|
||||
rules.push(rule);
|
||||
this._getElementRules(bindingElement, pseudo, inherited, options)
|
||||
.forEach(oneRule => {
|
||||
// The only case when there would be a pseudo here is
|
||||
// ::before/::after, and in this case we want to tell the
|
||||
// view that it belongs to the element (which is a
|
||||
// _moz_generated_content native anonymous element).
|
||||
oneRule.pseudoElement = null;
|
||||
rules.push(oneRule);
|
||||
});
|
||||
|
||||
// Now any pseudos (except for ::before / ::after, which was handled as
|
||||
// a 'normal rule' above.
|
||||
if (showElementStyles) {
|
||||
for (let pseudo of PSEUDO_ELEMENTS_TO_READ) {
|
||||
this._getElementRules(bindingElement, pseudo, inherited, options).forEach(rule => {
|
||||
rules.push(rule);
|
||||
for (let readPseudo of PSEUDO_ELEMENTS_TO_READ) {
|
||||
this._getElementRules(bindingElement, readPseudo, inherited, options)
|
||||
.forEach(oneRule => {
|
||||
rules.push(oneRule);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -741,7 +746,8 @@ var PageStyleActor = protocol.ActorClass({
|
|||
if (options.inherited) {
|
||||
let parent = this.walker.parentNode(node);
|
||||
while (parent && parent.rawNode.nodeType != Ci.nsIDOMNode.DOCUMENT_NODE) {
|
||||
entries = entries.concat(this._getAllElementRules(parent, parent, options));
|
||||
entries = entries.concat(this._getAllElementRules(parent, parent,
|
||||
options));
|
||||
parent = this.walker.parentNode(parent);
|
||||
}
|
||||
}
|
||||
|
@ -756,10 +762,12 @@ var PageStyleActor = protocol.ActorClass({
|
|||
let selectors = CssLogic.getSelectors(domRule);
|
||||
let element = entry.inherited ? entry.inherited.rawNode : node.rawNode;
|
||||
|
||||
let {bindingElement, pseudo} = CssLogic.getBindingElementAndPseudo(element);
|
||||
let {bindingElement, pseudo} =
|
||||
CssLogic.getBindingElementAndPseudo(element);
|
||||
entry.matchedSelectors = [];
|
||||
for (let i = 0; i < selectors.length; i++) {
|
||||
if (DOMUtils.selectorMatchesElement(bindingElement, domRule, i, pseudo)) {
|
||||
if (DOMUtils.selectorMatchesElement(bindingElement, domRule, i,
|
||||
pseudo)) {
|
||||
entry.matchedSelectors.push(selectors[i]);
|
||||
}
|
||||
}
|
||||
|
@ -1005,9 +1013,9 @@ var PageStyleActor = protocol.ActorClass({
|
|||
exports.PageStyleActor = PageStyleActor;
|
||||
|
||||
/**
|
||||
* Front object for the PageStyleActor
|
||||
* PageStyleFront, the front object for the PageStyleActor
|
||||
*/
|
||||
var PageStyleFront = protocol.FrontClass(PageStyleActor, {
|
||||
protocol.FrontClass(PageStyleActor, {
|
||||
initialize: function(conn, form, ctx, detail) {
|
||||
protocol.Front.prototype.initialize.call(this, conn, form, ctx, detail);
|
||||
this.inspector = this.parent();
|
||||
|
@ -1041,7 +1049,7 @@ var PageStyleFront = protocol.FrontClass(PageStyleActor, {
|
|||
impl: "_getMatchedSelectors"
|
||||
}),
|
||||
|
||||
getApplied: protocol.custom(Task.async(function*(node, options={}) {
|
||||
getApplied: protocol.custom(Task.async(function*(node, options = {}) {
|
||||
// If the getApplied method doesn't recreate the style cache itself, this
|
||||
// means a call to cssLogic.highlight is required before trying to access
|
||||
// the applied rules. Issue a request to getLayout if this is the case.
|
||||
|
@ -1126,7 +1134,7 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
return this.pageStyle.conn;
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
destroy: function() {
|
||||
if (!this.rawStyle) {
|
||||
return;
|
||||
}
|
||||
|
@ -1175,7 +1183,7 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
},
|
||||
|
||||
toString: function() {
|
||||
return "[StyleRuleActor for " + this.rawRule + "]"
|
||||
return "[StyleRuleActor for " + this.rawRule + "]";
|
||||
},
|
||||
|
||||
form: function(detail) {
|
||||
|
@ -1199,7 +1207,8 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
};
|
||||
|
||||
if (this.rawRule.parentRule) {
|
||||
form.parentRule = this.pageStyle._styleRef(this.rawRule.parentRule).actorID;
|
||||
form.parentRule =
|
||||
this.pageStyle._styleRef(this.rawRule.parentRule).actorID;
|
||||
|
||||
// CSS rules that we call media rules are STYLE_RULES that are children
|
||||
// of MEDIA_RULEs. We need to check the parentRule to check if a rule is
|
||||
|
@ -1213,7 +1222,8 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
}
|
||||
}
|
||||
if (this._parentSheet) {
|
||||
form.parentStyleSheet = this.pageStyle._sheetRef(this._parentSheet).actorID;
|
||||
form.parentStyleSheet =
|
||||
this.pageStyle._sheetRef(this._parentSheet).actorID;
|
||||
}
|
||||
|
||||
// One tricky thing here is that other methods in this actor must
|
||||
|
@ -1519,7 +1529,7 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
parentStyleSheet.insertRule(value + " " + ruleText, i);
|
||||
parentStyleSheet.deleteRule(i + 1);
|
||||
break;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// The selector could be invalid, or the rule could fail to insert.
|
||||
return null;
|
||||
}
|
||||
|
@ -1550,7 +1560,7 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
|
||||
let document = this.getDocument(this._parentSheet);
|
||||
// Extract the selector, and pseudo elements and classes
|
||||
let [selector, pseudoProp] = value.split(/(:{1,2}.+$)/);
|
||||
let [selector] = value.split(/(:{1,2}.+$)/);
|
||||
let selectorElement;
|
||||
|
||||
try {
|
||||
|
@ -1625,7 +1635,7 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
let isMatching = false;
|
||||
try {
|
||||
isMatching = node.rawNode.matches(value);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// This fails when value is an invalid selector.
|
||||
}
|
||||
|
||||
|
@ -1642,9 +1652,9 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
});
|
||||
|
||||
/**
|
||||
* Front for the StyleRule actor.
|
||||
* StyleRuleFront, the front for the StyleRule actor.
|
||||
*/
|
||||
var StyleRuleFront = protocol.FrontClass(StyleRuleActor, {
|
||||
protocol.FrontClass(StyleRuleActor, {
|
||||
initialize: function(client, form, ctx, detail) {
|
||||
protocol.Front.prototype.initialize.call(this, client, form, ctx, detail);
|
||||
},
|
||||
|
@ -1910,9 +1920,13 @@ var RuleModificationList = Class({
|
|||
* generally for setting properties
|
||||
* on an element's style.
|
||||
* @param {String} name current name of the property
|
||||
*
|
||||
* This parameter is also passed, but as it is not used in this
|
||||
* implementation, it is omitted. It is documented here as this
|
||||
* code also defined the interface implemented by @see RuleRewriter.
|
||||
* @param {String} newName new name of the property
|
||||
*/
|
||||
renameProperty: function(index, name, newName) {
|
||||
renameProperty: function(index, name) {
|
||||
this.removeProperty(index, name);
|
||||
},
|
||||
|
||||
|
@ -1940,6 +1954,11 @@ var RuleModificationList = Class({
|
|||
* Create a new property. This implementation does nothing, because
|
||||
* |setRuleText| is not available.
|
||||
*
|
||||
* These parameter are passed, but as they are not used in this
|
||||
* implementation, they are omitted. They are documented here as
|
||||
* this code also defined the interface implemented by @see
|
||||
* RuleRewriter.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* This can be -1 in the case where
|
||||
* the rule does not support setRuleText;
|
||||
|
@ -1950,7 +1969,7 @@ var RuleModificationList = Class({
|
|||
* @param {String} priority priority of the new property; either
|
||||
* the empty string or "important"
|
||||
*/
|
||||
createProperty: function(index, name, value, priority) {
|
||||
createProperty: function() {
|
||||
// Nothing.
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1032,6 +1032,9 @@ WebConsoleActor.prototype =
|
|||
if (key == "NetworkMonitor.saveRequestAndResponseBodies" &&
|
||||
this.networkMonitor) {
|
||||
this.networkMonitor.saveRequestAndResponseBodies = this._prefs[key];
|
||||
if (this.networkMonitorChild) {
|
||||
this.networkMonitorChild.saveRequestAndResponseBodies = this._prefs[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return { updated: Object.keys(aRequest.preferences) };
|
||||
|
|
|
@ -181,6 +181,8 @@ DominatorTreeNode.getLabelAndShallowSize = function (nodeId,
|
|||
* `maxSiblings` within any single node's children.
|
||||
*
|
||||
* @param {DominatorTree} dominatorTree
|
||||
* @param {HeapSnapshot} snapshot
|
||||
* @param {Object} breakdown
|
||||
* @param {Number} maxDepth
|
||||
* @param {Number} maxSiblings
|
||||
*
|
||||
|
@ -204,7 +206,7 @@ DominatorTreeNode.partialTraversal = function (dominatorTree,
|
|||
for (let i = 0; i < endIdx; i++) {
|
||||
DominatorTreeNode.addChild(node, dfs(childNodeIds[i], newDepth));
|
||||
}
|
||||
node.moreChildrenAvailable = childNodeIds.length < endIdx;
|
||||
node.moreChildrenAvailable = endIdx < childNodeIds.length;
|
||||
} else {
|
||||
node.moreChildrenAvailable = childNodeIds.length > 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that we correctly set `moreChildrenAvailable` when doing a partial
|
||||
// traversal of a dominator tree to create the initial incrementally loaded
|
||||
// `DominatorTreeNode` tree.
|
||||
|
||||
// `tree` maps parent to children:
|
||||
//
|
||||
// 100
|
||||
// |- 200
|
||||
// | |- 500
|
||||
// | |- 600
|
||||
// | `- 700
|
||||
// |- 300
|
||||
// | |- 800
|
||||
// | |- 900
|
||||
// `- 400
|
||||
// |- 1000
|
||||
// |- 1100
|
||||
// `- 1200
|
||||
const tree = new Map([
|
||||
[100, [200, 300, 400]],
|
||||
[200, [500, 600, 700]],
|
||||
[300, [800, 900]],
|
||||
[400, [1000, 1100, 1200]]
|
||||
]);
|
||||
|
||||
const mockDominatorTree = {
|
||||
root: 100,
|
||||
getRetainedSize: _ => 10,
|
||||
getImmediatelyDominated: id => (tree.get(id) || []).slice()
|
||||
};
|
||||
|
||||
const mockSnapshot = {
|
||||
describeNode: _ => ({
|
||||
objects: { count: 0, bytes: 0 },
|
||||
strings: { count: 0, bytes: 0 },
|
||||
scripts: { count: 0, bytes: 0 },
|
||||
other: { SomeType: { count: 1, bytes: 10 } }
|
||||
})
|
||||
};
|
||||
|
||||
const breakdown = {
|
||||
by: "coarseType",
|
||||
objects: { by: "count", count: true, bytes: true },
|
||||
strings: { by: "count", count: true, bytes: true },
|
||||
scripts: { by: "count", count: true, bytes: true },
|
||||
other: {
|
||||
by: "internalType",
|
||||
then: { by: "count", count: true, bytes: true }
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
nodeId: 100,
|
||||
label: [
|
||||
"other",
|
||||
"SomeType"
|
||||
],
|
||||
shallowSize: 10,
|
||||
retainedSize: 10,
|
||||
children: [
|
||||
{
|
||||
nodeId: 200,
|
||||
label: [
|
||||
"other",
|
||||
"SomeType"
|
||||
],
|
||||
shallowSize: 10,
|
||||
retainedSize: 10,
|
||||
parentId: 100,
|
||||
children: [
|
||||
{
|
||||
nodeId: 500,
|
||||
label: [
|
||||
"other",
|
||||
"SomeType"
|
||||
],
|
||||
shallowSize: 10,
|
||||
retainedSize: 10,
|
||||
parentId: 200,
|
||||
moreChildrenAvailable: false,
|
||||
children: undefined
|
||||
},
|
||||
{
|
||||
nodeId: 600,
|
||||
label: [
|
||||
"other",
|
||||
"SomeType"
|
||||
],
|
||||
shallowSize: 10,
|
||||
retainedSize: 10,
|
||||
parentId: 200,
|
||||
moreChildrenAvailable: false,
|
||||
children: undefined
|
||||
}
|
||||
],
|
||||
moreChildrenAvailable: true
|
||||
},
|
||||
{
|
||||
nodeId: 300,
|
||||
label: [
|
||||
"other",
|
||||
"SomeType"
|
||||
],
|
||||
shallowSize: 10,
|
||||
retainedSize: 10,
|
||||
parentId: 100,
|
||||
children: [
|
||||
{
|
||||
nodeId: 800,
|
||||
label: [
|
||||
"other",
|
||||
"SomeType"
|
||||
],
|
||||
shallowSize: 10,
|
||||
retainedSize: 10,
|
||||
parentId: 300,
|
||||
moreChildrenAvailable: false,
|
||||
children: undefined
|
||||
},
|
||||
{
|
||||
nodeId: 900,
|
||||
label: [
|
||||
"other",
|
||||
"SomeType"
|
||||
],
|
||||
shallowSize: 10,
|
||||
retainedSize: 10,
|
||||
parentId: 300,
|
||||
moreChildrenAvailable: false,
|
||||
children: undefined
|
||||
}
|
||||
],
|
||||
moreChildrenAvailable: false
|
||||
}
|
||||
],
|
||||
moreChildrenAvailable: true,
|
||||
parentId: undefined,
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
// Traverse the whole depth of the test tree, but one short of the number of
|
||||
// siblings. This will exercise the moreChildrenAvailable handling for
|
||||
// siblings.
|
||||
const actual = DominatorTreeNode.partialTraversal(mockDominatorTree,
|
||||
mockSnapshot,
|
||||
breakdown,
|
||||
/* maxDepth = */ 4,
|
||||
/* siblings = */ 2);
|
||||
|
||||
dumpn("Expected = " + JSON.stringify(expected, null, 2));
|
||||
dumpn("Actual = " + JSON.stringify(actual, null, 2));
|
||||
|
||||
assertStructurallyEquivalent(expected, actual);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that the retained size of a node is the sum of its children retained
|
||||
// sizes plus its shallow size.
|
||||
|
||||
// Note that we don't assert directly, only if we get an unexpected
|
||||
// value. There are just way too many nodes in the heap graph to assert for
|
||||
// every one. This test would constantly time out and assertion messages would
|
||||
// overflow the log size.
|
||||
function fastAssert(cond, msg) {
|
||||
if (!cond) {
|
||||
ok(false, msg);
|
||||
}
|
||||
}
|
||||
|
||||
var COUNT = { by: "count", count: false, bytes: true };
|
||||
|
||||
function run_test() {
|
||||
var path = saveNewHeapSnapshot();
|
||||
var snapshot = ChromeUtils.readHeapSnapshot(path);
|
||||
var dominatorTree = snapshot.computeDominatorTree();
|
||||
|
||||
// Do a traversal of the dominator tree and assert the relationship between
|
||||
// retained size, shallow size, and children's retained sizes.
|
||||
|
||||
var root = dominatorTree.root;
|
||||
var stack = [root];
|
||||
while (stack.length > 0) {
|
||||
var top = stack.pop();
|
||||
|
||||
var children = dominatorTree.getImmediatelyDominated(top);
|
||||
|
||||
var topRetainedSize = dominatorTree.getRetainedSize(top);
|
||||
var topShallowSize = snapshot.describeNode(COUNT, top).bytes;
|
||||
fastAssert(topShallowSize <= topRetainedSize,
|
||||
"The shallow size should be less than or equal to the " +
|
||||
"retained size");
|
||||
|
||||
var sumOfChildrensRetainedSizes = 0;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
sumOfChildrensRetainedSizes += dominatorTree.getRetainedSize(children[i]);
|
||||
stack.push(children[i]);
|
||||
}
|
||||
|
||||
fastAssert(sumOfChildrensRetainedSizes <= topRetainedSize,
|
||||
"The sum of the children's retained sizes should be less than " +
|
||||
"or equal to the retained size");
|
||||
fastAssert(sumOfChildrensRetainedSizes + topShallowSize === topRetainedSize,
|
||||
"The sum of the children's retained sizes plus the shallow " +
|
||||
"size should be equal to the retained size");
|
||||
}
|
||||
|
||||
ok(true, "Successfully walked the tree");
|
||||
do_test_finished();
|
||||
}
|
|
@ -33,6 +33,7 @@ support-files =
|
|||
[test_DominatorTree_03.js]
|
||||
[test_DominatorTree_04.js]
|
||||
[test_DominatorTree_05.js]
|
||||
[test_DominatorTree_06.js]
|
||||
[test_DominatorTreeNode_getNodeByIdAlongPath_01.js]
|
||||
[test_DominatorTreeNode_insert_01.js]
|
||||
[test_DominatorTreeNode_insert_02.js]
|
||||
|
@ -41,6 +42,7 @@ support-files =
|
|||
[test_DominatorTreeNode_LabelAndShallowSize_02.js]
|
||||
[test_DominatorTreeNode_LabelAndShallowSize_03.js]
|
||||
[test_DominatorTreeNode_LabelAndShallowSize_04.js]
|
||||
[test_DominatorTreeNode_partialTraversal_01.js]
|
||||
[test_HeapAnalyses_computeDominatorTree_01.js]
|
||||
[test_HeapAnalyses_computeDominatorTree_02.js]
|
||||
[test_HeapAnalyses_deleteHeapSnapshot_01.js]
|
||||
|
|
|
@ -223,8 +223,10 @@ NetworkResponseListener.prototype = {
|
|||
// In the multi-process mode, the conversion happens on the child side while we can
|
||||
// only monitor the channel on the parent side. If the content is gzipped, we have
|
||||
// to unzip it ourself. For that we use the stream converter services.
|
||||
// Do not do that for Service workers as they are run in the child process.
|
||||
let channel = this.request;
|
||||
if (channel instanceof Ci.nsIEncodedChannel &&
|
||||
if (!this.httpActivity.fromServiceWorker &&
|
||||
channel instanceof Ci.nsIEncodedChannel &&
|
||||
channel.contentEncodings &&
|
||||
!channel.applyConversion) {
|
||||
let encodingHeader = channel.getResponseHeader("Content-Encoding");
|
||||
|
@ -860,6 +862,7 @@ NetworkMonitor.prototype = {
|
|||
event.startedDateTime = (timestamp ? new Date(Math.round(timestamp / 1000)) : new Date()).toISOString();
|
||||
event.fromCache = fromCache;
|
||||
event.fromServiceWorker = fromServiceWorker;
|
||||
httpActivity.fromServiceWorker = fromServiceWorker;
|
||||
|
||||
if (extraStringData) {
|
||||
event.headersSize = extraStringData.length;
|
||||
|
|
|
@ -228,6 +228,10 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
|||
}
|
||||
|
||||
BluetoothA2dpManager::~BluetoothA2dpManager()
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::Uninit()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE_VOID(obs);
|
||||
|
@ -273,9 +277,9 @@ BluetoothA2dpManager::Get()
|
|||
// If we're in shutdown, don't create a new instance
|
||||
NS_ENSURE_FALSE(sInShutdown, nullptr);
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothA2dpManager* manager = new BluetoothA2dpManager();
|
||||
sBluetoothA2dpManager = manager;
|
||||
// Create a new instance and return
|
||||
sBluetoothA2dpManager = new BluetoothA2dpManager();
|
||||
|
||||
return sBluetoothA2dpManager;
|
||||
}
|
||||
|
||||
|
@ -297,6 +301,9 @@ public:
|
|||
sBtA2dpInterface->SetNotificationHandler(nullptr);
|
||||
sBtA2dpInterface = nullptr;
|
||||
|
||||
sBluetoothA2dpManager->Uninit();
|
||||
sBluetoothA2dpManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
@ -309,6 +316,9 @@ public:
|
|||
sBtA2dpInterface->SetNotificationHandler(nullptr);
|
||||
sBtA2dpInterface = nullptr;
|
||||
|
||||
sBluetoothA2dpManager->Uninit();
|
||||
sBluetoothA2dpManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ private:
|
|||
|
||||
BluetoothA2dpManager();
|
||||
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
||||
|
|
|
@ -268,6 +268,10 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
|||
}
|
||||
|
||||
BluetoothAvrcpManager::~BluetoothAvrcpManager()
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::Uninit()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE_VOID(obs);
|
||||
|
@ -294,9 +298,9 @@ BluetoothAvrcpManager::Get()
|
|||
// If we're in shutdown, don't create a new instance
|
||||
NS_ENSURE_FALSE(sInShutdown, nullptr);
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothAvrcpManager* manager = new BluetoothAvrcpManager();
|
||||
sBluetoothAvrcpManager = manager;
|
||||
// Create a new instance and return
|
||||
sBluetoothAvrcpManager = new BluetoothAvrcpManager();
|
||||
|
||||
return sBluetoothAvrcpManager;
|
||||
}
|
||||
|
||||
|
@ -318,6 +322,9 @@ public:
|
|||
sBtAvrcpInterface->SetNotificationHandler(nullptr);
|
||||
sBtAvrcpInterface = nullptr;
|
||||
|
||||
sBluetoothAvrcpManager->Uninit();
|
||||
sBluetoothAvrcpManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
@ -330,6 +337,9 @@ public:
|
|||
sBtAvrcpInterface->SetNotificationHandler(nullptr);
|
||||
sBtAvrcpInterface = nullptr;
|
||||
|
||||
sBluetoothAvrcpManager->Uninit();
|
||||
sBluetoothAvrcpManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ private:
|
|||
|
||||
BluetoothAvrcpManager();
|
||||
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
||||
|
|
|
@ -389,26 +389,39 @@ BluetoothGattManager::Get()
|
|||
NS_ENSURE_FALSE(mInShutdown, nullptr);
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothGattManager* manager = new BluetoothGattManager();
|
||||
NS_ENSURE_TRUE(manager->Init(), nullptr);
|
||||
RefPtr<BluetoothGattManager> manager = new BluetoothGattManager();
|
||||
NS_ENSURE_SUCCESS(manager->Init(), nullptr);
|
||||
|
||||
sBluetoothGattManager = manager;
|
||||
|
||||
return sBluetoothGattManager;
|
||||
}
|
||||
|
||||
bool
|
||||
nsresult
|
||||
BluetoothGattManager::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE(obs, false);
|
||||
NS_ENSURE_TRUE(obs, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
|
||||
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
BT_WARNING("Failed to add observers!");
|
||||
return false;
|
||||
return rv;
|
||||
}
|
||||
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::Uninit()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE_VOID(obs);
|
||||
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
|
||||
BT_WARNING("Failed to remove shutdown observer!");
|
||||
}
|
||||
}
|
||||
|
||||
class BluetoothGattManager::RegisterModuleResultHandler final
|
||||
|
@ -569,6 +582,11 @@ public:
|
|||
|
||||
sBluetoothGattInterface->SetNotificationHandler(nullptr);
|
||||
sBluetoothGattInterface = nullptr;
|
||||
sClients = nullptr;
|
||||
sServers = nullptr;
|
||||
|
||||
sBluetoothGattManager->Uninit();
|
||||
sBluetoothGattManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
|
@ -584,6 +602,9 @@ public:
|
|||
sClients = nullptr;
|
||||
sServers = nullptr;
|
||||
|
||||
sBluetoothGattManager->Uninit();
|
||||
sBluetoothGattManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
}
|
||||
|
@ -4090,13 +4111,7 @@ BluetoothGattManager::BluetoothGattManager()
|
|||
{ }
|
||||
|
||||
BluetoothGattManager::~BluetoothGattManager()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE_VOID(obs);
|
||||
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
|
||||
BT_WARNING("Failed to remove shutdown observer!");
|
||||
}
|
||||
}
|
||||
{ }
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothGattManager::Observe(nsISupports* aSubject,
|
||||
|
|
|
@ -216,8 +216,9 @@ private:
|
|||
class ServerSendIndicationResultHandler;
|
||||
|
||||
BluetoothGattManager();
|
||||
bool Init();
|
||||
|
||||
nsresult Init();
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
|
||||
void RegisterClientNotification(BluetoothGattStatus aStatus,
|
||||
|
|
|
@ -84,6 +84,8 @@ BluetoothMapSmsManager::HandleShutdown()
|
|||
|
||||
sInShutdown = true;
|
||||
Disconnect(nullptr);
|
||||
Uninit();
|
||||
|
||||
sMapSmsManager = nullptr;
|
||||
}
|
||||
|
||||
|
@ -98,27 +100,19 @@ BluetoothMapSmsManager::BluetoothMapSmsManager()
|
|||
}
|
||||
|
||||
BluetoothMapSmsManager::~BluetoothMapSmsManager()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return;
|
||||
}
|
||||
{ }
|
||||
|
||||
NS_WARN_IF(NS_FAILED(
|
||||
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
|
||||
}
|
||||
|
||||
bool
|
||||
nsresult
|
||||
BluetoothMapSmsManager::Init()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return false;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
|
||||
return false;
|
||||
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,7 +124,64 @@ BluetoothMapSmsManager::Init()
|
|||
* absence of read events when device boots up.
|
||||
*/
|
||||
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothMapSmsManager::Uninit()
|
||||
{
|
||||
if (mMasServerSocket) {
|
||||
mMasServerSocket->SetObserver(nullptr);
|
||||
|
||||
if (mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mMasServerSocket->Close();
|
||||
}
|
||||
mMasServerSocket = nullptr;
|
||||
}
|
||||
|
||||
if (mMasSocket) {
|
||||
mMasSocket->SetObserver(nullptr);
|
||||
|
||||
if (mMasSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mMasSocket->Close();
|
||||
}
|
||||
mMasSocket = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARN_IF(NS_FAILED(
|
||||
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothMapSmsManager::InitMapSmsInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aRes) {
|
||||
aRes->Init();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothMapSmsManager::DeinitMapSmsInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sMapSmsManager) {
|
||||
sMapSmsManager->Uninit();
|
||||
sMapSmsManager = nullptr;
|
||||
}
|
||||
|
||||
if (aRes) {
|
||||
aRes->Deinit();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
|
@ -150,8 +201,8 @@ BluetoothMapSmsManager::Get()
|
|||
}
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothMapSmsManager *manager = new BluetoothMapSmsManager();
|
||||
if (NS_WARN_IF(!manager->Init())) {
|
||||
RefPtr<BluetoothMapSmsManager> manager = new BluetoothMapSmsManager();
|
||||
if (NS_WARN_IF(NS_FAILED(manager->Init()))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -175,10 +226,11 @@ BluetoothMapSmsManager::Listen()
|
|||
* BT stops; otherwise no more read events would be received even if
|
||||
* BT restarts.
|
||||
*/
|
||||
if (mMasServerSocket) {
|
||||
if (mMasServerSocket &&
|
||||
mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mMasServerSocket->Close();
|
||||
mMasServerSocket = nullptr;
|
||||
}
|
||||
mMasServerSocket = nullptr;
|
||||
|
||||
mMasServerSocket = new BluetoothSocket(this);
|
||||
|
||||
|
@ -1510,7 +1562,17 @@ BluetoothMapSmsManager::OnSocketConnectError(BluetoothSocket* aSocket)
|
|||
}
|
||||
|
||||
// MAS socket connection error
|
||||
|
||||
if (mMasServerSocket &&
|
||||
mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mMasServerSocket->Close();
|
||||
}
|
||||
mMasServerSocket = nullptr;
|
||||
|
||||
if (mMasSocket &&
|
||||
mMasSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mMasSocket->Close();
|
||||
}
|
||||
mMasSocket = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1541,6 +1603,7 @@ BluetoothMapSmsManager::OnSocketDisconnect(BluetoothSocket* aSocket)
|
|||
// MAS socket is disconnected
|
||||
AfterMapSmsDisconnected();
|
||||
mDeviceAddress.Clear();
|
||||
|
||||
mMasSocket = nullptr;
|
||||
|
||||
Listen();
|
||||
|
|
|
@ -86,7 +86,10 @@ public:
|
|||
// By defualt SMS/MMS is default supported
|
||||
static const int SDP_SMS_MMS_INSTANCE_ID = 0;
|
||||
|
||||
static void InitMapSmsInterface(BluetoothProfileResultHandler* aRes);
|
||||
static void DeinitMapSmsInterface(BluetoothProfileResultHandler* aRes);
|
||||
static BluetoothMapSmsManager* Get();
|
||||
|
||||
bool Listen();
|
||||
|
||||
/**
|
||||
|
@ -194,7 +197,9 @@ protected:
|
|||
|
||||
private:
|
||||
BluetoothMapSmsManager();
|
||||
bool Init();
|
||||
|
||||
nsresult Init();
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
|
||||
void ReplyToConnect();
|
||||
|
|
|
@ -214,31 +214,24 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
|
|||
{ }
|
||||
|
||||
BluetoothOppManager::~BluetoothOppManager()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE_VOID(obs);
|
||||
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
|
||||
BT_WARNING("Failed to remove shutdown observer!");
|
||||
}
|
||||
{ }
|
||||
|
||||
if (NS_FAILED(obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED))) {
|
||||
BT_WARNING("Failed to remove volume observer!");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsresult
|
||||
BluetoothOppManager::Init()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE(obs, false);
|
||||
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
|
||||
NS_ENSURE_TRUE(obs, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
BT_WARNING("Failed to add shutdown observer!");
|
||||
return false;
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_FAILED(obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false))) {
|
||||
rv = obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
BT_WARNING("Failed to add ns volume observer!");
|
||||
return false;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,7 +243,67 @@ BluetoothOppManager::Init()
|
|||
* absence of read events when device boots up.
|
||||
*/
|
||||
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::Uninit()
|
||||
{
|
||||
if (mServerSocket) {
|
||||
mServerSocket->SetObserver(nullptr);
|
||||
|
||||
if (mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mServerSocket->Close();
|
||||
}
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
|
||||
if (mSocket) {
|
||||
mSocket->SetObserver(nullptr);
|
||||
|
||||
if (mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mSocket->Close();
|
||||
}
|
||||
mSocket = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE_VOID(obs);
|
||||
|
||||
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
|
||||
BT_WARNING("Failed to remove shutdown observer!");
|
||||
}
|
||||
|
||||
if (NS_FAILED(obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED))) {
|
||||
BT_WARNING("Failed to remove volume observer!");
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothOppManager::InitOppInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aRes) {
|
||||
aRes->Init();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothOppManager::DeinitOppInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sBluetoothOppManager) {
|
||||
sBluetoothOppManager->Uninit();
|
||||
sBluetoothOppManager = nullptr;
|
||||
}
|
||||
|
||||
if (aRes) {
|
||||
aRes->Deinit();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
|
@ -268,10 +321,11 @@ BluetoothOppManager::Get()
|
|||
NS_ENSURE_FALSE(sInShutdown, nullptr);
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothOppManager *manager = new BluetoothOppManager();
|
||||
NS_ENSURE_TRUE(manager->Init(), nullptr);
|
||||
RefPtr<BluetoothOppManager> manager = new BluetoothOppManager();
|
||||
NS_ENSURE_SUCCESS(manager->Init(), nullptr);
|
||||
|
||||
sBluetoothOppManager = manager;
|
||||
|
||||
return sBluetoothOppManager;
|
||||
}
|
||||
|
||||
|
@ -281,10 +335,11 @@ BluetoothOppManager::ConnectInternal(const BluetoothAddress& aDeviceAddress)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Stop listening because currently we only support one connection at a time.
|
||||
if (mServerSocket) {
|
||||
if (mServerSocket &&
|
||||
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mServerSocket->Close();
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
mServerSocket = nullptr;
|
||||
|
||||
mIsServer = false;
|
||||
|
||||
|
@ -310,6 +365,8 @@ BluetoothOppManager::HandleShutdown()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sInShutdown = true;
|
||||
Disconnect(nullptr);
|
||||
Uninit();
|
||||
|
||||
sBluetoothOppManager = nullptr;
|
||||
}
|
||||
|
||||
|
@ -356,10 +413,11 @@ BluetoothOppManager::Listen()
|
|||
* BT stops; otherwise no more read events would be received even if
|
||||
* BT restarts.
|
||||
*/
|
||||
if (mServerSocket) {
|
||||
if (mServerSocket &&
|
||||
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mServerSocket->Close();
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
mServerSocket = nullptr;
|
||||
|
||||
mServerSocket = new BluetoothSocket(this);
|
||||
|
||||
|
@ -1526,7 +1584,16 @@ BluetoothOppManager::OnSocketConnectError(BluetoothSocket* aSocket)
|
|||
{
|
||||
BT_LOGR("[%s]", (mIsServer)? "server" : "client");
|
||||
|
||||
if (mServerSocket &&
|
||||
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mServerSocket->Close();
|
||||
}
|
||||
mServerSocket = nullptr;
|
||||
|
||||
if (mSocket &&
|
||||
mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mSocket->Close();
|
||||
}
|
||||
mSocket = nullptr;
|
||||
|
||||
if (!mIsServer) {
|
||||
|
@ -1576,7 +1643,8 @@ BluetoothOppManager::OnSocketDisconnect(BluetoothSocket* aSocket)
|
|||
mDeviceAddress.Clear();
|
||||
mSuccessFlag = false;
|
||||
|
||||
mSocket = nullptr;
|
||||
mSocket = nullptr; // should already be closed
|
||||
|
||||
// Listen as a server if there's no more batch to process
|
||||
if (!ProcessNextBatch()) {
|
||||
Listen();
|
||||
|
|
|
@ -40,6 +40,7 @@ class BluetoothOppManager : public BluetoothSocketObserver
|
|||
class SendSocketDataTask;
|
||||
|
||||
public:
|
||||
|
||||
BT_DECL_PROFILE_MGR_BASE
|
||||
BT_DECL_SOCKET_OBSERVER
|
||||
virtual void GetName(nsACString& aName)
|
||||
|
@ -49,7 +50,10 @@ public:
|
|||
|
||||
static const int MAX_PACKET_LENGTH = 0xFFFE;
|
||||
|
||||
static void InitOppInterface(BluetoothProfileResultHandler* aRes);
|
||||
static void DeinitOppInterface(BluetoothProfileResultHandler* aRes);
|
||||
static BluetoothOppManager* Get();
|
||||
|
||||
void ClientDataHandler(mozilla::ipc::UnixSocketBuffer* aMessage);
|
||||
void ServerDataHandler(mozilla::ipc::UnixSocketBuffer* aMessage);
|
||||
|
||||
|
@ -75,7 +79,8 @@ protected:
|
|||
|
||||
private:
|
||||
BluetoothOppManager();
|
||||
bool Init();
|
||||
nsresult Init();
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
void HandleVolumeStateChanged(nsISupports* aSubject);
|
||||
|
||||
|
|
|
@ -94,6 +94,8 @@ BluetoothPbapManager::HandleShutdown()
|
|||
|
||||
sInShutdown = true;
|
||||
Disconnect(nullptr);
|
||||
Uninit();
|
||||
|
||||
sPbapManager = nullptr;
|
||||
}
|
||||
|
||||
|
@ -105,27 +107,19 @@ BluetoothPbapManager::BluetoothPbapManager() : mPhonebookSizeRequired(false)
|
|||
}
|
||||
|
||||
BluetoothPbapManager::~BluetoothPbapManager()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return;
|
||||
}
|
||||
{ }
|
||||
|
||||
NS_WARN_IF(NS_FAILED(
|
||||
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
|
||||
}
|
||||
|
||||
bool
|
||||
nsresult
|
||||
BluetoothPbapManager::Init()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return false;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
|
||||
return false;
|
||||
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,7 +131,64 @@ BluetoothPbapManager::Init()
|
|||
* absence of read events when device boots up.
|
||||
*/
|
||||
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothPbapManager::Uninit()
|
||||
{
|
||||
if (mServerSocket) {
|
||||
mServerSocket->SetObserver(nullptr);
|
||||
|
||||
if (mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mServerSocket->Close();
|
||||
}
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
|
||||
if (mSocket) {
|
||||
mSocket->SetObserver(nullptr);
|
||||
|
||||
if (mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mSocket->Close();
|
||||
}
|
||||
mSocket = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARN_IF(NS_FAILED(
|
||||
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothPbapManager::InitPbapInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aRes) {
|
||||
aRes->Init();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothPbapManager::DeinitPbapInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sPbapManager) {
|
||||
sPbapManager->Uninit();
|
||||
sPbapManager = nullptr;
|
||||
}
|
||||
|
||||
if (aRes) {
|
||||
aRes->Deinit();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
|
@ -157,8 +208,8 @@ BluetoothPbapManager::Get()
|
|||
}
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothPbapManager *manager = new BluetoothPbapManager();
|
||||
if (NS_WARN_IF(!manager->Init())) {
|
||||
RefPtr<BluetoothPbapManager> manager = new BluetoothPbapManager();
|
||||
if (NS_WARN_IF(NS_FAILED(manager->Init()))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -181,10 +232,11 @@ BluetoothPbapManager::Listen()
|
|||
* BT stops; otherwise no more read events would be received even if
|
||||
* BT restarts.
|
||||
*/
|
||||
if (mServerSocket) {
|
||||
if (mServerSocket &&
|
||||
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mServerSocket->Close();
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
mServerSocket = nullptr;
|
||||
|
||||
mServerSocket = new BluetoothSocket(this);
|
||||
|
||||
|
@ -1131,7 +1183,16 @@ BluetoothPbapManager::OnSocketConnectSuccess(BluetoothSocket* aSocket)
|
|||
void
|
||||
BluetoothPbapManager::OnSocketConnectError(BluetoothSocket* aSocket)
|
||||
{
|
||||
if (mServerSocket &&
|
||||
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mServerSocket->Close();
|
||||
}
|
||||
mServerSocket = nullptr;
|
||||
|
||||
if (mSocket &&
|
||||
mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
|
||||
mSocket->Close();
|
||||
}
|
||||
mSocket = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1147,7 +1208,8 @@ BluetoothPbapManager::OnSocketDisconnect(BluetoothSocket* aSocket)
|
|||
|
||||
AfterPbapDisconnected();
|
||||
mDeviceAddress.Clear();
|
||||
mSocket = nullptr;
|
||||
|
||||
mSocket = nullptr; // should already be closed
|
||||
|
||||
Listen();
|
||||
}
|
||||
|
|
|
@ -67,7 +67,10 @@ public:
|
|||
static const int MAX_PACKET_LENGTH = 0xFFFE;
|
||||
static const int DIGEST_LENGTH = 16;
|
||||
|
||||
static void InitPbapInterface(BluetoothProfileResultHandler* aRes);
|
||||
static void DeinitPbapInterface(BluetoothProfileResultHandler* aRes);
|
||||
static BluetoothPbapManager* Get();
|
||||
|
||||
bool Listen();
|
||||
|
||||
/**
|
||||
|
@ -146,7 +149,9 @@ protected:
|
|||
|
||||
private:
|
||||
BluetoothPbapManager();
|
||||
bool Init();
|
||||
|
||||
nsresult Init();
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
|
||||
void ReplyToConnect(const nsAString& aPassword = EmptyString());
|
||||
|
|
|
@ -138,6 +138,10 @@ public:
|
|||
void Init() override
|
||||
{
|
||||
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
|
||||
BluetoothMapSmsManager::InitMapSmsInterface,
|
||||
BluetoothOppManager::InitOppInterface,
|
||||
BluetoothPbapManager::InitPbapInterface,
|
||||
BluetoothHidManager::InitHidInterface,
|
||||
BluetoothHfpManager::InitHfpInterface,
|
||||
BluetoothA2dpManager::InitA2dpInterface,
|
||||
BluetoothAvrcpManager::InitAvrcpInterface,
|
||||
|
@ -280,14 +284,15 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
static BluetoothProfileManagerBase* sProfiles[] = {
|
||||
BluetoothHfpManager::Get(),
|
||||
BluetoothProfileManagerBase* sProfiles[] = {
|
||||
// BluetoothGattManager not handled here
|
||||
BluetoothAvrcpManager::Get(),
|
||||
BluetoothA2dpManager::Get(),
|
||||
BluetoothOppManager::Get(),
|
||||
BluetoothHfpManager::Get(),
|
||||
BluetoothHidManager::Get(),
|
||||
BluetoothPbapManager::Get(),
|
||||
BluetoothMapSmsManager::Get(),
|
||||
BluetoothHidManager::Get()
|
||||
BluetoothOppManager::Get(),
|
||||
BluetoothMapSmsManager::Get()
|
||||
};
|
||||
|
||||
// Disconnect all connected profiles
|
||||
|
@ -2037,7 +2042,11 @@ BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
|
|||
BluetoothGattManager::DeinitGattInterface,
|
||||
BluetoothAvrcpManager::DeinitAvrcpInterface,
|
||||
BluetoothA2dpManager::DeinitA2dpInterface,
|
||||
BluetoothHfpManager::DeinitHfpInterface
|
||||
BluetoothHfpManager::DeinitHfpInterface,
|
||||
BluetoothHidManager::DeinitHidInterface,
|
||||
BluetoothPbapManager::DeinitPbapInterface,
|
||||
BluetoothOppManager::DeinitOppInterface,
|
||||
BluetoothMapSmsManager::DeinitMapSmsInterface
|
||||
};
|
||||
|
||||
// Return error if BluetoothService is unavailable
|
||||
|
|
|
@ -20,24 +20,6 @@ using namespace mozilla::ipc;
|
|||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
static const size_t MAX_READ_SIZE = 1 << 16;
|
||||
static BluetoothSocketInterface* sBluetoothSocketInterface;
|
||||
|
||||
// helper functions
|
||||
static bool
|
||||
EnsureBluetoothSocketHalLoad()
|
||||
{
|
||||
if (sBluetoothSocketInterface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
||||
NS_ENSURE_TRUE(btInf, false);
|
||||
|
||||
sBluetoothSocketInterface = btInf->GetBluetoothSocketInterface();
|
||||
NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class mozilla::dom::bluetooth::DroidSocketImpl
|
||||
: public mozilla::ipc::UnixFdWatcher
|
||||
|
@ -429,24 +411,20 @@ private:
|
|||
class InvokeAcceptTask final : public SocketTask<DroidSocketImpl>
|
||||
{
|
||||
public:
|
||||
InvokeAcceptTask(DroidSocketImpl* aImpl, int aFd)
|
||||
InvokeAcceptTask(DroidSocketImpl* aImpl, int aListenFd)
|
||||
: SocketTask<DroidSocketImpl>(aImpl)
|
||||
, mFd(aFd)
|
||||
, mListenFd(aListenFd)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
{
|
||||
MOZ_ASSERT(GetIO()->IsConsumerThread());
|
||||
MOZ_ASSERT(sBluetoothSocketInterface);
|
||||
|
||||
BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO());
|
||||
GetIO()->mConsumer->SetCurrentResultHandler(res);
|
||||
|
||||
sBluetoothSocketInterface->Accept(mFd, res);
|
||||
GetIO()->mConsumer->Accept(mListenFd, new AcceptResultHandler(GetIO()));
|
||||
}
|
||||
|
||||
private:
|
||||
int mFd;
|
||||
int mListenFd;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -581,22 +559,27 @@ DroidSocketImpl::DiscardBuffer()
|
|||
//
|
||||
|
||||
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver)
|
||||
: mObserver(aObserver)
|
||||
: mSocketInterface(nullptr)
|
||||
, mObserver(aObserver)
|
||||
, mCurrentRes(nullptr)
|
||||
, mImpl(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aObserver);
|
||||
|
||||
MOZ_COUNT_CTOR_INHERITED(BluetoothSocket, DataSocket);
|
||||
|
||||
EnsureBluetoothSocketHalLoad();
|
||||
}
|
||||
|
||||
BluetoothSocket::~BluetoothSocket()
|
||||
{
|
||||
MOZ_ASSERT(!mImpl); // Socket is closed
|
||||
|
||||
MOZ_COUNT_DTOR_INHERITED(BluetoothSocket, DataSocket);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::SetObserver(BluetoothSocketObserver* aObserver)
|
||||
{
|
||||
mObserver = aObserver;
|
||||
}
|
||||
|
||||
class ConnectSocketResultHandler final : public BluetoothSocketResultHandler
|
||||
{
|
||||
public:
|
||||
|
@ -655,6 +638,11 @@ BluetoothSocket::Connect(const BluetoothAddress& aDeviceAddress,
|
|||
{
|
||||
MOZ_ASSERT(!mImpl);
|
||||
|
||||
auto rv = LoadSocketInterface();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
SetConnectionStatus(SOCKET_CONNECTING);
|
||||
|
||||
mImpl = new DroidSocketImpl(aConsumerLoop, aIOLoop, this);
|
||||
|
@ -662,7 +650,7 @@ BluetoothSocket::Connect(const BluetoothAddress& aDeviceAddress,
|
|||
BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
|
||||
SetCurrentResultHandler(res);
|
||||
|
||||
sBluetoothSocketInterface->Connect(
|
||||
mSocketInterface->Connect(
|
||||
aDeviceAddress, aType,
|
||||
aServiceUuid, aChannel,
|
||||
aEncrypt, aAuth, res);
|
||||
|
@ -719,8 +707,13 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
|
|||
{
|
||||
MOZ_ASSERT(!mImpl);
|
||||
|
||||
auto rv = LoadSocketInterface();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
BluetoothServiceName serviceName;
|
||||
nsresult rv = StringToServiceName(aServiceName, serviceName);
|
||||
rv = StringToServiceName(aServiceName, serviceName);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -732,7 +725,7 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
|
|||
BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
|
||||
SetCurrentResultHandler(res);
|
||||
|
||||
sBluetoothSocketInterface->Listen(
|
||||
mSocketInterface->Listen(
|
||||
aType,
|
||||
serviceName, aServiceUuid, aChannel,
|
||||
aEncrypt, aAuth, res);
|
||||
|
@ -751,12 +744,26 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
|
|||
MessageLoop::current(), XRE_GetIOMessageLoop());
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothSocket::Accept(int aListenFd, BluetoothSocketResultHandler* aRes)
|
||||
{
|
||||
auto rv = LoadSocketInterface();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
SetCurrentResultHandler(aRes);
|
||||
mSocketInterface->Accept(aListenFd, aRes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(mObserver);
|
||||
|
||||
if (mObserver) {
|
||||
mObserver->ReceiveSocketData(this, aBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// |DataSocket|
|
||||
|
@ -778,50 +785,86 @@ BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
|
|||
void
|
||||
BluetoothSocket::Close()
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothSocketInterface);
|
||||
|
||||
if (!mImpl) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mImpl->IsConsumerThread());
|
||||
|
||||
// Stop any watching |SocketMessageWatcher|
|
||||
if (mCurrentRes) {
|
||||
sBluetoothSocketInterface->Close(mCurrentRes);
|
||||
}
|
||||
|
||||
// From this point on, we consider mImpl as being deleted.
|
||||
// We sever the relationship here so any future calls to listen or connect
|
||||
// will create a new implementation.
|
||||
mImpl->ShutdownOnConsumerThread();
|
||||
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
|
||||
mImpl = nullptr;
|
||||
|
||||
NotifyDisconnect();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::OnConnectSuccess()
|
||||
{
|
||||
MOZ_ASSERT(mObserver);
|
||||
|
||||
SetCurrentResultHandler(nullptr);
|
||||
|
||||
if (mObserver) {
|
||||
mObserver->OnSocketConnectSuccess(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::OnConnectError()
|
||||
{
|
||||
MOZ_ASSERT(mObserver);
|
||||
auto observer = mObserver;
|
||||
|
||||
SetCurrentResultHandler(nullptr);
|
||||
mObserver->OnSocketConnectError(this);
|
||||
Cleanup();
|
||||
|
||||
if (observer) {
|
||||
observer->OnSocketConnectError(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::OnDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(mObserver);
|
||||
mObserver->OnSocketDisconnect(this);
|
||||
auto observer = mObserver;
|
||||
|
||||
Cleanup();
|
||||
|
||||
if (observer) {
|
||||
observer->OnSocketDisconnect(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothSocket::LoadSocketInterface()
|
||||
{
|
||||
if (mSocketInterface) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto interface = BluetoothInterface::GetInstance();
|
||||
NS_ENSURE_TRUE(!!interface, NS_ERROR_FAILURE);
|
||||
|
||||
auto socketInterface = interface->GetBluetoothSocketInterface();
|
||||
NS_ENSURE_TRUE(!!socketInterface, NS_ERROR_FAILURE);
|
||||
|
||||
mSocketInterface = socketInterface;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::Cleanup()
|
||||
{
|
||||
MOZ_ASSERT(mSocketInterface);
|
||||
MOZ_ASSERT(mImpl);
|
||||
MOZ_ASSERT(mImpl->IsConsumerThread());
|
||||
|
||||
// Stop any watching |SocketMessageWatcher|
|
||||
if (mCurrentRes) {
|
||||
mSocketInterface->Close(mCurrentRes);
|
||||
}
|
||||
|
||||
// From this point on, we consider mImpl as being deleted. We
|
||||
// sever the relationship here so any future calls to listen
|
||||
// or connect will create a new implementation.
|
||||
mImpl->ShutdownOnConsumerThread();
|
||||
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
|
||||
mImpl = nullptr;
|
||||
|
||||
mSocketInterface = nullptr;
|
||||
mObserver = nullptr;
|
||||
mCurrentRes = nullptr;
|
||||
mDeviceAddress.Clear();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ class MessageLoop;
|
|||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothSocketInterface;
|
||||
class BluetoothSocketObserver;
|
||||
class BluetoothSocketResultHandler;
|
||||
class DroidSocketImpl;
|
||||
|
@ -24,6 +25,8 @@ public:
|
|||
BluetoothSocket(BluetoothSocketObserver* aObserver);
|
||||
~BluetoothSocket();
|
||||
|
||||
void SetObserver(BluetoothSocketObserver* aObserver);
|
||||
|
||||
nsresult Connect(const BluetoothAddress& aDeviceAddress,
|
||||
const BluetoothUuid& aServiceUuid,
|
||||
BluetoothSocketType aType,
|
||||
|
@ -52,6 +55,8 @@ public:
|
|||
int aChannel,
|
||||
bool aAuth, bool aEncrypt);
|
||||
|
||||
nsresult Accept(int aListenFd, BluetoothSocketResultHandler* aRes);
|
||||
|
||||
/**
|
||||
* Method to be called whenever data is received. This is only called on the
|
||||
* consumer thread.
|
||||
|
@ -70,11 +75,6 @@ public:
|
|||
mDeviceAddress = aDeviceAddress;
|
||||
}
|
||||
|
||||
inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
|
||||
{
|
||||
mCurrentRes = aRes;
|
||||
}
|
||||
|
||||
// Methods for |DataSocket|
|
||||
//
|
||||
|
||||
|
@ -90,6 +90,15 @@ public:
|
|||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
nsresult LoadSocketInterface();
|
||||
void Cleanup();
|
||||
|
||||
inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
|
||||
{
|
||||
mCurrentRes = aRes;
|
||||
}
|
||||
|
||||
BluetoothSocketInterface* mSocketInterface;
|
||||
BluetoothSocketObserver* mObserver;
|
||||
BluetoothSocketResultHandler* mCurrentRes;
|
||||
DroidSocketImpl* mImpl;
|
||||
|
|
|
@ -176,6 +176,8 @@ BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
sBluetoothHfpManager = nullptr;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* Implement DeinitHfpInterface() for applications that want to create SCO
|
||||
|
|
|
@ -446,6 +446,7 @@ public:
|
|||
|
||||
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
|
||||
sBluetoothHfpInterface = nullptr;
|
||||
sBluetoothHfpManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
|
@ -458,6 +459,7 @@ public:
|
|||
|
||||
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
|
||||
sBluetoothHfpInterface = nullptr;
|
||||
sBluetoothHfpManager = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
|
|
|
@ -78,6 +78,30 @@ BluetoothHidManager::~BluetoothHidManager()
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aRes) {
|
||||
aRes->Init();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothHidManager::DeinitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
sBluetoothHidManager = nullptr;
|
||||
|
||||
if (aRes) {
|
||||
aRes->Deinit();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
BluetoothHidManager*
|
||||
BluetoothHidManager::Get()
|
||||
|
|
|
@ -22,6 +22,8 @@ public:
|
|||
aName.AssignLiteral("HID");
|
||||
}
|
||||
|
||||
static void InitHidInterface(BluetoothProfileResultHandler* aRes);
|
||||
static void DeinitHidInterface(BluetoothProfileResultHandler* aRes);
|
||||
static BluetoothHidManager* Get();
|
||||
|
||||
// HID-specific functions
|
||||
|
|
|
@ -36,7 +36,6 @@ const kSmsDeletedObserverTopic = "sms-deleted";
|
|||
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
||||
const kNetworkConnStateChangedTopic = "network-connection-state-changed";
|
||||
|
||||
const kPrefRilRadioDisabled = "ril.radio.disabled";
|
||||
const kPrefMmsDebuggingEnabled = "mms.debugging.enabled";
|
||||
|
||||
// HTTP status codes:
|
||||
|
@ -194,18 +193,12 @@ function getDefaultServiceId() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return Radio disabled state.
|
||||
* Return radio disabled state.
|
||||
*/
|
||||
function getRadioDisabledState() {
|
||||
let state;
|
||||
try {
|
||||
state = Services.prefs.getBoolPref(kPrefRilRadioDisabled);
|
||||
} catch (e) {
|
||||
if (DEBUG) debug("Getting preference 'ril.radio.disabled' fails.");
|
||||
state = false;
|
||||
}
|
||||
|
||||
return state;
|
||||
function isRadioOff(aServiceId) {
|
||||
let connection = gMobileConnectionService.getItemByServiceId(aServiceId);
|
||||
return connection.radioState
|
||||
!== Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -422,7 +415,7 @@ MmsConnection.prototype = {
|
|||
this.pendingCallbacks.push(callback);
|
||||
|
||||
let errorStatus;
|
||||
if (getRadioDisabledState()) {
|
||||
if (isRadioOff(this.serviceId)) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
|
||||
errorStatus = _HTTP_STATUS_RADIO_DISABLED;
|
||||
} else if (this.getCardState() != Ci.nsIIcc.CARD_STATE_READY) {
|
||||
|
@ -993,7 +986,8 @@ function CancellableTransaction(cancellableId, serviceId) {
|
|||
this.isCancelled = false;
|
||||
}
|
||||
CancellableTransaction.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsIMobileConnectionListener]),
|
||||
|
||||
// The timer for retrying sending or retrieving process.
|
||||
timer: null,
|
||||
|
@ -1010,8 +1004,9 @@ CancellableTransaction.prototype = {
|
|||
if (!this.isObserversAdded) {
|
||||
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
Services.obs.addObserver(this, kSmsDeletedObserverTopic, false);
|
||||
Services.prefs.addObserver(kPrefRilRadioDisabled, this, false);
|
||||
Services.prefs.addObserver(kPrefDefaultServiceId, this, false);
|
||||
gMobileConnectionService
|
||||
.getItemByServiceId(this.serviceId).registerListener(this);
|
||||
this.isObserversAdded = true;
|
||||
}
|
||||
|
||||
|
@ -1023,8 +1018,9 @@ CancellableTransaction.prototype = {
|
|||
if (this.isObserversAdded) {
|
||||
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
Services.obs.removeObserver(this, kSmsDeletedObserverTopic);
|
||||
Services.prefs.removeObserver(kPrefRilRadioDisabled, this);
|
||||
Services.prefs.removeObserver(kPrefDefaultServiceId, this);
|
||||
gMobileConnectionService
|
||||
.getItemByServiceId(this.serviceId).unregisterListener(this);
|
||||
this.isObserversAdded = false;
|
||||
}
|
||||
},
|
||||
|
@ -1080,18 +1076,35 @@ CancellableTransaction.prototype = {
|
|||
break;
|
||||
}
|
||||
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: {
|
||||
if (data == kPrefRilRadioDisabled) {
|
||||
if (getRadioDisabledState()) {
|
||||
this.cancelRunning(_MMS_ERROR_RADIO_DISABLED);
|
||||
}
|
||||
} else if (data === kPrefDefaultServiceId &&
|
||||
if (data === kPrefDefaultServiceId &&
|
||||
this.serviceId != getDefaultServiceId()) {
|
||||
this.cancelRunning(_MMS_ERROR_SIM_CARD_CHANGED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// nsIMobileConnectionListener
|
||||
|
||||
notifyVoiceChanged: function() {},
|
||||
notifyDataChanged: function() {},
|
||||
notifyDataError: function(message) {},
|
||||
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
|
||||
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
|
||||
notifyOtaStatusChanged: function(status) {},
|
||||
|
||||
notifyRadioStateChanged: function() {
|
||||
if (isRadioOff(this.serviceId)) {
|
||||
this.cancelRunning(_MMS_ERROR_RADIO_DISABLED);
|
||||
}
|
||||
},
|
||||
|
||||
notifyClirModeChanged: function(mode) {},
|
||||
notifyLastKnownNetworkChanged: function() {},
|
||||
notifyLastKnownHomeNetworkChanged: function() {},
|
||||
notifyNetworkSelectionModeChanged: function() {},
|
||||
notifyDeviceIdentitiesChanged: function() {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2388,7 +2401,7 @@ MmsService.prototype = {
|
|||
}
|
||||
|
||||
// Check radio state in prior to default service Id.
|
||||
if (getRadioDisabledState()) {
|
||||
if (isRadioOff(aServiceId)) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
|
||||
sendTransactionCb(mmsMessage,
|
||||
Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR,
|
||||
|
@ -2502,7 +2515,13 @@ MmsService.prototype = {
|
|||
// Hence, for manual retrieving, instead of checking radio state later
|
||||
// in MmsConnection.acquire(), We have to check radio state in prior to
|
||||
// iccId to return the error correctly.
|
||||
if (getRadioDisabledState()) {
|
||||
let numRadioInterfaces = gMobileConnectionService.numItems;
|
||||
let isAllRadioOff = true;
|
||||
for (let serviceId = 0; serviceId < numRadioInterfaces; serviceId++) {
|
||||
isAllRadioOff &= isRadioOff(serviceId);
|
||||
}
|
||||
|
||||
if (isAllRadioOff) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when retrieving MMS.");
|
||||
aRequest.notifyGetMessageFailed(
|
||||
Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR);
|
||||
|
|
|
@ -663,3 +663,60 @@ function runIfMultiSIM(aTest) {
|
|||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to enable/disable connection radio state.
|
||||
*
|
||||
* @param aConnection
|
||||
* connection to enable / disable
|
||||
* @param aEnabled
|
||||
* True to enable the radio.
|
||||
* @return a Promise object.
|
||||
*/
|
||||
function setRadioEnabled(aConnection, aEnabled) {
|
||||
log("setRadioEnabled to " + aEnabled);
|
||||
|
||||
let deferred = Promise.defer();
|
||||
let finalState = (aEnabled) ? "enabled" : "disabled";
|
||||
if (aConnection.radioState == finalState) {
|
||||
return deferred.resolve(aConnection);
|
||||
}
|
||||
|
||||
aConnection.onradiostatechange = function() {
|
||||
log("Received 'radiostatechange', radioState: " + aConnection.radioState);
|
||||
|
||||
if (aConnection.radioState == finalState) {
|
||||
deferred.resolve(aConnection);
|
||||
aConnection.onradiostatechange = null;
|
||||
}
|
||||
};
|
||||
|
||||
let req = aConnection.setRadioEnabled(aEnabled);
|
||||
|
||||
req.onsuccess = function() {
|
||||
log("setRadioEnabled success");
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, "setRadioEnabled should not fail");
|
||||
deferred.reject();
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to enable/disable all connections radio state.
|
||||
*
|
||||
* @param aEnabled
|
||||
* True to enable the radio.
|
||||
* @return a Promise object.
|
||||
*/
|
||||
function setAllRadioEnabled(aEnabled) {
|
||||
let promises = []
|
||||
for (let i = 0; i < window.navigator.mozMobileConnections.length; ++i) {
|
||||
promises.push(ensureMobileConnection(i)
|
||||
.then((connection) => setRadioEnabled(connection, aEnabled)));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
|
||||
// We apply "chrome" context to be more flexible to
|
||||
// specify the content of M-Notification.ind such as iccId
|
||||
// for different kinds of testing.
|
||||
|
@ -17,11 +18,17 @@ var gMobileMessageDatabaseService =
|
|||
.getService(Ci.nsIGonkMobileMessageDatabaseService);
|
||||
|
||||
var gUuidGenerator =
|
||||
Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator);
|
||||
Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
|
||||
var gMmsService = Cc["@mozilla.org/mms/gonkmmsservice;1"]
|
||||
.getService(Ci.nsIMmsService);
|
||||
var gMmsService =
|
||||
Cc["@mozilla.org/mms/gonkmmsservice;1"].getService(Ci.nsIMmsService);
|
||||
|
||||
var gMobileConnectionService =
|
||||
Cc["@mozilla.org/mobileconnection/mobileconnectionservice;1"]
|
||||
.getService(Ci.nsIMobileConnectionService);
|
||||
|
||||
var gIccService =
|
||||
Cc["@mozilla.org/icc/gonkiccservice;1"].getService(Ci.nsIIccService);
|
||||
|
||||
function saveMmsNotification() {
|
||||
log("saveMmsNotification()");
|
||||
|
@ -101,23 +108,111 @@ function retrieveMmsWithFailure(aId) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
function testRetrieve(aCause, aInit, aCleanup) {
|
||||
function testRetrieve(aCause) {
|
||||
log("testRetrieve: aCause = " + aCause);
|
||||
return Promise.resolve()
|
||||
.then(() => { if (aInit) aInit(); })
|
||||
.then(saveMmsNotification)
|
||||
.then((message) => retrieveMmsWithFailure(message.id))
|
||||
.then((response) => verifyErrorCause(response, aCause))
|
||||
.then(() => { if (aCleanup) aCleanup(); });
|
||||
.then((response) => verifyErrorCause(response, aCause));
|
||||
}
|
||||
|
||||
var setRadioDisabled = function(aDisabled) {
|
||||
log("set ril.radio.disabled to " + aDisabled);
|
||||
Services.prefs.setBoolPref("ril.radio.disabled", aDisabled);
|
||||
};
|
||||
function setRadioEnabled(aConnection, aEnabled) {
|
||||
let deferred = Promise.defer();
|
||||
let finalState = (aEnabled) ?
|
||||
Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED :
|
||||
Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED;
|
||||
|
||||
testRetrieve(Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR,
|
||||
setRadioDisabled.bind(null, true),
|
||||
setRadioDisabled.bind(null, false))
|
||||
if (aConnection.radioState == finalState) {
|
||||
return deferred.resolve(aConnection);
|
||||
}
|
||||
let listener = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionListener]),
|
||||
notifyVoiceChanged: function() {},
|
||||
notifyDataChanged: function() {},
|
||||
notifyDataError: function(message) {},
|
||||
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
|
||||
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
|
||||
notifyOtaStatusChanged: function(status) {},
|
||||
notifyRadioStateChanged: function() {
|
||||
log("setRadioEnabled state changed to " + aConnection.radioState);
|
||||
if (aConnection.radioState == finalState) {
|
||||
aConnection.unregisterListener(listener);
|
||||
deferred.resolve(aConnection);
|
||||
}
|
||||
},
|
||||
notifyClirModeChanged: function(mode) {},
|
||||
notifyLastKnownNetworkChanged: function() {},
|
||||
notifyLastKnownHomeNetworkChanged: function() {},
|
||||
notifyNetworkSelectionModeChanged: function() {},
|
||||
notifyDeviceIdentitiesChanged: function() {}
|
||||
};
|
||||
let callback = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
|
||||
notifySuccess() {},
|
||||
notifySuccessWithBoolean(result) {},
|
||||
notifyGetNetworksSuccess(count, networks) {},
|
||||
notifyGetCallForwardingSuccess(count, results) {},
|
||||
notifyGetCallBarringSuccess(program, enabled, serviceClass) {},
|
||||
notifyGetCallWaitingSuccess(serviceClass) {},
|
||||
notifyGetClirStatusSuccess(n, m) {},
|
||||
notifyGetPreferredNetworkTypeSuccess(type) {},
|
||||
notifyGetRoamingPreferenceSuccess(mode) {},
|
||||
notifyError(name) {
|
||||
log("setRadioEnabled reject");
|
||||
aConnection.unregisterListener(listener);
|
||||
deferred.reject();
|
||||
}
|
||||
};
|
||||
aConnection.registerListener(listener);
|
||||
aConnection.setRadioEnabled(aEnabled, callback);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function setAllRadioEnabled(aEnabled) {
|
||||
log("setAllRadioEnabled connection number = " +
|
||||
gMobileConnectionService.numItems);
|
||||
|
||||
let promises = [];
|
||||
for (let i = 0; i < gMobileConnectionService.numItems; ++i) {
|
||||
promises.push(setRadioEnabled(
|
||||
gMobileConnectionService.getItemByServiceId(i), aEnabled));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function waitIccReady(aIcc) {
|
||||
let deferred = Promise.defer();
|
||||
if (aIcc.cardState == Ci.nsIIcc.CARD_STATE_READY) {
|
||||
return deferred.resolve(aIcc);
|
||||
}
|
||||
let listener = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccListener]),
|
||||
notifyStkCommand(aStkProactiveCmd) {},
|
||||
notifyStkSessionEnd() {},
|
||||
notifyCardStateChanged() {
|
||||
if (aIcc.cardState == Ci.nsIIcc.CARD_STATE_READY) {
|
||||
aIcc.unregisterListener(listener);
|
||||
deferred.resolve(aIcc);
|
||||
}
|
||||
},
|
||||
notifyIccInfoChanged() {}
|
||||
};
|
||||
aIcc.registerListener(listener);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitAllIccReady() {
|
||||
let promises = [];
|
||||
for (let i = 0; i < gMobileConnectionService.numItems; ++i) {
|
||||
let icc = gIccService.getIccByServiceId(i);
|
||||
promises.push(waitIccReady(icc));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
setAllRadioEnabled(false)
|
||||
.then(() => testRetrieve(Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR))
|
||||
.then(() => setAllRadioEnabled(true))
|
||||
.then(() => waitAllIccReady())
|
||||
.then(() => testRetrieve(Ci.nsIMobileMessageCallback.SIM_NOT_MATCHED_ERROR))
|
||||
.then(finish);
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const kPrefRilRadioDisabled = "ril.radio.disabled";
|
||||
|
||||
function testSendFailed(aCause, aServiceId) {
|
||||
log("testSendFailed, aCause: " + aCause + ", aServiceId: " + aServiceId);
|
||||
let sendParameters;
|
||||
|
@ -44,13 +42,9 @@ function testSendFailed(aCause, aServiceId) {
|
|||
|
||||
startTestCommon(function testCaseMain() {
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
SpecialPowers.setBoolPref(kPrefRilRadioDisabled, true);
|
||||
})
|
||||
.then(() => testSendFailed("RadioDisabledError"))
|
||||
.then(() => {
|
||||
SpecialPowers.setBoolPref(kPrefRilRadioDisabled, false);
|
||||
})
|
||||
.then(() => setAllRadioEnabled(false))
|
||||
.then(() => testSendFailed("RadioDisabledError"), 0)
|
||||
.then(() => setAllRadioEnabled(true))
|
||||
.then(() => runIfMultiSIM(
|
||||
() => testSendFailed("NonActiveSimCardError", 1)));
|
||||
});
|
||||
|
|
|
@ -4,79 +4,6 @@
|
|||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const kPrefRilRadioDisabled = "ril.radio.disabled";
|
||||
|
||||
var connection;
|
||||
function ensureMobileConnection() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let permissions = [{
|
||||
"type": "mobileconnection",
|
||||
"allow": true,
|
||||
"context": document,
|
||||
}];
|
||||
SpecialPowers.pushPermissions(permissions, function() {
|
||||
ok(true, "permissions pushed: " + JSON.stringify(permissions));
|
||||
|
||||
connection = window.navigator.mozMobileConnections[0];
|
||||
if (connection) {
|
||||
log("navigator.mozMobileConnections[0] is instance of " + connection.constructor);
|
||||
} else {
|
||||
log("navigator.mozMobileConnections[0] is undefined.");
|
||||
}
|
||||
|
||||
if (connection instanceof MozMobileConnection) {
|
||||
deferred.resolve(connection);
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitRadioState(state) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
waitFor(function() {
|
||||
deferred.resolve();
|
||||
}, function() {
|
||||
return connection.radioState == state;
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function setRadioEnabled(enabled) {
|
||||
log("setRadioEnabled to " + enabled);
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let finalState = (enabled) ? "enabled" : "disabled";
|
||||
connection.onradiostatechange = function() {
|
||||
let state = connection.radioState;
|
||||
log("Received 'radiostatechange' event, radioState: " + state);
|
||||
|
||||
if (state == finalState) {
|
||||
deferred.resolve();
|
||||
connection.onradiostatechange = null;
|
||||
}
|
||||
};
|
||||
|
||||
let req = connection.setRadioEnabled(enabled);
|
||||
|
||||
req.onsuccess = function() {
|
||||
log("setRadioEnabled success");
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, "setRadioEnabled should not fail");
|
||||
deferred.reject();
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function testSendFailed(aCause) {
|
||||
log("testSendFailed, aCause: " + aCause);
|
||||
|
||||
|
@ -98,8 +25,7 @@ function testSendFailed(aCause) {
|
|||
|
||||
startTestCommon(function testCaseMain() {
|
||||
return ensureMobileConnection()
|
||||
.then(() => waitRadioState("enabled"))
|
||||
.then(() => setRadioEnabled(false))
|
||||
.then(() => setRadioEnabled(mobileConnection, false))
|
||||
.then(() => testSendFailed("RadioDisabledError"))
|
||||
.then(() => setRadioEnabled(true));
|
||||
.then(() => setRadioEnabled(mobileConnection, true));
|
||||
});
|
||||
|
|
|
@ -37,7 +37,20 @@
|
|||
is(sheet.parsingMode, "author",
|
||||
"author sheet has expected mode");
|
||||
results[sss.AUTHOR_SHEET] = 1;
|
||||
} else if (sheet.href === "about:PreferenceStyleSheet") {
|
||||
is(sheet.parsingMode, "agent",
|
||||
"about:PreferenceStyleSheet has agent mode");
|
||||
continue;
|
||||
} else {
|
||||
// Ignore sheets we don't care about.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check that re-parsing preserves the mode.
|
||||
let mode = sheet.parsingMode;
|
||||
domutils.parseStyleSheet(sheet, "body { color: chartreuse; }");
|
||||
is(sheet.parsingMode, mode,
|
||||
"check that re-parsing preserved mode " + mode);
|
||||
}
|
||||
|
||||
ok(results[sss.AGENT_SHEET] && results[sss.USER_SHEET] &&
|
||||
|
|
|
@ -2280,12 +2280,6 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput)
|
|||
mInner->mFirstChild = nullptr;
|
||||
mInner->mNameSpaceMap = nullptr;
|
||||
|
||||
// allow agent features if the style sheet's principal is the system principal
|
||||
css::SheetParsingMode parsingMode =
|
||||
nsContentUtils::IsSystemPrincipal(mInner->mPrincipal)
|
||||
? css::eAgentSheetFeatures
|
||||
: css::eAuthorSheetFeatures;
|
||||
|
||||
uint32_t lineNumber = 1;
|
||||
if (mOwningNode) {
|
||||
nsCOMPtr<nsIStyleSheetLinkingElement> link = do_QueryInterface(mOwningNode);
|
||||
|
@ -2297,7 +2291,7 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput)
|
|||
nsCSSParser parser(loader, this);
|
||||
nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI,
|
||||
mInner->mPrincipal, lineNumber,
|
||||
parsingMode, &reusableSheets);
|
||||
mParsingMode, &reusableSheets);
|
||||
DidDirty(); // we are always 'dirty' here since we always remove rules first
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
|
@ -815,6 +815,7 @@ nsLayoutStylesheetCache::BuildPreferenceSheet(RefPtr<CSSStyleSheet>& aSheet,
|
|||
nsPresContext* aPresContext)
|
||||
{
|
||||
aSheet = new CSSStyleSheet(CORS_NONE, mozilla::net::RP_Default);
|
||||
aSheet->SetParsingMode(eAgentSheetFeatures);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr);
|
||||
|
|
|
@ -16,12 +16,21 @@
|
|||
android:targetSdkVersion="23"/>
|
||||
|
||||
#include ../services/manifests/FxAccountAndroidManifest_permissions.xml.in
|
||||
#include ../services/manifests/SyncAndroidManifest_permissions.xml.in
|
||||
|
||||
#ifdef MOZ_ANDROID_SEARCH_ACTIVITY
|
||||
#include ../search/manifests/SearchAndroidManifest_permissions.xml.in
|
||||
#endif
|
||||
|
||||
<!-- A signature level permission specific to each Firefox version (Android
|
||||
package name, e.g., org.mozilla.firefox). Use this permission to
|
||||
broadcast securely within a single Firefox version. This needs to
|
||||
agree with GlobalConstants.PER_ANDROID_PACKAGE_PERMISSION. -->
|
||||
<permission
|
||||
android:name="@ANDROID_PACKAGE_NAME@.permission.PER_ANDROID_PACKAGE"
|
||||
android:protectionLevel="signature"/>
|
||||
|
||||
<uses-permission android:name="@ANDROID_PACKAGE_NAME@.permission.PER_ANDROID_PACKAGE" />
|
||||
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
|
@ -356,7 +365,6 @@
|
|||
</receiver>
|
||||
|
||||
#include ../services/manifests/FxAccountAndroidManifest_activities.xml.in
|
||||
#include ../services/manifests/SyncAndroidManifest_activities.xml.in
|
||||
#ifdef MOZ_ANDROID_SEARCH_ACTIVITY
|
||||
#include ../search/manifests/SearchAndroidManifest_activities.xml.in
|
||||
#endif
|
||||
|
@ -463,7 +471,6 @@
|
|||
|
||||
|
||||
#include ../services/manifests/FxAccountAndroidManifest_services.xml.in
|
||||
#include ../services/manifests/SyncAndroidManifest_services.xml.in
|
||||
|
||||
<service
|
||||
android:name="org.mozilla.gecko.tabqueue.TabReceivedService"
|
||||
|
|
|
@ -194,13 +194,6 @@ public class AppConstants {
|
|||
false;
|
||||
//#endif
|
||||
|
||||
public static final boolean MOZ_ANDROID_READING_LIST_SERVICE =
|
||||
//#ifdef MOZ_ANDROID_READING_LIST_SERVICE
|
||||
true;
|
||||
//#else
|
||||
false;
|
||||
//#endif
|
||||
|
||||
public static final boolean MOZ_TELEMETRY_ON_BY_DEFAULT =
|
||||
//#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
|
||||
true;
|
||||
|
|
|
@ -765,7 +765,6 @@ sync_thirdparty_java_files = [
|
|||
|
||||
sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozilla/gecko/' + x for x in [
|
||||
'background/BackgroundService.java',
|
||||
'background/common/DateUtils.java',
|
||||
'background/common/EditorBranch.java',
|
||||
'background/common/GlobalConstants.java',
|
||||
'background/common/log/Logger.java',
|
||||
|
@ -782,12 +781,9 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'background/common/telemetry/TelemetryWrapper.java',
|
||||
'background/db/CursorDumper.java',
|
||||
'background/db/Tab.java',
|
||||
'background/fxa/FxAccount10AuthDelegate.java',
|
||||
'background/fxa/FxAccount10CreateDelegate.java',
|
||||
'background/fxa/FxAccount20CreateDelegate.java',
|
||||
'background/fxa/FxAccount20LoginDelegate.java',
|
||||
'background/fxa/FxAccountClient.java',
|
||||
'background/fxa/FxAccountClient10.java',
|
||||
'background/fxa/FxAccountClient20.java',
|
||||
'background/fxa/FxAccountClientException.java',
|
||||
'background/fxa/FxAccountRemoteError.java',
|
||||
|
@ -854,7 +850,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'fxa/receivers/FxAccountDeletedReceiver.java',
|
||||
'fxa/receivers/FxAccountDeletedService.java',
|
||||
'fxa/receivers/FxAccountUpgradeReceiver.java',
|
||||
'fxa/sync/FxAccountGlobalSession.java',
|
||||
'fxa/sync/FxAccountNotificationManager.java',
|
||||
'fxa/sync/FxAccountProfileService.java',
|
||||
'fxa/sync/FxAccountSchedulePolicy.java',
|
||||
|
@ -870,10 +865,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'sync/CollectionKeys.java',
|
||||
'sync/CommandProcessor.java',
|
||||
'sync/CommandRunner.java',
|
||||
'sync/config/AccountPickler.java',
|
||||
'sync/config/activities/SelectEnginesActivity.java',
|
||||
'sync/config/ClientRecordTerminator.java',
|
||||
'sync/config/ConfigurationMigrator.java',
|
||||
'sync/CredentialException.java',
|
||||
'sync/crypto/CryptoException.java',
|
||||
'sync/crypto/CryptoInfo.java',
|
||||
|
@ -886,14 +877,12 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'sync/crypto/PersistedCrypto5Keys.java',
|
||||
'sync/CryptoRecord.java',
|
||||
'sync/DelayedWorkTracker.java',
|
||||
'sync/delegates/BaseGlobalSessionCallback.java',
|
||||
'sync/delegates/ClientsDataDelegate.java',
|
||||
'sync/delegates/FreshStartDelegate.java',
|
||||
'sync/delegates/GlobalSessionCallback.java',
|
||||
'sync/delegates/JSONRecordFetchDelegate.java',
|
||||
'sync/delegates/KeyUploadDelegate.java',
|
||||
'sync/delegates/MetaGlobalDelegate.java',
|
||||
'sync/delegates/NodeAssignmentCallback.java',
|
||||
'sync/delegates/WipeServerDelegate.java',
|
||||
'sync/EngineSettings.java',
|
||||
'sync/ExtendedJSONObject.java',
|
||||
|
@ -901,29 +890,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'sync/HTTPFailureException.java',
|
||||
'sync/InfoCollections.java',
|
||||
'sync/InfoCounts.java',
|
||||
'sync/jpake/BigIntegerHelper.java',
|
||||
'sync/jpake/Gx3OrGx4IsZeroOrOneException.java',
|
||||
'sync/jpake/IncorrectZkpException.java',
|
||||
'sync/jpake/JPakeClient.java',
|
||||
'sync/jpake/JPakeCrypto.java',
|
||||
'sync/jpake/JPakeJson.java',
|
||||
'sync/jpake/JPakeNoActivePairingException.java',
|
||||
'sync/jpake/JPakeNumGenerator.java',
|
||||
'sync/jpake/JPakeNumGeneratorRandom.java',
|
||||
'sync/jpake/JPakeParty.java',
|
||||
'sync/jpake/stage/CompleteStage.java',
|
||||
'sync/jpake/stage/ComputeFinalStage.java',
|
||||
'sync/jpake/stage/ComputeKeyVerificationStage.java',
|
||||
'sync/jpake/stage/ComputeStepOneStage.java',
|
||||
'sync/jpake/stage/ComputeStepTwoStage.java',
|
||||
'sync/jpake/stage/DecryptDataStage.java',
|
||||
'sync/jpake/stage/DeleteChannel.java',
|
||||
'sync/jpake/stage/GetChannelStage.java',
|
||||
'sync/jpake/stage/GetRequestStage.java',
|
||||
'sync/jpake/stage/JPakeStage.java',
|
||||
'sync/jpake/stage/PutRequestStage.java',
|
||||
'sync/jpake/stage/VerifyPairingStage.java',
|
||||
'sync/jpake/Zkp.java',
|
||||
'sync/JSONRecordFetcher.java',
|
||||
'sync/KeyBundleProvider.java',
|
||||
'sync/MetaGlobal.java',
|
||||
|
@ -934,7 +900,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'sync/middleware/Crypto5MiddlewareRepositorySession.java',
|
||||
'sync/middleware/MiddlewareRepository.java',
|
||||
'sync/middleware/MiddlewareRepositorySession.java',
|
||||
'sync/MigrationSentinelSyncStage.java',
|
||||
'sync/net/AbstractBearerTokenAuthHeaderProvider.java',
|
||||
'sync/net/AuthHeaderProvider.java',
|
||||
'sync/net/BaseResource.java',
|
||||
|
@ -969,9 +934,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'sync/NullClusterURLException.java',
|
||||
'sync/PersistedMetaGlobal.java',
|
||||
'sync/PrefsBackoffHandler.java',
|
||||
'sync/receivers/SyncAccountDeletedReceiver.java',
|
||||
'sync/receivers/SyncAccountDeletedService.java',
|
||||
'sync/receivers/UpgradeReceiver.java',
|
||||
'sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java',
|
||||
'sync/repositories/android/AndroidBrowserBookmarksRepository.java',
|
||||
'sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java',
|
||||
|
@ -1049,35 +1011,17 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'sync/repositories/StoreTrackingRepositorySession.java',
|
||||
'sync/Server11PreviousPostFailedException.java',
|
||||
'sync/Server11RecordPostFailedException.java',
|
||||
'sync/setup/activities/AccountActivity.java',
|
||||
'sync/setup/activities/ActivityUtils.java',
|
||||
'sync/setup/activities/RedirectToSetupActivity.java',
|
||||
'sync/setup/activities/SendTabData.java',
|
||||
'sync/setup/activities/SetupFailureActivity.java',
|
||||
'sync/setup/activities/SetupSuccessActivity.java',
|
||||
'sync/setup/activities/SetupSyncActivity.java',
|
||||
'sync/setup/activities/SyncActivity.java',
|
||||
'sync/setup/activities/WebURLFinder.java',
|
||||
'sync/setup/activities/WebViewActivity.java',
|
||||
'sync/setup/auth/AccountAuthenticator.java',
|
||||
'sync/setup/auth/AuthenticateAccountStage.java',
|
||||
'sync/setup/auth/AuthenticationResult.java',
|
||||
'sync/setup/auth/AuthenticatorStage.java',
|
||||
'sync/setup/auth/EnsureUserExistenceStage.java',
|
||||
'sync/setup/auth/FetchUserNodeStage.java',
|
||||
'sync/setup/Constants.java',
|
||||
'sync/setup/InvalidSyncKeyException.java',
|
||||
'sync/setup/SyncAccounts.java',
|
||||
'sync/setup/SyncAuthenticatorService.java',
|
||||
'sync/SharedPreferencesClientsDataDelegate.java',
|
||||
'sync/SharedPreferencesNodeAssignmentCallback.java',
|
||||
'sync/stage/AbstractNonRepositorySyncStage.java',
|
||||
'sync/stage/AbstractSessionManagingSyncStage.java',
|
||||
'sync/stage/AndroidBrowserBookmarksServerSyncStage.java',
|
||||
'sync/stage/AndroidBrowserHistoryServerSyncStage.java',
|
||||
'sync/stage/CheckPreconditionsStage.java',
|
||||
'sync/stage/CompletedStage.java',
|
||||
'sync/stage/EnsureClusterURLStage.java',
|
||||
'sync/stage/EnsureCrypto5KeysStage.java',
|
||||
'sync/stage/FennecTabsServerSyncStage.java',
|
||||
'sync/stage/FetchInfoCollectionsStage.java',
|
||||
|
@ -1085,15 +1029,12 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'sync/stage/FormHistoryServerSyncStage.java',
|
||||
'sync/stage/GlobalSyncStage.java',
|
||||
'sync/stage/NoSuchStageException.java',
|
||||
'sync/stage/NoSyncIDException.java',
|
||||
'sync/stage/PasswordsServerSyncStage.java',
|
||||
'sync/stage/SafeConstrainedServer11Repository.java',
|
||||
'sync/stage/ServerSyncStage.java',
|
||||
'sync/stage/SyncClientsEngineStage.java',
|
||||
'sync/stage/UploadMetaGlobalStage.java',
|
||||
'sync/Sync11Configuration.java',
|
||||
'sync/syncadapter/SyncAdapter.java',
|
||||
'sync/syncadapter/SyncService.java',
|
||||
'sync/SyncConfiguration.java',
|
||||
'sync/SyncConfigurationException.java',
|
||||
'sync/SyncConstants.java',
|
||||
|
@ -1124,29 +1065,3 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'tokenserver/TokenServerException.java',
|
||||
'tokenserver/TokenServerToken.java',
|
||||
]]
|
||||
reading_list_service_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozilla/gecko/' + x for x in [
|
||||
'reading/ClientMetadata.java',
|
||||
'reading/ClientReadingListRecord.java',
|
||||
'reading/FetchSpec.java',
|
||||
'reading/LocalReadingListStorage.java',
|
||||
'reading/ReadingListBackoffObserver.java',
|
||||
'reading/ReadingListChangeAccumulator.java',
|
||||
'reading/ReadingListClient.java',
|
||||
'reading/ReadingListClientContentValuesFactory.java',
|
||||
'reading/ReadingListClientRecordFactory.java',
|
||||
'reading/ReadingListDeleteDelegate.java',
|
||||
'reading/ReadingListInvalidAuthenticationException.java',
|
||||
'reading/ReadingListRecord.java',
|
||||
'reading/ReadingListRecordDelegate.java',
|
||||
'reading/ReadingListRecordResponse.java',
|
||||
'reading/ReadingListRecordUploadDelegate.java',
|
||||
'reading/ReadingListResponse.java',
|
||||
'reading/ReadingListStorage.java',
|
||||
'reading/ReadingListStorageResponse.java',
|
||||
'reading/ReadingListSyncAdapter.java',
|
||||
'reading/ReadingListSynchronizer.java',
|
||||
'reading/ReadingListSynchronizerDelegate.java',
|
||||
'reading/ReadingListSyncService.java',
|
||||
'reading/ReadingListWipeDelegate.java',
|
||||
'reading/ServerReadingListRecord.java',
|
||||
]]
|
||||
|
|
|
@ -14,6 +14,7 @@ import android.accounts.OperationCanceledException;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
|
@ -25,7 +26,6 @@ import org.mozilla.gecko.fxa.login.State;
|
|||
import org.mozilla.gecko.restrictions.Restrictable;
|
||||
import org.mozilla.gecko.sync.SyncConfiguration;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
|
@ -252,8 +252,7 @@ public class AccountsHelper implements NativeEventListener {
|
|||
|
||||
try {
|
||||
if ("any".equals(kind)) {
|
||||
response.put("exists", SyncAccounts.syncAccountsExist(mContext) ||
|
||||
FirefoxAccounts.firefoxAccountsExist(mContext));
|
||||
response.put("exists", FirefoxAccounts.firefoxAccountsExist(mContext));
|
||||
callback.sendSuccess(response);
|
||||
} else if ("fxa".equals(kind)) {
|
||||
final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
|
||||
|
@ -276,9 +275,6 @@ public class AccountsHelper implements NativeEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
callback.sendSuccess(response);
|
||||
} else if ("sync11".equals(kind)) {
|
||||
response.put("exists", SyncAccounts.syncAccountsExist(mContext));
|
||||
callback.sendSuccess(response);
|
||||
} else {
|
||||
callback.sendError("Could not query account existence: unknown kind.");
|
||||
|
|
|
@ -149,10 +149,6 @@ public class RemoteTabsPanel extends HomeFragment {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (SyncConstants.ACCOUNTTYPE_SYNC.equals(account.type)) {
|
||||
return Action.None;
|
||||
}
|
||||
|
||||
if (!FxAccountConstants.ACCOUNT_TYPE.equals(account.type)) {
|
||||
Log.wtf(LOGTAG, "Non Sync, non Firefox Android Account returned by AccountLoader; returning null.");
|
||||
return null;
|
||||
|
|
|
@ -14,8 +14,8 @@ import android.os.Bundle;
|
|||
import android.os.Parcelable;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.RemoteClient;
|
||||
import org.mozilla.gecko.db.TabsAccessor;
|
||||
|
@ -29,9 +29,6 @@ import org.mozilla.gecko.sync.CommandProcessor;
|
|||
import org.mozilla.gecko.sync.CommandRunner;
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.SyncConfiguration;
|
||||
import org.mozilla.gecko.sync.SyncConstants;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
import org.mozilla.gecko.sync.syncadapter.SyncAdapter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -168,17 +165,6 @@ public class SendTab extends ShareMethod {
|
|||
return;
|
||||
}
|
||||
|
||||
final Account[] syncAccounts = accountManager.getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC);
|
||||
if (syncAccounts.length > 0) {
|
||||
tabSender = new Sync11TabSender(context, syncAccounts[0], accountManager);
|
||||
|
||||
updateClientList(tabSender);
|
||||
|
||||
Log.i(LOGTAG, "Allowing tab send for Sync account.");
|
||||
registerDisplayURICommand();
|
||||
return;
|
||||
}
|
||||
|
||||
// Have registered UIs offer to set up a Firefox Account.
|
||||
setOverrideIntentAction(FxAccountConstants.ACTION_FXA_GET_STARTED);
|
||||
}
|
||||
|
@ -308,32 +294,4 @@ public class SendTab extends ShareMethod {
|
|||
fxAccount.requestSync(FirefoxAccounts.FORCE, STAGES_TO_SYNC, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Sync11TabSender implements TabSender {
|
||||
private final Account account;
|
||||
private final AccountManager accountManager;
|
||||
private final Context context;
|
||||
|
||||
private Sync11TabSender(Context aContext, Account syncAccount, AccountManager manager) {
|
||||
context = aContext;
|
||||
account = syncAccount;
|
||||
accountManager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccountGUID() {
|
||||
try {
|
||||
SharedPreferences prefs = SyncAccounts.blockingPrefsFromDefaultProfileV0(context, accountManager, account);
|
||||
return prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null);
|
||||
} catch (Exception e) {
|
||||
Log.w(LOGTAG, "Could not get Sync account parameters or preferences; aborting.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sync() {
|
||||
SyncAdapter.requestImmediateSync(account, STAGES_TO_SYNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,11 @@
|
|||
|
||||
package org.mozilla.gecko.preferences;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.preference.Preference;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
@ -22,19 +19,14 @@ import org.mozilla.gecko.R;
|
|||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.TelemetryContract.Method;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.activities.FxAccountWebFlowActivity;
|
||||
import org.mozilla.gecko.fxa.activities.PicassoPreferenceIconTarget;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
class SyncPreference extends Preference {
|
||||
private static final boolean DEFAULT_TO_FXA = true;
|
||||
|
||||
private final Context mContext;
|
||||
private final Target profileAvatarTarget;
|
||||
|
||||
|
@ -45,18 +37,6 @@ class SyncPreference extends Preference {
|
|||
profileAvatarTarget = new PicassoPreferenceIconTarget(mContext.getResources(), this, cornerRadius);
|
||||
}
|
||||
|
||||
private void openSync11Settings() {
|
||||
// Show Sync setup if no accounts exist; otherwise, show account settings.
|
||||
if (SyncAccounts.syncAccountsExist(mContext)) {
|
||||
// We don't check for failure here. If you already have Sync set up,
|
||||
// then there's nothing we can do.
|
||||
SyncAccounts.openSyncSettings(mContext);
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(mContext, SetupSyncActivity.class);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
private void launchFxASetup() {
|
||||
final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
|
||||
intent.putExtra(FxAccountWebFlowActivity.EXTRA_ENDPOINT, FxAccountConstants.ENDPOINT_PREFERENCES);
|
||||
|
@ -120,23 +100,8 @@ class SyncPreference extends Preference {
|
|||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
// If we're not defaulting to FxA, just do what we've always done.
|
||||
if (!DEFAULT_TO_FXA) {
|
||||
openSync11Settings();
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's a legacy Sync account (or a pickled one on disk),
|
||||
// open the settings page.
|
||||
if (SyncAccounts.syncAccountsExist(mContext)) {
|
||||
if (SyncAccounts.openSyncSettings(mContext) != null) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.SETTINGS, "sync_settings");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, launch the FxA "Get started" activity, which will
|
||||
// dispatch to the right location.
|
||||
// Launch the FxA "Get started" activity, which will dispatch to the
|
||||
// right location.
|
||||
launchFxASetup();
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.SETTINGS, "sync_setup");
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче