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: const { windows, isInteractive, isDocumentLoaded, michael@0: getOuterId, isTopLevel } = require("../window/utils"); michael@0: const { InputPort } = require("./system"); michael@0: const { lift, merges, foldp, keepIf, start, Input } = require("../event/utils"); michael@0: const { patch } = require("diffpatcher/index"); michael@0: const { on } = require("../event/core"); michael@0: const { Sequence, seq, filter, object, pairs } = require("../util/sequence"); michael@0: michael@0: michael@0: // Create lazy iterators from the regular arrays, although michael@0: // once https://github.com/mozilla/addon-sdk/pull/1314 lands michael@0: // `windows` will be transforme to lazy iterators. michael@0: // When iterated over belowe sequences items will represent michael@0: // state of windows at the time of iteration. michael@0: const opened = seq(function*() { michael@0: const items = windows(null, {includePrivates: true}); michael@0: for (let item of items) michael@0: yield [getOuterId(item), item]; michael@0: }); michael@0: const interactive = filter(([_, window]) => isInteractive(window), opened); michael@0: const loaded = filter(([_, window]) => isDocumentLoaded(window), opened); michael@0: michael@0: // Helper function that converts given argument to a delta. michael@0: const Update = window => window && object([getOuterId(window), window]); michael@0: const Delete = window => window && object([getOuterId(window), null]); michael@0: michael@0: // Signal represents delta for last opened top level window. michael@0: const LastOpened = lift(Update, new InputPort({topic: "domwindowopened"})); michael@0: exports.LastOpened = LastOpened; michael@0: michael@0: // Signal represents delta for last top level window close. michael@0: const LastClosed = lift(Delete, new InputPort({topic: "domwindowclosed"})); michael@0: exports.LastClosed = LastClosed; michael@0: michael@0: const windowFor = document => document && document.defaultView; michael@0: michael@0: // Signal represent delta for last top level window document becoming interactive. michael@0: const InteractiveDoc = new InputPort({topic: "chrome-document-interactive"}); michael@0: const InteractiveWin = lift(windowFor, InteractiveDoc); michael@0: const LastInteractive = lift(Update, keepIf(isTopLevel, null, InteractiveWin)); michael@0: exports.LastInteractive = LastInteractive; michael@0: michael@0: // Signal represent delta for last top level window loaded. michael@0: const LoadedDoc = new InputPort({topic: "chrome-document-loaded"}); michael@0: const LoadedWin = lift(windowFor, LoadedDoc); michael@0: const LastLoaded = lift(Update, keepIf(isTopLevel, null, LoadedWin)); michael@0: exports.LastLoaded = LastLoaded; michael@0: michael@0: michael@0: const initialize = input => { michael@0: if (!input.initialized) { michael@0: input.value = object(...input.value); michael@0: Input.start(input); michael@0: input.initialized = true; michael@0: } michael@0: }; michael@0: michael@0: // Signal represents set of currently opened top level windows, updated michael@0: // to new set any time window is opened or closed. michael@0: const Opened = foldp(patch, opened, merges([LastOpened, LastClosed])); michael@0: Opened[start] = initialize; michael@0: exports.Opened = Opened; michael@0: michael@0: // Signal represents set of top level interactive windows, updated any michael@0: // time new window becomes interactive or one get's closed. michael@0: const Interactive = foldp(patch, interactive, merges([LastInteractive, michael@0: LastClosed])); michael@0: Interactive[start] = initialize; michael@0: exports.Interactive = Interactive; michael@0: michael@0: // Signal represents set of top level loaded window, updated any time michael@0: // new window becomes interactive or one get's closed. michael@0: const Loaded = foldp(patch, loaded, merges([LastLoaded, LastClosed])); michael@0: Loaded[start] = initialize; michael@0: exports.Loaded = Loaded;