Skip to content

Commit 230fef8

Browse files
committed
v.5.0.0 contd
* some simplifications and minor changes
1 parent 65d3d50 commit 230fef8

10 files changed

Lines changed: 292 additions & 44 deletions

File tree

build/modelview.bundle.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/modelview.js

Lines changed: 134 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
*
33
* ModelView.js
44
* @version: 5.0.0
5-
* @built on 2022-03-28 20:00:42
5+
* @built on 2022-03-30 11:03:44
66
*
77
* A simple, light-weight, versatile and fast isomorphic MVVM JavaScript framework (Browser and Server)
88
* https://github.com/foo123/modelview.js
@@ -11,7 +11,7 @@
1111
*
1212
* ModelView.js
1313
* @version: 5.0.0
14-
* @built on 2022-03-28 20:00:42
14+
* @built on 2022-03-30 11:03:44
1515
*
1616
* A simple, light-weight, versatile and fast isomorphic MVVM JavaScript framework (Browser and Server)
1717
* https://github.com/foo123/modelview.js
@@ -196,13 +196,53 @@ function is_array_index(n)
196196
}
197197
return false
198198
}
199+
function nextNode(node, m, NEXT)
200+
{
201+
for (var i=0; node && (i<m); ++i)
202+
node = node[NEXT];
203+
return node;
204+
}
205+
function moveNodes(dom, node, m, edge)
206+
{
207+
var i, next;
208+
if (edge)
209+
{
210+
for (next=node[NEXT],i=0; node && (i<m); ++i)
211+
{
212+
dom.insertBefore(node, edge);
213+
node = next; next = node ? node[NEXT] : null;
214+
}
215+
}
216+
else
217+
{
218+
for (next=node[NEXT],i=0; node && (i<m); ++i)
219+
{
220+
dom.appendChild(node);
221+
node = next; next = node ? node[NEXT] : null;
222+
}
223+
}
224+
}
225+
function swap(array, i1, i2)
226+
{
227+
var t = array[i1];
228+
array[i1] = array[i2];
229+
array[i2] = t;
230+
return array;
231+
}
232+
function swapNodes(dom, node1, node2, m)
233+
{
234+
var last = nextNode(node2, m, NEXT);
235+
moveNodes(dom, node2, m, node1);
236+
moveNodes(dom, node1, m, last);
237+
}
199238
function permute(list, perm)
200239
{
201240
for (var copy=slice.call(list),i=0,l=list.length; i<l; ++i) list[i] = copy[perm[i]];
202241
return list;
203242
}
204243
function permuteNodes(dom, start, perm, m)
205244
{
245+
// not necessarily min DOM ops
206246
var i, j, len = perm.length, tlen = len*m,
207247
frag = Fragment(),
208248
edge = dom.childNodes[start+tlen],
@@ -213,6 +253,92 @@ function permuteNodes(dom, start, perm, m)
213253
frag.appendChild(nodes[perm[i]*m+j]);
214254
if (edge) dom.insertBefore(frag, edge);
215255
else dom.appendChild(frag);
256+
/*
257+
// permute DOM tree using minimum DOM operations
258+
var rNodes = dom.childNodes, cNodes,
259+
rnode, rnodef, rnode2, left,
260+
i1, i2, i, j, x, z, pos,
261+
places, lis, needsReorder, loop = true;
262+
263+
i1 = 0; i2 = perm.length-1;
264+
rnode = rNodes[start+m*i1];
265+
rnodef = rNodes[start+m*i2];
266+
x = nextNode(rnodef, m, NEXT);
267+
268+
while (loop)
269+
{
270+
loop = false;
271+
// start
272+
while ((i1 <= i2) && (i1 === perm[i1]))
273+
{
274+
++i1;
275+
if (i1 > i2) {loop = false; break;}
276+
rnode = nextNode(rnode, m, NEXT);
277+
}
278+
// end
279+
while ((i1 <= i2) && (i2 === perm[i2]))
280+
{
281+
x = rnodef;
282+
--i2;
283+
if (i1 > i2) {loop = false; break;}
284+
rnodef = nextNode(rnodef, m, PREV);
285+
}
286+
// swap
287+
while ((i1 <= i2) && (i1 === perm[i2]) && (i2 === perm[i1]))
288+
{
289+
loop = true;
290+
rnode2 = nextNode(rnodef, m, PREV);
291+
moveNodes(dom, rnodef, m, rnode);
292+
rnodef = rnode2;
293+
rnode2 = nextNode(rnode, m, NEXT);
294+
moveNodes(dom, rnode, m, x);
295+
x = rnode;
296+
rnode = rnode2;
297+
++i1; --i2;
298+
if (i1 > i2) {loop = false; break;}
299+
}
300+
}
301+
302+
if (i1 <= i2)
303+
{
304+
left = i2-i1+1;
305+
places = new A32I(left);
306+
needsReorder = false;
307+
pos = 0;
308+
for (i=i1; i<=i2; ++i)
309+
{
310+
j = perm[i];
311+
places[j - i1] = i + 1;
312+
if (pos > j) needsReorder = true;
313+
else pos = j;
314+
}
315+
if (needsReorder)
316+
{
317+
// matched entries are not in increasing order
318+
// compute longest increasing subsequence
319+
lis = longest_incr_subseq(places); // O(n log n) !!
320+
j = lis.length - 1;
321+
cNodes = slice.call(rNodes, start+m*i1, start+m*i2+1); // store as immutable
322+
for (i=left-1; i>=0; --i)
323+
{
324+
pos = places[i];
325+
if ((0 > j) || (i !== lis[j]))
326+
{
327+
// move existing entry in correct place
328+
z = cNodes[m*(pos-1-i1)];
329+
moveNodes(dom, z, m, x);
330+
x = z;
331+
}
332+
else
333+
{
334+
// new place for entry
335+
x = cNodes[m*(pos-1-i1)];
336+
--j;
337+
}
338+
}
339+
}
340+
}
341+
*/
216342
}
217343
function flatten(array)
218344
{
@@ -2366,6 +2492,9 @@ function morphCollection(view, r, v, start, end, end2, startv, count, forced)
23662492
count = 0;
23672493
return count; // break from diff loop completely, this should be only diff
23682494
break;
2495+
case 'swap':
2496+
swapNodes(r, rNodes[start+d.from*m], rNodes[start+d.to*m], m);
2497+
break;
23692498
case 'add':
23702499
len = (d.to-d.from+1)*m;
23712500
items = collection.mapped(d.from, d.to);
@@ -2377,14 +2506,6 @@ function morphCollection(view, r, v, start, end, end2, startv, count, forced)
23772506
delNodes(view, r, start+d.from*m, len);
23782507
if (0 < count) count -= len;
23792508
break;
2380-
case 'swap':
2381-
i = slice.call(rNodes, start+d.from*m, start+d.from*m+m);
2382-
j = slice.call(rNodes, start+d.to*m, start+d.to*m+m);
2383-
k = j[j.length-1][NEXT];
2384-
for (l=0; l<m; ++l) r.replaceChild(j[l], i[l]);
2385-
if (k) for (l=0; l<m; ++l) r.insertBefore(i[l], k);
2386-
else for (l=0; l<m; ++l) r.appendChild(i[l]);
2387-
break;
23882509
case 'change':
23892510
len = (d.to-d.from+1)*m;
23902511
z = new Array(len);
@@ -3408,15 +3529,8 @@ function morphCollectionSimple(view, list, key, collection, isDirty, model, only
34083529
permute(list.map, d.from);
34093530
return;
34103531
case 'swap':
3411-
x = list.map[d.from];
3412-
list.map[d.from] = list.map[d.to];
3413-
list.map[d.to] = x;
3414-
i = slice.call(parentNode.childNodes, startIndex+1+d.from*m, startIndex+1+d.from*m+m);
3415-
j = slice.call(parentNode.childNodes, startIndex+1+d.to*m, startIndex+1+d.to*m+m);
3416-
k = j[j.length-1][NEXT];
3417-
for (l=0; l<m; ++l) parentNode.replaceChild(j[l], i[l]);
3418-
if (k) for (l=0; l<m; ++l) parentNode.insertBefore(i[l], k);
3419-
else for (l=0; l<m; ++l) parentNode.appendChild(i[l]);
3532+
swapNodes(parentNode, parentNode.childNodes[startIndex+1+d.from*m], parentNode.childNodes[startIndex+1+d.to*m], m);
3533+
swap(list.map, d.from, d.to);
34203534
break;
34213535
case 'del':
34223536
list.map.splice(d.from, d.to-d.from+1);
@@ -8001,6 +8115,7 @@ view.components( Object components );
80018115
out = c.out.call(component, data, children||[], htmlNode);
80028116
out.component = component;
80038117
out.changed = changed;
8118+
out.simple = false; // components are not simple nodes
80048119
return out;
80058120
}
80068121
}

build/modelview.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/collection-simple.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ <h1>ModelView.js Collection Simple Test</h1>
2525
<button mv-evt mv-on-click="splice_items">Splice Item 1</button>
2626
<button mv-evt mv-on-click="append_tag_item1">Append Tag Item 1</button>
2727
<button mv-evt mv-on-click="splice_tags_item1">Splice Tags Item 1</button>
28+
<button mv-evt mv-on-click="reverse">Reverse</button>
2829
<button mv-evt mv-on-click="reorder">Reorder</button>
2930
<button mv-evt mv-on-click="empty">Empty</button>
3031
<button mv-evt mv-on-click="notchanged">Not Changed</button>
@@ -73,10 +74,18 @@ <h1>ModelView.js Collection Simple Test</h1>
7374
splice_items: function() {
7475
this.model().del('items.1', true);
7576
},
76-
reorder: function() {
77+
reverse: function() {
7778
this.model().data().items.sort(function(a,b){return a.label<b.label ? 1 : (a.label>b.label ? -1 : 0);});
7879
this.model().notify('items');
7980
},
81+
reorder: function() {
82+
this.model().set('items', [
83+
{label: 'item2', tags: new ModelView.Model.Collection(['tag3', 'tag2'])},
84+
{label: 'item1', tags: new ModelView.Model.Collection(['tag1', 'tag2'])},
85+
{label: 'item4', tags: new ModelView.Model.Collection(['tag6', 'tag1'])},
86+
{label: 'item3', tags: new ModelView.Model.Collection(['tag4', 'tag5'])}
87+
], true);
88+
},
8089
empty: function() {
8190
this.model().set('items', [], true);
8291
},

examples/collection.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ <h1>ModelView.js Collection Test</h1>
3333
<button mv-evt mv-on-click="splice_items">Splice Item 1</button>
3434
<button mv-evt mv-on-click="append_tag_item1">Append Tag Item 1</button>
3535
<button mv-evt mv-on-click="splice_tags_item1">Splice Tags Item 1</button>
36+
<button mv-evt mv-on-click="reverse">Reverse</button>
3637
<button mv-evt mv-on-click="reorder">Reorder</button>
3738
<button mv-evt mv-on-click="empty">Empty</button>
3839
<button mv-evt mv-on-click="notchanged">Not Changed</button>
@@ -85,10 +86,18 @@ <h1>ModelView.js Collection Test</h1>
8586
splice_items: function() {
8687
this.model().del('items.1', true);
8788
},
88-
reorder: function() {
89+
reverse: function() {
8990
this.model().data().items.sort(function(a,b){return a.label<b.label ? 1 : (a.label>b.label ? -1 : 0);});
9091
this.model().notify('items');
9192
},
93+
reorder: function() {
94+
this.model().set('items', [
95+
{label: 'item2', tags: new ModelView.Model.Collection(['tag3', 'tag2'])},
96+
{label: 'item1', tags: new ModelView.Model.Collection(['tag1', 'tag2'])},
97+
{label: 'item4', tags: new ModelView.Model.Collection(['tag6', 'tag1'])},
98+
{label: 'item3', tags: new ModelView.Model.Collection(['tag4', 'tag5'])}
99+
], true);
100+
},
92101
empty: function() {
93102
this.model().set('items', [], true);
94103
},

examples/hello-world.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ <h1>ModelView.js Hello Earth!</h1>
2424
<button class="button" mv-evt mv-on-click=":hello_world">Hello World ({this.model.getVal('clicks')})</button>
2525
</script>
2626
<script id="InputControlComponent" type="text/x-template">
27-
The local component value "{this.model.getVal('mylocalvar')}" can be updated here: <input type="text" name=":model[mylocalvar]" size="5" value={this.model.getVal('mylocalvar')} />
27+
<span>The local component value "{this.model.getVal('mylocalvar')}" can be updated here: <input type="text" name=":model[mylocalvar]" size="5" value={this.model.getVal('mylocalvar')} /></span>
2828
</script>
2929
<script id="content" type="text/x-template">
3030
<b>Note:</b> Arbitrary JavaScript Expressions can be run inside &#123; and &#125; template placeholders

src/utils-jsx.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,9 @@ function morphCollection(view, r, v, start, end, end2, startv, count, forced)
17851785
count = 0;
17861786
return count; // break from diff loop completely, this should be only diff
17871787
break;
1788+
case 'swap':
1789+
swapNodes(r, rNodes[start+d.from*m], rNodes[start+d.to*m], m);
1790+
break;
17881791
case 'add':
17891792
len = (d.to-d.from+1)*m;
17901793
items = collection.mapped(d.from, d.to);
@@ -1796,14 +1799,6 @@ function morphCollection(view, r, v, start, end, end2, startv, count, forced)
17961799
delNodes(view, r, start+d.from*m, len);
17971800
if (0 < count) count -= len;
17981801
break;
1799-
case 'swap':
1800-
i = slice.call(rNodes, start+d.from*m, start+d.from*m+m);
1801-
j = slice.call(rNodes, start+d.to*m, start+d.to*m+m);
1802-
k = j[j.length-1][NEXT];
1803-
for (l=0; l<m; ++l) r.replaceChild(j[l], i[l]);
1804-
if (k) for (l=0; l<m; ++l) r.insertBefore(i[l], k);
1805-
else for (l=0; l<m; ++l) r.appendChild(i[l]);
1806-
break;
18071802
case 'change':
18081803
len = (d.to-d.from+1)*m;
18091804
z = new Array(len);

src/utils-simple.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -473,15 +473,8 @@ function morphCollectionSimple(view, list, key, collection, isDirty, model, only
473473
permute(list.map, d.from);
474474
return;
475475
case 'swap':
476-
x = list.map[d.from];
477-
list.map[d.from] = list.map[d.to];
478-
list.map[d.to] = x;
479-
i = slice.call(parentNode.childNodes, startIndex+1+d.from*m, startIndex+1+d.from*m+m);
480-
j = slice.call(parentNode.childNodes, startIndex+1+d.to*m, startIndex+1+d.to*m+m);
481-
k = j[j.length-1][NEXT];
482-
for (l=0; l<m; ++l) parentNode.replaceChild(j[l], i[l]);
483-
if (k) for (l=0; l<m; ++l) parentNode.insertBefore(i[l], k);
484-
else for (l=0; l<m; ++l) parentNode.appendChild(i[l]);
476+
swapNodes(parentNode, parentNode.childNodes[startIndex+1+d.from*m], parentNode.childNodes[startIndex+1+d.to*m], m);
477+
swap(list.map, d.from, d.to);
485478
break;
486479
case 'del':
487480
list.map.splice(d.from, d.to-d.from+1);

0 commit comments

Comments
 (0)