зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1349944 - Add browser.theme.getCurrent() to query the selected theme. r=jaws,mixedpuppy
MozReview-Commit-ID: Hzdm21riVlb --HG-- extra : rebase_source : 135464563d5b6c3784cd475cfe1dbe4a7c72de7b
This commit is contained in:
Родитель
dba3425d42
Коммит
9056c46ef4
|
@ -28,14 +28,29 @@ class Theme {
|
|||
* to show manifest warnings to the theme author.
|
||||
*/
|
||||
constructor(baseURI, logger) {
|
||||
// A dictionary of light weight theme styles.
|
||||
this.lwtStyles = {
|
||||
icons: {},
|
||||
};
|
||||
// The base theme applied to all windows.
|
||||
this.baseProperties = {};
|
||||
|
||||
// Window-specific theme overrides.
|
||||
this.windowOverrides = new WeakMap();
|
||||
|
||||
this.baseURI = baseURI;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current theme for a specified window
|
||||
*
|
||||
* @param {Object} window
|
||||
* @returns {Object} The theme of the specified window
|
||||
*/
|
||||
getWindowTheme(window) {
|
||||
if (this.windowOverrides.has(window)) {
|
||||
return this.windowOverrides.get(window);
|
||||
}
|
||||
return this.baseProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a theme by reading the properties from the extension's manifest.
|
||||
* This method will override any currently applied theme.
|
||||
|
@ -46,6 +61,10 @@ class Theme {
|
|||
* this parameter will apply the theme globally.
|
||||
*/
|
||||
load(details, targetWindow) {
|
||||
this.lwtStyles = {
|
||||
icons: {},
|
||||
};
|
||||
|
||||
if (targetWindow) {
|
||||
this.lwtStyles.window = getWinUtils(targetWindow).outerWindowID;
|
||||
}
|
||||
|
@ -70,6 +89,11 @@ class Theme {
|
|||
if (this.lwtStyles.headerURL &&
|
||||
this.lwtStyles.accentcolor &&
|
||||
this.lwtStyles.textcolor) {
|
||||
if (!targetWindow) {
|
||||
this.baseProperties = details;
|
||||
} else {
|
||||
this.windowOverrides.set(targetWindow, details);
|
||||
}
|
||||
LightweightThemeManager.fallbackThemeData = this.lwtStyles;
|
||||
Services.obs.notifyObservers(null,
|
||||
"lightweight-theme-styling-update",
|
||||
|
@ -245,7 +269,7 @@ class Theme {
|
|||
* @param {Object} targetWindow The window the theme should be unloaded from
|
||||
*/
|
||||
unload(targetWindow) {
|
||||
let lwtStyles = {
|
||||
this.lwtStyles = {
|
||||
headerURL: "",
|
||||
accentcolor: "",
|
||||
additionalBackgrounds: "",
|
||||
|
@ -256,16 +280,20 @@ class Theme {
|
|||
};
|
||||
|
||||
if (targetWindow) {
|
||||
lwtStyles.window = getWinUtils(targetWindow).outerWindowID;
|
||||
this.lwtStyles.window = getWinUtils(targetWindow).outerWindowID;
|
||||
this.windowOverrides.set(targetWindow, {});
|
||||
} else {
|
||||
this.windowOverrides = new WeakMap();
|
||||
this.baseProperties = {};
|
||||
}
|
||||
|
||||
for (let icon of ICONS) {
|
||||
lwtStyles.icons[`--${icon}--icon`] = "";
|
||||
this.lwtStyles.icons[`--${icon}--icon`] = "";
|
||||
}
|
||||
LightweightThemeManager.fallbackThemeData = null;
|
||||
Services.obs.notifyObservers(null,
|
||||
"lightweight-theme-styling-update",
|
||||
JSON.stringify(lwtStyles));
|
||||
JSON.stringify(this.lwtStyles));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,6 +327,23 @@ this.theme = class extends ExtensionAPI {
|
|||
|
||||
return {
|
||||
theme: {
|
||||
getCurrent: (windowId) => {
|
||||
// Return empty theme if none is applied.
|
||||
if (!this.theme) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
// Return theme applied on last focused window when no ID is supplied.
|
||||
if (!windowId) {
|
||||
return Promise.resolve(this.theme.getWindowTheme(windowTracker.topWindow));
|
||||
}
|
||||
|
||||
const browserWindow = windowTracker.getWindow(windowId, context);
|
||||
if (!browserWindow) {
|
||||
return Promise.reject(`Invalid window ID: ${windowId}`);
|
||||
}
|
||||
return Promise.resolve(this.theme.getWindowTheme(browserWindow));
|
||||
},
|
||||
update: (windowId, details) => {
|
||||
if (!gThemesEnabled) {
|
||||
// Return early if themes are disabled.
|
||||
|
|
|
@ -458,11 +458,25 @@
|
|||
"description": "The theme API allows customizing of visual elements of the browser.",
|
||||
"permissions": ["theme"],
|
||||
"functions": [
|
||||
{
|
||||
"name": "getCurrent",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "Returns the current theme for the specified window or the last focused window.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "windowId",
|
||||
"optional": true,
|
||||
"description": "The window for which we want the theme."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "update",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "Make complete or partial updates to the theme. Resolves when the update has completed.",
|
||||
"description": "Make complete updates to the theme. Resolves when the update has completed.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
|
|
@ -4,6 +4,7 @@ support-files =
|
|||
|
||||
[browser_ext_management_themes.js]
|
||||
[browser_ext_themes_chromeparity.js]
|
||||
[browser_ext_themes_dynamic_getCurrent.js]
|
||||
[browser_ext_themes_dynamic_updates.js]
|
||||
[browser_ext_themes_lwtsupport.js]
|
||||
[browser_ext_themes_multiple_backgrounds.js]
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
"use strict";
|
||||
|
||||
// This test checks whether browser.theme.getCurrent() works correctly in different
|
||||
// configurations and with different parameter.
|
||||
|
||||
// PNG image data for a simple red dot.
|
||||
const BACKGROUND_1 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
|
||||
// PNG image data for the Mozilla dino head.
|
||||
const BACKGROUND_2 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
|
||||
|
||||
add_task(async function test_get_current() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
const ACCENT_COLOR_1 = "#a14040";
|
||||
const TEXT_COLOR_1 = "#fac96e";
|
||||
|
||||
const ACCENT_COLOR_2 = "#03fe03";
|
||||
const TEXT_COLOR_2 = "#0ef325";
|
||||
|
||||
const theme1 = {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_1,
|
||||
"textcolor": TEXT_COLOR_1,
|
||||
},
|
||||
};
|
||||
|
||||
const theme2 = {
|
||||
"images": {
|
||||
"headerURL": "image2.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_2,
|
||||
"textcolor": TEXT_COLOR_2,
|
||||
},
|
||||
};
|
||||
|
||||
function testTheme1(returnedTheme) {
|
||||
browser.test.assertTrue(returnedTheme.images.headerURL.includes("image1.png"),
|
||||
"Theme 1 header URL should be applied");
|
||||
browser.test.assertEq(ACCENT_COLOR_1, returnedTheme.colors.accentcolor,
|
||||
"Theme 1 accent color should be applied");
|
||||
browser.test.assertEq(TEXT_COLOR_1, returnedTheme.colors.textcolor,
|
||||
"Theme 1 text color should be applied");
|
||||
}
|
||||
|
||||
function testTheme2(returnedTheme) {
|
||||
browser.test.assertTrue(returnedTheme.images.headerURL.includes("image2.png"),
|
||||
"Theme 2 header URL should be applied");
|
||||
browser.test.assertEq(ACCENT_COLOR_2, returnedTheme.colors.accentcolor,
|
||||
"Theme 2 accent color should be applied");
|
||||
browser.test.assertEq(TEXT_COLOR_2, returnedTheme.colors.textcolor,
|
||||
"Theme 2 text color should be applied");
|
||||
}
|
||||
|
||||
function testEmptyTheme(returnedTheme) {
|
||||
browser.test.assertEq(0, Object.keys(returnedTheme).length, JSON.stringify(returnedTheme, null, 2));
|
||||
}
|
||||
|
||||
browser.test.log("Testing getCurrent() with initial unthemed window");
|
||||
const firstWin = await browser.windows.getCurrent();
|
||||
testEmptyTheme(await browser.theme.getCurrent());
|
||||
testEmptyTheme(await browser.theme.getCurrent(firstWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() with after theme.update()");
|
||||
await browser.theme.update(theme1);
|
||||
testTheme1(await browser.theme.getCurrent());
|
||||
testTheme1(await browser.theme.getCurrent(firstWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() with after theme.update(windowId)");
|
||||
const secondWin = await browser.windows.create();
|
||||
await browser.theme.update(secondWin.id, theme2);
|
||||
testTheme2(await browser.theme.getCurrent());
|
||||
testTheme1(await browser.theme.getCurrent(firstWin.id));
|
||||
testTheme2(await browser.theme.getCurrent(secondWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() after window focus change");
|
||||
await browser.windows.update(firstWin.id, {focused: true});
|
||||
testTheme1(await browser.theme.getCurrent());
|
||||
testTheme1(await browser.theme.getCurrent(firstWin.id));
|
||||
testTheme2(await browser.theme.getCurrent(secondWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() after another window focus change");
|
||||
await browser.windows.update(secondWin.id, {focused: true});
|
||||
testTheme2(await browser.theme.getCurrent());
|
||||
testTheme1(await browser.theme.getCurrent(firstWin.id));
|
||||
testTheme2(await browser.theme.getCurrent(secondWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() after theme.reset(windowId)");
|
||||
await browser.theme.reset(firstWin.id);
|
||||
testTheme2(await browser.theme.getCurrent());
|
||||
testEmptyTheme(await browser.theme.getCurrent(firstWin.id));
|
||||
testTheme2(await browser.theme.getCurrent(secondWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() after reset and window focus change");
|
||||
await browser.windows.update(firstWin.id, {focused: true});
|
||||
testEmptyTheme(await browser.theme.getCurrent());
|
||||
testEmptyTheme(await browser.theme.getCurrent(firstWin.id));
|
||||
testTheme2(await browser.theme.getCurrent(secondWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() after theme.update(windowId)");
|
||||
await browser.theme.update(firstWin.id, theme1);
|
||||
testTheme1(await browser.theme.getCurrent());
|
||||
testTheme1(await browser.theme.getCurrent(firstWin.id));
|
||||
testTheme2(await browser.theme.getCurrent(secondWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() after theme.reset()");
|
||||
await browser.theme.reset();
|
||||
testEmptyTheme(await browser.theme.getCurrent());
|
||||
testEmptyTheme(await browser.theme.getCurrent(firstWin.id));
|
||||
testEmptyTheme(await browser.theme.getCurrent(secondWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() after closing a window");
|
||||
await browser.windows.remove(secondWin.id);
|
||||
testEmptyTheme(await browser.theme.getCurrent());
|
||||
testEmptyTheme(await browser.theme.getCurrent(firstWin.id));
|
||||
|
||||
browser.test.log("Testing getCurrent() with invalid window ID");
|
||||
await browser.test.assertRejects(
|
||||
browser.theme.getCurrent(secondWin.id),
|
||||
/Invalid window/,
|
||||
"Invalid window should throw",
|
||||
);
|
||||
browser.test.notifyPass("get_current");
|
||||
},
|
||||
manifest: {
|
||||
permissions: ["theme"],
|
||||
},
|
||||
files: {
|
||||
"image1.png": BACKGROUND_1,
|
||||
"image2.png": BACKGROUND_2,
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitFinish("get_current");
|
||||
await extension.unload();
|
||||
});
|
Загрузка…
Ссылка в новой задаче