diff options
author | Matt A. Tobin <email@mattatobin.com> | 2018-02-09 06:46:43 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2018-02-09 06:46:43 -0500 |
commit | ac46df8daea09899ce30dc8fd70986e258c746bf (patch) | |
tree | 2750d3125fc253fd5b0671e4bd268eff1fd97296 /addon-sdk/source/lib/sdk/ui/frame | |
parent | 8cecf8d5208f3945b35f879bba3015bb1a11bec6 (diff) | |
download | UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.gz UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.lz UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.xz UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.zip |
Move Add-on SDK source to toolkit/jetpack
Diffstat (limited to 'addon-sdk/source/lib/sdk/ui/frame')
-rw-r--r-- | addon-sdk/source/lib/sdk/ui/frame/model.js | 154 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/ui/frame/view.html | 18 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/ui/frame/view.js | 150 |
3 files changed, 0 insertions, 322 deletions
diff --git a/addon-sdk/source/lib/sdk/ui/frame/model.js b/addon-sdk/source/lib/sdk/ui/frame/model.js deleted file mode 100644 index 627310874..000000000 --- a/addon-sdk/source/lib/sdk/ui/frame/model.js +++ /dev/null @@ -1,154 +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": "experimental", - "engines": { - "Firefox": "> 28" - } -}; - -const { Class } = require("../../core/heritage"); -const { EventTarget } = require("../../event/target"); -const { emit, off, setListeners } = require("../../event/core"); -const { Reactor, foldp, send, merges } = require("../../event/utils"); -const { Disposable } = require("../../core/disposable"); -const { OutputPort } = require("../../output/system"); -const { InputPort } = require("../../input/system"); -const { identify } = require("../id"); -const { pairs, object, map, each } = require("../../util/sequence"); -const { patch, diff } = require("diffpatcher/index"); -const { isLocalURL } = require("../../url"); -const { compose } = require("../../lang/functional"); -const { contract } = require("../../util/contract"); -const { id: addonID, data: { url: resolve }} = require("../../self"); -const { Frames } = require("../../input/frame"); - - -const output = new OutputPort({ id: "frame-change" }); -const mailbox = new OutputPort({ id: "frame-mailbox" }); -const input = Frames; - - -const makeID = url => - ("frame-" + addonID + "-" + url). - split("/").join("-"). - split(".").join("-"). - replace(/[^A-Za-z0-9_\-]/g, ""); - -const validate = contract({ - name: { - is: ["string", "undefined"], - ok: x => /^[a-z][a-z0-9-_]+$/i.test(x), - msg: "The `option.name` must be a valid alphanumeric string (hyphens and " + - "underscores are allowed) starting with letter." - }, - url: { - map: x => x.toString(), - is: ["string"], - ok: x => isLocalURL(x), - msg: "The `options.url` must be a valid local URI." - } -}); - -const Source = function({id, ownerID}) { - this.id = id; - this.ownerID = ownerID; -}; -Source.postMessage = ({id, ownerID}, data, origin) => { - send(mailbox, object([id, { - inbox: { - target: {id: id, ownerID: ownerID}, - timeStamp: Date.now(), - data: data, - origin: origin - } - }])); -}; -Source.prototype.postMessage = function(data, origin) { - Source.postMessage(this, data, origin); -}; - -const Message = function({type, data, source, origin, timeStamp}) { - this.type = type; - this.data = data; - this.origin = origin; - this.timeStamp = timeStamp; - this.source = new Source(source); -}; - - -const frames = new Map(); -const sources = new Map(); - -const Frame = Class({ - extends: EventTarget, - implements: [Disposable, Source], - initialize: function(params={}) { - const options = validate(params); - const id = makeID(options.name || options.url); - - if (frames.has(id)) - throw Error("Frame with this id already exists: " + id); - - const initial = { id: id, url: resolve(options.url) }; - this.id = id; - - setListeners(this, params); - - frames.set(this.id, this); - - send(output, object([id, initial])); - }, - get url() { - const state = reactor.value[this.id]; - return state && state.url; - }, - destroy: function() { - send(output, object([this.id, null])); - frames.delete(this.id); - off(this); - }, - // `JSON.stringify` serializes objects based of the return - // value of this method. For convinienc we provide this method - // to serialize actual state data. - toJSON: function() { - return { id: this.id, url: this.url }; - } -}); -identify.define(Frame, frame => frame.id); - -exports.Frame = Frame; - -const reactor = new Reactor({ - onStep: (present, past) => { - const delta = diff(past, present); - - each(([id, update]) => { - const frame = frames.get(id); - if (update) { - if (!past[id]) - emit(frame, "register"); - - if (update.outbox) - emit(frame, "message", new Message(present[id].outbox)); - - each(([ownerID, state]) => { - const readyState = state ? state.readyState : "detach"; - const type = readyState === "loading" ? "attach" : - readyState === "interactive" ? "ready" : - readyState === "complete" ? "load" : - readyState; - - // TODO: Cache `Source` instances somewhere to preserve - // identity. - emit(frame, type, {type: type, - source: new Source({id: id, ownerID: ownerID})}); - }, pairs(update.owners)); - } - }, pairs(delta)); - } -}); -reactor.run(input); diff --git a/addon-sdk/source/lib/sdk/ui/frame/view.html b/addon-sdk/source/lib/sdk/ui/frame/view.html deleted file mode 100644 index 2a405b583..000000000 --- a/addon-sdk/source/lib/sdk/ui/frame/view.html +++ /dev/null @@ -1,18 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <script> - // HACK: This is not an ideal way to deliver chrome messages - // to an inner frame content but seems only way that would - // make `event.source` this (outer frame) window. - window.onmessage = function(event) { - var frame = document.querySelector("iframe"); - var content = frame.contentWindow; - // If message is posted from chrome it has no `event.source`. - if (event.source === null) - content.postMessage(event.data, "*"); - }; - </script> - </head> - <body style="overflow: hidden"></body> -</html> diff --git a/addon-sdk/source/lib/sdk/ui/frame/view.js b/addon-sdk/source/lib/sdk/ui/frame/view.js deleted file mode 100644 index 2eb4df2b7..000000000 --- a/addon-sdk/source/lib/sdk/ui/frame/view.js +++ /dev/null @@ -1,150 +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": "experimental", - "engines": { - "Firefox": "> 28" - } -}; - -const { Cu, Ci } = require("chrome"); -const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); -const { subscribe, send, Reactor, foldp, lift, merges, keepIf } = require("../../event/utils"); -const { InputPort } = require("../../input/system"); -const { OutputPort } = require("../../output/system"); -const { LastClosed } = require("../../input/browser"); -const { pairs, keys, object, each } = require("../../util/sequence"); -const { curry, compose } = require("../../lang/functional"); -const { getFrameElement, getOuterId, - getByOuterId, getOwnerBrowserWindow } = require("../../window/utils"); -const { patch, diff } = require("diffpatcher/index"); -const { encode } = require("../../base64"); -const { Frames } = require("../../input/frame"); - -const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; -const HTML_NS = "http://www.w3.org/1999/xhtml"; -const OUTER_FRAME_URI = module.uri.replace(/\.js$/, ".html"); - -const mailbox = new OutputPort({ id: "frame-mailbox" }); - -const frameID = frame => frame.id.replace("outer-", ""); -const windowID = compose(getOuterId, getOwnerBrowserWindow); - -const getOuterFrame = (windowID, frameID) => - getByOuterId(windowID).document.getElementById("outer-" + frameID); - -const listener = ({target, source, data, origin, timeStamp}) => { - // And sent received message to outbox so that frame API model - // will deal with it. - if (source && source !== target) { - const frame = getFrameElement(target); - const id = frameID(frame); - send(mailbox, object([id, { - outbox: {type: "message", - source: {id: id, ownerID: windowID(frame)}, - data: data, - origin: origin, - timeStamp: timeStamp}}])); - } -}; - -// Utility function used to create frame with a given `state` and -// inject it into given `window`. -const registerFrame = ({id, url}) => { - CustomizableUI.createWidget({ - id: id, - type: "custom", - removable: true, - onBuild: document => { - let view = document.createElementNS(XUL_NS, "toolbaritem"); - view.setAttribute("id", id); - view.setAttribute("flex", 2); - - let outerFrame = document.createElementNS(XUL_NS, "iframe"); - outerFrame.setAttribute("src", OUTER_FRAME_URI); - outerFrame.setAttribute("id", "outer-" + id); - outerFrame.setAttribute("data-is-sdk-outer-frame", true); - outerFrame.setAttribute("type", "content"); - outerFrame.setAttribute("transparent", true); - outerFrame.setAttribute("flex", 2); - outerFrame.setAttribute("style", "overflow: hidden;"); - outerFrame.setAttribute("scrolling", "no"); - outerFrame.setAttribute("disablehistory", true); - outerFrame.setAttribute("seamless", "seamless"); - outerFrame.addEventListener("load", function onload() { - outerFrame.removeEventListener("load", onload, true); - - let doc = outerFrame.contentDocument; - - let innerFrame = doc.createElementNS(HTML_NS, "iframe"); - innerFrame.setAttribute("id", id); - innerFrame.setAttribute("src", url); - innerFrame.setAttribute("seamless", "seamless"); - innerFrame.setAttribute("sandbox", "allow-scripts"); - innerFrame.setAttribute("scrolling", "no"); - innerFrame.setAttribute("data-is-sdk-inner-frame", true); - innerFrame.setAttribute("style", [ "border:none", - "position:absolute", "width:100%", "top: 0", - "left: 0", "overflow: hidden"].join(";")); - - doc.body.appendChild(innerFrame); - }, true); - - view.appendChild(outerFrame); - - return view; - } - }); -}; - -const unregisterFrame = CustomizableUI.destroyWidget; - -const deliverMessage = curry((frameID, data, windowID) => { - const frame = getOuterFrame(windowID, frameID); - const content = frame && frame.contentWindow; - - if (content) - content.postMessage(data, content.location.origin); -}); - -const updateFrame = (id, {inbox, owners}, present) => { - if (inbox) { - const { data, target:{ownerID}, source } = present[id].inbox; - if (ownerID) - deliverMessage(id, data, ownerID); - else - each(deliverMessage(id, data), keys(present[id].owners)); - } - - each(setupView(id), pairs(owners)); -}; - -const setupView = curry((frameID, [windowID, state]) => { - if (state && state.readyState === "loading") { - const frame = getOuterFrame(windowID, frameID); - // Setup a message listener on contentWindow. - frame.contentWindow.addEventListener("message", listener); - } -}); - - -const reactor = new Reactor({ - onStep: (present, past) => { - const delta = diff(past, present); - - // Apply frame changes - each(([id, update]) => { - if (update === null) - unregisterFrame(id); - else if (past[id]) - updateFrame(id, update, present); - else - registerFrame(update); - }, pairs(delta)); - }, - onEnd: state => each(unregisterFrame, keys(state)) -}); -reactor.run(Frames); |