UNPKG

5.66 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var snabbdom_1 = require("snabbdom");
4var xstream_1 = require("xstream");
5var concat_1 = require("xstream/extra/concat");
6var sampleCombine_1 = require("xstream/extra/sampleCombine");
7var MainDOMSource_1 = require("./MainDOMSource");
8var VNodeWrapper_1 = require("./VNodeWrapper");
9var utils_1 = require("./utils");
10var modules_1 = require("./modules");
11var IsolateModule_1 = require("./IsolateModule");
12var EventDelegator_1 = require("./EventDelegator");
13function makeDOMDriverInputGuard(modules) {
14 if (!Array.isArray(modules)) {
15 throw new Error("Optional modules option must be an array for snabbdom modules");
16 }
17}
18function domDriverInputGuard(view$) {
19 if (!view$ ||
20 typeof view$.addListener !== "function" ||
21 typeof view$.fold !== "function") {
22 throw new Error("The DOM driver function expects as input a Stream of " +
23 "virtual DOM elements");
24 }
25}
26function dropCompletion(input) {
27 return xstream_1.default.merge(input, xstream_1.default.never());
28}
29function unwrapElementFromVNode(vnode) {
30 return vnode.elm;
31}
32function defaultReportSnabbdomError(err) {
33 (console.error || console.log)(err);
34}
35function makeDOMReady$() {
36 return xstream_1.default.create({
37 start: function (lis) {
38 if (document.readyState === 'loading') {
39 document.addEventListener('readystatechange', function () {
40 var state = document.readyState;
41 if (state === 'interactive' || state === 'complete') {
42 lis.next(null);
43 lis.complete();
44 }
45 });
46 }
47 else {
48 lis.next(null);
49 lis.complete();
50 }
51 },
52 stop: function () { },
53 });
54}
55function addRootScope(vnode) {
56 vnode.data = vnode.data || {};
57 vnode.data.isolate = [];
58 return vnode;
59}
60function makeDOMDriver(container, options) {
61 if (options === void 0) { options = {}; }
62 utils_1.checkValidContainer(container);
63 var modules = options.modules || modules_1.default;
64 makeDOMDriverInputGuard(modules);
65 var isolateModule = new IsolateModule_1.IsolateModule();
66 var snabbdomOptions = options && options.snabbdomOptions || undefined;
67 var patch = snabbdom_1.init([isolateModule.createModule()].concat(modules), undefined, snabbdomOptions);
68 var domReady$ = makeDOMReady$();
69 var vnodeWrapper;
70 var mutationObserver;
71 var mutationConfirmed$ = xstream_1.default.create({
72 start: function (listener) {
73 mutationObserver = new MutationObserver(function () { return listener.next(null); });
74 },
75 stop: function () {
76 mutationObserver.disconnect();
77 },
78 });
79 function DOMDriver(vnode$, name) {
80 if (name === void 0) { name = 'DOM'; }
81 domDriverInputGuard(vnode$);
82 var sanitation$ = xstream_1.default.create();
83 var firstRoot$ = domReady$.map(function () {
84 var firstRoot = utils_1.getValidNode(container) || document.body;
85 vnodeWrapper = new VNodeWrapper_1.VNodeWrapper(firstRoot);
86 return firstRoot;
87 });
88 // We need to subscribe to the sink (i.e. vnode$) synchronously inside this
89 // driver, and not later in the map().flatten() because this sink is in
90 // reality a SinkProxy from @cycle/run, and we don't want to miss the first
91 // emission when the main() is connected to the drivers.
92 // Read more in issue #739.
93 var rememberedVNode$ = vnode$.remember();
94 rememberedVNode$.addListener({});
95 // The mutation observer internal to mutationConfirmed$ should
96 // exist before elementAfterPatch$ calls mutationObserver.observe()
97 mutationConfirmed$.addListener({});
98 var elementAfterPatch$ = firstRoot$
99 .map(function (firstRoot) {
100 return xstream_1.default
101 .merge(rememberedVNode$.endWhen(sanitation$), sanitation$)
102 .map(function (vnode) { return vnodeWrapper.call(vnode); })
103 .startWith(addRootScope(snabbdom_1.toVNode(firstRoot)))
104 .fold(patch, snabbdom_1.toVNode(firstRoot))
105 .drop(1)
106 .map(unwrapElementFromVNode)
107 .startWith(firstRoot)
108 .map(function (el) {
109 mutationObserver.observe(el, {
110 childList: true,
111 attributes: true,
112 characterData: true,
113 subtree: true,
114 attributeOldValue: true,
115 characterDataOldValue: true,
116 });
117 return el;
118 })
119 .compose(dropCompletion);
120 } // don't complete this stream
121 )
122 .flatten();
123 var rootElement$ = concat_1.default(domReady$, mutationConfirmed$)
124 .endWhen(sanitation$)
125 .compose(sampleCombine_1.default(elementAfterPatch$))
126 .map(function (arr) { return arr[1]; })
127 .remember();
128 // Start the snabbdom patching, over time
129 rootElement$.addListener({
130 error: options.reportSnabbdomError || defaultReportSnabbdomError,
131 });
132 var delegator = new EventDelegator_1.EventDelegator(rootElement$, isolateModule);
133 return new MainDOMSource_1.MainDOMSource(rootElement$, sanitation$, [], isolateModule, delegator, name);
134 }
135 return DOMDriver;
136}
137exports.makeDOMDriver = makeDOMDriver;
138//# sourceMappingURL=makeDOMDriver.js.map
\No newline at end of file