зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
78ab08e8be
|
@ -1379,44 +1379,37 @@ var BookmarkingUI = {
|
||||||
aHeaderItem.nextSibling.remove();
|
aHeaderItem.nextSibling.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
let onItemCommand = function (aEvent) {
|
||||||
.asyncExecuteLegacyQueries([query], 1, options, {
|
let item = aEvent.target;
|
||||||
handleResult: function (aResultSet) {
|
openUILink(item.getAttribute("targetURI"), aEvent);
|
||||||
let onItemCommand = function (aEvent) {
|
CustomizableUI.hidePanelForNode(item);
|
||||||
let item = aEvent.target;
|
};
|
||||||
openUILink(item.getAttribute("targetURI"), aEvent);
|
|
||||||
CustomizableUI.hidePanelForNode(item);
|
|
||||||
};
|
|
||||||
|
|
||||||
let fragment = document.createDocumentFragment();
|
let fragment = document.createDocumentFragment();
|
||||||
let row;
|
let root = PlacesUtils.history.executeQuery(query, options).root;
|
||||||
while ((row = aResultSet.getNextRow())) {
|
root.containerOpen = true;
|
||||||
let uri = row.getResultByIndex(1);
|
for (let i = 0; i < root.childCount; i++) {
|
||||||
let title = row.getResultByIndex(2);
|
let node = root.getChild(i);
|
||||||
let icon = row.getResultByIndex(6);
|
let uri = node.uri;
|
||||||
|
let title = node.title;
|
||||||
|
let icon = node.icon;
|
||||||
|
|
||||||
let item =
|
let item =
|
||||||
document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||||
"menuitem");
|
"menuitem");
|
||||||
item.setAttribute("label", title || uri);
|
item.setAttribute("label", title || uri);
|
||||||
item.setAttribute("targetURI", uri);
|
item.setAttribute("targetURI", uri);
|
||||||
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
|
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
|
||||||
extraCSSClass);
|
extraCSSClass);
|
||||||
item.addEventListener("command", onItemCommand);
|
item.addEventListener("command", onItemCommand);
|
||||||
if (icon) {
|
if (icon) {
|
||||||
let iconURL = "moz-anno:favicon:" + icon;
|
let iconURL = "moz-anno:favicon:" + icon;
|
||||||
item.setAttribute("image", iconURL);
|
item.setAttribute("image", iconURL);
|
||||||
}
|
}
|
||||||
fragment.appendChild(item);
|
fragment.appendChild(item);
|
||||||
}
|
}
|
||||||
aHeaderItem.parentNode.insertBefore(fragment, aHeaderItem.nextSibling);
|
root.containerOpen = false;
|
||||||
},
|
aHeaderItem.parentNode.insertBefore(fragment, aHeaderItem.nextSibling);
|
||||||
handleError: function (aError) {
|
|
||||||
Cu.reportError("Error while attempting to show recent bookmarks: " + aError);
|
|
||||||
},
|
|
||||||
handleCompletion: function (aReason) {
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -252,7 +252,8 @@ ContentSearchUIController.prototype = {
|
||||||
let searchText = this.input;
|
let searchText = this.input;
|
||||||
let searchTerms;
|
let searchTerms;
|
||||||
if (this._table.hidden ||
|
if (this._table.hidden ||
|
||||||
aEvent.originalTarget.id == "contentSearchDefaultEngineHeader") {
|
aEvent.originalTarget.id == "contentSearchDefaultEngineHeader" ||
|
||||||
|
aEvent instanceof KeyboardEvent) {
|
||||||
searchTerms = searchText.value;
|
searchTerms = searchText.value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -290,7 +290,6 @@ skip-if = os == 'win' || e10s # Bug 1159268 - Need a content-process safe versio
|
||||||
[browser_bug1070778.js]
|
[browser_bug1070778.js]
|
||||||
[browser_accesskeys.js]
|
[browser_accesskeys.js]
|
||||||
[browser_canonizeURL.js]
|
[browser_canonizeURL.js]
|
||||||
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
|
|
||||||
[browser_clipboard.js]
|
[browser_clipboard.js]
|
||||||
[browser_contentAreaClick.js]
|
[browser_contentAreaClick.js]
|
||||||
[browser_contextmenu.js]
|
[browser_contextmenu.js]
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
testNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
var pairs = [
|
var pairs = [
|
||||||
["example", "http://www.example.net/"],
|
["example", "http://www.example.net/"],
|
||||||
["ex-ample", "http://www.ex-ample.net/"],
|
["ex-ample", "http://www.ex-ample.net/"],
|
||||||
|
@ -20,37 +15,56 @@ var pairs = [
|
||||||
["ex ample", Services.search.defaultEngine.getSubmission("ex ample", null, "keyword").uri.spec],
|
["ex ample", Services.search.defaultEngine.getSubmission("ex ample", null, "keyword").uri.spec],
|
||||||
];
|
];
|
||||||
|
|
||||||
function testNext() {
|
add_task(function*() {
|
||||||
if (!pairs.length) {
|
for (let [inputValue, expectedURL] of pairs) {
|
||||||
finish();
|
let focusEventPromise = BrowserTestUtils.waitForEvent(gURLBar, "focus");
|
||||||
return;
|
let messagePromise = BrowserTestUtils.waitForMessage(gBrowser.selectedBrowser.messageManager,
|
||||||
}
|
"browser_canonizeURL:start");
|
||||||
|
|
||||||
let [inputValue, expectedURL] = pairs.shift();
|
let stoppedLoadPromise = ContentTask.spawn(gBrowser.selectedBrowser, [inputValue, expectedURL],
|
||||||
|
function([inputValue, expectedURL]) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let wpl = {
|
||||||
|
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||||
|
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
|
||||||
|
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
|
||||||
|
if (!aRequest || !(aRequest instanceof Ci.nsIChannel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aRequest.QueryInterface(Ci.nsIChannel);
|
||||||
|
is(aRequest.originalURI.spec, expectedURL,
|
||||||
|
"entering '" + inputValue + "' loads expected URL");
|
||||||
|
|
||||||
gBrowser.addProgressListener({
|
webProgress.removeProgressListener(filter);
|
||||||
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
|
filter.removeProgressListener(wpl);
|
||||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
|
docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
|
docShell.stop(docShell.STOP_ALL);
|
||||||
is(aRequest.originalURI.spec, expectedURL,
|
resolve();
|
||||||
"entering '" + inputValue + "' loads expected URL");
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
||||||
|
.createInstance(Ci.nsIWebProgress);
|
||||||
|
filter.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||||
|
|
||||||
gBrowser.removeProgressListener(this);
|
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
gBrowser.stop();
|
.getInterface(Ci.nsIWebProgress);
|
||||||
|
webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||||
executeSoon(testNext);
|
// We're sending this off to trigger the start of the this test, when all the
|
||||||
|
// listeners are in place:
|
||||||
|
sendAsyncMessage("browser_canonizeURL:start");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
});
|
|
||||||
|
gBrowser.selectedBrowser.focus();
|
||||||
|
gURLBar.focus();
|
||||||
|
|
||||||
|
yield Promise.all([focusEventPromise, messagePromise]);
|
||||||
|
|
||||||
gURLBar.addEventListener("focus", function onFocus() {
|
|
||||||
gURLBar.removeEventListener("focus", onFocus);
|
|
||||||
gURLBar.inputField.value = inputValue.slice(0, -1);
|
gURLBar.inputField.value = inputValue.slice(0, -1);
|
||||||
EventUtils.synthesizeKey(inputValue.slice(-1) , {});
|
EventUtils.synthesizeKey(inputValue.slice(-1) , {});
|
||||||
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
|
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
|
||||||
});
|
yield stoppedLoadPromise;
|
||||||
|
}
|
||||||
gBrowser.selectedBrowser.focus();
|
});
|
||||||
gURLBar.focus();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
when-connection="secure secure-ev"/>
|
when-connection="secure secure-ev"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
<vbox id="identity-popup-securityView-body">
|
<vbox id="identity-popup-securityView-body" flex="1">
|
||||||
<!-- (EV) Certificate Information -->
|
<!-- (EV) Certificate Information -->
|
||||||
<description id="identity-popup-content-verified-by"
|
<description id="identity-popup-content-verified-by"
|
||||||
when-connection="secure-ev">&identity.connectionVerified1;</description>
|
when-connection="secure-ev">&identity.connectionVerified1;</description>
|
||||||
|
@ -168,7 +168,9 @@
|
||||||
label="&identity.enableMixedContentBlocking.label;"
|
label="&identity.enableMixedContentBlocking.label;"
|
||||||
accesskey="&identity.enableMixedContentBlocking.accesskey;"
|
accesskey="&identity.enableMixedContentBlocking.accesskey;"
|
||||||
oncommand="gIdentityHandler.enableMixedContentProtection()"/>
|
oncommand="gIdentityHandler.enableMixedContentProtection()"/>
|
||||||
|
</vbox>
|
||||||
|
|
||||||
|
<vbox id="identity-popup-securityView-footer">
|
||||||
<!-- More Security Information -->
|
<!-- More Security Information -->
|
||||||
<button label="&identity.moreInfoLinkText2;"
|
<button label="&identity.moreInfoLinkText2;"
|
||||||
oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
|
oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
|
||||||
|
|
|
@ -346,11 +346,47 @@ DistributionCustomizer.prototype = {
|
||||||
Cu.reportError(e);
|
Cu.reportError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var usedPreferences = [];
|
||||||
|
|
||||||
|
if (sections["Preferences-" + this._locale]) {
|
||||||
|
for (let key of enumerate(this._ini.getKeys("Preferences-" + this._locale))) {
|
||||||
|
try {
|
||||||
|
let value = this._ini.getString("Preferences-" + this._locale, key);
|
||||||
|
if (value) {
|
||||||
|
Preferences.set(key, parseValue(value));
|
||||||
|
}
|
||||||
|
usedPreferences.push(key);
|
||||||
|
} catch (e) { /* ignore bad prefs and move on */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sections["Preferences-" + this._language]) {
|
||||||
|
for (let key of enumerate(this._ini.getKeys("Preferences-" + this._language))) {
|
||||||
|
if (usedPreferences.indexOf(key) > -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let value = this._ini.getString("Preferences-" + this._language, key);
|
||||||
|
if (value) {
|
||||||
|
Preferences.set(key, parseValue(value));
|
||||||
|
}
|
||||||
|
usedPreferences.push(key);
|
||||||
|
} catch (e) { /* ignore bad prefs and move on */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sections["Preferences"]) {
|
if (sections["Preferences"]) {
|
||||||
for (let key of enumerate(this._ini.getKeys("Preferences"))) {
|
for (let key of enumerate(this._ini.getKeys("Preferences"))) {
|
||||||
|
if (usedPreferences.indexOf(key) > -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let value = parseValue(this._ini.getString("Preferences", key));
|
let value = this._ini.getString("Preferences", key);
|
||||||
Preferences.set(key, value);
|
if (value) {
|
||||||
|
value = value.replace(/%LOCALE%/g, this._locale);
|
||||||
|
value = value.replace(/%LANGUAGE%/g, this._language);
|
||||||
|
Preferences.set(key, parseValue(value));
|
||||||
|
}
|
||||||
} catch (e) { /* ignore bad prefs and move on */ }
|
} catch (e) { /* ignore bad prefs and move on */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,8 +399,9 @@ DistributionCustomizer.prototype = {
|
||||||
if (sections["LocalizablePreferences-" + this._locale]) {
|
if (sections["LocalizablePreferences-" + this._locale]) {
|
||||||
for (let key of enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) {
|
for (let key of enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) {
|
||||||
try {
|
try {
|
||||||
let value = parseValue(this._ini.getString("LocalizablePreferences-" + this._locale, key));
|
let value = this._ini.getString("LocalizablePreferences-" + this._locale, key);
|
||||||
if (value !== undefined) {
|
if (value) {
|
||||||
|
value = parseValue(value);
|
||||||
localizedStr.data = "data:text/plain," + key + "=" + value;
|
localizedStr.data = "data:text/plain," + key + "=" + value;
|
||||||
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
||||||
}
|
}
|
||||||
|
@ -379,8 +416,9 @@ DistributionCustomizer.prototype = {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let value = parseValue(this._ini.getString("LocalizablePreferences-" + this._language, key));
|
let value = this._ini.getString("LocalizablePreferences-" + this._language, key);
|
||||||
if (value !== undefined) {
|
if (value) {
|
||||||
|
value = parseValue(value);
|
||||||
localizedStr.data = "data:text/plain," + key + "=" + value;
|
localizedStr.data = "data:text/plain," + key + "=" + value;
|
||||||
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
||||||
}
|
}
|
||||||
|
@ -395,13 +433,14 @@ DistributionCustomizer.prototype = {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let value = parseValue(this._ini.getString("LocalizablePreferences", key));
|
let value = this._ini.getString("LocalizablePreferences", key);
|
||||||
if (value !== undefined) {
|
if (value) {
|
||||||
|
value = parseValue(value);
|
||||||
value = value.replace(/%LOCALE%/g, this._locale);
|
value = value.replace(/%LOCALE%/g, this._locale);
|
||||||
value = value.replace(/%LANGUAGE%/g, this._language);
|
value = value.replace(/%LANGUAGE%/g, this._language);
|
||||||
localizedStr.data = "data:text/plain," + key + "=" + value;
|
localizedStr.data = "data:text/plain," + key + "=" + value;
|
||||||
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
|
||||||
}
|
}
|
||||||
|
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
||||||
} catch (e) { /* ignore bad prefs and move on */ }
|
} catch (e) { /* ignore bad prefs and move on */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,19 @@ global.makeWidgetId = id => {
|
||||||
return id.replace(/[^a-z0-9_-]/g, "_");
|
return id.replace(/[^a-z0-9_-]/g, "_");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function promisePopupShown(popup) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (popup.state == "open") {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
popup.addEventListener("popupshown", function onPopupShown(event) {
|
||||||
|
popup.removeEventListener("popupshown", onPopupShown);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class BasePopup {
|
class BasePopup {
|
||||||
constructor(extension, viewNode, popupURL) {
|
constructor(extension, viewNode, popupURL) {
|
||||||
let popupURI = Services.io.newURI(popupURL, null, extension.baseURI);
|
let popupURI = Services.io.newURI(popupURL, null, extension.baseURI);
|
||||||
|
@ -254,6 +267,10 @@ class BasePopup {
|
||||||
|
|
||||||
// Resizes the browser to match the preferred size of the content.
|
// Resizes the browser to match the preferred size of the content.
|
||||||
resizeBrowser() {
|
resizeBrowser() {
|
||||||
|
if (!this.browser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let width, height;
|
let width, height;
|
||||||
try {
|
try {
|
||||||
let w = {}, h = {};
|
let w = {}, h = {};
|
||||||
|
@ -310,7 +327,12 @@ global.PanelPopup = class PanelPopup extends BasePopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
closePopup() {
|
closePopup() {
|
||||||
this.viewNode.hidePopup();
|
promisePopupShown(this.viewNode).then(() => {
|
||||||
|
// Make sure we're not already destroyed.
|
||||||
|
if (this.viewNode) {
|
||||||
|
this.viewNode.hidePopup();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function* testInArea(area) {
|
function* testInArea(area) {
|
||||||
|
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head></html>`;
|
||||||
|
|
||||||
let extension = ExtensionTestUtils.loadExtension({
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
manifest: {
|
manifest: {
|
||||||
"background": {
|
"background": {
|
||||||
|
@ -14,17 +16,22 @@ function* testInArea(area) {
|
||||||
},
|
},
|
||||||
|
|
||||||
files: {
|
files: {
|
||||||
"popup-a.html": `<script src="popup-a.js"></script>`,
|
"popup-a.html": scriptPage("popup-a.js"),
|
||||||
"popup-a.js": function() {
|
"popup-a.js": function() {
|
||||||
browser.runtime.sendMessage("from-popup-a");
|
browser.runtime.sendMessage("from-popup-a");
|
||||||
|
browser.runtime.onMessage.addListener(msg => {
|
||||||
|
if (msg == "close-popup") {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
"data/popup-b.html": `<script src="popup-b.js"></script>`,
|
"data/popup-b.html": scriptPage("popup-b.js"),
|
||||||
"data/popup-b.js": function() {
|
"data/popup-b.js": function() {
|
||||||
browser.runtime.sendMessage("from-popup-b");
|
browser.runtime.sendMessage("from-popup-b");
|
||||||
},
|
},
|
||||||
|
|
||||||
"data/background.html": `<script src="background.js"></script>`,
|
"data/background.html": scriptPage("background.js"),
|
||||||
|
|
||||||
"data/background.js": function() {
|
"data/background.js": function() {
|
||||||
let sendClick;
|
let sendClick;
|
||||||
|
@ -51,26 +58,36 @@ function* testInArea(area) {
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
browser.browserAction.setPopup({popup: "/popup-a.html"});
|
browser.browserAction.setPopup({popup: "/popup-a.html"});
|
||||||
sendClick({expectEvent: false, expectPopup: "a"});
|
sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
browser.test.sendMessage("next-test", {expectClosed: true});
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let expect = {};
|
let expect = {};
|
||||||
sendClick = ({expectEvent, expectPopup}) => {
|
sendClick = ({expectEvent, expectPopup, runNextTest}) => {
|
||||||
expect = {event: expectEvent, popup: expectPopup};
|
expect = {event: expectEvent, popup: expectPopup, runNextTest};
|
||||||
browser.test.sendMessage("send-click");
|
browser.test.sendMessage("send-click");
|
||||||
};
|
};
|
||||||
|
|
||||||
browser.runtime.onMessage.addListener(msg => {
|
browser.runtime.onMessage.addListener(msg => {
|
||||||
if (expect.popup) {
|
if (msg == "close-popup") {
|
||||||
|
return;
|
||||||
|
} else if (expect.popup) {
|
||||||
browser.test.assertEq(msg, `from-popup-${expect.popup}`,
|
browser.test.assertEq(msg, `from-popup-${expect.popup}`,
|
||||||
"expected popup opened");
|
"expected popup opened");
|
||||||
} else {
|
} else {
|
||||||
browser.test.fail("unexpected popup");
|
browser.test.fail(`unexpected popup: ${msg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect.popup = null;
|
expect.popup = null;
|
||||||
browser.test.sendMessage("next-test");
|
if (expect.runNextTest) {
|
||||||
|
expect.runNextTest = false;
|
||||||
|
tests.shift()();
|
||||||
|
} else {
|
||||||
|
browser.test.sendMessage("next-test");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.browserAction.onClicked.addListener(() => {
|
browser.browserAction.onClicked.addListener(() => {
|
||||||
|
@ -85,6 +102,11 @@ function* testInArea(area) {
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.test.onMessage.addListener((msg) => {
|
browser.test.onMessage.addListener((msg) => {
|
||||||
|
if (msg == "close-popup") {
|
||||||
|
browser.runtime.sendMessage("close-popup");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg != "next-test") {
|
if (msg != "next-test") {
|
||||||
browser.test.fail("Expecting 'next-test' message");
|
browser.test.fail("Expecting 'next-test' message");
|
||||||
}
|
}
|
||||||
|
@ -107,13 +129,23 @@ function* testInArea(area) {
|
||||||
});
|
});
|
||||||
|
|
||||||
let widget;
|
let widget;
|
||||||
extension.onMessage("next-test", Task.async(function* () {
|
extension.onMessage("next-test", Task.async(function* (expecting = {}) {
|
||||||
if (!widget) {
|
if (!widget) {
|
||||||
widget = getBrowserActionWidget(extension);
|
widget = getBrowserActionWidget(extension);
|
||||||
CustomizableUI.addWidgetToArea(widget.id, area);
|
CustomizableUI.addWidgetToArea(widget.id, area);
|
||||||
}
|
}
|
||||||
|
if (expecting.expectClosed) {
|
||||||
|
let panel = getBrowserActionPopup(extension);
|
||||||
|
ok(panel, "Expect panel to exist");
|
||||||
|
yield promisePopupShown(panel);
|
||||||
|
|
||||||
yield closeBrowserAction(extension);
|
extension.sendMessage("close-popup");
|
||||||
|
|
||||||
|
yield promisePopupHidden(panel);
|
||||||
|
ok(true, "Panel is closed");
|
||||||
|
} else {
|
||||||
|
yield closeBrowserAction(extension);
|
||||||
|
}
|
||||||
|
|
||||||
extension.sendMessage("next-test");
|
extension.sendMessage("next-test");
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -19,6 +19,11 @@ add_task(function* testPageActionPopup() {
|
||||||
"popup-a.html": scriptPage("popup-a.js"),
|
"popup-a.html": scriptPage("popup-a.js"),
|
||||||
"popup-a.js": function() {
|
"popup-a.js": function() {
|
||||||
browser.runtime.sendMessage("from-popup-a");
|
browser.runtime.sendMessage("from-popup-a");
|
||||||
|
browser.runtime.onMessage.addListener(msg => {
|
||||||
|
if (msg == "close-popup") {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
"data/popup-b.html": scriptPage("popup-b.js"),
|
"data/popup-b.html": scriptPage("popup-b.js"),
|
||||||
|
@ -55,26 +60,36 @@ add_task(function* testPageActionPopup() {
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
browser.pageAction.setPopup({tabId, popup: "/popup-a.html"});
|
browser.pageAction.setPopup({tabId, popup: "/popup-a.html"});
|
||||||
sendClick({expectEvent: false, expectPopup: "a"});
|
sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
browser.test.sendMessage("next-test", {expectClosed: true});
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let expect = {};
|
let expect = {};
|
||||||
sendClick = ({expectEvent, expectPopup}) => {
|
sendClick = ({expectEvent, expectPopup, runNextTest}) => {
|
||||||
expect = {event: expectEvent, popup: expectPopup};
|
expect = {event: expectEvent, popup: expectPopup, runNextTest};
|
||||||
browser.test.sendMessage("send-click");
|
browser.test.sendMessage("send-click");
|
||||||
};
|
};
|
||||||
|
|
||||||
browser.runtime.onMessage.addListener(msg => {
|
browser.runtime.onMessage.addListener(msg => {
|
||||||
if (expect.popup) {
|
if (msg == "close-popup") {
|
||||||
|
return;
|
||||||
|
} else if (expect.popup) {
|
||||||
browser.test.assertEq(msg, `from-popup-${expect.popup}`,
|
browser.test.assertEq(msg, `from-popup-${expect.popup}`,
|
||||||
"expected popup opened");
|
"expected popup opened");
|
||||||
} else {
|
} else {
|
||||||
browser.test.fail("unexpected popup");
|
browser.test.fail(`unexpected popup: ${msg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect.popup = null;
|
expect.popup = null;
|
||||||
browser.test.sendMessage("next-test");
|
if (expect.runNextTest) {
|
||||||
|
expect.runNextTest = false;
|
||||||
|
tests.shift()();
|
||||||
|
} else {
|
||||||
|
browser.test.sendMessage("next-test");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.pageAction.onClicked.addListener(() => {
|
browser.pageAction.onClicked.addListener(() => {
|
||||||
|
@ -89,6 +104,11 @@ add_task(function* testPageActionPopup() {
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.test.onMessage.addListener((msg) => {
|
browser.test.onMessage.addListener((msg) => {
|
||||||
|
if (msg == "close-popup") {
|
||||||
|
browser.runtime.sendMessage("close-popup");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg != "next-test") {
|
if (msg != "next-test") {
|
||||||
browser.test.fail("Expecting 'next-test' message");
|
browser.test.fail("Expecting 'next-test' message");
|
||||||
}
|
}
|
||||||
|
@ -118,12 +138,22 @@ add_task(function* testPageActionPopup() {
|
||||||
clickPageAction(extension);
|
clickPageAction(extension);
|
||||||
});
|
});
|
||||||
|
|
||||||
extension.onMessage("next-test", Task.async(function* () {
|
extension.onMessage("next-test", Task.async(function* (expecting = {}) {
|
||||||
let panel = document.getElementById(panelId);
|
let panel = document.getElementById(panelId);
|
||||||
if (panel) {
|
if (expecting.expectClosed) {
|
||||||
|
ok(panel, "Expect panel to exist");
|
||||||
|
yield promisePopupShown(panel);
|
||||||
|
|
||||||
|
extension.sendMessage("close-popup");
|
||||||
|
|
||||||
|
yield promisePopupHidden(panel);
|
||||||
|
ok(true, `Panel is closed`);
|
||||||
|
} else if (panel) {
|
||||||
yield promisePopupShown(panel);
|
yield promisePopupShown(panel);
|
||||||
panel.hidePopup();
|
panel.hidePopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panel) {
|
||||||
panel = document.getElementById(panelId);
|
panel = document.getElementById(panelId);
|
||||||
is(panel, null, "panel successfully removed from document after hiding");
|
is(panel, null, "panel successfully removed from document after hiding");
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,9 @@ add_task(function* testWebNavigationFrames() {
|
||||||
is(getAllFramesDetails.length, collectedDetails.length,
|
is(getAllFramesDetails.length, collectedDetails.length,
|
||||||
"number of frames found should equal the number onCompleted events collected");
|
"number of frames found should equal the number onCompleted events collected");
|
||||||
|
|
||||||
|
is(getAllFramesDetails[0].frameId, 0, "the root frame has the expected frameId");
|
||||||
|
is(getAllFramesDetails[0].parentFrameId, -1, "the root frame has the expected parentFrameId");
|
||||||
|
|
||||||
// ordered by frameId
|
// ordered by frameId
|
||||||
let sortByFrameId = (el1, el2) => {
|
let sortByFrameId = (el1, el2) => {
|
||||||
let val1 = el1 ? el1.frameId : -1;
|
let val1 = el1 ? el1.frameId : -1;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* clickBrowserAction clickPageAction
|
* clickBrowserAction clickPageAction
|
||||||
* getBrowserActionPopup getPageActionPopup
|
* getBrowserActionPopup getPageActionPopup
|
||||||
* closeBrowserAction closePageAction
|
* closeBrowserAction closePageAction
|
||||||
* promisePopupShown
|
* promisePopupShown promisePopupHidden
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
|
var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||||
|
@ -59,6 +59,16 @@ function promisePopupShown(popup) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function promisePopupHidden(popup) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let onPopupHidden = event => {
|
||||||
|
popup.removeEventListener("popuphidden", onPopupHidden);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
popup.addEventListener("popuphidden", onPopupHidden);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getBrowserActionWidget(extension) {
|
function getBrowserActionWidget(extension) {
|
||||||
return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
|
return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
|
||||||
}
|
}
|
||||||
|
@ -68,6 +78,8 @@ function getBrowserActionPopup(extension, win = window) {
|
||||||
|
|
||||||
if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
|
if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
|
||||||
return win.document.getElementById("customizationui-widget-panel");
|
return win.document.getElementById("customizationui-widget-panel");
|
||||||
|
} else {
|
||||||
|
return win.PanelUI.panel;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ skip-if = e10s # Bug ?????? - test fails - "Number of dragged items should be th
|
||||||
[browser_library_search.js]
|
[browser_library_search.js]
|
||||||
[browser_library_views_liveupdate.js]
|
[browser_library_views_liveupdate.js]
|
||||||
[browser_markPageAsFollowedLink.js]
|
[browser_markPageAsFollowedLink.js]
|
||||||
skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly (test does EventUtils.sendMouseEvent...)
|
|
||||||
[browser_sidebarpanels_click.js]
|
[browser_sidebarpanels_click.js]
|
||||||
skip-if = true # temporarily disabled for breaking the treeview - bug 658744
|
skip-if = true # temporarily disabled for breaking the treeview - bug 658744
|
||||||
[browser_sort_in_library.js]
|
[browser_sort_in_library.js]
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that visits across frames are correctly represented in the database.
|
* Tests that visits across frames are correctly represented in the database.
|
||||||
*/
|
*/
|
||||||
|
@ -11,76 +7,61 @@ const PAGE_URL = BASE_URL + "/framedPage.html";
|
||||||
const LEFT_URL = BASE_URL + "/frameLeft.html";
|
const LEFT_URL = BASE_URL + "/frameLeft.html";
|
||||||
const RIGHT_URL = BASE_URL + "/frameRight.html";
|
const RIGHT_URL = BASE_URL + "/frameRight.html";
|
||||||
|
|
||||||
var gTabLoaded = false;
|
add_task(function* test() {
|
||||||
var gLeftFrameVisited = false;
|
// We must wait for both frames to be loaded and the visits to be registered.
|
||||||
|
let deferredLeftFrameVisit = PromiseUtils.defer();
|
||||||
|
let deferredRightFrameVisit = PromiseUtils.defer();
|
||||||
|
|
||||||
var observer = {
|
Services.obs.addObserver(function observe(subject) {
|
||||||
observe: function(aSubject, aTopic, aData)
|
Task.spawn(function* () {
|
||||||
{
|
let url = subject.QueryInterface(Ci.nsIURI).spec;
|
||||||
let url = aSubject.QueryInterface(Ci.nsIURI).spec;
|
if (url == LEFT_URL ) {
|
||||||
if (url == LEFT_URL ) {
|
is((yield getTransitionForUrl(url)), null,
|
||||||
is(getTransitionForUrl(url), null,
|
"Embed visits should not get a database entry.");
|
||||||
"Embed visits should not get a database entry.");
|
deferredLeftFrameVisit.resolve();
|
||||||
gLeftFrameVisited = true;
|
}
|
||||||
maybeClickLink();
|
else if (url == RIGHT_URL ) {
|
||||||
}
|
is((yield getTransitionForUrl(url)),
|
||||||
else if (url == RIGHT_URL ) {
|
PlacesUtils.history.TRANSITION_FRAMED_LINK,
|
||||||
is(getTransitionForUrl(url), PlacesUtils.history.TRANSITION_FRAMED_LINK,
|
"User activated visits should get a FRAMED_LINK transition.");
|
||||||
"User activated visits should get a FRAMED_LINK transition.");
|
Services.obs.removeObserver(observe, "uri-visit-saved");
|
||||||
finish();
|
deferredRightFrameVisit.resolve();
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
|
}, "uri-visit-saved", false);
|
||||||
};
|
|
||||||
Services.obs.addObserver(observer, "uri-visit-saved", false);
|
|
||||||
|
|
||||||
function test()
|
// Open a tab and wait for all the subframes to load.
|
||||||
{
|
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
|
||||||
waitForExplicitFinish();
|
|
||||||
gBrowser.selectedTab = gBrowser.addTab(PAGE_URL);
|
|
||||||
let frameCount = 0;
|
|
||||||
gBrowser.selectedBrowser.addEventListener("DOMContentLoaded",
|
|
||||||
function (event)
|
|
||||||
{
|
|
||||||
// Wait for all the frames.
|
|
||||||
if (frameCount++ < 2)
|
|
||||||
return;
|
|
||||||
gBrowser.selectedBrowser.removeEventListener("DOMContentLoaded", arguments.callee, false)
|
|
||||||
gTabLoaded = true;
|
|
||||||
maybeClickLink();
|
|
||||||
}, false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function maybeClickLink() {
|
// Wait for the left frame visit to be registered.
|
||||||
if (gTabLoaded && gLeftFrameVisited) {
|
info("Waiting left frame visit");
|
||||||
// Click on the link in the left frame to cause a page load in the
|
yield deferredLeftFrameVisit.promise;
|
||||||
// right frame.
|
|
||||||
EventUtils.sendMouseEvent({type: "click"}, "clickme", content.frames[0]);
|
// Click on the link in the left frame to cause a page load in the
|
||||||
|
// right frame.
|
||||||
|
info("Clicking link");
|
||||||
|
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
|
||||||
|
content.frames[0].document.getElementById("clickme").click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the right frame visit to be registered.
|
||||||
|
info("Waiting right frame visit");
|
||||||
|
yield deferredRightFrameVisit.promise;
|
||||||
|
|
||||||
|
yield BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
function* getTransitionForUrl(url) {
|
||||||
|
// Ensure all the transactions completed.
|
||||||
|
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||||
|
let db = yield PlacesUtils.promiseDBConnection();
|
||||||
|
let rows = yield db.execute(`
|
||||||
|
SELECT visit_type
|
||||||
|
FROM moz_historyvisits
|
||||||
|
WHERE place_id = (SELECT id FROM moz_places WHERE url = :url)`,
|
||||||
|
{ url });
|
||||||
|
if (rows.length) {
|
||||||
|
return rows[0].getResultByName("visit_type");
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTransitionForUrl(aUrl)
|
|
||||||
{
|
|
||||||
let dbConn = PlacesUtils.history
|
|
||||||
.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
|
||||||
let stmt = dbConn.createStatement(
|
|
||||||
"SELECT visit_type FROM moz_historyvisits WHERE place_id = " +
|
|
||||||
"(SELECT id FROM moz_places WHERE url = :page_url)");
|
|
||||||
stmt.params.page_url = aUrl;
|
|
||||||
try {
|
|
||||||
if (!stmt.executeStep()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return stmt.row.visit_type;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.finalize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerCleanupFunction(function ()
|
|
||||||
{
|
|
||||||
gBrowser.removeTab(gBrowser.selectedTab);
|
|
||||||
Services.obs.removeObserver(observer, "uri-visit-saved");
|
|
||||||
})
|
|
||||||
|
|
|
@ -13,6 +13,28 @@ distribution.test.string.noquotes=Test String
|
||||||
distribution.test.int=777
|
distribution.test.int=777
|
||||||
distribution.test.bool.true=true
|
distribution.test.bool.true=true
|
||||||
distribution.test.bool.false=false
|
distribution.test.bool.false=false
|
||||||
|
distribution.test.empty=
|
||||||
|
|
||||||
|
distribution.test.pref.locale="%LOCALE%"
|
||||||
|
distribution.test.pref.language.reset="Preference Set"
|
||||||
|
distribution.test.pref.locale.reset="Preference Set"
|
||||||
|
distribution.test.pref.locale.set="Preference Set"
|
||||||
|
distribution.test.pref.language.set="Preference Set"
|
||||||
|
|
||||||
|
[Preferences-en]
|
||||||
|
distribution.test.pref.language.en="en"
|
||||||
|
distribution.test.pref.language.reset=
|
||||||
|
distribution.test.pref.language.set="Language Set"
|
||||||
|
distribution.test.pref.locale.set="Language Set"
|
||||||
|
|
||||||
|
[Preferences-en-US]
|
||||||
|
distribution.test.pref.locale.en-US="en-US"
|
||||||
|
distribution.test.pref.locale.reset=
|
||||||
|
distribution.test.pref.locale.set="Locale Set"
|
||||||
|
|
||||||
|
|
||||||
|
[Preferences-de]
|
||||||
|
distribution.test.pref.language.de="de"
|
||||||
|
|
||||||
[LocalizablePreferences]
|
[LocalizablePreferences]
|
||||||
distribution.test.locale="%LOCALE%"
|
distribution.test.locale="%LOCALE%"
|
||||||
|
@ -33,4 +55,4 @@ distribution.test.locale.reset=
|
||||||
distribution.test.locale.set="Locale Set"
|
distribution.test.locale.set="Locale Set"
|
||||||
|
|
||||||
[LocalizablePreferences-de]
|
[LocalizablePreferences-de]
|
||||||
distribution.test.locale.de="de"
|
distribution.test.language.de="de"
|
||||||
|
|
|
@ -71,10 +71,30 @@ add_task(function* () {
|
||||||
Assert.equal(Services.prefs.getIntPref("distribution.test.int"), 777);
|
Assert.equal(Services.prefs.getIntPref("distribution.test.int"), 777);
|
||||||
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.true"), true);
|
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.true"), true);
|
||||||
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.false"), false);
|
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.false"), false);
|
||||||
|
|
||||||
|
Assert.throws(() => Services.prefs.getCharPref("distribution.test.empty"));
|
||||||
|
Assert.throws(() => Services.prefs.getIntPref("distribution.test.empty"));
|
||||||
|
Assert.throws(() => Services.prefs.getBoolPref("distribution.test.empty"));
|
||||||
|
|
||||||
|
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale"), "en-US");
|
||||||
|
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.en"), "en");
|
||||||
|
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.en-US"), "en-US");
|
||||||
|
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.de"));
|
||||||
|
// This value was never set because of the empty language specific pref
|
||||||
|
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.reset"));
|
||||||
|
// This value was never set because of the empty locale specific pref
|
||||||
|
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.locale.reset"));
|
||||||
|
// This value was overridden by a locale specific setting
|
||||||
|
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Locale Set");
|
||||||
|
// This value was overridden by a language specific setting
|
||||||
|
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.set"), "Language Set");
|
||||||
|
// Language should not override locale
|
||||||
|
Assert.notEqual(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Language Set");
|
||||||
|
|
||||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale", Ci.nsIPrefLocalizedString).data, "en-US");
|
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale", Ci.nsIPrefLocalizedString).data, "en-US");
|
||||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.language.en", Ci.nsIPrefLocalizedString).data, "en");
|
Assert.equal(Services.prefs.getComplexValue("distribution.test.language.en", Ci.nsIPrefLocalizedString).data, "en");
|
||||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale.en-US", Ci.nsIPrefLocalizedString).data, "en-US");
|
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale.en-US", Ci.nsIPrefLocalizedString).data, "en-US");
|
||||||
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.locale.de", Ci.nsIPrefLocalizedString));
|
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.de", Ci.nsIPrefLocalizedString));
|
||||||
// This value was never set because of the empty language specific pref
|
// This value was never set because of the empty language specific pref
|
||||||
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.reset", Ci.nsIPrefLocalizedString));
|
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.reset", Ci.nsIPrefLocalizedString));
|
||||||
// This value was never set because of the empty locale specific pref
|
// This value was never set because of the empty locale specific pref
|
||||||
|
|
|
@ -61,6 +61,15 @@ var ContentClick = {
|
||||||
|
|
||||||
// Note: We don't need the sidebar code here.
|
// Note: We don't need the sidebar code here.
|
||||||
|
|
||||||
|
// Mark the page as a user followed link. This is done so that history can
|
||||||
|
// distinguish automatic embed visits from user activated ones. For example
|
||||||
|
// pages loaded in frames are embed visits and lost with the session, while
|
||||||
|
// visits across frames should be preserved.
|
||||||
|
try {
|
||||||
|
if (!PrivateBrowsingUtils.isWindowPrivate(window))
|
||||||
|
PlacesUIUtils.markPageAsFollowedLink(json.href);
|
||||||
|
} catch (ex) { /* Skip invalid URIs. */ }
|
||||||
|
|
||||||
// This part is based on handleLinkClick.
|
// This part is based on handleLinkClick.
|
||||||
var where = window.whereToOpenLink(json);
|
var where = window.whereToOpenLink(json);
|
||||||
if (where == "current")
|
if (where == "current")
|
||||||
|
@ -73,14 +82,5 @@ var ContentClick = {
|
||||||
referrerPolicy: json.referrerPolicy,
|
referrerPolicy: json.referrerPolicy,
|
||||||
noReferrer: json.noReferrer };
|
noReferrer: json.noReferrer };
|
||||||
window.openLinkIn(json.href, where, params);
|
window.openLinkIn(json.href, where, params);
|
||||||
|
|
||||||
// Mark the page as a user followed link. This is done so that history can
|
|
||||||
// distinguish automatic embed visits from user activated ones. For example
|
|
||||||
// pages loaded in frames are embed visits and lost with the session, while
|
|
||||||
// visits across frames should be preserved.
|
|
||||||
try {
|
|
||||||
if (!PrivateBrowsingUtils.isWindowPrivate(window))
|
|
||||||
PlacesUIUtils.markPageAsFollowedLink(json.href);
|
|
||||||
} catch (ex) { /* Skip invalid URIs. */ }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,15 @@
|
||||||
@hudButtonFocused@
|
@hudButtonFocused@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
|
||||||
|
border-bottom-right-radius: 3.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews:-moz-locale-dir(rtl) {
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-bottom-left-radius: 3.5px;
|
||||||
|
}
|
||||||
|
|
||||||
#tracking-action-block,
|
#tracking-action-block,
|
||||||
#tracking-action-unblock,
|
#tracking-action-unblock,
|
||||||
#tracking-action-unblock-private,
|
#tracking-action-unblock-private,
|
||||||
|
|
|
@ -83,15 +83,9 @@
|
||||||
|
|
||||||
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
|
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
|
||||||
background: var(--panel-arrowcontent-background);
|
background: var(--panel-arrowcontent-background);
|
||||||
border-bottom-right-radius: 3.5px;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews:-moz-locale-dir(rtl) {
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-bottom-left-radius: 3.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.identity-popup-section:not(:first-child) {
|
.identity-popup-section:not(:first-child) {
|
||||||
border-top: 1px solid var(--panel-separator-color);
|
border-top: 1px solid var(--panel-separator-color);
|
||||||
}
|
}
|
||||||
|
@ -100,14 +94,19 @@
|
||||||
#identity-popup-security-content,
|
#identity-popup-security-content,
|
||||||
#identity-popup-permissions-content,
|
#identity-popup-permissions-content,
|
||||||
#tracking-protection-content {
|
#tracking-protection-content {
|
||||||
padding: 0.5em 0 1em;
|
|
||||||
-moz-padding-start: calc(2em + 24px);
|
|
||||||
-moz-padding-end: 1em;
|
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 1em 1em;
|
background-position: 1em 1em;
|
||||||
background-size: 24px auto;
|
background-size: 24px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#identity-popup-security-content,
|
||||||
|
#identity-popup-permissions-content,
|
||||||
|
#tracking-protection-content {
|
||||||
|
padding: 0.5em 0 1em;
|
||||||
|
-moz-padding-start: calc(2em + 24px);
|
||||||
|
-moz-padding-end: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
#identity-popup-securityView:-moz-locale-dir(rtl),
|
#identity-popup-securityView:-moz-locale-dir(rtl),
|
||||||
#identity-popup-security-content:-moz-locale-dir(rtl),
|
#identity-popup-security-content:-moz-locale-dir(rtl),
|
||||||
#identity-popup-permissions-content:-moz-locale-dir(rtl),
|
#identity-popup-permissions-content:-moz-locale-dir(rtl),
|
||||||
|
@ -208,7 +207,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#identity-popup-securityView {
|
#identity-popup-securityView {
|
||||||
padding-bottom: 2em;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +250,14 @@
|
||||||
color: Graytext;
|
color: Graytext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#identity-popup-securityView-header,
|
||||||
|
#identity-popup-securityView-body {
|
||||||
|
-moz-margin-start: calc(2em + 24px);
|
||||||
|
-moz-margin-end: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
#identity-popup-securityView-header {
|
#identity-popup-securityView-header {
|
||||||
|
margin-top: 0.5em;
|
||||||
border-bottom: 1px solid var(--panel-separator-color);
|
border-bottom: 1px solid var(--panel-separator-color);
|
||||||
padding-bottom: 1em;
|
padding-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
@ -261,6 +266,30 @@
|
||||||
-moz-padding-end: 1em;
|
-moz-padding-end: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#identity-popup-securityView-footer {
|
||||||
|
margin-top: 1em;
|
||||||
|
background-color: hsla(210,4%,10%,.07);
|
||||||
|
}
|
||||||
|
|
||||||
|
#identity-popup-securityView-footer > button {
|
||||||
|
-moz-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
padding: 8px 20px;
|
||||||
|
color: ButtonText;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#identity-popup-securityView-footer > button:hover,
|
||||||
|
#identity-popup-securityView-footer > button:focus {
|
||||||
|
background-color: hsla(210,4%,10%,.07);
|
||||||
|
}
|
||||||
|
|
||||||
|
#identity-popup-securityView-footer > button:hover:active {
|
||||||
|
background-color: hsla(210,4%,10%,.12);
|
||||||
|
}
|
||||||
|
|
||||||
#identity-popup-content-verifier ~ description {
|
#identity-popup-content-verifier ~ description {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
color: Graytext;
|
color: Graytext;
|
||||||
|
|
|
@ -8,6 +8,13 @@ const Cu = Components.utils;
|
||||||
const Ci = Components.interfaces;
|
const Ci = Components.interfaces;
|
||||||
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||||
|
|
||||||
|
function actionOccurred(id) {
|
||||||
|
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||||
|
let Telemetry = require("devtools/client/shared/telemetry");;
|
||||||
|
let telemetry = new Telemetry();
|
||||||
|
telemetry.actionOccurred(id);
|
||||||
|
}
|
||||||
|
|
||||||
// Helper to listen to a key on all windows
|
// Helper to listen to a key on all windows
|
||||||
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
|
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
|
||||||
let keyListener = function (event) {
|
let keyListener = function (event) {
|
||||||
|
@ -150,6 +157,8 @@ function reload(event) {
|
||||||
gDevTools.showToolbox(target);
|
gDevTools.showToolbox(target);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actionOccurred("reloadAddonReload");
|
||||||
}
|
}
|
||||||
|
|
||||||
let listener;
|
let listener;
|
||||||
|
@ -165,5 +174,7 @@ function shutdown() {
|
||||||
listener.stop();
|
listener.stop();
|
||||||
listener = null;
|
listener = null;
|
||||||
}
|
}
|
||||||
function install() {}
|
function install() {
|
||||||
|
actionOccurred("reloadAddonInstalled");
|
||||||
|
}
|
||||||
function uninstall() {}
|
function uninstall() {}
|
||||||
|
|
|
@ -82,7 +82,10 @@ const EVENTS = {
|
||||||
OPTIONS_POPUP_HIDDEN: "Debugger:OptionsPopupHidden",
|
OPTIONS_POPUP_HIDDEN: "Debugger:OptionsPopupHidden",
|
||||||
|
|
||||||
// When the widgets layout has been changed.
|
// When the widgets layout has been changed.
|
||||||
LAYOUT_CHANGED: "Debugger:LayoutChanged"
|
LAYOUT_CHANGED: "Debugger:LayoutChanged",
|
||||||
|
|
||||||
|
// When a worker has been selected.
|
||||||
|
WORKER_SELECTED: "Debugger::WorkerSelected"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Descriptions for what a stack frame represents after the debugger pauses.
|
// Descriptions for what a stack frame represents after the debugger pauses.
|
||||||
|
@ -108,7 +111,7 @@ Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||||
var L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
|
var L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
|
||||||
|
|
||||||
Cu.import("resource://devtools/client/shared/browser-loader.js");
|
Cu.import("resource://devtools/client/shared/browser-loader.js");
|
||||||
const require = BrowserLoader("resource://devtools/client/debugger/", this).require;
|
const require = BrowserLoader("resource://devtools/client/debugger/", window).require;
|
||||||
XPCOMUtils.defineConstant(this, "require", require);
|
XPCOMUtils.defineConstant(this, "require", require);
|
||||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||||
|
|
||||||
|
@ -491,8 +494,8 @@ Workers.prototype = {
|
||||||
|
|
||||||
for (let workerActor in this._workerForms) {
|
for (let workerActor in this._workerForms) {
|
||||||
if (!(workerActor in workerForms)) {
|
if (!(workerActor in workerForms)) {
|
||||||
|
DebuggerView.Workers.removeWorker(this._workerForms[workerActor]);
|
||||||
delete this._workerForms[workerActor];
|
delete this._workerForms[workerActor];
|
||||||
DebuggerView.Workers.removeWorker(workerActor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +503,7 @@ Workers.prototype = {
|
||||||
if (!(workerActor in this._workerForms)) {
|
if (!(workerActor in this._workerForms)) {
|
||||||
let workerForm = workerForms[workerActor];
|
let workerForm = workerForms[workerActor];
|
||||||
this._workerForms[workerActor] = workerForm;
|
this._workerForms[workerActor] = workerForm;
|
||||||
DebuggerView.Workers.addWorker(workerActor, workerForm.url);
|
DebuggerView.Workers.addWorker(workerForm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -510,10 +513,11 @@ Workers.prototype = {
|
||||||
this._updateWorkerList();
|
this._updateWorkerList();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onWorkerSelect: function (workerActor) {
|
_onWorkerSelect: function (workerForm) {
|
||||||
DebuggerController.client.attachWorker(workerActor, (response, workerClient) => {
|
DebuggerController.client.attachWorker(workerForm.actor, (response, workerClient) => {
|
||||||
gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
|
let toolbox = gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
|
||||||
"jsdebugger", Toolbox.HostType.WINDOW);
|
"jsdebugger", Toolbox.HostType.WINDOW);
|
||||||
|
window.emit(EVENTS.WORKER_SELECTED, toolbox);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,6 +45,9 @@ support-files =
|
||||||
code_ugly-7.js
|
code_ugly-7.js
|
||||||
code_ugly-8
|
code_ugly-8
|
||||||
code_ugly-8^headers^
|
code_ugly-8^headers^
|
||||||
|
code_worker-source-map.coffee
|
||||||
|
code_worker-source-map.js
|
||||||
|
code_worker-source-map.js.map
|
||||||
code_WorkerActor.attach-worker1.js
|
code_WorkerActor.attach-worker1.js
|
||||||
code_WorkerActor.attach-worker2.js
|
code_WorkerActor.attach-worker2.js
|
||||||
code_WorkerActor.attachThread-worker.js
|
code_WorkerActor.attachThread-worker.js
|
||||||
|
@ -112,6 +115,7 @@ support-files =
|
||||||
doc_watch-expressions.html
|
doc_watch-expressions.html
|
||||||
doc_watch-expression-button.html
|
doc_watch-expression-button.html
|
||||||
doc_with-frame.html
|
doc_with-frame.html
|
||||||
|
doc_worker-source-map.html
|
||||||
doc_WorkerActor.attach-tab1.html
|
doc_WorkerActor.attach-tab1.html
|
||||||
doc_WorkerActor.attach-tab2.html
|
doc_WorkerActor.attach-tab2.html
|
||||||
doc_WorkerActor.attachThread-tab.html
|
doc_WorkerActor.attachThread-tab.html
|
||||||
|
@ -592,6 +596,8 @@ skip-if = e10s && debug
|
||||||
skip-if = e10s && debug
|
skip-if = e10s && debug
|
||||||
[browser_dbg_worker-console.js]
|
[browser_dbg_worker-console.js]
|
||||||
skip-if = e10s && debug
|
skip-if = e10s && debug
|
||||||
|
[browser_dbg_worker-source-map.js]
|
||||||
|
skip-if = e10s && debug
|
||||||
[browser_dbg_worker-window.js]
|
[browser_dbg_worker-window.js]
|
||||||
skip-if = e10s && debug
|
skip-if = e10s && debug
|
||||||
[browser_dbg_WorkerActor.attach.js]
|
[browser_dbg_WorkerActor.attach.js]
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
const TAB_URL = EXAMPLE_URL + "doc_worker-source-map.html";
|
||||||
|
const WORKER_URL = "code_worker-source-map.js";
|
||||||
|
const COFFEE_URL = EXAMPLE_URL + "code_worker-source-map.coffee";
|
||||||
|
|
||||||
|
function selectWorker(aPanel, aURL) {
|
||||||
|
let panelWin = aPanel.panelWin;
|
||||||
|
let promise = waitForDebuggerEvents(aPanel, panelWin.EVENTS.WORKER_SELECTED);
|
||||||
|
let Workers = panelWin.DebuggerView.Workers;
|
||||||
|
let item = Workers.getItemForAttachment((workerForm) => {
|
||||||
|
return workerForm.url === aURL;
|
||||||
|
});
|
||||||
|
Workers.selectedItem = item;
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
return Task.spawn(function* () {
|
||||||
|
yield pushPrefs(["devtools.debugger.workers", true]);
|
||||||
|
|
||||||
|
let [tab,, panel] = yield initDebugger(TAB_URL);
|
||||||
|
let toolbox = yield selectWorker(panel, WORKER_URL);
|
||||||
|
let workerPanel = toolbox.getCurrentPanel();
|
||||||
|
yield waitForSourceShown(workerPanel, ".coffee");
|
||||||
|
let panelWin = workerPanel.panelWin;
|
||||||
|
let Sources = panelWin.DebuggerView.Sources;
|
||||||
|
let editor = panelWin.DebuggerView.editor;
|
||||||
|
let threadClient = panelWin.gThreadClient;
|
||||||
|
|
||||||
|
isnot(Sources.selectedItem.attachment.source.url.indexOf(".coffee"), -1,
|
||||||
|
"The debugger should show the source mapped coffee source file.");
|
||||||
|
is(Sources.selectedValue.indexOf(".js"), -1,
|
||||||
|
"The debugger should not show the generated js source file.");
|
||||||
|
is(editor.getText().indexOf("isnt"), 211,
|
||||||
|
"The debugger's editor should have the coffee source source displayed.");
|
||||||
|
is(editor.getText().indexOf("function"), -1,
|
||||||
|
"The debugger's editor should not have the JS source displayed.");
|
||||||
|
|
||||||
|
yield threadClient.interrupt();
|
||||||
|
let sourceForm = getSourceForm(Sources, COFFEE_URL);
|
||||||
|
let source = threadClient.source(sourceForm);
|
||||||
|
let response = yield source.setBreakpoint({ line: 5 });
|
||||||
|
|
||||||
|
ok(!response.error,
|
||||||
|
"Should be able to set a breakpoint in a coffee source file.");
|
||||||
|
ok(!response.actualLocation,
|
||||||
|
"Should be able to set a breakpoint on line 5.");
|
||||||
|
|
||||||
|
let promise = new Promise((resolve) => {
|
||||||
|
threadClient.addOneTimeListener("paused", (event, packet) => {
|
||||||
|
is(packet.type, "paused",
|
||||||
|
"We should now be paused again.");
|
||||||
|
is(packet.why.type, "breakpoint",
|
||||||
|
"and the reason we should be paused is because we hit a breakpoint.");
|
||||||
|
|
||||||
|
// Check that we stopped at the right place, by making sure that the
|
||||||
|
// environment is in the state that we expect.
|
||||||
|
is(packet.frame.environment.bindings.variables.start.value, 0,
|
||||||
|
"'start' is 0.");
|
||||||
|
is(packet.frame.environment.bindings.variables.stop.value.type, "undefined",
|
||||||
|
"'stop' hasn't been assigned to yet.");
|
||||||
|
is(packet.frame.environment.bindings.variables.pivot.value.type, "undefined",
|
||||||
|
"'pivot' hasn't been assigned to yet.");
|
||||||
|
|
||||||
|
waitForCaretUpdated(workerPanel, 5).then(resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// This will cause the breakpoint to be hit, and put us back in the
|
||||||
|
// paused state.
|
||||||
|
yield threadClient.resume();
|
||||||
|
callInTab(tab, "binary_search", [0, 2, 3, 5, 7, 10], 5);
|
||||||
|
yield promise;
|
||||||
|
|
||||||
|
yield threadClient.resume();
|
||||||
|
yield toolbox.destroy();
|
||||||
|
yield closeDebuggerAndFinish(panel);
|
||||||
|
|
||||||
|
yield popPrefs();
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Uses a binary search algorithm to locate a value in the specified array.
|
||||||
|
binary_search = (items, value) ->
|
||||||
|
|
||||||
|
start = 0
|
||||||
|
stop = items.length - 1
|
||||||
|
pivot = Math.floor (start + stop) / 2
|
||||||
|
|
||||||
|
while items[pivot] isnt value and start < stop
|
||||||
|
|
||||||
|
# Adjust the search area.
|
||||||
|
stop = pivot - 1 if value < items[pivot]
|
||||||
|
start = pivot + 1 if value > items[pivot]
|
||||||
|
|
||||||
|
# Recalculate the pivot.
|
||||||
|
pivot = Math.floor (stop + start) / 2
|
||||||
|
|
||||||
|
# Make sure we've found the correct value.
|
||||||
|
if items[pivot] is value then pivot else -1
|
||||||
|
|
||||||
|
self.onmessage = (event) ->
|
||||||
|
data = event.data
|
||||||
|
binary_search(data.items, data.value)
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Generated by CoffeeScript 1.10.0
|
||||||
|
(function() {
|
||||||
|
var binary_search;
|
||||||
|
|
||||||
|
binary_search = function(items, value) {
|
||||||
|
var pivot, start, stop;
|
||||||
|
start = 0;
|
||||||
|
stop = items.length - 1;
|
||||||
|
pivot = Math.floor((start + stop) / 2);
|
||||||
|
while (items[pivot] !== value && start < stop) {
|
||||||
|
if (value < items[pivot]) {
|
||||||
|
stop = pivot - 1;
|
||||||
|
}
|
||||||
|
if (value > items[pivot]) {
|
||||||
|
start = pivot + 1;
|
||||||
|
}
|
||||||
|
pivot = Math.floor((stop + start) / 2);
|
||||||
|
}
|
||||||
|
if (items[pivot] === value) {
|
||||||
|
return pivot;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onmessage = function(event) {
|
||||||
|
console.log("EUTA");
|
||||||
|
var data;
|
||||||
|
data = event.data;
|
||||||
|
return binary_search(data.items, data.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
|
|
||||||
|
//# sourceMappingURL=code_worker-source-map.js.map
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"file": "code_worker-source-map.js",
|
||||||
|
"sourceRoot": "",
|
||||||
|
"sources": [
|
||||||
|
"code_worker-source-map.coffee"
|
||||||
|
],
|
||||||
|
"names": [],
|
||||||
|
"mappings": ";AACA;AAAA,MAAA;;EAAA,aAAA,GAAgB,SAAC,KAAD,EAAQ,KAAR;AAEd,QAAA;IAAA,KAAA,GAAQ;IACR,IAAA,GAAQ,KAAK,CAAC,MAAN,GAAe;IACvB,KAAA,GAAQ,IAAI,CAAC,KAAL,CAAW,CAAC,KAAA,GAAQ,IAAT,CAAA,GAAiB,CAA5B;AAER,WAAM,KAAM,CAAA,KAAA,CAAN,KAAkB,KAAlB,IAA4B,KAAA,GAAQ,IAA1C;MAGE,IAAqB,KAAA,GAAQ,KAAM,CAAA,KAAA,CAAnC;QAAA,IAAA,GAAQ,KAAA,GAAQ,EAAhB;;MACA,IAAqB,KAAA,GAAQ,KAAM,CAAA,KAAA,CAAnC;QAAA,KAAA,GAAQ,KAAA,GAAQ,EAAhB;;MAGA,KAAA,GAAQ,IAAI,CAAC,KAAL,CAAW,CAAC,IAAA,GAAO,KAAR,CAAA,GAAiB,CAA5B;IAPV;IAUA,IAAG,KAAM,CAAA,KAAA,CAAN,KAAgB,KAAnB;aAA8B,MAA9B;KAAA,MAAA;aAAyC,CAAC,EAA1C;;EAhBc;;EAkBhB,IAAI,CAAC,SAAL,GAAiB,SAAC,KAAD;AACf,QAAA;IAAA,IAAA,GAAO,KAAK,CAAC;WACb,aAAA,CAAc,IAAI,CAAC,KAAnB,EAA0B,IAAI,CAAC,KAA/B;EAFe;AAlBjB"
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<script>
|
||||||
|
var worker = new Worker("code_worker-source-map.js");
|
||||||
|
|
||||||
|
function binary_search(items, value) {
|
||||||
|
worker.postMessage({
|
||||||
|
items: items,
|
||||||
|
value: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -28,22 +28,24 @@ WorkersView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
this.widget.addEventListener("select", this._onWorkerSelect, false);
|
this.widget.addEventListener("select", this._onWorkerSelect, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
addWorker: function (actor, name) {
|
addWorker: function (workerForm) {
|
||||||
let element = document.createElement("label");
|
let element = document.createElement("label");
|
||||||
element.className = "plain dbg-worker-item";
|
element.className = "plain dbg-worker-item";
|
||||||
element.setAttribute("value", name);
|
element.setAttribute("value", workerForm.url);
|
||||||
element.setAttribute("flex", "1");
|
element.setAttribute("flex", "1");
|
||||||
|
|
||||||
this.push([element, actor], {});
|
this.push([element, workerForm.actor], {
|
||||||
|
attachment: workerForm
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
removeWorker: function (actor) {
|
removeWorker: function (workerForm) {
|
||||||
this.remove(this.getItemByValue(actor));
|
this.remove(this.getItemByValue(workerForm.actor));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onWorkerSelect: function () {
|
_onWorkerSelect: function () {
|
||||||
if (this.selectedItem !== null) {
|
if (this.selectedItem !== null) {
|
||||||
DebuggerController.Workers._onWorkerSelect(this.selectedItem.value);
|
DebuggerController.Workers._onWorkerSelect(this.selectedItem.attachment);
|
||||||
this.selectedItem = null;
|
this.selectedItem = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -912,6 +912,10 @@ Toolbox.prototype = {
|
||||||
if (!this.target.hasActor("gcli")) {
|
if (!this.target.hasActor("gcli")) {
|
||||||
return promise.resolve();
|
return promise.resolve();
|
||||||
}
|
}
|
||||||
|
// Disable gcli in browser toolbox until there is usages of it
|
||||||
|
if (this.target.chrome) {
|
||||||
|
return promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
environment: CommandUtils.createEnvironment(this, '_target')
|
environment: CommandUtils.createEnvironment(this, '_target')
|
||||||
|
|
|
@ -233,7 +233,15 @@ Telemetry.prototype = {
|
||||||
histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT",
|
histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT",
|
||||||
userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
|
userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
|
||||||
timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS"
|
timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS"
|
||||||
}
|
},
|
||||||
|
reloadAddonInstalled: {
|
||||||
|
histogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_COUNT",
|
||||||
|
userHistogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_PER_USER_FLAG",
|
||||||
|
},
|
||||||
|
reloadAddonReload: {
|
||||||
|
histogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_COUNT",
|
||||||
|
userHistogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_PER_USER_FLAG",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1150,6 +1150,8 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||||
upgradeDatabaseFrom25to26(db);
|
upgradeDatabaseFrom25to26(db);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// case 27 occurs in UrlMetadataTable.onUpgrade
|
||||||
|
|
||||||
case 28:
|
case 28:
|
||||||
upgradeDatabaseFrom27to28(db);
|
upgradeDatabaseFrom27to28(db);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.mozilla.gecko.AboutPages;
|
import org.mozilla.gecko.AboutPages;
|
||||||
import org.mozilla.gecko.GeckoProfile;
|
import org.mozilla.gecko.GeckoProfile;
|
||||||
|
import org.mozilla.gecko.R;
|
||||||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||||
import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
|
import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
|
||||||
|
@ -694,21 +695,25 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
|
|
||||||
final String TABLE_TOPSITES = "topsites";
|
final String TABLE_TOPSITES = "topsites";
|
||||||
|
|
||||||
final String totalLimit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT);
|
final String limitParam = uri.getQueryParameter(BrowserContract.PARAM_LIMIT);
|
||||||
final String suggestedGridLimit = uri.getQueryParameter(BrowserContract.PARAM_SUGGESTEDSITES_LIMIT);
|
final String gridLimitParam = uri.getQueryParameter(BrowserContract.PARAM_SUGGESTEDSITES_LIMIT);
|
||||||
|
|
||||||
final String[] suggestedGridLimitArgs = new String[] {
|
final int totalLimit;
|
||||||
suggestedGridLimit
|
final int suggestedGridLimit;
|
||||||
};
|
|
||||||
|
|
||||||
final String[] totalLimitArgs = new String[] {
|
if (limitParam == null) {
|
||||||
totalLimit
|
totalLimit = 50;
|
||||||
};
|
} else {
|
||||||
|
totalLimit = Integer.parseInt(limitParam, 10);
|
||||||
|
}
|
||||||
|
|
||||||
final String pinnedSitesFromClause = "FROM " + TABLE_BOOKMARKS + " WHERE " + Bookmarks.PARENT + " == ?";
|
if (gridLimitParam == null) {
|
||||||
final String[] pinnedSitesArgs = new String[] {
|
suggestedGridLimit = getContext().getResources().getInteger(R.integer.number_of_top_sites);
|
||||||
String.valueOf(Bookmarks.FIXED_PINNED_LIST_ID)
|
} else {
|
||||||
};
|
suggestedGridLimit = Integer.parseInt(gridLimitParam, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String pinnedSitesFromClause = "FROM " + TABLE_BOOKMARKS + " WHERE " + Bookmarks.PARENT + " == " + Bookmarks.FIXED_PINNED_LIST_ID;
|
||||||
|
|
||||||
// Ideally we'd use a recursive CTE to generate our sequence, e.g. something like this worked at one point:
|
// Ideally we'd use a recursive CTE to generate our sequence, e.g. something like this worked at one point:
|
||||||
// " WITH RECURSIVE" +
|
// " WITH RECURSIVE" +
|
||||||
|
@ -725,12 +730,7 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
" ON numbers.position > free_ids.position" +
|
" ON numbers.position > free_ids.position" +
|
||||||
" GROUP BY numbers.position" +
|
" GROUP BY numbers.position" +
|
||||||
" ORDER BY numbers.position ASC" +
|
" ORDER BY numbers.position ASC" +
|
||||||
" LIMIT ?";
|
" LIMIT " + suggestedGridLimit;
|
||||||
|
|
||||||
final String[] freeIDArgs = DBUtils.concatenateSelectionArgs(
|
|
||||||
pinnedSitesArgs,
|
|
||||||
pinnedSitesArgs,
|
|
||||||
suggestedGridLimitArgs);
|
|
||||||
|
|
||||||
// Filter out: unvisited pages (history_id == -1) pinned (and other special) sites, deleted sites,
|
// Filter out: unvisited pages (history_id == -1) pinned (and other special) sites, deleted sites,
|
||||||
// and about: pages.
|
// and about: pages.
|
||||||
|
@ -739,17 +739,15 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
" AND " +
|
" AND " +
|
||||||
Combined.URL + " NOT IN (SELECT " +
|
Combined.URL + " NOT IN (SELECT " +
|
||||||
Bookmarks.URL + " FROM bookmarks WHERE " +
|
Bookmarks.URL + " FROM bookmarks WHERE " +
|
||||||
DBUtils.qualifyColumn("bookmarks", Bookmarks.PARENT) + " < ? AND " +
|
DBUtils.qualifyColumn("bookmarks", Bookmarks.PARENT) + " < " + Bookmarks.FIXED_ROOT_ID + " AND " +
|
||||||
DBUtils.qualifyColumn("bookmarks", Bookmarks.IS_DELETED) + " == 0)" +
|
DBUtils.qualifyColumn("bookmarks", Bookmarks.IS_DELETED) + " == 0)" +
|
||||||
" AND " +
|
" AND " +
|
||||||
"(" + Combined.URL + " NOT LIKE ?)";
|
"(" + Combined.URL + " NOT LIKE ?)";
|
||||||
|
|
||||||
final String[] ignoreForTopSitesArgs = new String[] {
|
final String[] ignoreForTopSitesArgs = new String[] {
|
||||||
String.valueOf(Bookmarks.FIXED_ROOT_ID),
|
|
||||||
AboutPages.URL_FILTER
|
AboutPages.URL_FILTER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Stuff the suggested sites into SQL: this allows us to filter pinned and topsites out of the suggested
|
// Stuff the suggested sites into SQL: this allows us to filter pinned and topsites out of the suggested
|
||||||
// sites list as part of the final query (as opposed to walking cursors in java)
|
// sites list as part of the final query (as opposed to walking cursors in java)
|
||||||
final SuggestedSites suggestedSites = GeckoProfile.get(getContext(), uri.getQueryParameter(BrowserContract.PARAM_PROFILE)).getDB().getSuggestedSites();
|
final SuggestedSites suggestedSites = GeckoProfile.get(getContext(), uri.getQueryParameter(BrowserContract.PARAM_PROFILE)).getDB().getSuggestedSites();
|
||||||
|
@ -759,7 +757,7 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
// sites list, which means we'd need to process the lists within SuggestedSites in any case. If we're doing
|
// sites list, which means we'd need to process the lists within SuggestedSites in any case. If we're doing
|
||||||
// that processing, there is little real between us using a MatrixCursor, or a Map (or List) instead of the
|
// that processing, there is little real between us using a MatrixCursor, or a Map (or List) instead of the
|
||||||
// MatrixCursor.
|
// MatrixCursor.
|
||||||
final Cursor suggestedSitesCursor = suggestedSites.get(Integer.parseInt(suggestedGridLimit));
|
final Cursor suggestedSitesCursor = suggestedSites.get(suggestedGridLimit);
|
||||||
|
|
||||||
String[] suggestedSiteArgs = new String[0];
|
String[] suggestedSiteArgs = new String[0];
|
||||||
|
|
||||||
|
@ -791,11 +789,8 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
|
|
||||||
// To restrict suggested sites to the grid, we simply subtract the number of topsites (which have already had
|
// To restrict suggested sites to the grid, we simply subtract the number of topsites (which have already had
|
||||||
// the pinned sites filtered out), and the number of pinned sites.
|
// the pinned sites filtered out), and the number of pinned sites.
|
||||||
// SQLite completely ignores negative limits, hence we need to manually totalLimit to 0 in this case.
|
// SQLite completely ignores negative limits, hence we need to manually limit to 0 in this case.
|
||||||
final String suggestedLimitClause = " LIMIT MAX(0, (? - (SELECT COUNT(*) FROM " + TABLE_TOPSITES + ") - (SELECT COUNT(*) " + pinnedSitesFromClause + "))) ";
|
final String suggestedLimitClause = " LIMIT MAX(0, (" + suggestedGridLimit + " - (SELECT COUNT(*) FROM " + TABLE_TOPSITES + ") - (SELECT COUNT(*) " + pinnedSitesFromClause + "))) ";
|
||||||
|
|
||||||
final String[] suggestedLimitArgs = DBUtils.concatenateSelectionArgs(suggestedGridLimitArgs,
|
|
||||||
pinnedSitesArgs);
|
|
||||||
|
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
try {
|
try {
|
||||||
|
@ -813,10 +808,9 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
" FROM " + Combined.VIEW_NAME +
|
" FROM " + Combined.VIEW_NAME +
|
||||||
" WHERE " + ignoreForTopSitesWhereClause +
|
" WHERE " + ignoreForTopSitesWhereClause +
|
||||||
" ORDER BY " + BrowserContract.getFrecencySortOrder(true, false) +
|
" ORDER BY " + BrowserContract.getFrecencySortOrder(true, false) +
|
||||||
" LIMIT ?",
|
" LIMIT " + totalLimit,
|
||||||
|
|
||||||
DBUtils.appendSelectionArgs(ignoreForTopSitesArgs,
|
ignoreForTopSitesArgs);
|
||||||
totalLimitArgs));
|
|
||||||
|
|
||||||
if (!hasProcessedAnySuggestedSites) {
|
if (!hasProcessedAnySuggestedSites) {
|
||||||
db.execSQL("INSERT INTO " + TABLE_TOPSITES +
|
db.execSQL("INSERT INTO " + TABLE_TOPSITES +
|
||||||
|
@ -838,11 +832,17 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
Bookmarks.URL + " NOT IN (SELECT url " + pinnedSitesFromClause + ")" +
|
Bookmarks.URL + " NOT IN (SELECT url " + pinnedSitesFromClause + ")" +
|
||||||
suggestedLimitClause + " )",
|
suggestedLimitClause + " )",
|
||||||
|
|
||||||
DBUtils.concatenateSelectionArgs(suggestedSiteArgs,
|
suggestedSiteArgs);
|
||||||
pinnedSitesArgs,
|
|
||||||
suggestedLimitArgs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we retrieve more topsites than we have free positions for in the freeIdSubquery,
|
||||||
|
// we will have topsites that don't receive a position when joining TABLE_TOPSITES
|
||||||
|
// with freeIdSubquery. Hence we need to coalesce the position with a generated position.
|
||||||
|
// We know that the difference in positions will be at most suggestedGridLimit, hence we
|
||||||
|
// can add that to the rowid to generate a safe position.
|
||||||
|
// I.e. if we have 6 pinned sites then positions 0..5 are filled, the JOIN results in
|
||||||
|
// the first N rows having positions 6..(N+6), so row N+1 should receive a position that is at
|
||||||
|
// least N+1+6, which is equal to rowid + 6.
|
||||||
final SQLiteCursor c = (SQLiteCursor) db.rawQuery(
|
final SQLiteCursor c = (SQLiteCursor) db.rawQuery(
|
||||||
"SELECT " +
|
"SELECT " +
|
||||||
Bookmarks._ID + ", " +
|
Bookmarks._ID + ", " +
|
||||||
|
@ -850,7 +850,9 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
TopSites.HISTORY_ID + ", " +
|
TopSites.HISTORY_ID + ", " +
|
||||||
Bookmarks.URL + ", " +
|
Bookmarks.URL + ", " +
|
||||||
Bookmarks.TITLE + ", " +
|
Bookmarks.TITLE + ", " +
|
||||||
Bookmarks.POSITION + ", " +
|
"COALESCE(" + Bookmarks.POSITION + ", " +
|
||||||
|
DBUtils.qualifyColumn(TABLE_TOPSITES, "rowid") + " + " + suggestedGridLimit +
|
||||||
|
")" + " AS " + Bookmarks.POSITION + ", " +
|
||||||
Combined.HISTORY_ID + ", " +
|
Combined.HISTORY_ID + ", " +
|
||||||
TopSites.TYPE +
|
TopSites.TYPE +
|
||||||
" FROM " + TABLE_TOPSITES +
|
" FROM " + TABLE_TOPSITES +
|
||||||
|
@ -871,12 +873,11 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||||
"NULL AS " + Combined.HISTORY_ID + ", " +
|
"NULL AS " + Combined.HISTORY_ID + ", " +
|
||||||
TopSites.TYPE_PINNED + " as " + TopSites.TYPE +
|
TopSites.TYPE_PINNED + " as " + TopSites.TYPE +
|
||||||
" FROM " + TABLE_BOOKMARKS +
|
" FROM " + TABLE_BOOKMARKS +
|
||||||
" WHERE " + Bookmarks.PARENT + " == ? " +
|
" WHERE " + Bookmarks.PARENT + " == " + Bookmarks.FIXED_PINNED_LIST_ID +
|
||||||
|
|
||||||
" ORDER BY " + Bookmarks.POSITION,
|
" ORDER BY " + Bookmarks.POSITION,
|
||||||
|
|
||||||
DBUtils.appendSelectionArgs(freeIDArgs,
|
null);
|
||||||
pinnedSitesArgs));
|
|
||||||
|
|
||||||
c.setNotificationUri(getContext().getContentResolver(),
|
c.setNotificationUri(getContext().getContentResolver(),
|
||||||
BrowserContract.AUTHORITY_URI);
|
BrowserContract.AUTHORITY_URI);
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.mozilla.gecko.GeckoAppShell;
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
import org.mozilla.gecko.Telemetry;
|
import org.mozilla.gecko.Telemetry;
|
||||||
|
import org.mozilla.gecko.favicons.Favicons;
|
||||||
import org.mozilla.gecko.util.ThreadUtils;
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
@ -79,7 +80,6 @@ public class LocalURLMetadata implements URLMetadata {
|
||||||
if (obj.has("touchIconList") &&
|
if (obj.has("touchIconList") &&
|
||||||
(icons = obj.getJSONObject("touchIconList")).length() > 0) {
|
(icons = obj.getJSONObject("touchIconList")).length() > 0) {
|
||||||
int preferredSize = GeckoAppShell.getPreferredIconSize();
|
int preferredSize = GeckoAppShell.getPreferredIconSize();
|
||||||
int bestSizeFound = -1;
|
|
||||||
|
|
||||||
Iterator<String> keys = icons.keys();
|
Iterator<String> keys = icons.keys();
|
||||||
|
|
||||||
|
@ -88,21 +88,8 @@ public class LocalURLMetadata implements URLMetadata {
|
||||||
sizes.add(new Integer(keys.next()));
|
sizes.add(new Integer(keys.next()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(sizes);
|
final int bestSize = Favicons.selectBestSizeFromList(sizes, preferredSize);
|
||||||
for (int size : sizes) {
|
final String iconURL = icons.getString(Integer.toString(bestSize));
|
||||||
if (size >= preferredSize) {
|
|
||||||
bestSizeFound = size;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If all icons are smaller than the preferred size then we don't have an icon
|
|
||||||
// selected yet (bestSizeFound == -1), therefore just take the largest (last) icon.
|
|
||||||
if (bestSizeFound == -1) {
|
|
||||||
bestSizeFound = sizes.get(sizes.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
String iconURL = icons.getString(Integer.toString(bestSizeFound));
|
|
||||||
|
|
||||||
data.put(URLMetadataTable.TOUCH_ICON_COLUMN, iconURL);
|
data.put(URLMetadataTable.TOUCH_ICON_COLUMN, iconURL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,32 @@ public class Favicons {
|
||||||
|
|
||||||
private static FaviconCache faviconsCache;
|
private static FaviconCache faviconsCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select the closest icon size from a list of icon sizes.
|
||||||
|
* We just find the first icon that is larger than the preferred size if available, or otherwise select the
|
||||||
|
* largest icon (if all icons are smaller than the preferred size).
|
||||||
|
*
|
||||||
|
* @return The closes icon size, or -1 if no sizes are supplied.
|
||||||
|
*/
|
||||||
|
public static int selectBestSizeFromList(final List<Integer> sizes, final int preferredSize) {
|
||||||
|
Collections.sort(sizes);
|
||||||
|
|
||||||
|
for (int size : sizes) {
|
||||||
|
if (size >= preferredSize) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all icons are smaller than the preferred size then we don't have an icon
|
||||||
|
// selected yet, therefore just take the largest (last) icon.
|
||||||
|
if (sizes.size() > 0) {
|
||||||
|
return sizes.get(sizes.size() - 1);
|
||||||
|
} else {
|
||||||
|
// This isn't ideal, however current code assumes this as an error value for now.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns either NOT_LOADING, or LOADED if the onFaviconLoaded call could
|
* Returns either NOT_LOADING, or LOADED if the onFaviconLoaded call could
|
||||||
* be made on the main thread.
|
* be made on the main thread.
|
||||||
|
@ -584,6 +610,6 @@ public class Favicons {
|
||||||
*/
|
*/
|
||||||
public static void getPreferredSizeFaviconForPage(Context context, String url, String iconURL, OnFaviconLoadedListener onFaviconLoadedListener) {
|
public static void getPreferredSizeFaviconForPage(Context context, String url, String iconURL, OnFaviconLoadedListener onFaviconLoadedListener) {
|
||||||
int preferredSize = GeckoAppShell.getPreferredIconSize();
|
int preferredSize = GeckoAppShell.getPreferredIconSize();
|
||||||
loadUncachedFavicon(context, url, iconURL, 0, preferredSize, onFaviconLoadedListener);
|
loadUncachedFavicon(context, url, iconURL, LoadFaviconTask.FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS, preferredSize, onFaviconLoadedListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,14 @@ import org.mozilla.gecko.util.IOUtils;
|
||||||
import org.mozilla.gecko.util.ThreadUtils;
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@ -50,6 +52,14 @@ public class LoadFaviconTask {
|
||||||
private static final HashMap<String, LoadFaviconTask> loadsInFlight = new HashMap<>();
|
private static final HashMap<String, LoadFaviconTask> loadsInFlight = new HashMap<>();
|
||||||
|
|
||||||
public static final int FLAG_PERSIST = 1;
|
public static final int FLAG_PERSIST = 1;
|
||||||
|
/**
|
||||||
|
* Bypass all caches - this is used to directly retrieve the requested icon. Without this flag,
|
||||||
|
* favicons will first be pushed into the memory cache (and possibly permanent cache if using FLAG_PERSIST),
|
||||||
|
* where they will be downscaled to the maximum cache size, before being retrieved from the cache (resulting
|
||||||
|
* in a possibly smaller icon size).
|
||||||
|
*/
|
||||||
|
public static final int FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS = 2;
|
||||||
|
|
||||||
private static final int MAX_REDIRECTS_TO_FOLLOW = 5;
|
private static final int MAX_REDIRECTS_TO_FOLLOW = 5;
|
||||||
// The default size of the buffer to use for downloading Favicons in the event no size is given
|
// The default size of the buffer to use for downloading Favicons in the event no size is given
|
||||||
// by the server.
|
// by the server.
|
||||||
|
@ -417,10 +427,13 @@ public class LoadFaviconTask {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadFaviconResult loadedBitmaps = null;
|
||||||
// If there are no valid bitmaps decoded, the returned LoadFaviconResult is null.
|
// If there are no valid bitmaps decoded, the returned LoadFaviconResult is null.
|
||||||
LoadFaviconResult loadedBitmaps = loadFaviconFromDb(db);
|
if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) == 0) {
|
||||||
if (loadedBitmaps != null) {
|
loadedBitmaps = loadFaviconFromDb(db);
|
||||||
return pushToCacheAndGetResult(loadedBitmaps);
|
if (loadedBitmaps != null) {
|
||||||
|
return pushToCacheAndGetResult(loadedBitmaps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onlyFromLocal || isCancelled()) {
|
if (onlyFromLocal || isCancelled()) {
|
||||||
|
@ -445,11 +458,25 @@ public class LoadFaviconTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadedBitmaps != null) {
|
if (loadedBitmaps != null) {
|
||||||
// Fetching bytes to store can fail. saveFaviconToDb will
|
if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) == 0) {
|
||||||
// do the right thing, but we still choose to cache the
|
// Fetching bytes to store can fail. saveFaviconToDb will
|
||||||
// downloaded icon in memory.
|
// do the right thing, but we still choose to cache the
|
||||||
saveFaviconToDb(db, loadedBitmaps.getBytesForDatabaseStorage());
|
// downloaded icon in memory.
|
||||||
return pushToCacheAndGetResult(loadedBitmaps);
|
saveFaviconToDb(db, loadedBitmaps.getBytesForDatabaseStorage());
|
||||||
|
return pushToCacheAndGetResult(loadedBitmaps);
|
||||||
|
} else {
|
||||||
|
final Map<Integer, Bitmap> iconMap = new HashMap<>();
|
||||||
|
final List<Integer> sizes = new ArrayList<>();
|
||||||
|
|
||||||
|
while (loadedBitmaps.getBitmaps().hasNext()) {
|
||||||
|
final Bitmap b = loadedBitmaps.getBitmaps().next();
|
||||||
|
iconMap.put(b.getWidth(), b);
|
||||||
|
sizes.add(b.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
int bestSize = Favicons.selectBestSizeFromList(sizes, targetWidth);
|
||||||
|
return iconMap.get(bestSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUsingDefaultURL) {
|
if (isUsingDefaultURL) {
|
||||||
|
@ -545,11 +572,15 @@ public class LoadFaviconTask {
|
||||||
|
|
||||||
private void processResult(Bitmap image) {
|
private void processResult(Bitmap image) {
|
||||||
Favicons.removeLoadTask(id);
|
Favicons.removeLoadTask(id);
|
||||||
Bitmap scaled = image;
|
final Bitmap scaled;
|
||||||
|
|
||||||
// Notify listeners, scaling if required.
|
// Notify listeners, scaling if required.
|
||||||
if (targetWidth != -1 && image != null && image.getWidth() != targetWidth) {
|
if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) != 0) {
|
||||||
|
scaled = Bitmap.createScaledBitmap(image, targetWidth, targetWidth, true);
|
||||||
|
} else if (targetWidth != -1 && image != null && image.getWidth() != targetWidth) {
|
||||||
scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth);
|
scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth);
|
||||||
|
} else {
|
||||||
|
scaled = image;
|
||||||
}
|
}
|
||||||
|
|
||||||
Favicons.dispatchResult(pageUrl, faviconURL, scaled, listener);
|
Favicons.dispatchResult(pageUrl, faviconURL, scaled, listener);
|
||||||
|
|
|
@ -25,6 +25,7 @@ import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
@ -35,9 +36,9 @@ public class TwoLinePageRow extends LinearLayout
|
||||||
|
|
||||||
private final TextView mTitle;
|
private final TextView mTitle;
|
||||||
private final TextView mUrl;
|
private final TextView mUrl;
|
||||||
|
private final ImageView mStatusIcon;
|
||||||
|
|
||||||
private int mSwitchToTabIconId;
|
private int mSwitchToTabIconId;
|
||||||
private int mPageTypeIconId;
|
|
||||||
|
|
||||||
private final FaviconView mFavicon;
|
private final FaviconView mFavicon;
|
||||||
|
|
||||||
|
@ -90,11 +91,14 @@ public class TwoLinePageRow extends LinearLayout
|
||||||
setGravity(Gravity.CENTER_VERTICAL);
|
setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
LayoutInflater.from(context).inflate(R.layout.two_line_page_row, this);
|
LayoutInflater.from(context).inflate(R.layout.two_line_page_row, this);
|
||||||
|
// Merge layouts lose their padding, so set it dynamically.
|
||||||
|
setPadding(0, 0, (int) getResources().getDimension(R.dimen.page_row_padding_right), 0);
|
||||||
|
|
||||||
mTitle = (TextView) findViewById(R.id.title);
|
mTitle = (TextView) findViewById(R.id.title);
|
||||||
mUrl = (TextView) findViewById(R.id.url);
|
mUrl = (TextView) findViewById(R.id.url);
|
||||||
|
mStatusIcon = (ImageView) findViewById(R.id.status_icon_bookmark);
|
||||||
|
|
||||||
mSwitchToTabIconId = NO_ICON;
|
mSwitchToTabIconId = NO_ICON;
|
||||||
mPageTypeIconId = NO_ICON;
|
|
||||||
mShowIcons = true;
|
mShowIcons = true;
|
||||||
|
|
||||||
mFavicon = (FaviconView) findViewById(R.id.icon);
|
mFavicon = (FaviconView) findViewById(R.id.icon);
|
||||||
|
@ -173,16 +177,12 @@ public class TwoLinePageRow extends LinearLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
mSwitchToTabIconId = iconId;
|
mSwitchToTabIconId = iconId;
|
||||||
mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0);
|
mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPageTypeIcon(int iconId) {
|
private void showBookmarkIcon(boolean toShow) {
|
||||||
if (mPageTypeIconId == iconId) {
|
final int visibility = toShow ? VISIBLE : GONE;
|
||||||
return;
|
mStatusIcon.setVisibility(visibility);
|
||||||
}
|
|
||||||
|
|
||||||
mPageTypeIconId = iconId;
|
|
||||||
mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -231,13 +231,10 @@ public class TwoLinePageRow extends LinearLayout
|
||||||
if (mShowIcons) {
|
if (mShowIcons) {
|
||||||
// The bookmark id will be 0 (null in database) when the url
|
// The bookmark id will be 0 (null in database) when the url
|
||||||
// is not a bookmark.
|
// is not a bookmark.
|
||||||
if (bookmarkId == 0) {
|
final boolean isBookmark = bookmarkId != 0;
|
||||||
setPageTypeIcon(NO_ICON);
|
showBookmarkIcon(isBookmark);
|
||||||
} else {
|
|
||||||
setPageTypeIcon(R.drawable.ic_url_bar_star);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setPageTypeIcon(NO_ICON);
|
showBookmarkIcon(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the URL instead of an empty title for consistency with the normal URL
|
// Use the URL instead of an empty title for consistency with the normal URL
|
||||||
|
|
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ic_url_bar_star.png
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ic_url_bar_star.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 277 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 600 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/ic_url_bar_star.png
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/ic_url_bar_star.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 368 B |
|
@ -14,29 +14,38 @@
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
tools:background="@drawable/favicon_globe"/>
|
tools:background="@drawable/favicon_globe"/>
|
||||||
|
|
||||||
<LinearLayout android:layout_width="match_parent"
|
<LinearLayout android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:orientation="vertical"
|
android:paddingRight="10dp"
|
||||||
android:paddingRight="25dp">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<org.mozilla.gecko.widget.FadedSingleColorTextView
|
<org.mozilla.gecko.widget.FadedSingleColorTextView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
style="@style/Widget.TwoLinePageRow.Title"
|
style="@style/Widget.TwoLinePageRow.Title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
gecko:fadeWidth="30dp"
|
gecko:fadeWidth="90dp"
|
||||||
tools:text="This is a long test title"/>
|
tools:text="This is a long test title"/>
|
||||||
|
|
||||||
<TextView android:id="@+id/url"
|
<org.mozilla.gecko.widget.FadedSingleColorTextView android:id="@+id/url"
|
||||||
style="@style/Widget.TwoLinePageRow.Url"
|
style="@style/Widget.TwoLinePageRow.Url"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:drawablePadding="5dp"
|
android:drawablePadding="5dp"
|
||||||
android:maxLength="1024"
|
android:maxLength="1024"
|
||||||
|
gecko:fadeWidth="90dp"
|
||||||
tools:text="http://test.com/test"
|
tools:text="http://test.com/test"
|
||||||
tools:drawableLeft="@drawable/ic_url_bar_tab"
|
tools:drawableLeft="@drawable/ic_url_bar_tab"/>
|
||||||
tools:drawableRight="@drawable/ic_url_bar_star"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView android:id="@+id/status_icon_bookmark"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:src="@drawable/bookmarked_star"/>
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
|
|
@ -79,6 +79,8 @@
|
||||||
<dimen name="site_security_unknown_inset_top">1dp</dimen>
|
<dimen name="site_security_unknown_inset_top">1dp</dimen>
|
||||||
<dimen name="site_security_unknown_inset_bottom">-1dp</dimen>
|
<dimen name="site_security_unknown_inset_bottom">-1dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="page_row_padding_right">15dp</dimen>
|
||||||
|
|
||||||
<!-- Regular page row on about:home -->
|
<!-- Regular page row on about:home -->
|
||||||
<dimen name="page_row_height">64dp</dimen>
|
<dimen name="page_row_height">64dp</dimen>
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,6 @@
|
||||||
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
|
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
|
||||||
<item name="android:includeFontPadding">false</item>
|
<item name="android:includeFontPadding">false</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
<item name="android:ellipsize">middle</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Widget.ReadingListRow" />
|
<style name="Widget.ReadingListRow" />
|
||||||
|
@ -413,7 +412,9 @@
|
||||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.Widget.Home.ItemTitle" parent="TextAppearance.Medium"/>
|
<style name="TextAppearance.Widget.Home.ItemTitle" parent="TextAppearance">
|
||||||
|
<item name="android:textSize">16dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.Widget.Home.ItemDescription" parent="TextAppearance.Micro">
|
<style name="TextAppearance.Widget.Home.ItemDescription" parent="TextAppearance.Micro">
|
||||||
<item name="android:textColor">@color/tabs_tray_icon_grey</item>
|
<item name="android:textColor">@color/tabs_tray_icon_grey</item>
|
||||||
|
|
|
@ -63,8 +63,9 @@ var ActionBarHandler = {
|
||||||
|
|
||||||
// Else, update an open ActionBar.
|
// Else, update an open ActionBar.
|
||||||
if (this._selectionID) {
|
if (this._selectionID) {
|
||||||
if ([this._targetElement, this._contentWindow] ===
|
let [element, win] = this._getSelectionTargets();
|
||||||
[Services.focus.focusedElement, Services.focus.focusedWindow]) {
|
if (this._targetElement === element &&
|
||||||
|
this._contentWindow === win) {
|
||||||
// We have the same focused window/element as before. Trigger "TextSelection:ActionbarStatus"
|
// We have the same focused window/element as before. Trigger "TextSelection:ActionbarStatus"
|
||||||
// message only if available actions differ from when last we checked.
|
// message only if available actions differ from when last we checked.
|
||||||
this._sendActionBarActions();
|
this._sendActionBarActions();
|
||||||
|
@ -225,8 +226,14 @@ var ActionBarHandler = {
|
||||||
*/
|
*/
|
||||||
_sendActionBarActions: function(sendAlways) {
|
_sendActionBarActions: function(sendAlways) {
|
||||||
let actions = this._getActionBarActions();
|
let actions = this._getActionBarActions();
|
||||||
|
let actionCountUnchanged = this._actionBarActions &&
|
||||||
|
actions.length === this._actionBarActions.length;
|
||||||
|
let actionsMatch = actionCountUnchanged &&
|
||||||
|
this._actionBarActions.every((e,i) => {
|
||||||
|
return e.id === actions[i].id;
|
||||||
|
});
|
||||||
|
|
||||||
if (sendAlways || actions !== this._actionBarActions) {
|
if (sendAlways || !actionsMatch) {
|
||||||
Messaging.sendRequest({
|
Messaging.sendRequest({
|
||||||
type: "TextSelection:ActionbarStatus",
|
type: "TextSelection:ActionbarStatus",
|
||||||
actions: actions,
|
actions: actions,
|
||||||
|
|
|
@ -208,6 +208,9 @@ let SyncedTabsInternal = {
|
||||||
Preferences.reset("services.sync.lastTabFetch");
|
Preferences.reset("services.sync.lastTabFetch");
|
||||||
Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
|
Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
|
||||||
break;
|
break;
|
||||||
|
case "nsPref:changed":
|
||||||
|
Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -232,6 +235,10 @@ let SyncedTabsInternal = {
|
||||||
|
|
||||||
Services.obs.addObserver(SyncedTabsInternal, "weave:engine:sync:finish", false);
|
Services.obs.addObserver(SyncedTabsInternal, "weave:engine:sync:finish", false);
|
||||||
Services.obs.addObserver(SyncedTabsInternal, "weave:service:start-over", false);
|
Services.obs.addObserver(SyncedTabsInternal, "weave:service:start-over", false);
|
||||||
|
// Observe the pref the indicates the state of the tabs engine has changed.
|
||||||
|
// This will force consumers to re-evaluate the state of sync and update
|
||||||
|
// accordingly.
|
||||||
|
Services.prefs.addObserver("services.sync.engine.tabs", SyncedTabsInternal, false);
|
||||||
|
|
||||||
// The public interface.
|
// The public interface.
|
||||||
this.SyncedTabs = {
|
this.SyncedTabs = {
|
||||||
|
|
|
@ -591,6 +591,27 @@ this.BrowserTestUtils = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for a message to be fired from a particular message manager
|
||||||
|
*
|
||||||
|
* @param {nsIMessageManager} messageManager
|
||||||
|
* The message manager that should be used.
|
||||||
|
* @param {String} message
|
||||||
|
* The message we're waiting for.
|
||||||
|
* @param {Function} checkFn (optional)
|
||||||
|
* Optional function to invoke to check the message.
|
||||||
|
*/
|
||||||
|
waitForMessage(messageManager, message, checkFn) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
messageManager.addMessageListener(message, function onMessage(msg) {
|
||||||
|
if (!checkFn || checkFn(msg)) {
|
||||||
|
messageManager.removeMessageListener(message, onMessage);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version of synthesizeMouse that uses the center of the target as the mouse
|
* Version of synthesizeMouse that uses the center of the target as the mouse
|
||||||
* location. Arguments and the return value are the same.
|
* location. Arguments and the return value are the same.
|
||||||
|
|
|
@ -7021,6 +7021,20 @@
|
||||||
"description": "Number of times a custom developer tool has been opened.",
|
"description": "Number of times a custom developer tool has been opened.",
|
||||||
"releaseChannelCollection": "opt-out"
|
"releaseChannelCollection": "opt-out"
|
||||||
},
|
},
|
||||||
|
"DEVTOOLS_RELOAD_ADDON_INSTALLED_COUNT": {
|
||||||
|
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
|
||||||
|
"expires_in_version": "55",
|
||||||
|
"kind": "count",
|
||||||
|
"description": "Number of times the reload addon has been installed.",
|
||||||
|
"bug_numbers": [1248435]
|
||||||
|
},
|
||||||
|
"DEVTOOLS_RELOAD_ADDON_RELOAD_COUNT": {
|
||||||
|
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
|
||||||
|
"expires_in_version": "55",
|
||||||
|
"kind": "count",
|
||||||
|
"description": "Number of times the tools have been reloaded by the reload addon.",
|
||||||
|
"bug_numbers": [1248435]
|
||||||
|
},
|
||||||
"DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG": {
|
"DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG": {
|
||||||
"expires_in_version": "never",
|
"expires_in_version": "never",
|
||||||
"kind": "flag",
|
"kind": "flag",
|
||||||
|
@ -7204,6 +7218,20 @@
|
||||||
"kind": "flag",
|
"kind": "flag",
|
||||||
"description": "Number of users that have opened a custom developer tool via the toolbox button."
|
"description": "Number of users that have opened a custom developer tool via the toolbox button."
|
||||||
},
|
},
|
||||||
|
"DEVTOOLS_RELOAD_ADDON_INSTALLED_PER_USER_FLAG": {
|
||||||
|
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
|
||||||
|
"expires_in_version": "55",
|
||||||
|
"kind": "flag",
|
||||||
|
"description": "Records once per browser version if the reload add-on is installed.",
|
||||||
|
"bug_numbers": [1248435]
|
||||||
|
},
|
||||||
|
"DEVTOOLS_RELOAD_ADDON_RELOAD_PER_USER_FLAG": {
|
||||||
|
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
|
||||||
|
"expires_in_version": "55",
|
||||||
|
"kind": "flag",
|
||||||
|
"description": "Records once per browser version if the tools have been reloaded via the reload add-on.",
|
||||||
|
"bug_numbers": [1248435]
|
||||||
|
},
|
||||||
"DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS": {
|
"DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS": {
|
||||||
"expires_in_version": "never",
|
"expires_in_version": "never",
|
||||||
"kind": "exponential",
|
"kind": "exponential",
|
||||||
|
@ -8452,6 +8480,15 @@
|
||||||
"releaseChannelCollection": "opt-out",
|
"releaseChannelCollection": "opt-out",
|
||||||
"description": "Number of sessions where at least one chat message was exchanged"
|
"description": "Number of sessions where at least one chat message was exchanged"
|
||||||
},
|
},
|
||||||
|
"LOOP_INFOBAR_ACTION_BUTTONS": {
|
||||||
|
"alert_emails": ["firefox-dev@mozilla.org", "mbanner@mozilla.com"],
|
||||||
|
"expires_in_version": "51",
|
||||||
|
"kind": "enumerated",
|
||||||
|
"n_values": 4,
|
||||||
|
"releaseChannelCollection": "opt-out",
|
||||||
|
"bug_numbers": [1245486],
|
||||||
|
"description": "Number times info bar buttons are clicked (0=PAUSED, 1=CREATED)"
|
||||||
|
},
|
||||||
"E10S_STATUS": {
|
"E10S_STATUS": {
|
||||||
"alert_emails": ["firefox-dev@mozilla.org"],
|
"alert_emails": ["firefox-dev@mozilla.org"],
|
||||||
"expires_in_version": "never",
|
"expires_in_version": "never",
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
function doUpdate(update) {
|
||||||
|
const { classes: Cc, interfaces: Ci, results: Cr } = Components;
|
||||||
|
|
||||||
|
let listener = {
|
||||||
|
QueryInterface: function(iid)
|
||||||
|
{
|
||||||
|
if (iid.equals(Ci.nsISupports) ||
|
||||||
|
iid.equals(Ci.nsIUrlClassifierUpdateObserver))
|
||||||
|
return this;
|
||||||
|
|
||||||
|
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||||
|
},
|
||||||
|
updateUrlRequested: function(url) { },
|
||||||
|
streamFinished: function(status) { },
|
||||||
|
updateError: function(errorCode) {
|
||||||
|
sendAsyncMessage("updateError", { errorCode });
|
||||||
|
},
|
||||||
|
updateSuccess: function(requestedTimeout) {
|
||||||
|
sendAsyncMessage("loadTestFrame");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
|
||||||
|
.getService(Ci.nsIUrlClassifierDBService);
|
||||||
|
|
||||||
|
dbService.beginUpdate(listener, "test-malware-simple,test-unwanted-simple", "");
|
||||||
|
dbService.beginStream("", "");
|
||||||
|
dbService.updateStream(update);
|
||||||
|
dbService.finishStream();
|
||||||
|
dbService.finishUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
addMessageListener("doUpdate", ({ testUpdate }) => {
|
||||||
|
doUpdate(testUpdate);
|
||||||
|
});
|
|
@ -1,7 +1,8 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
skip-if = buildapp == 'b2g' || e10s
|
skip-if = buildapp == 'b2g'
|
||||||
support-files =
|
support-files =
|
||||||
classifiedAnnotatedPBFrame.html
|
classifiedAnnotatedPBFrame.html
|
||||||
|
classifierCommon.js
|
||||||
classifierFrame.html
|
classifierFrame.html
|
||||||
cleanWorker.js
|
cleanWorker.js
|
||||||
good.js
|
good.js
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
|
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
var Cc = SpecialPowers.Cc;
|
|
||||||
var Ci = SpecialPowers.Ci;
|
|
||||||
var firstLoad = true;
|
var firstLoad = true;
|
||||||
|
|
||||||
// Add some URLs to the malware database.
|
// Add some URLs to the malware database.
|
||||||
|
@ -30,51 +28,33 @@ testUpdate +=
|
||||||
"a:524:32:" + testData.length + "\n" +
|
"a:524:32:" + testData.length + "\n" +
|
||||||
testData;
|
testData;
|
||||||
|
|
||||||
var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
|
|
||||||
.getService(Ci.nsIUrlClassifierDBService);
|
|
||||||
|
|
||||||
function loadTestFrame() {
|
function loadTestFrame() {
|
||||||
document.getElementById("testFrame").src = "classifierFrame.html";
|
document.getElementById("testFrame").src = "classifierFrame.html";
|
||||||
}
|
}
|
||||||
|
|
||||||
function doUpdate(update) {
|
const CLASSIFIER_COMMON_URL = SimpleTest.getTestFileURL("classifierCommon.js");
|
||||||
var listener = {
|
let classifierCommonScript = SpecialPowers.loadChromeScript(CLASSIFIER_COMMON_URL);
|
||||||
QueryInterface: SpecialPowers.wrapCallback(function(iid)
|
|
||||||
{
|
|
||||||
if (iid.equals(Ci.nsISupports) ||
|
|
||||||
iid.equals(Ci.nsIUrlClassifierUpdateObserver))
|
|
||||||
return this;
|
|
||||||
|
|
||||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
// Expected finish() call is in "classifierFrame.html".
|
||||||
}),
|
SimpleTest.waitForExplicitFinish();
|
||||||
updateUrlRequested: function(url) { },
|
|
||||||
streamFinished: function(status) { },
|
|
||||||
updateError: function(errorCode) {
|
|
||||||
ok(false, "Couldn't update classifier.");
|
|
||||||
// Abort test.
|
|
||||||
SimpleTest.finish();
|
|
||||||
},
|
|
||||||
updateSuccess: function(requestedTimeout) {
|
|
||||||
SpecialPowers.pushPrefEnv(
|
|
||||||
{"set" : [["browser.safebrowsing.malware.enabled", true]]},
|
|
||||||
loadTestFrame);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
dbService.beginUpdate(listener, "test-malware-simple,test-unwanted-simple", "");
|
classifierCommonScript.addMessageListener("loadTestFrame", () => {
|
||||||
dbService.beginStream("", "");
|
SpecialPowers.pushPrefEnv(
|
||||||
dbService.updateStream(update);
|
{"set" : [["browser.safebrowsing.malware.enabled", true]]},
|
||||||
dbService.finishStream();
|
loadTestFrame);
|
||||||
dbService.finishUpdate();
|
});
|
||||||
}
|
classifierCommonScript.addMessageListener("updateError", ({ errorCode }) => {
|
||||||
|
ok(false, "Couldn't update classifier. Error code: " + errorCode);
|
||||||
|
// Abort test.
|
||||||
|
SimpleTest.finish();
|
||||||
|
});
|
||||||
|
|
||||||
SpecialPowers.pushPrefEnv(
|
SpecialPowers.pushPrefEnv(
|
||||||
{"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"],
|
{"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"],
|
||||||
["urlclassifier.phishTable", "test-phish-simple"]]},
|
["urlclassifier.phishTable", "test-phish-simple"]]},
|
||||||
function() { doUpdate(testUpdate); });
|
function() {
|
||||||
|
classifierCommonScript.sendAsyncMessage("doUpdate", { testUpdate });
|
||||||
// Expected finish() call is in "classifierFrame.html".
|
});
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,6 @@
|
||||||
|
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
var Cc = SpecialPowers.Cc;
|
|
||||||
var Ci = SpecialPowers.Ci;
|
|
||||||
|
|
||||||
// Add some URLs to the malware database.
|
// Add some URLs to the malware database.
|
||||||
var testData = "example.com/tests/toolkit/components/url-classifier/tests/mochitest/evilWorker.js";
|
var testData = "example.com/tests/toolkit/components/url-classifier/tests/mochitest/evilWorker.js";
|
||||||
var testUpdate =
|
var testUpdate =
|
||||||
|
@ -29,42 +26,9 @@ testUpdate +=
|
||||||
"a:550:32:" + testData.length + "\n" +
|
"a:550:32:" + testData.length + "\n" +
|
||||||
testData;
|
testData;
|
||||||
|
|
||||||
var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
|
function loadTestFrame() {
|
||||||
.getService(Ci.nsIUrlClassifierDBService);
|
document.getElementById("testFrame").src =
|
||||||
|
"http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/workerFrame.html";
|
||||||
function doUpdate(update) {
|
|
||||||
var listener = {
|
|
||||||
QueryInterface: SpecialPowers.wrapCallback(function(iid)
|
|
||||||
{
|
|
||||||
if (iid.equals(Ci.nsISupports) ||
|
|
||||||
iid.equals(Ci.nsIUrlClassifierUpdateObserver))
|
|
||||||
return this;
|
|
||||||
|
|
||||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
|
||||||
}),
|
|
||||||
updateUrlRequested: function(url) { },
|
|
||||||
streamFinished: function(status) { },
|
|
||||||
updateError: function(errorCode) {
|
|
||||||
ok(false, "Couldn't update classifier.");
|
|
||||||
// Abort test.
|
|
||||||
SimpleTest.finish();
|
|
||||||
},
|
|
||||||
updateSuccess: function(requestedTimeout) {
|
|
||||||
SpecialPowers.pushPrefEnv(
|
|
||||||
{"set" : [["browser.safebrowsing.malware.enabled", true]]},
|
|
||||||
function loadTestFrame() {
|
|
||||||
document.getElementById("testFrame").src =
|
|
||||||
"http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/workerFrame.html";
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
dbService.beginUpdate(listener, "test-malware-simple,test-unwanted-simple", "");
|
|
||||||
dbService.beginStream("", "");
|
|
||||||
dbService.updateStream(update);
|
|
||||||
dbService.finishStream();
|
|
||||||
dbService.finishUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onmessage(event)
|
function onmessage(event)
|
||||||
|
@ -78,10 +42,26 @@ function onmessage(event)
|
||||||
is(pieces[0], "success", pieces[1]);
|
is(pieces[0], "success", pieces[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CLASSIFIER_COMMON_URL = SimpleTest.getTestFileURL("classifierCommon.js");
|
||||||
|
let classifierCommonScript = SpecialPowers.loadChromeScript(CLASSIFIER_COMMON_URL);
|
||||||
|
|
||||||
|
classifierCommonScript.addMessageListener("loadTestFrame", () => {
|
||||||
|
SpecialPowers.pushPrefEnv(
|
||||||
|
{"set" : [["browser.safebrowsing.malware.enabled", true]]},
|
||||||
|
loadTestFrame);
|
||||||
|
});
|
||||||
|
classifierCommonScript.addMessageListener("updateError", ({ errorCode }) => {
|
||||||
|
ok(false, "Couldn't update classifier. Error code: " + errorCode);
|
||||||
|
// Abort test.
|
||||||
|
SimpleTest.finish();
|
||||||
|
});
|
||||||
|
|
||||||
SpecialPowers.pushPrefEnv(
|
SpecialPowers.pushPrefEnv(
|
||||||
{"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"],
|
{"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"],
|
||||||
["urlclassifier.phishTable", "test-phish-simple"]]},
|
["urlclassifier.phishTable", "test-phish-simple"]]},
|
||||||
function() { doUpdate(testUpdate); });
|
function() {
|
||||||
|
classifierCommonScript.sendAsyncMessage("doUpdate", { testUpdate });
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener("message", onmessage, false);
|
window.addEventListener("message", onmessage, false);
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ skip-if = buildapp == 'b2g'
|
||||||
support-files =
|
support-files =
|
||||||
handlerApp.xhtml
|
handlerApp.xhtml
|
||||||
handlerApps.js
|
handlerApps.js
|
||||||
|
unsafeBidi_chromeScript.js
|
||||||
unsafeBidiFileName.sjs
|
unsafeBidiFileName.sjs
|
||||||
|
|
||||||
[test_badMimeType.html]
|
[test_badMimeType.html]
|
||||||
[test_handlerApps.xhtml]
|
[test_handlerApps.xhtml]
|
||||||
skip-if = (toolkit == 'android' || os == 'mac') || e10s # OS X: bug 786938
|
skip-if = (toolkit == 'android' || os == 'mac') || e10s # OS X: bug 786938
|
||||||
[test_unsafeBidiChars.xhtml]
|
[test_unsafeBidiChars.xhtml]
|
||||||
skip-if = e10s
|
|
||||||
|
|
|
@ -2,21 +2,22 @@
|
||||||
<head>
|
<head>
|
||||||
<title>Test for Handling of unsafe bidi chars</title>
|
<title>Test for Handling of unsafe bidi chars</title>
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
</head>
|
</head>
|
||||||
<body onload="load();">
|
<body>
|
||||||
<p id="display"></p>
|
<p id="display"></p>
|
||||||
<iframe id="test"></iframe>
|
<iframe id="test"></iframe>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
|
|
||||||
var unsafeBidiChars = {
|
var unsafeBidiChars = [
|
||||||
LRE: "\xe2\x80\xaa",
|
"\xe2\x80\xaa", // LRE
|
||||||
RLE: "\xe2\x80\xab",
|
"\xe2\x80\xab", // RLE
|
||||||
PDF: "\xe2\x80\xac",
|
"\xe2\x80\xac", // PDF
|
||||||
LRO: "\xe2\x80\xad",
|
"\xe2\x80\xad", // LRO
|
||||||
RLO: "\xe2\x80\xae"
|
"\xe2\x80\xae" // RLO
|
||||||
};
|
];
|
||||||
|
|
||||||
var tests = [
|
var tests = [
|
||||||
"{1}.test",
|
"{1}.test",
|
||||||
|
@ -37,100 +38,40 @@ function sanitize(name) {
|
||||||
return replace(name, '_');
|
return replace(name, '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
var gTests = [];
|
add_task(function* () {
|
||||||
function make_test(param, expected) {
|
let url = SimpleTest.getTestFileURL("unsafeBidi_chromeScript.js");
|
||||||
gTests.push({
|
let chromeScript = SpecialPowers.loadChromeScript(url);
|
||||||
param: param,
|
|
||||||
expected: expected,
|
for (let test of tests) {
|
||||||
|
for (let char of unsafeBidiChars) {
|
||||||
|
let promiseName = new Promise(function(resolve) {
|
||||||
|
chromeScript.addMessageListener("suggestedFileName",
|
||||||
|
function listener(data) {
|
||||||
|
chromeScript.removeMessageListener("suggestedFileName", listener);
|
||||||
|
resolve(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let name = replace(test, char);
|
||||||
|
let expected = sanitize(test);
|
||||||
|
document.getElementById("test").src =
|
||||||
|
"unsafeBidiFileName.sjs?name=" + encodeURIComponent(name);
|
||||||
|
is((yield promiseName), expected, "got the expected sanitized name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let promise = new Promise(function(resolve) {
|
||||||
|
chromeScript.addMessageListener("unregistered", function listener() {
|
||||||
|
chromeScript.removeMessageListener("unregistered", listener);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
chromeScript.sendAsyncMessage("unregister");
|
||||||
|
yield promise;
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
chromeScript.destroy();
|
||||||
|
});
|
||||||
function load() {
|
|
||||||
var iframe = document.getElementById("test");
|
|
||||||
var gCallback = null;
|
|
||||||
function run_test(test, cb) {
|
|
||||||
var url = "unsafeBidiFileName.sjs?name=" + encodeURIComponent(test.param);
|
|
||||||
gCallback = cb;
|
|
||||||
iframe.src = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
var gCounter = -1;
|
|
||||||
function run_next_test() {
|
|
||||||
if (++gCounter == gTests.length)
|
|
||||||
finish_test();
|
|
||||||
else
|
|
||||||
run_test(gTests[gCounter], run_next_test);
|
|
||||||
}
|
|
||||||
|
|
||||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
|
||||||
|
|
||||||
const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
|
|
||||||
const HELPERAPP_DIALOG_CID = SpecialPowers.wrap(SpecialPowers.Components).ID(SpecialPowers.Cc[HELPERAPP_DIALOG_CONTRACT].number);
|
|
||||||
|
|
||||||
const FAKE_CID = SpecialPowers.Cc["@mozilla.org/uuid-generator;1"].
|
|
||||||
getService(SpecialPowers.Ci.nsIUUIDGenerator).generateUUID();
|
|
||||||
|
|
||||||
function HelperAppLauncherDialog() {}
|
|
||||||
HelperAppLauncherDialog.prototype = {
|
|
||||||
REASON_CANTHANDLE: 0,
|
|
||||||
REASON_SERVERREQUEST: 1,
|
|
||||||
REASON_TYPESNIFFED: 2,
|
|
||||||
show: function(aLauncher, aWindowContext, aReason) {
|
|
||||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
|
||||||
var test = gTests[gCounter];
|
|
||||||
is(aLauncher.suggestedFileName, test.expected,
|
|
||||||
"The filename should be correctly sanitized");
|
|
||||||
gCallback();
|
|
||||||
},
|
|
||||||
QueryInterface: function(aIID) {
|
|
||||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
|
||||||
if (aIID.equals(SpecialPowers.Ci.nsISupports) ||
|
|
||||||
aIID.equals(SpecialPowers.Ci.nsIHelperAppLauncherDialog))
|
|
||||||
return this;
|
|
||||||
throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var factory = {
|
|
||||||
createInstance: function(aOuter, aIID) {
|
|
||||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
|
||||||
if (aOuter != null)
|
|
||||||
throw SpecialPowers.Cr.NS_ERROR_NO_AGGREGATION;
|
|
||||||
return new HelperAppLauncherDialog().QueryInterface(aIID);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.wrap(SpecialPowers.Components).manager
|
|
||||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
|
|
||||||
.registerFactory(FAKE_CID, "",
|
|
||||||
HELPERAPP_DIALOG_CONTRACT,
|
|
||||||
factory);
|
|
||||||
|
|
||||||
function finish_test() {
|
|
||||||
SpecialPowers.wrap(SpecialPowers.Components).manager
|
|
||||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
|
|
||||||
.registerFactory(HELPERAPP_DIALOG_CID, "",
|
|
||||||
HELPERAPP_DIALOG_CONTRACT,
|
|
||||||
null);
|
|
||||||
SimpleTest.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
var i,j;
|
|
||||||
|
|
||||||
for (i = 0; i < tests.length; ++i) {
|
|
||||||
for (j in unsafeBidiChars) {
|
|
||||||
make_test(replace(tests[i], unsafeBidiChars[j]),
|
|
||||||
sanitize(tests[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run_next_test();
|
|
||||||
}
|
|
||||||
|
|
||||||
]]>
|
]]>
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
|
||||||
|
const HELPERAPP_DIALOG_CID =
|
||||||
|
Components.ID(Cc[HELPERAPP_DIALOG_CONTRACT].number);
|
||||||
|
|
||||||
|
const FAKE_CID = Cc["@mozilla.org/uuid-generator;1"].
|
||||||
|
getService(Ci.nsIUUIDGenerator).generateUUID();
|
||||||
|
|
||||||
|
function HelperAppLauncherDialog() {}
|
||||||
|
HelperAppLauncherDialog.prototype = {
|
||||||
|
show: function(aLauncher, aWindowContext, aReason) {
|
||||||
|
sendAsyncMessage("suggestedFileName", aLauncher.suggestedFileName);
|
||||||
|
},
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
|
||||||
|
};
|
||||||
|
|
||||||
|
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||||
|
registrar.registerFactory(FAKE_CID, "", HELPERAPP_DIALOG_CONTRACT,
|
||||||
|
XPCOMUtils._getFactory(HelperAppLauncherDialog));
|
||||||
|
|
||||||
|
addMessageListener("unregister", function() {
|
||||||
|
registrar.registerFactory(HELPERAPP_DIALOG_CID, "",
|
||||||
|
HELPERAPP_DIALOG_CONTRACT, null);
|
||||||
|
sendAsyncMessage("unregistered");
|
||||||
|
});
|
Загрузка…
Ссылка в новой задаче