@@ -34,54 +34,54 @@ function upper_bound(low: number, high: number, key: (index: number) => number,
34
34
function init_hydrate ( target : NodeEx ) {
35
35
if ( target . hydrate_init ) return ;
36
36
target . hydrate_init = true ;
37
-
37
+
38
38
type NodeEx2 = NodeEx & { claim_order : number } ;
39
-
39
+
40
40
// We know that all children have claim_order values since the unclaimed have been detached
41
41
const children = target . childNodes as NodeListOf < NodeEx2 > ;
42
-
43
- /*
42
+
43
+ /*
44
44
* Reorder claimed children optimally.
45
45
* We can reorder claimed children optimally by finding the longest subsequence of
46
46
* nodes that are already claimed in order and only moving the rest. The longest
47
47
* subsequence subsequence of nodes that are claimed in order can be found by
48
48
* computing the longest increasing subsequence of .claim_order values.
49
- *
49
+ *
50
50
* This algorithm is optimal in generating the least amount of reorder operations
51
51
* possible.
52
- *
52
+ *
53
53
* Proof:
54
54
* We know that, given a set of reordering operations, the nodes that do not move
55
55
* always form an increasing subsequence, since they do not move among each other
56
56
* meaning that they must be already ordered among each other. Thus, the maximal
57
57
* set of nodes that do not move form a longest increasing subsequence.
58
58
*/
59
-
59
+
60
60
// Compute longest increasing subsequence
61
61
// m: subsequence length j => index k of smallest value that ends an increasing subsequence of length j
62
62
const m = new Int32Array ( children . length + 1 ) ;
63
63
// Predecessor indices + 1
64
64
const p = new Int32Array ( children . length ) ;
65
-
65
+
66
66
m [ 0 ] = - 1 ;
67
67
let longest = 0 ;
68
68
for ( let i = 0 ; i < children . length ; i ++ ) {
69
69
const current = children [ i ] . claim_order ;
70
70
// Find the largest subsequence length such that it ends in a value less than our current value
71
-
71
+
72
72
// upper_bound returns first greater value, so we subtract one
73
73
const seqLen = upper_bound ( 1 , longest + 1 , idx => children [ m [ idx ] ] . claim_order , current ) - 1 ;
74
-
74
+
75
75
p [ i ] = m [ seqLen ] + 1 ;
76
-
76
+
77
77
const newLen = seqLen + 1 ;
78
-
78
+
79
79
// We can guarantee that current is the smallest value. Otherwise, we would have generated a longer sequence.
80
80
m [ newLen ] = i ;
81
-
81
+
82
82
longest = Math . max ( newLen , longest ) ;
83
83
}
84
-
84
+
85
85
// The longest increasing subsequence of nodes (initially reversed)
86
86
const lis : NodeEx2 [ ] = [ ] ;
87
87
// The rest of the nodes, nodes that will be moved
@@ -98,10 +98,10 @@ function init_hydrate(target: NodeEx) {
98
98
toMove . push ( children [ last ] ) ;
99
99
}
100
100
lis . reverse ( ) ;
101
-
101
+
102
102
// We sort the nodes being moved to guarantee that their insertion order matches the claim order
103
103
toMove . sort ( ( a , b ) => a . claim_order - b . claim_order ) ;
104
-
104
+
105
105
// Finally, we move the nodes
106
106
for ( let i = 0 , j = 0 ; i < toMove . length ; i ++ ) {
107
107
while ( j < lis . length && toMove [ i ] . claim_order >= lis [ j ] . claim_order ) {
@@ -115,7 +115,7 @@ function init_hydrate(target: NodeEx) {
115
115
export function append ( target : NodeEx , node : NodeEx ) {
116
116
if ( is_hydrating ) {
117
117
init_hydrate ( target ) ;
118
-
118
+
119
119
if ( ( target . actual_end_child === undefined ) || ( ( target . actual_end_child !== null ) && ( target . actual_end_child . parentElement !== target ) ) ) {
120
120
target . actual_end_child = target . firstChild ;
121
121
}
@@ -132,7 +132,7 @@ export function append(target: NodeEx, node: NodeEx) {
132
132
export function insert ( target : NodeEx , node : NodeEx , anchor ?: NodeEx ) {
133
133
if ( is_hydrating && ! anchor ) {
134
134
append ( target , node ) ;
135
- } else if ( node . parentNode !== target || ( anchor && node . nextSibling !== anchor ) ) {
135
+ } else if ( node . parentNode !== target || node . nextSibling != anchor ) {
136
136
target . insertBefore ( node , anchor || null ) ;
137
137
}
138
138
}
@@ -309,12 +309,12 @@ function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (no
309
309
if ( nodes . claim_info === undefined ) {
310
310
nodes . claim_info = { last_index : 0 , total_claimed : 0 } ;
311
311
}
312
-
312
+
313
313
const resultNode = ( ( ) => {
314
314
// We first try to find an element after the previous one
315
315
for ( let i = nodes . claim_info . last_index ; i < nodes . length ; i ++ ) {
316
316
const node = nodes [ i ] ;
317
-
317
+
318
318
if ( predicate ( node ) ) {
319
319
processNode ( node ) ;
320
320
@@ -325,13 +325,13 @@ function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (no
325
325
return node ;
326
326
}
327
327
}
328
-
329
-
328
+
329
+
330
330
// Otherwise, we try to find one before
331
331
// We iterate in reverse so that we don't go too far back
332
332
for ( let i = nodes . claim_info . last_index - 1 ; i >= 0 ; i -- ) {
333
333
const node = nodes [ i ] ;
334
-
334
+
335
335
if ( predicate ( node ) ) {
336
336
processNode ( node ) ;
337
337
@@ -345,11 +345,11 @@ function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (no
345
345
return node ;
346
346
}
347
347
}
348
-
348
+
349
349
// If we can't find any matching node, we create a new one
350
350
return createNode ( ) ;
351
351
} ) ( ) ;
352
-
352
+
353
353
resultNode . claim_order = nodes . claim_info . total_claimed ;
354
354
nodes . claim_info . total_claimed += 1 ;
355
355
return resultNode ;
0 commit comments