Skip to content

Commit 7876e2e

Browse files
committed
add dom-array.js, update demo to use it instead of dom-observer.js
1 parent 99d9416 commit 7876e2e

File tree

2 files changed

+150
-11
lines changed

2 files changed

+150
-11
lines changed

dom-array.js

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
var DomArray = (function() {
2+
3+
// constructor
4+
5+
function DomArray(collection, parent, renderer) {
6+
this.parent = parent;
7+
this.renderer = renderer;
8+
this.collection = collection;
9+
this.nodeMap = typeof Map === 'function' ? new Map() : null;
10+
11+
this.push.apply(this, collection);
12+
13+
// observe changes on collection if it's observable
14+
if (typeof collection.on === 'function') {
15+
var methods = 'shift pop unshift push splice reverse sort'.split(' ');
16+
each(methods, function(method) {
17+
collection.on(method, this[method].bind(this));
18+
}, this);
19+
}
20+
};
21+
22+
23+
// methods that remove items
24+
25+
DomArray.prototype.shift = function() {
26+
this.parent.removeChild(this.parent.firstChild);
27+
};
28+
29+
DomArray.prototype.pop = function() {
30+
this.parent.removeChild(this.parent.lastChild);
31+
};
32+
33+
34+
// methods that add items
35+
36+
DomArray.prototype.push = function() {
37+
if (!arguments.length) return;
38+
var node = renderAll(arguments, this.renderer);
39+
this.parent.appendChild(node);
40+
};
41+
42+
DomArray.prototype.unshift = function() {
43+
if (!arguments.length) return;
44+
var node = renderAll(arguments, this.renderer);
45+
this.parent.insertBefore(node, this.parent.firstChild);
46+
};
47+
48+
49+
// other methods
50+
51+
DomArray.prototype.splice = function(start, deleteCount) {
52+
var childNodes = this.parent.childNodes;
53+
54+
// If `start` is negative, begin that many elements from the end
55+
start = start < 0 ? childNodes.length + start : start
56+
57+
// remove the element at index `start` `deleteCount` times
58+
deleteCount = typeof deleteCount === 'number' ? deleteCount : childNodes.length - start;
59+
var stop = start + deleteCount;
60+
for (var i = start; i < stop && childNodes[start]; i++) {
61+
this.parent.removeChild(childNodes[start]);
62+
}
63+
64+
// add new elements at index `start`
65+
if (arguments.length > 2) {
66+
var newItems = [].slice.call(arguments, 2);
67+
var node = renderAll(newItems, this.renderer);
68+
this.parent.insertBefore(node, childNodes[start]);
69+
}
70+
};
71+
72+
DomArray.prototype.reverse = function() {
73+
var docFrag = document.createDocumentFragment();
74+
75+
// append every last child of parent to doc frag
76+
while (this.parent.lastChild) {
77+
docFrag.appendChild(
78+
this.parent.removeChild(this.parent.lastChild)
79+
);
80+
}
81+
82+
// append doc frag to parent
83+
this.parent.appendChild(docFrag);
84+
};
85+
86+
DomArray.prototype.sort = function() {
87+
if (!nodeMap) throw new TypeError('DomArray.prototype.sort() requires Map support.');
88+
var docFrag = document.createDocumentFragment();
89+
each(this.collection, function(obj){
90+
var node = this.nodeMap.get(obj);
91+
parent.removeChild(node);
92+
docFrag.appendChild(node);
93+
});
94+
parent.appendChild(docFrag);
95+
};
96+
97+
98+
// helper functions
99+
100+
function each(arr, fn, scope) {
101+
for (var i = 0, l = arr.length; i < l; i++) {
102+
fn.call(scope, arr[i], i, arr);
103+
}
104+
}
105+
106+
// renderAll returns a single node containing the rendered nodes
107+
function renderAll(collection, renderer) {
108+
var nodeMap = this.nodeMap;
109+
if (collection.length > 1) {
110+
var docFrag = document.createDocumentFragment();
111+
each(collection, function(item) {
112+
// call renderer (should return a DOM node) for each item in collection
113+
var node = renderer.apply(null, arguments);
114+
if (nodeMap) nodeMap.set(item, node);
115+
docFrag.appendChild(node);
116+
});
117+
return docFrag;
118+
} else {
119+
return renderer.apply(null, arguments);
120+
}
121+
}
122+
123+
return DomArray;
124+
})();

index.html

+26-11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width">
66
<title>Observable Array</title>
7+
<style>
8+
.visible-scripts script {
9+
display: block;
10+
white-space: pre-wrap;
11+
}
12+
</style>
713
</head>
814
<body>
915

@@ -12,34 +18,43 @@
1218
<!-- observable-array depends on subscribable.js -->
1319
<script src="bower_components/subscribable.js/subscribable.js"></script>
1420
<script src="observable-array.js"></script>
15-
<script src="dom-observer.js"></script>
21+
<script src="dom-array.js"></script>
1622

23+
<div class="visible-scripts">
1724
<h3>Create an observable array</h3>
18-
<script style="display: block; white-space: pre;">var nums = new ObservableArray([1,2,3,4,5,6,7,8,9,10,11]);</script>
25+
<script>var nums = new ObservableArray([1, 2, 3]);</script>
1926

2027
<h3>Get notified when it changes</h3>
21-
<script style="display: block; white-space: pre;">nums.on('push', function() {
28+
<script>nums.on('push', function() {
2229
console.log('this: ', this, '\narguments: ', arguments);
2330
});</script>
2431

2532
<h3>Use all the native Array methods to make changes, loop, etc.</h3>
26-
<script style="display: block; white-space: pre;">// remove last 4
27-
nums.splice(-4);
33+
<script>
2834

29-
// add 2
30-
nums.push(8, 9);
35+
// add 4
36+
nums.push(4, 5, 6, 7);
3137

32-
// try this in the console!</script>
38+
39+
// remove last 2
40+
nums.splice(-2);
41+
42+
// try these in the console:
43+
// .shift() .pop() .unshift() .push() .splice() .reverse() .sort()
44+
45+
// as well as these which don't modify the array:
46+
// slice, concat, join, some, every, forEach, map, filter, reduce, reduceRight, indexOf, lastIndexOf, toString, toLocaleString</script>
3347

3448
<h3>Add a DOM observer which will get live updates</h3>
35-
<script style="display: block; white-space: pre;">var ul = document.querySelector('ul');
36-
var domObserver = nums.addDomObserver(ul, function(num) {
49+
<script>var ul = document.querySelector('ul');
50+
var listView = new DomArray(nums, ul, function(num) {
3751
var li = document.createElement('li');
3852
li.textContent = 'number: ' + num;
3953
return li;
4054
});</script>
4155

4256
<h3>Stop observing when you're done</h3>
43-
<script style="display: block; white-space: pre;">// domObserver.stop();</script>
57+
<script>// domObserver.stop();</script>
58+
</div>
4459
</body>
4560
</html>

0 commit comments

Comments
 (0)