Skip to content

Commit 12af99b

Browse files
author
Andrea Giammarchi
committed
cleaned up Updates.js using 3rd parts disconnected module
1 parent f6577e7 commit 12af99b

12 files changed

Lines changed: 342 additions & 371 deletions

File tree

cjs/3rd/disconnected.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
'use strict';
2+
/* AUTOMATICALLY IMPORTED, DO NOT MODIFY */
3+
/*! (c) Andrea Giammarchi */
4+
function disconnected(poly) {'use strict';
5+
var CONNECTED = 'connected';
6+
var DISCONNECTED = 'dis' + CONNECTED;
7+
var Event = poly.Event;
8+
var WeakSet = poly.WeakSet;
9+
var notObserving = true;
10+
var observer = new WeakSet;
11+
return function observe(node) {
12+
if (notObserving) {
13+
notObserving = !notObserving;
14+
startObserving(node.ownerDocument);
15+
}
16+
observer.add(node);
17+
return node;
18+
};
19+
function startObserving(document) {
20+
var dispatched = null;
21+
try {
22+
(new MutationObserver(changes)).observe(
23+
document,
24+
{subtree: true, childList: true}
25+
);
26+
}
27+
catch(o_O) {
28+
var timer = 0;
29+
var records = [];
30+
var reschedule = function (record) {
31+
records.push(record);
32+
clearTimeout(timer);
33+
timer = setTimeout(
34+
function () {
35+
changes(records.splice(timer = 0, records.length));
36+
},
37+
0
38+
);
39+
};
40+
document.addEventListener(
41+
'DOMNodeRemoved',
42+
function (event) {
43+
reschedule({addedNodes: [], removedNodes: [event.target]});
44+
},
45+
true
46+
);
47+
document.addEventListener(
48+
'DOMNodeInserted',
49+
function (event) {
50+
reschedule({addedNodes: [event.target], removedNodes: []});
51+
},
52+
true
53+
);
54+
}
55+
function changes(records) {
56+
dispatched = new Tracker;
57+
for (var
58+
record,
59+
length = records.length,
60+
i = 0; i < length; i++
61+
) {
62+
record = records[i];
63+
dispatchAll(record.removedNodes, DISCONNECTED, CONNECTED);
64+
dispatchAll(record.addedNodes, CONNECTED, DISCONNECTED);
65+
}
66+
dispatched = null;
67+
}
68+
function dispatchAll(nodes, type, counter) {
69+
for (var
70+
node,
71+
event = new Event(type),
72+
length = nodes.length,
73+
i = 0; i < length;
74+
(node = nodes[i++]).nodeType === 1 &&
75+
dispatchTarget(node, event, type, counter)
76+
);
77+
}
78+
function dispatchTarget(node, event, type, counter) {
79+
if (observer.has(node) && !dispatched[type].has(node)) {
80+
dispatched[counter].delete(node);
81+
dispatched[type].add(node);
82+
node.dispatchEvent(event);
83+
/*
84+
// The event is not bubbling (perf reason: should it?),
85+
// hence there's no way to know if
86+
// stop/Immediate/Propagation() was called.
87+
// Should DOM Level 0 work at all?
88+
// I say it's a YAGNI case for the time being,
89+
// and easy to implement in user-land.
90+
if (!event.cancelBubble) {
91+
var fn = node['on' + type];
92+
if (fn)
93+
fn.call(node, event);
94+
}
95+
*/
96+
}
97+
for (var
98+
children = node.children,
99+
length = children.length,
100+
i = 0; i < length;
101+
dispatchTarget(children[i++], event, type, counter)
102+
);
103+
}
104+
function Tracker() {
105+
this[CONNECTED] = new WeakSet;
106+
this[DISCONNECTED] = new WeakSet;
107+
}
108+
}
109+
}
110+
Object.defineProperty(exports, '__esModule', {value: true}).default = disconnected;

cjs/objects/Updates.js

Lines changed: 10 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,11 @@ const domdiff = (m => m.__esModule ? m.default : m)(require('../3rd/domdiff.js')
1313
// import { create as createElement, text } from '../shared/easy-dom.js';
1414
const { text } = require('../shared/easy-dom.js');
1515
const { Event, WeakSet, isArray, trim } = require('../shared/poorlyfills.js');
16-
const { createFragment, getChildren, slice } = require('../shared/utils.js');
16+
const { createFragment, slice } = require('../shared/utils.js');
17+
const disconnected = (m => m.__esModule ? m.default : m)(require('../3rd/disconnected.js'));
1718

18-
const { document, clearTimeout, setTimeout } = G;
19-
20-
// hyper.Component have a connected/disconnected
21-
// mechanism provided by MutationObserver
22-
// This weak set is used to recognize components
23-
// as DOM node that needs to trigger connected/disconnected events
24-
const components = new WeakSet;
19+
const { document } = G;
20+
const observe = disconnected({Event, WeakSet});
2521

2622
// a basic dictionary used to filter already cached attributes
2723
// while looking for special hyperHTML values.
@@ -219,16 +215,6 @@ const isPromise_ish = value => value != null && 'then' in value;
219215
// list of attributes that should not be directly assigned
220216
const readOnly = /^(?:form|list)$/i;
221217

222-
// exposed to make any node observable through
223-
// connected / disconnected event listeners
224-
const observe = node => {
225-
if (notObserving) {
226-
notObserving = false;
227-
startObserving();
228-
}
229-
components.add(node);
230-
};
231-
232218
// in a hyper(node)`<div>${content}</div>` case
233219
// everything could happen:
234220
// * it's a JS primitive, stored as text
@@ -378,14 +364,17 @@ const setAttribute = (node, name, original) => {
378364
if (type === CONNECTED || type === DISCONNECTED) {
379365
observe(node);
380366
}
381-
else if (name.toLowerCase() in node) {
367+
else if (name.toLowerCase()
368+
in node) {
382369
type = type.toLowerCase();
383370
}
384371
return newValue => {
385372
if (oldValue !== newValue) {
386-
if (oldValue) node.removeEventListener(type, oldValue, false);
373+
if (oldValue)
374+
node.removeEventListener(type, oldValue, false);
387375
oldValue = newValue;
388-
if (newValue) node.addEventListener(type, newValue, false);
376+
if (newValue)
377+
node.addEventListener(type, newValue, false);
389378
}
390379
};
391380
}
@@ -481,101 +470,3 @@ const setTextContent = node => {
481470
Object.defineProperty(exports, '__esModule', {value: true}).default = {create, find};
482471

483472
exports.observe = observe;
484-
485-
// hyper.Components might need connected/disconnected notifications
486-
// used by components and their onconnect/ondisconnect callbacks.
487-
// When one of these callbacks is encountered,
488-
// the document starts being observed.
489-
let notObserving = true;
490-
function startObserving() {
491-
492-
// used to avoid duplicated invokes of
493-
// dis/connected nodes and their children
494-
// - - -
495-
// this has been verified in Neverland,
496-
// a node observed and dispatched via children loop
497-
// might also be part of the nodes that have been inserted
498-
// or removed, so but triggering twice should **never** happen
499-
let dispatched = null;
500-
const init = () => {
501-
dispatched = {
502-
disconnected: new WeakSet,
503-
connected: new WeakSet
504-
};
505-
};
506-
507-
// when hyper.Component related DOM nodes
508-
// are appended or removed from the live tree
509-
// these might listen to connected/disconnected events
510-
// This utility is in charge of finding all components
511-
// involved in the DOM update/change and dispatch
512-
// related information to them
513-
const dispatchAll = (nodes, type, counter) => {
514-
const event = new Event(type);
515-
const length = nodes.length;
516-
for (let i = 0; i < length; i++) {
517-
let node = nodes[i];
518-
if (node.nodeType === ELEMENT_NODE) {
519-
dispatchTarget(node, event, type, counter);
520-
}
521-
}
522-
};
523-
524-
// the way it's done is via the components weak set
525-
// and recursively looking for nested components too
526-
const dispatchTarget = (node, event, type, counter) => {
527-
if (components.has(node) && !dispatched[type].has(node)) {
528-
dispatched[counter].delete(node);
529-
dispatched[type].add(node);
530-
node.dispatchEvent(event);
531-
}
532-
533-
/* istanbul ignore next */
534-
const children = node.children || getChildren(node);
535-
const length = children.length;
536-
for (let i = 0; i < length; i++) {
537-
dispatchTarget(children[i], event, type, counter);
538-
}
539-
}
540-
541-
const changes = records => {
542-
const length = records.length;
543-
init();
544-
for (let i = 0; i < length; i++) {
545-
let record = records[i];
546-
dispatchAll(record.removedNodes, DISCONNECTED, CONNECTED);
547-
dispatchAll(record.addedNodes, CONNECTED, DISCONNECTED);
548-
}
549-
dispatched = null;
550-
};
551-
552-
// The MutationObserver is the best way to implement that
553-
// but there is a fallback to deprecated DOMNodeInserted/Removed
554-
// so that even older browsers/engines can help components life-cycle
555-
try {
556-
(new MutationObserver(changes)).observe(
557-
document,
558-
{subtree: true, childList: true}
559-
);
560-
} catch(o_O) {
561-
let timer = 0;
562-
const records = [];
563-
const reschedule = record => {
564-
records.push(record);
565-
clearTimeout(timer);
566-
timer = setTimeout(
567-
() => {
568-
timer = 0;
569-
changes(records.splice(0, records.length));
570-
},
571-
0
572-
);
573-
};
574-
document.addEventListener('DOMNodeRemoved', event => {
575-
reschedule({addedNodes: [], removedNodes: [event.target]});
576-
}, false);
577-
document.addEventListener('DOMNodeInserted', event => {
578-
reschedule({addedNodes: [event.target], removedNodes: []});
579-
}, false);
580-
}
581-
}

0 commit comments

Comments
 (0)