summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/lib/sdk/content/page-mod.js
diff options
context:
space:
mode:
Diffstat (limited to 'addon-sdk/source/lib/sdk/content/page-mod.js')
-rw-r--r--addon-sdk/source/lib/sdk/content/page-mod.js236
1 files changed, 0 insertions, 236 deletions
diff --git a/addon-sdk/source/lib/sdk/content/page-mod.js b/addon-sdk/source/lib/sdk/content/page-mod.js
deleted file mode 100644
index 8ff9b1e7b..000000000
--- a/addon-sdk/source/lib/sdk/content/page-mod.js
+++ /dev/null
@@ -1,236 +0,0 @@
-/* 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": "stable"
-};
-
-const { getAttachEventType } = require('../content/utils');
-const { Class } = require('../core/heritage');
-const { Disposable } = require('../core/disposable');
-const { WeakReference } = require('../core/reference');
-const { WorkerChild } = require('./worker-child');
-const { EventTarget } = require('../event/target');
-const { on, emit, once, setListeners } = require('../event/core');
-const { on: domOn, removeListener: domOff } = require('../dom/events');
-const { isRegExp, isUndefined } = require('../lang/type');
-const { merge } = require('../util/object');
-const { isBrowser, getFrames } = require('../window/utils');
-const { getTabs, getURI: getTabURI } = require('../tabs/utils');
-const { ignoreWindow } = require('../private-browsing/utils');
-const { Style } = require("../stylesheet/style");
-const { attach, detach } = require("../content/mod");
-const { has, hasAny } = require("../util/array");
-const { Rules } = require("../util/rules");
-const { List, addListItem, removeListItem } = require('../util/list');
-const { when } = require("../system/unload");
-const { uuid } = require('../util/uuid');
-const { frames, process } = require('../remote/child');
-
-const pagemods = new Map();
-const styles = new WeakMap();
-var styleFor = (mod) => styles.get(mod);
-
-// Helper functions
-var modMatchesURI = (mod, uri) => mod.include.matchesAny(uri) && !mod.exclude.matchesAny(uri);
-
-/**
- * PageMod constructor (exported below).
- * @constructor
- */
-const ChildPageMod = Class({
- implements: [
- EventTarget,
- Disposable,
- ],
- setup: function PageMod(model) {
- merge(this, model);
-
- // Set listeners on {PageMod} itself, not the underlying worker,
- // like `onMessage`, as it'll get piped.
- setListeners(this, model);
-
- function deserializeRules(rules) {
- for (let rule of rules) {
- yield rule.type == "string" ? rule.value
- : new RegExp(rule.pattern, rule.flags);
- }
- }
-
- let include = [...deserializeRules(this.include)];
- this.include = Rules();
- this.include.add.apply(this.include, include);
-
- let exclude = [...deserializeRules(this.exclude)];
- this.exclude = Rules();
- this.exclude.add.apply(this.exclude, exclude);
-
- if (this.contentStyle || this.contentStyleFile) {
- styles.set(this, Style({
- uri: this.contentStyleFile,
- source: this.contentStyle
- }));
- }
-
- pagemods.set(this.id, this);
- this.seenDocuments = new WeakMap();
-
- // `applyOnExistingDocuments` has to be called after `pagemods.add()`
- // otherwise its calls to `onContent` method won't do anything.
- if (has(this.attachTo, 'existing'))
- applyOnExistingDocuments(this);
- },
-
- dispose: function() {
- let style = styleFor(this);
- if (style)
- detach(style);
-
- for (let i in this.include)
- this.include.remove(this.include[i]);
-
- pagemods.delete(this.id);
- }
-});
-
-function onContentWindow({ target: document }) {
- // Return if we have no pagemods
- if (pagemods.size === 0)
- return;
-
- let window = document.defaultView;
- // XML documents don't have windows, and we don't yet support them.
- if (!window)
- return;
-
- // Frame event listeners are bound to the frame the event came from by default
- let frame = this;
- // We apply only on documents in tabs of Firefox
- if (!frame.isTab)
- return;
-
- // When the tab is private, only addons with 'private-browsing' flag in
- // their package.json can apply content script to private documents
- if (ignoreWindow(window))
- return;
-
- for (let pagemod of pagemods.values()) {
- if (modMatchesURI(pagemod, window.location.href))
- onContent(pagemod, window);
- }
-}
-frames.addEventListener("DOMDocElementInserted", onContentWindow, true);
-
-function applyOnExistingDocuments (mod) {
- for (let frame of frames) {
- // Fake a newly created document
- let window = frame.content;
- // on startup with e10s, contentWindow might not exist yet,
- // in which case we will get notified by "document-element-inserted".
- if (!window || !window.frames)
- return;
- let uri = window.location.href;
- if (has(mod.attachTo, "top") && modMatchesURI(mod, uri))
- onContent(mod, window);
- if (has(mod.attachTo, "frame"))
- getFrames(window).
- filter(iframe => modMatchesURI(mod, iframe.location.href)).
- forEach(frame => onContent(mod, frame));
- }
-}
-
-function createWorker(mod, window) {
- let workerId = String(uuid());
-
- // Instruct the parent to connect to this worker. Do this first so the parent
- // side is connected before the worker attempts to send any messages there
- let frame = frames.getFrameForWindow(window.top);
- frame.port.emit('sdk/page-mod/worker-create', mod.id, {
- id: workerId,
- url: window.location.href
- });
-
- // Create a child worker and notify the parent
- let worker = WorkerChild({
- id: workerId,
- window: window,
- contentScript: mod.contentScript,
- contentScriptFile: mod.contentScriptFile,
- contentScriptOptions: mod.contentScriptOptions
- });
-
- once(worker, 'detach', () => worker.destroy());
-}
-
-function onContent (mod, window) {
- let isTopDocument = window.top === window;
- // Is a top level document and `top` is not set, ignore
- if (isTopDocument && !has(mod.attachTo, "top"))
- return;
- // Is a frame document and `frame` is not set, ignore
- if (!isTopDocument && !has(mod.attachTo, "frame"))
- return;
-
- // ensure we attach only once per document
- let seen = mod.seenDocuments;
- if (seen.has(window.document))
- return;
- seen.set(window.document, true);
-
- let style = styleFor(mod);
- if (style)
- attach(style, window);
-
- // Immediately evaluate content script if the document state is already
- // matching contentScriptWhen expectations
- if (isMatchingAttachState(mod, window)) {
- createWorker(mod, window);
- return;
- }
-
- let eventName = getAttachEventType(mod) || 'load';
- domOn(window, eventName, function onReady (e) {
- if (e.target.defaultView !== window)
- return;
- domOff(window, eventName, onReady, true);
- createWorker(mod, window);
-
- // Attaching is asynchronous so if the document is already loaded we will
- // miss the pageshow event so send a synthetic one.
- if (window.document.readyState == "complete") {
- mod.on('attach', worker => {
- try {
- worker.send('pageshow');
- emit(worker, 'pageshow');
- }
- catch (e) {
- // This can fail if an earlier attach listener destroyed the worker
- }
- });
- }
- }, true);
-}
-
-function isMatchingAttachState (mod, window) {
- let state = window.document.readyState;
- return 'start' === mod.contentScriptWhen ||
- // Is `load` event already dispatched?
- 'complete' === state ||
- // Is DOMContentLoaded already dispatched and waiting for it?
- ('ready' === mod.contentScriptWhen && state === 'interactive')
-}
-
-process.port.on('sdk/page-mod/create', (process, model) => {
- if (pagemods.has(model.id))
- return;
-
- new ChildPageMod(model);
-});
-
-process.port.on('sdk/page-mod/destroy', (process, id) => {
- let mod = pagemods.get(id);
- if (mod)
- mod.destroy();
-});