Bug 1247455 - Add a .removeCSS method to complement .insertCSS. r=kmag

This commit is contained in:
Claas Augner
2016-04-15 00:39:09 +02:00
parent 453d6a0de7
commit 1737833daa
5 changed files with 156 additions and 6 deletions

View File

@@ -707,6 +707,7 @@ extensions.registerSchemaAPI("tabs", null, (extension, context) => {
{}, {recipient});
},
// Used to executeScript, insertCSS and removeCSS.
_execute: function(tabId, details, kind, method) {
let tab = tabId !== null ? TabManager.getTab(tabId) : TabManager.activeTab;
let mm = tab.linkedBrowser.messageManager;
@@ -714,6 +715,7 @@ extensions.registerSchemaAPI("tabs", null, (extension, context) => {
let options = {
js: [],
css: [],
remove_css: method == "removeCSS",
};
// We require a `code` or a `file` property, but we can't accept both.
@@ -773,6 +775,10 @@ extensions.registerSchemaAPI("tabs", null, (extension, context) => {
return self.tabs._execute(tabId, details, "css", "insertCSS");
},
removeCSS: function(tabId, details) {
return self.tabs._execute(tabId, details, "css", "removeCSS");
},
connect: function(tabId, connectInfo) {
let tab = TabManager.getTab(tabId);
let mm = tab.linkedBrowser.messageManager;

View File

@@ -866,6 +866,33 @@
}
]
},
{
"name": "removeCSS",
"type": "function",
"description": "Removes injected CSS from a page. For details, see the $(topic:content_scripts)[programmatic injection] section of the content scripts doc.",
"async": "callback",
"parameters": [
{
"type": "integer",
"name": "tabId",
"minimum": 0,
"optional": true,
"description": "The ID of the tab from which to remove the injected CSS; defaults to the active tab of the current window."
},
{
"$ref": "extensionTypes.InjectDetails",
"name": "details",
"description": "Details of the CSS text to remove."
},
{
"type": "function",
"name": "callback",
"optional": true,
"description": "Called when all the CSS has been removed.",
"parameters": []
}
]
},
{
"name": "setZoom",
"type": "function",

View File

@@ -53,6 +53,7 @@ support-files =
[browser_ext_tabs_executeScript_runAt.js]
[browser_ext_tabs_getCurrent.js]
[browser_ext_tabs_insertCSS.js]
[browser_ext_tabs_removeCSS.js]
[browser_ext_tabs_move.js]
[browser_ext_tabs_move_window.js]
[browser_ext_tabs_move_window_multiple.js]

View File

@@ -0,0 +1,103 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testExecuteScript() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true);
function background() {
let promises = [
// Insert CSS file.
{
background: "transparent",
foreground: "rgb(0, 113, 4)",
promise: () => {
return browser.tabs.insertCSS({
file: "file2.css",
});
},
},
// Insert CSS code.
{
background: "rgb(42, 42, 42)",
foreground: "rgb(0, 113, 4)",
promise: () => {
return browser.tabs.insertCSS({
code: "* { background: rgb(42, 42, 42) }",
});
},
},
// Remove CSS code again.
{
background: "transparent",
foreground: "rgb(0, 113, 4)",
promise: () => {
return browser.tabs.removeCSS({
code: "* { background: rgb(42, 42, 42) }",
});
},
},
// Remove CSS file again.
{
background: "transparent",
foreground: "rgb(0, 0, 0)",
promise: () => {
return browser.tabs.removeCSS({
file: "file2.css",
});
},
},
];
function checkCSS() {
let computedStyle = window.getComputedStyle(document.body);
return [computedStyle.backgroundColor, computedStyle.color];
}
function next() {
if (!promises.length) {
return;
}
let {promise, background, foreground} = promises.shift();
return promise().then(result => {
browser.test.assertEq(undefined, result, "Expected callback result");
return browser.tabs.executeScript({
code: `(${checkCSS})()`,
});
}).then(result => {
browser.test.assertEq(background, result[0], "Expected background color");
browser.test.assertEq(foreground, result[1], "Expected foreground color");
return next();
});
}
next().then(() => {
browser.test.notifyPass("removeCSS");
}).catch(e => {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFailure("removeCSS");
});
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["http://mochi.test/"],
},
background,
files: {
"file2.css": "* { color: rgb(0, 113, 4) }",
},
});
yield extension.startup();
yield extension.awaitFinish("removeCSS");
yield extension.unload();
yield BrowserTestUtils.removeTab(tab);
});

View File

@@ -155,6 +155,7 @@ function Script(options, deferred = PromiseUtils.defer()) {
this.run_at = this.options.run_at;
this.js = this.options.js || [];
this.css = this.options.css || [];
this.remove_css = this.options.remove_css;
this.deferred = deferred;
@@ -211,15 +212,25 @@ Script.prototype = {
let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
for (let url of this.css) {
url = extension.baseURI.resolve(url);
runSafeSyncWithoutClone(winUtils.loadSheetUsingURIString, url, winUtils.AUTHOR_SHEET);
this.deferred.resolve();
// We can handle CSS urls (css) and CSS code (cssCode).
let cssUrls = [];
for (let cssUrl of this.css) {
cssUrl = extension.baseURI.resolve(cssUrl);
cssUrls.push(cssUrl);
}
if (this.options.cssCode) {
let url = "data:text/css;charset=utf-8," + encodeURIComponent(this.options.cssCode);
runSafeSyncWithoutClone(winUtils.loadSheetUsingURIString, url, winUtils.AUTHOR_SHEET);
let cssUrl = "data:text/css;charset=utf-8," + encodeURIComponent(this.options.cssCode);
cssUrls.push(cssUrl);
}
// We can insertCSS and removeCSS.
let method = this.remove_css ? winUtils.removeSheetUsingURIString : winUtils.loadSheetUsingURIString;
for (let cssUrl of cssUrls) {
runSafeSyncWithoutClone(method, cssUrl, winUtils.AUTHOR_SHEET);
}
if (cssUrls.length > 0) {
this.deferred.resolve();
}
}
@@ -548,6 +559,7 @@ DocumentManager = {
}
},
// Used to executeScript, insertCSS and removeCSS.
executeScript(global, extensionId, options) {
let executeInWin = (window) => {
let deferred = PromiseUtils.defer();
@@ -881,6 +893,7 @@ class ExtensionGlobal {
});
}
// Used to executeScript, insertCSS and removeCSS.
handleExtensionExecute(target, extensionId, options) {
return DocumentManager.executeScript(target, extensionId, options).then(result => {
try {