addon-sdk/source/lib/sdk/ui/frame/model.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 "use strict";
michael@0 5
michael@0 6 module.metadata = {
michael@0 7 "stability": "experimental",
michael@0 8 "engines": {
michael@0 9 "Firefox": "> 28"
michael@0 10 }
michael@0 11 };
michael@0 12
michael@0 13 const { Class } = require("../../core/heritage");
michael@0 14 const { EventTarget } = require("../../event/target");
michael@0 15 const { emit, off, setListeners } = require("../../event/core");
michael@0 16 const { Reactor, foldp, send, merges } = require("../../event/utils");
michael@0 17 const { Disposable } = require("../../core/disposable");
michael@0 18 const { OutputPort } = require("../../output/system");
michael@0 19 const { InputPort } = require("../../input/system");
michael@0 20 const { identify } = require("../id");
michael@0 21 const { pairs, object, map, each } = require("../../util/sequence");
michael@0 22 const { patch, diff } = require("diffpatcher/index");
michael@0 23 const { isLocalURL } = require("../../url");
michael@0 24 const { compose } = require("../../lang/functional");
michael@0 25 const { contract } = require("../../util/contract");
michael@0 26 const { id: addonID, data: { url: resolve }} = require("../../self");
michael@0 27 const { Frames } = require("../../input/frame");
michael@0 28
michael@0 29
michael@0 30 const output = new OutputPort({ id: "frame-change" });
michael@0 31 const mailbox = new OutputPort({ id: "frame-mailbox" });
michael@0 32 const input = Frames;
michael@0 33
michael@0 34
michael@0 35 const makeID = url =>
michael@0 36 ("frame-" + addonID + "-" + url).
michael@0 37 split("/").join("-").
michael@0 38 split(".").join("-").
michael@0 39 replace(/[^A-Za-z0-9_\-]/g, "");
michael@0 40
michael@0 41 const validate = contract({
michael@0 42 name: {
michael@0 43 is: ["string", "undefined"],
michael@0 44 ok: x => /^[a-z][a-z0-9-_]+$/i.test(x),
michael@0 45 msg: "The `option.name` must be a valid alphanumeric string (hyphens and " +
michael@0 46 "underscores are allowed) starting with letter."
michael@0 47 },
michael@0 48 url: {
michael@0 49 map: x => x.toString(),
michael@0 50 is: ["string"],
michael@0 51 ok: x => isLocalURL(x),
michael@0 52 msg: "The `options.url` must be a valid local URI."
michael@0 53 }
michael@0 54 });
michael@0 55
michael@0 56 const Source = function({id, ownerID}) {
michael@0 57 this.id = id;
michael@0 58 this.ownerID = ownerID;
michael@0 59 };
michael@0 60 Source.postMessage = ({id, ownerID}, data, origin) => {
michael@0 61 send(mailbox, object([id, {
michael@0 62 inbox: {
michael@0 63 target: {id: id, ownerID: ownerID},
michael@0 64 timeStamp: Date.now(),
michael@0 65 data: data,
michael@0 66 origin: origin
michael@0 67 }
michael@0 68 }]));
michael@0 69 };
michael@0 70 Source.prototype.postMessage = function(data, origin) {
michael@0 71 Source.postMessage(this, data, origin);
michael@0 72 };
michael@0 73
michael@0 74 const Message = function({type, data, source, origin, timeStamp}) {
michael@0 75 this.type = type;
michael@0 76 this.data = data;
michael@0 77 this.origin = origin;
michael@0 78 this.timeStamp = timeStamp;
michael@0 79 this.source = new Source(source);
michael@0 80 };
michael@0 81
michael@0 82
michael@0 83 const frames = new Map();
michael@0 84 const sources = new Map();
michael@0 85
michael@0 86 const Frame = Class({
michael@0 87 extends: EventTarget,
michael@0 88 implements: [Disposable, Source],
michael@0 89 initialize: function(params={}) {
michael@0 90 const options = validate(params);
michael@0 91 const id = makeID(options.name || options.url);
michael@0 92
michael@0 93 if (frames.has(id))
michael@0 94 throw Error("Frame with this id already exists: " + id);
michael@0 95
michael@0 96 const initial = { id: id, url: resolve(options.url) };
michael@0 97 this.id = id;
michael@0 98
michael@0 99 setListeners(this, params);
michael@0 100
michael@0 101 frames.set(this.id, this);
michael@0 102
michael@0 103 send(output, object([id, initial]));
michael@0 104 },
michael@0 105 get url() {
michael@0 106 const state = reactor.value[this.id];
michael@0 107 return state && state.url;
michael@0 108 },
michael@0 109 destroy: function() {
michael@0 110 send(output, object([this.id, null]));
michael@0 111 frames.delete(this.id);
michael@0 112 off(this);
michael@0 113 },
michael@0 114 // `JSON.stringify` serializes objects based of the return
michael@0 115 // value of this method. For convinienc we provide this method
michael@0 116 // to serialize actual state data.
michael@0 117 toJSON: function() {
michael@0 118 return { id: this.id, url: this.url };
michael@0 119 }
michael@0 120 });
michael@0 121 identify.define(Frame, frame => frame.id);
michael@0 122
michael@0 123 exports.Frame = Frame;
michael@0 124
michael@0 125 const reactor = new Reactor({
michael@0 126 onStep: (present, past) => {
michael@0 127 const delta = diff(past, present);
michael@0 128
michael@0 129 each(([id, update]) => {
michael@0 130 const frame = frames.get(id);
michael@0 131 if (update) {
michael@0 132 if (!past[id])
michael@0 133 emit(frame, "register");
michael@0 134
michael@0 135 if (update.outbox)
michael@0 136 emit(frame, "message", new Message(present[id].outbox));
michael@0 137
michael@0 138 each(([ownerID, state]) => {
michael@0 139 const readyState = state ? state.readyState : "detach";
michael@0 140 const type = readyState === "loading" ? "attach" :
michael@0 141 readyState === "interactive" ? "ready" :
michael@0 142 readyState === "complete" ? "load" :
michael@0 143 readyState;
michael@0 144
michael@0 145 // TODO: Cache `Source` instances somewhere to preserve
michael@0 146 // identity.
michael@0 147 emit(frame, type, {type: type,
michael@0 148 source: new Source({id: id, ownerID: ownerID})});
michael@0 149 }, pairs(update.owners));
michael@0 150 }
michael@0 151 }, pairs(delta));
michael@0 152 }
michael@0 153 });
michael@0 154 reactor.run(input);

mercurial