michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: "use strict"; michael@0: michael@0: module.metadata = { michael@0: "stability": "experimental" michael@0: }; michael@0: michael@0: const { Cc, Ci } = require("chrome"); michael@0: const { Class } = require("../core/heritage"); michael@0: const { ns } = require("../core/namespace"); michael@0: const { URL } = require('../url'); michael@0: const events = require("../system/events"); michael@0: const { loadSheet, removeSheet, isTypeValid } = require("./utils"); michael@0: const { isString } = require("../lang/type"); michael@0: const { attachTo, detachFrom, getTargetWindow } = require("../content/mod"); michael@0: michael@0: const { freeze, create } = Object; michael@0: const LOCAL_URI_SCHEMES = ['resource', 'data']; michael@0: michael@0: function isLocalURL(item) { michael@0: try { michael@0: return LOCAL_URI_SCHEMES.indexOf(URL(item).scheme) > -1; michael@0: } michael@0: catch(e) {} michael@0: michael@0: return false; michael@0: } michael@0: michael@0: function Style({ source, uri, type }) { michael@0: source = source == null ? null : freeze([].concat(source)); michael@0: uri = uri == null ? null : freeze([].concat(uri)); michael@0: type = type == null ? "author" : type; michael@0: michael@0: if (source && !source.every(isString)) michael@0: throw new Error('Style.source must be a string or an array of strings.'); michael@0: michael@0: if (uri && !uri.every(isLocalURL)) michael@0: throw new Error('Style.uri must be a local URL or an array of local URLs'); michael@0: michael@0: if (type && !isTypeValid(type)) michael@0: throw new Error('Style.type must be "agent", "user" or "author"'); michael@0: michael@0: return freeze(create(Style.prototype, { michael@0: "source": { value: source, enumerable: true }, michael@0: "uri": { value: uri, enumerable: true }, michael@0: "type": { value: type, enumerable: true } michael@0: })); michael@0: }; michael@0: michael@0: exports.Style = Style; michael@0: michael@0: attachTo.define(Style, function (style, window) { michael@0: if (style.uri) { michael@0: for (let uri of style.uri) michael@0: loadSheet(window, uri, style.type); michael@0: } michael@0: michael@0: if (style.source) { michael@0: let uri = "data:text/css;charset=utf-8,"; michael@0: michael@0: uri += encodeURIComponent(style.source.join("")); michael@0: michael@0: loadSheet(window, uri, style.type); michael@0: } michael@0: }); michael@0: michael@0: detachFrom.define(Style, function (style, window) { michael@0: if (style.uri) michael@0: for (let uri of style.uri) michael@0: removeSheet(window, uri); michael@0: michael@0: if (style.source) { michael@0: let uri = "data:text/css;charset=utf-8,"; michael@0: michael@0: uri += encodeURIComponent(style.source.join("")); michael@0: michael@0: removeSheet(window, uri, style.type); michael@0: } michael@0: });