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.

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

mercurial