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': 'unstable' michael@0: }; michael@0: michael@0: let { merge } = require('../util/object'); michael@0: let assetsURI = require('../self').data.url(); michael@0: let isArray = Array.isArray; michael@0: let method = require('../../method/core'); michael@0: michael@0: function isAddonContent({ contentURL }) { michael@0: return typeof(contentURL) === 'string' && contentURL.indexOf(assetsURI) === 0; michael@0: } michael@0: exports.isAddonContent = isAddonContent; michael@0: michael@0: function hasContentScript({ contentScript, contentScriptFile }) { michael@0: return (isArray(contentScript) ? contentScript.length > 0 : michael@0: !!contentScript) || michael@0: (isArray(contentScriptFile) ? contentScriptFile.length > 0 : michael@0: !!contentScriptFile); michael@0: } michael@0: exports.hasContentScript = hasContentScript; michael@0: michael@0: function requiresAddonGlobal(model) { michael@0: return model.injectInDocument || (isAddonContent(model) && !hasContentScript(model)); michael@0: } michael@0: exports.requiresAddonGlobal = requiresAddonGlobal; michael@0: michael@0: function getAttachEventType(model) { michael@0: if (!model) return null; michael@0: let when = model.contentScriptWhen; michael@0: return requiresAddonGlobal(model) ? 'document-element-inserted' : michael@0: when === 'start' ? 'document-element-inserted' : michael@0: when === 'ready' ? 'DOMContentLoaded' : michael@0: when === 'end' ? 'load' : michael@0: null; michael@0: } michael@0: exports.getAttachEventType = getAttachEventType; michael@0: michael@0: let attach = method('worker-attach'); michael@0: exports.attach = attach; michael@0: michael@0: let detach = method('worker-detach'); michael@0: exports.detach = detach; michael@0: michael@0: let destroy = method('worker-destroy'); michael@0: exports.destroy = destroy; michael@0: michael@0: function WorkerHost (workerFor) { michael@0: // Define worker properties that just proxy to underlying worker michael@0: return ['postMessage', 'port', 'url', 'tab'].reduce(function(proto, name) { michael@0: // Use descriptor properties instead so we can call michael@0: // the worker function in the context of the worker so we michael@0: // don't have to create new functions with `fn.bind(worker)` michael@0: let descriptorProp = { michael@0: value: function (...args) { michael@0: let worker = workerFor(this); michael@0: return worker[name].apply(worker, args); michael@0: } michael@0: }; michael@0: michael@0: let accessorProp = { michael@0: get: function () { return workerFor(this)[name]; }, michael@0: set: function (value) { workerFor(this)[name] = value; } michael@0: }; michael@0: michael@0: Object.defineProperty(proto, name, merge({ michael@0: enumerable: true, michael@0: configurable: false, michael@0: }, isDescriptor(name) ? descriptorProp : accessorProp)); michael@0: return proto; michael@0: }, {}); michael@0: michael@0: function isDescriptor (prop) { michael@0: return ~['postMessage'].indexOf(prop); michael@0: } michael@0: } michael@0: exports.WorkerHost = WorkerHost;