summaryrefslogtreecommitdiff
path: root/toolkit/jetpack/dev/theme.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/jetpack/dev/theme.js')
-rw-r--r--toolkit/jetpack/dev/theme.js135
1 files changed, 135 insertions, 0 deletions
diff --git a/toolkit/jetpack/dev/theme.js b/toolkit/jetpack/dev/theme.js
new file mode 100644
index 0000000000..05930a502c
--- /dev/null
+++ b/toolkit/jetpack/dev/theme.js
@@ -0,0 +1,135 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+module.metadata = {
+ "stability": "experimental"
+};
+
+const { Class } = require("../sdk/core/heritage");
+const { EventTarget } = require("../sdk/event/target");
+const { Disposable, setup, dispose } = require("../sdk/core/disposable");
+const { contract, validate } = require("../sdk/util/contract");
+const { id: addonID } = require("../sdk/self");
+const { onEnable, onDisable } = require("dev/theme/hooks");
+const { isString, instanceOf, isFunction } = require("sdk/lang/type");
+const { add } = require("sdk/util/array");
+const { data } = require("../sdk/self");
+const { isLocalURL } = require("../sdk/url");
+
+const makeID = name =>
+ ("dev-theme-" + addonID + (name ? "-" + name : "")).
+ split(/[ . /]/).join("-").
+ replace(/[^A-Za-z0-9_\-]/g, "");
+
+const Theme = Class({
+ extends: Disposable,
+ implements: [EventTarget],
+
+ initialize: function(options) {
+ this.name = options.name;
+ this.label = options.label;
+ this.styles = options.styles;
+
+ // Event handlers
+ this.onEnable = options.onEnable;
+ this.onDisable = options.onDisable;
+ },
+ get id() {
+ return makeID(this.name || this.label);
+ },
+ setup: function() {
+ // Any initialization steps done at the registration time.
+ },
+ getStyles: function() {
+ if (!this.styles) {
+ return [];
+ }
+
+ if (isString(this.styles)) {
+ if (isLocalURL(this.styles)) {
+ return [data.url(this.styles)];
+ }
+ }
+
+ let result = [];
+ for (let style of this.styles) {
+ if (isString(style)) {
+ if (isLocalURL(style)) {
+ style = data.url(style);
+ }
+ add(result, style);
+ } else if (instanceOf(style, Theme)) {
+ result = result.concat(style.getStyles());
+ }
+ }
+ return result;
+ },
+ getClassList: function() {
+ let result = [];
+ for (let style of this.styles) {
+ if (instanceOf(style, Theme)) {
+ result = result.concat(style.getClassList());
+ }
+ }
+
+ if (this.name) {
+ add(result, this.name);
+ }
+
+ return result;
+ }
+});
+
+exports.Theme = Theme;
+
+// Initialization & dispose
+
+setup.define(Theme, (theme) => {
+ theme.classList = [];
+ theme.setup();
+});
+
+dispose.define(Theme, function(theme) {
+ theme.dispose();
+});
+
+// Validation
+
+validate.define(Theme, contract({
+ label: {
+ is: ["string"],
+ msg: "The `option.label` must be a provided"
+ },
+}));
+
+// Support theme events: apply and unapply the theme.
+
+onEnable.define(Theme, (theme, {window, oldTheme}) => {
+ if (isFunction(theme.onEnable)) {
+ theme.onEnable(window, oldTheme);
+ }
+});
+
+onDisable.define(Theme, (theme, {window, newTheme}) => {
+ if (isFunction(theme.onDisable)) {
+ theme.onDisable(window, newTheme);
+ }
+});
+
+// Support for built-in themes
+
+const LightTheme = Theme({
+ name: "theme-light",
+ styles: "chrome://devtools/skin/light-theme.css",
+});
+
+const DarkTheme = Theme({
+ name: "theme-dark",
+ styles: "chrome://devtools/skin/dark-theme.css",
+});
+
+exports.LightTheme = LightTheme;
+exports.DarkTheme = DarkTheme;