clapton 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/app/helpers/clapton/clapton_helper.rb +16 -1
- data/lib/clapton/engine.rb +14 -10
- data/lib/clapton/javascripts/dist/client.js +31 -19
- data/lib/clapton/javascripts/dist/components-for-test.js +439 -0
- data/lib/clapton/javascripts/dist/components.js +356 -382
- data/lib/clapton/javascripts/node_modules/diff-dom/LICENSE.txt +165 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/README.md +224 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/TraceLogger.d.ts +28 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/apply.d.ts +4 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/fromVirtual.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/index.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/undo.d.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/helpers.d.ts +11 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/index.d.ts +10 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/types.d.ts +104 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/apply.d.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/diff.d.ts +22 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromDOM.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromString.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/helpers.d.ts +40 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/index.d.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/index.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.d.ts +136 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js +1996 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js +1991 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/index.html +62 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/package.json +54 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/rollup.config.mjs +67 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/TraceLogger.ts +143 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/apply.ts +227 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/fromVirtual.ts +83 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/index.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/undo.ts +90 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/helpers.ts +40 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/index.ts +121 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/types.ts +154 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/apply.ts +349 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/diff.ts +855 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromDOM.ts +74 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromString.ts +239 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/helpers.ts +461 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/index.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/index.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/tsconfig.json +103 -0
- data/lib/clapton/javascripts/rollup.config.mjs +17 -2
- data/lib/clapton/javascripts/src/actions/initialize-actions.ts +6 -3
- data/lib/clapton/javascripts/src/channel/clapton-channel.js +6 -3
- data/lib/clapton/javascripts/src/client.ts +15 -15
- data/lib/clapton/javascripts/src/components-for-test.ts +29 -0
- data/lib/clapton/javascripts/src/components.ts +4 -1
- data/lib/clapton/javascripts/src/dom/update-component.ts +3 -2
- data/lib/clapton/javascripts/src/inputs/initialize-inputs.ts +2 -2
- data/lib/clapton/test_helper/base.rb +1 -1
- data/lib/clapton/version.rb +1 -1
- metadata +49 -3
- data/lib/clapton/javascripts/src/dom/update-component.spec.ts +0 -32
@@ -0,0 +1,461 @@
|
|
1
|
+
import {
|
2
|
+
diffNodeType,
|
3
|
+
elementDiffNodeType,
|
4
|
+
elementNodeType,
|
5
|
+
nodeType,
|
6
|
+
subsetType,
|
7
|
+
textDiffNodeType,
|
8
|
+
textNodeType,
|
9
|
+
} from "../types"
|
10
|
+
import { Diff } from "../helpers"
|
11
|
+
const elementDescriptors = (el: diffNodeType) => {
|
12
|
+
const output = []
|
13
|
+
output.push(el.nodeName)
|
14
|
+
if (el.nodeName !== "#text" && el.nodeName !== "#comment") {
|
15
|
+
el = el as elementDiffNodeType
|
16
|
+
if (el.attributes) {
|
17
|
+
if (el.attributes["class"]) {
|
18
|
+
output.push(
|
19
|
+
`${el.nodeName}.${el.attributes["class"].replace(
|
20
|
+
/ /g,
|
21
|
+
".",
|
22
|
+
)}`,
|
23
|
+
)
|
24
|
+
}
|
25
|
+
if (el.attributes.id) {
|
26
|
+
output.push(`${el.nodeName}#${el.attributes.id}`)
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
return output
|
31
|
+
}
|
32
|
+
|
33
|
+
const findUniqueDescriptors = (li: diffNodeType[]) => {
|
34
|
+
const uniqueDescriptors = {}
|
35
|
+
const duplicateDescriptors = {}
|
36
|
+
|
37
|
+
li.forEach((node: nodeType) => {
|
38
|
+
elementDescriptors(node).forEach((descriptor) => {
|
39
|
+
const inUnique = descriptor in uniqueDescriptors
|
40
|
+
const inDupes = descriptor in duplicateDescriptors
|
41
|
+
if (!inUnique && !inDupes) {
|
42
|
+
uniqueDescriptors[descriptor] = true
|
43
|
+
} else if (inUnique) {
|
44
|
+
delete uniqueDescriptors[descriptor]
|
45
|
+
duplicateDescriptors[descriptor] = true
|
46
|
+
}
|
47
|
+
})
|
48
|
+
})
|
49
|
+
|
50
|
+
return uniqueDescriptors
|
51
|
+
}
|
52
|
+
|
53
|
+
export const uniqueInBoth = (l1: diffNodeType[], l2: diffNodeType[]) => {
|
54
|
+
const l1Unique = findUniqueDescriptors(l1)
|
55
|
+
const l2Unique = findUniqueDescriptors(l2)
|
56
|
+
const inBoth = {}
|
57
|
+
|
58
|
+
Object.keys(l1Unique).forEach((key) => {
|
59
|
+
if (l2Unique[key]) {
|
60
|
+
inBoth[key] = true
|
61
|
+
}
|
62
|
+
})
|
63
|
+
|
64
|
+
return inBoth
|
65
|
+
}
|
66
|
+
|
67
|
+
export const removeDone = (tree: elementDiffNodeType) => {
|
68
|
+
delete tree.outerDone
|
69
|
+
delete tree.innerDone
|
70
|
+
delete tree.valueDone
|
71
|
+
if (tree.childNodes) {
|
72
|
+
return tree.childNodes.every(removeDone)
|
73
|
+
} else {
|
74
|
+
return true
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
export const cleanNode = (diffNode: diffNodeType) => {
|
79
|
+
if (Object.prototype.hasOwnProperty.call(diffNode, "data")) {
|
80
|
+
const textNode: textNodeType = {
|
81
|
+
nodeName: diffNode.nodeName === "#text" ? "#text" : "#comment",
|
82
|
+
data: (diffNode as textDiffNodeType).data,
|
83
|
+
}
|
84
|
+
return textNode
|
85
|
+
} else {
|
86
|
+
const elementNode: elementNodeType = {
|
87
|
+
nodeName: diffNode.nodeName,
|
88
|
+
}
|
89
|
+
diffNode = diffNode as elementDiffNodeType
|
90
|
+
if (Object.prototype.hasOwnProperty.call(diffNode, "attributes")) {
|
91
|
+
elementNode.attributes = { ...diffNode.attributes }
|
92
|
+
}
|
93
|
+
if (Object.prototype.hasOwnProperty.call(diffNode, "checked")) {
|
94
|
+
elementNode.checked = diffNode.checked
|
95
|
+
}
|
96
|
+
if (Object.prototype.hasOwnProperty.call(diffNode, "value")) {
|
97
|
+
elementNode.value = diffNode.value
|
98
|
+
}
|
99
|
+
if (Object.prototype.hasOwnProperty.call(diffNode, "selected")) {
|
100
|
+
elementNode.selected = diffNode.selected
|
101
|
+
}
|
102
|
+
if (Object.prototype.hasOwnProperty.call(diffNode, "childNodes")) {
|
103
|
+
elementNode.childNodes = diffNode.childNodes.map((diffChildNode) =>
|
104
|
+
cleanNode(diffChildNode),
|
105
|
+
)
|
106
|
+
}
|
107
|
+
return elementNode
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
export const isEqual = (e1: diffNodeType, e2: diffNodeType) => {
|
112
|
+
if (
|
113
|
+
!["nodeName", "value", "checked", "selected", "data"].every(
|
114
|
+
(element) => {
|
115
|
+
if (e1[element] !== e2[element]) {
|
116
|
+
return false
|
117
|
+
}
|
118
|
+
return true
|
119
|
+
},
|
120
|
+
)
|
121
|
+
) {
|
122
|
+
return false
|
123
|
+
}
|
124
|
+
if (Object.prototype.hasOwnProperty.call(e1, "data")) {
|
125
|
+
// Comment or Text
|
126
|
+
return true
|
127
|
+
}
|
128
|
+
e1 = e1 as elementDiffNodeType
|
129
|
+
e2 = e2 as elementDiffNodeType
|
130
|
+
if (Boolean(e1.attributes) !== Boolean(e2.attributes)) {
|
131
|
+
return false
|
132
|
+
}
|
133
|
+
|
134
|
+
if (Boolean(e1.childNodes) !== Boolean(e2.childNodes)) {
|
135
|
+
return false
|
136
|
+
}
|
137
|
+
if (e1.attributes) {
|
138
|
+
const e1Attributes = Object.keys(e1.attributes)
|
139
|
+
const e2Attributes = Object.keys(e2.attributes)
|
140
|
+
|
141
|
+
if (e1Attributes.length !== e2Attributes.length) {
|
142
|
+
return false
|
143
|
+
}
|
144
|
+
if (
|
145
|
+
!e1Attributes.every((attribute) => {
|
146
|
+
if (
|
147
|
+
(e1 as elementDiffNodeType).attributes[attribute] !==
|
148
|
+
(e2 as elementDiffNodeType).attributes[attribute]
|
149
|
+
) {
|
150
|
+
return false
|
151
|
+
}
|
152
|
+
return true
|
153
|
+
})
|
154
|
+
) {
|
155
|
+
return false
|
156
|
+
}
|
157
|
+
}
|
158
|
+
if (e1.childNodes) {
|
159
|
+
if (e1.childNodes.length !== e2.childNodes.length) {
|
160
|
+
return false
|
161
|
+
}
|
162
|
+
if (
|
163
|
+
!e1.childNodes.every((childNode: nodeType, index: number) =>
|
164
|
+
isEqual(childNode, e2.childNodes[index]),
|
165
|
+
)
|
166
|
+
) {
|
167
|
+
return false
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
return true
|
172
|
+
}
|
173
|
+
|
174
|
+
export const roughlyEqual = (
|
175
|
+
e1: diffNodeType,
|
176
|
+
e2: diffNodeType,
|
177
|
+
uniqueDescriptors: { [key: string]: boolean },
|
178
|
+
sameSiblings: boolean,
|
179
|
+
preventRecursion = false,
|
180
|
+
) => {
|
181
|
+
if (!e1 || !e2) {
|
182
|
+
return false
|
183
|
+
}
|
184
|
+
|
185
|
+
if (e1.nodeName !== e2.nodeName) {
|
186
|
+
return false
|
187
|
+
}
|
188
|
+
|
189
|
+
if (["#text", "#comment"].includes(e1.nodeName)) {
|
190
|
+
// Note that we initially don't care what the text content of a node is,
|
191
|
+
// the mere fact that it's the same tag and "has text" means it's roughly
|
192
|
+
// equal, and then we can find out the true text difference later.
|
193
|
+
return preventRecursion
|
194
|
+
? true
|
195
|
+
: (e1 as textDiffNodeType).data === (e2 as textDiffNodeType).data
|
196
|
+
}
|
197
|
+
|
198
|
+
e1 = e1 as elementDiffNodeType
|
199
|
+
e2 = e2 as elementDiffNodeType
|
200
|
+
|
201
|
+
if (e1.nodeName in uniqueDescriptors) {
|
202
|
+
return true
|
203
|
+
}
|
204
|
+
|
205
|
+
if (e1.attributes && e2.attributes) {
|
206
|
+
if (e1.attributes.id) {
|
207
|
+
if (e1.attributes.id !== e2.attributes.id) {
|
208
|
+
return false
|
209
|
+
} else {
|
210
|
+
const idDescriptor = `${e1.nodeName}#${e1.attributes.id}`
|
211
|
+
if (idDescriptor in uniqueDescriptors) {
|
212
|
+
return true
|
213
|
+
}
|
214
|
+
}
|
215
|
+
}
|
216
|
+
if (
|
217
|
+
e1.attributes["class"] &&
|
218
|
+
e1.attributes["class"] === e2.attributes["class"]
|
219
|
+
) {
|
220
|
+
const classDescriptor = `${e1.nodeName}.${e1.attributes[
|
221
|
+
"class"
|
222
|
+
].replace(/ /g, ".")}`
|
223
|
+
if (classDescriptor in uniqueDescriptors) {
|
224
|
+
return true
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
if (sameSiblings) {
|
230
|
+
return true
|
231
|
+
}
|
232
|
+
|
233
|
+
const nodeList1 = e1.childNodes ? e1.childNodes.slice().reverse() : []
|
234
|
+
const nodeList2 = e2.childNodes ? e2.childNodes.slice().reverse() : []
|
235
|
+
|
236
|
+
if (nodeList1.length !== nodeList2.length) {
|
237
|
+
return false
|
238
|
+
}
|
239
|
+
|
240
|
+
if (preventRecursion) {
|
241
|
+
return nodeList1.every(
|
242
|
+
(element: nodeType, index: number) =>
|
243
|
+
element.nodeName === nodeList2[index].nodeName,
|
244
|
+
)
|
245
|
+
} else {
|
246
|
+
// note: we only allow one level of recursion at any depth. If 'preventRecursion'
|
247
|
+
// was not set, we must explicitly force it to true for child iterations.
|
248
|
+
const childUniqueDescriptors = uniqueInBoth(nodeList1, nodeList2)
|
249
|
+
return nodeList1.every((element: nodeType, index: number) =>
|
250
|
+
roughlyEqual(
|
251
|
+
element,
|
252
|
+
nodeList2[index],
|
253
|
+
childUniqueDescriptors,
|
254
|
+
true,
|
255
|
+
true,
|
256
|
+
),
|
257
|
+
)
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
/**
|
262
|
+
* based on https://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Longest_common_substring#JavaScript
|
263
|
+
*/
|
264
|
+
const findCommonSubsets = (
|
265
|
+
c1: diffNodeType[],
|
266
|
+
c2: diffNodeType[],
|
267
|
+
marked1: boolean[],
|
268
|
+
marked2: boolean[],
|
269
|
+
) => {
|
270
|
+
let lcsSize = 0
|
271
|
+
let index: number[] = []
|
272
|
+
const c1Length = c1.length
|
273
|
+
const c2Length = c2.length
|
274
|
+
|
275
|
+
const // set up the matching table
|
276
|
+
matches = [...new Array(c1Length + 1)].map(() => [])
|
277
|
+
|
278
|
+
const uniqueDescriptors = uniqueInBoth(c1, c2)
|
279
|
+
|
280
|
+
let // If all of the elements are the same tag, id and class, then we can
|
281
|
+
// consider them roughly the same even if they have a different number of
|
282
|
+
// children. This will reduce removing and re-adding similar elements.
|
283
|
+
subsetsSame = c1Length === c2Length
|
284
|
+
|
285
|
+
if (subsetsSame) {
|
286
|
+
c1.some((element: nodeType, i: number) => {
|
287
|
+
const c1Desc = elementDescriptors(element)
|
288
|
+
const c2Desc = elementDescriptors(c2[i])
|
289
|
+
if (c1Desc.length !== c2Desc.length) {
|
290
|
+
subsetsSame = false
|
291
|
+
return true
|
292
|
+
}
|
293
|
+
c1Desc.some((description, i) => {
|
294
|
+
if (description !== c2Desc[i]) {
|
295
|
+
subsetsSame = false
|
296
|
+
return true
|
297
|
+
}
|
298
|
+
})
|
299
|
+
if (!subsetsSame) {
|
300
|
+
return true
|
301
|
+
}
|
302
|
+
})
|
303
|
+
}
|
304
|
+
|
305
|
+
// fill the matches with distance values
|
306
|
+
for (let c1Index = 0; c1Index < c1Length; c1Index++) {
|
307
|
+
const c1Element = c1[c1Index]
|
308
|
+
for (let c2Index = 0; c2Index < c2Length; c2Index++) {
|
309
|
+
const c2Element = c2[c2Index]
|
310
|
+
if (
|
311
|
+
!marked1[c1Index] &&
|
312
|
+
!marked2[c2Index] &&
|
313
|
+
roughlyEqual(
|
314
|
+
c1Element,
|
315
|
+
c2Element,
|
316
|
+
uniqueDescriptors,
|
317
|
+
subsetsSame,
|
318
|
+
)
|
319
|
+
) {
|
320
|
+
matches[c1Index + 1][c2Index + 1] = matches[c1Index][c2Index]
|
321
|
+
? matches[c1Index][c2Index] + 1
|
322
|
+
: 1
|
323
|
+
if (matches[c1Index + 1][c2Index + 1] >= lcsSize) {
|
324
|
+
lcsSize = matches[c1Index + 1][c2Index + 1]
|
325
|
+
index = [c1Index + 1, c2Index + 1]
|
326
|
+
}
|
327
|
+
} else {
|
328
|
+
matches[c1Index + 1][c2Index + 1] = 0
|
329
|
+
}
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
if (lcsSize === 0) {
|
334
|
+
return false
|
335
|
+
}
|
336
|
+
|
337
|
+
return {
|
338
|
+
oldValue: index[0] - lcsSize,
|
339
|
+
newValue: index[1] - lcsSize,
|
340
|
+
length: lcsSize,
|
341
|
+
}
|
342
|
+
}
|
343
|
+
|
344
|
+
const makeBooleanArray = (n: number, v: boolean) =>
|
345
|
+
[...new Array(n)].map(() => v)
|
346
|
+
|
347
|
+
/**
|
348
|
+
* Generate arrays that indicate which node belongs to which subset,
|
349
|
+
* or whether it's actually an orphan node, existing in only one
|
350
|
+
* of the two trees, rather than somewhere in both.
|
351
|
+
*
|
352
|
+
* So if t1 = <img><canvas><br>, t2 = <canvas><br><img>.
|
353
|
+
* The longest subset is "<canvas><br>" (length 2), so it will group 0.
|
354
|
+
* The second longest is "<img>" (length 1), so it will be group 1.
|
355
|
+
* gaps1 will therefore be [1,0,0] and gaps2 [0,0,1].
|
356
|
+
*
|
357
|
+
* If an element is not part of any group, it will stay being 'true', which
|
358
|
+
* is the initial value. For example:
|
359
|
+
* t1 = <img><p></p><br><canvas>, t2 = <b></b><br><canvas><img>
|
360
|
+
*
|
361
|
+
* The "<p></p>" and "<b></b>" do only show up in one of the two and will
|
362
|
+
* therefore be marked by "true". The remaining parts are parts of the
|
363
|
+
* groups 0 and 1:
|
364
|
+
* gaps1 = [1, true, 0, 0], gaps2 = [true, 0, 0, 1]
|
365
|
+
*
|
366
|
+
*/
|
367
|
+
export const getGapInformation = (
|
368
|
+
t1: elementDiffNodeType,
|
369
|
+
t2: elementDiffNodeType,
|
370
|
+
stable: subsetType[],
|
371
|
+
) => {
|
372
|
+
const gaps1: (true | number)[] = t1.childNodes
|
373
|
+
? (makeBooleanArray(t1.childNodes.length, true) as true[])
|
374
|
+
: []
|
375
|
+
const gaps2: (true | number)[] = t2.childNodes
|
376
|
+
? (makeBooleanArray(t2.childNodes.length, true) as true[])
|
377
|
+
: []
|
378
|
+
let group = 0
|
379
|
+
|
380
|
+
// give elements from the same subset the same group number
|
381
|
+
stable.forEach((subset: subsetType) => {
|
382
|
+
const endOld = subset.oldValue + subset.length
|
383
|
+
const endNew = subset.newValue + subset.length
|
384
|
+
|
385
|
+
for (let j = subset.oldValue; j < endOld; j += 1) {
|
386
|
+
gaps1[j] = group
|
387
|
+
}
|
388
|
+
for (let j = subset.newValue; j < endNew; j += 1) {
|
389
|
+
gaps2[j] = group
|
390
|
+
}
|
391
|
+
group += 1
|
392
|
+
})
|
393
|
+
|
394
|
+
return {
|
395
|
+
gaps1,
|
396
|
+
gaps2,
|
397
|
+
}
|
398
|
+
}
|
399
|
+
|
400
|
+
/**
|
401
|
+
* Find all matching subsets, based on immediate child differences only.
|
402
|
+
*/
|
403
|
+
const markBoth = (marked1, marked2, subset: subsetType, i: number) => {
|
404
|
+
marked1[subset.oldValue + i] = true
|
405
|
+
marked2[subset.newValue + i] = true
|
406
|
+
}
|
407
|
+
|
408
|
+
export const markSubTrees = (
|
409
|
+
oldTree: elementDiffNodeType,
|
410
|
+
newTree: elementDiffNodeType,
|
411
|
+
) => {
|
412
|
+
// note: the child lists are views, and so update as we update old/newTree
|
413
|
+
const oldChildren = oldTree.childNodes ? oldTree.childNodes : []
|
414
|
+
|
415
|
+
const newChildren = newTree.childNodes ? newTree.childNodes : []
|
416
|
+
const marked1 = makeBooleanArray(oldChildren.length, false)
|
417
|
+
const marked2 = makeBooleanArray(newChildren.length, false)
|
418
|
+
const subsets = []
|
419
|
+
|
420
|
+
const returnIndex = function () {
|
421
|
+
return arguments[1]
|
422
|
+
}
|
423
|
+
|
424
|
+
let foundAllSubsets = false
|
425
|
+
|
426
|
+
while (!foundAllSubsets) {
|
427
|
+
const subset = findCommonSubsets(
|
428
|
+
oldChildren,
|
429
|
+
newChildren,
|
430
|
+
marked1,
|
431
|
+
marked2,
|
432
|
+
)
|
433
|
+
if (subset) {
|
434
|
+
subsets.push(subset)
|
435
|
+
const subsetArray = [...new Array(subset.length)].map(returnIndex)
|
436
|
+
subsetArray.forEach((item) =>
|
437
|
+
markBoth(marked1, marked2, subset, item),
|
438
|
+
)
|
439
|
+
} else {
|
440
|
+
foundAllSubsets = true
|
441
|
+
}
|
442
|
+
}
|
443
|
+
|
444
|
+
oldTree.subsets = subsets
|
445
|
+
oldTree.subsetsAge = 100
|
446
|
+
return subsets
|
447
|
+
}
|
448
|
+
|
449
|
+
export class DiffTracker {
|
450
|
+
list: Diff[]
|
451
|
+
constructor() {
|
452
|
+
this.list = []
|
453
|
+
}
|
454
|
+
|
455
|
+
add(diffs: Diff[]) {
|
456
|
+
this.list.push(...diffs)
|
457
|
+
}
|
458
|
+
forEach(fn: (Diff) => void) {
|
459
|
+
this.list.forEach((li: Diff) => fn(li))
|
460
|
+
}
|
461
|
+
}
|
@@ -0,0 +1,103 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
/* Visit https://aka.ms/tsconfig to read more about this file */
|
4
|
+
|
5
|
+
/* Projects */
|
6
|
+
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
7
|
+
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
8
|
+
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
9
|
+
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
10
|
+
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
11
|
+
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
12
|
+
|
13
|
+
/* Language and Environment */
|
14
|
+
//"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
15
|
+
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
16
|
+
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
17
|
+
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
18
|
+
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
19
|
+
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
20
|
+
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
21
|
+
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
22
|
+
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
23
|
+
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
24
|
+
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
25
|
+
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
26
|
+
|
27
|
+
/* Modules */
|
28
|
+
//"module": "commonjs", /* Specify what module code is generated. */
|
29
|
+
// "rootDir": "./", /* Specify the root folder within your source files. */
|
30
|
+
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
31
|
+
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
32
|
+
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
33
|
+
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
34
|
+
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
35
|
+
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
36
|
+
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
37
|
+
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
38
|
+
// "resolveJsonModule": true, /* Enable importing .json files. */
|
39
|
+
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
40
|
+
|
41
|
+
/* JavaScript Support */
|
42
|
+
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
43
|
+
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
44
|
+
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
45
|
+
|
46
|
+
/* Emit */
|
47
|
+
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
48
|
+
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
49
|
+
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
50
|
+
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
51
|
+
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
52
|
+
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
53
|
+
// "removeComments": true, /* Disable emitting comments. */
|
54
|
+
// "noEmit": true, /* Disable emitting files from a compilation. */
|
55
|
+
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
56
|
+
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
57
|
+
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
58
|
+
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
59
|
+
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
60
|
+
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
61
|
+
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
62
|
+
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
63
|
+
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
64
|
+
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
65
|
+
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
66
|
+
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
67
|
+
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
68
|
+
"declarationDir": "dts", /* Specify the output directory for generated declaration files. */
|
69
|
+
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
70
|
+
|
71
|
+
/* Interop Constraints */
|
72
|
+
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
73
|
+
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
74
|
+
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
75
|
+
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
76
|
+
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
77
|
+
|
78
|
+
/* Type Checking */
|
79
|
+
//"strict": true, /* Enable all strict type-checking options. */
|
80
|
+
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
81
|
+
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
82
|
+
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
83
|
+
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
84
|
+
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
85
|
+
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
86
|
+
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
87
|
+
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
88
|
+
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
89
|
+
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
90
|
+
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
91
|
+
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
92
|
+
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
93
|
+
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
94
|
+
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
95
|
+
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
96
|
+
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
97
|
+
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
98
|
+
|
99
|
+
/* Completeness */
|
100
|
+
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
101
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
102
|
+
}
|
103
|
+
}
|
@@ -7,8 +7,23 @@ export default [
|
|
7
7
|
input: 'src/components.ts',
|
8
8
|
output: {
|
9
9
|
file: 'dist/components.js',
|
10
|
-
format: '
|
11
|
-
|
10
|
+
format: 'esm'
|
11
|
+
},
|
12
|
+
plugins: [
|
13
|
+
resolve(),
|
14
|
+
commonjs(),
|
15
|
+
typescript({
|
16
|
+
tsconfig: './tsconfig.json',
|
17
|
+
sourceMap: false
|
18
|
+
})
|
19
|
+
]
|
20
|
+
},
|
21
|
+
{
|
22
|
+
input: 'src/components-for-test.ts',
|
23
|
+
output: {
|
24
|
+
file: 'dist/components-for-test.js',
|
25
|
+
format: "iife",
|
26
|
+
name: "Clapton"
|
12
27
|
},
|
13
28
|
plugins: [
|
14
29
|
resolve(),
|
@@ -15,9 +15,12 @@ const initializeActionsForElement = (element: HTMLElement) => {
|
|
15
15
|
if (!eventType || !componentName || !fnName) return;
|
16
16
|
|
17
17
|
if (eventType === "render") {
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
const interval = setInterval(() => {
|
19
|
+
if ((window as any).actionCableConnected === true) {
|
20
|
+
handleAction(element, stateName, fnName);
|
21
|
+
clearInterval(interval);
|
22
|
+
}
|
23
|
+
}, 10);
|
21
24
|
element.setAttribute("data-render-event-handler", "true");
|
22
25
|
return;
|
23
26
|
}
|
@@ -5,14 +5,17 @@ import { initializeInputs } from "../inputs/initialize-inputs.ts"
|
|
5
5
|
const consumer = createConsumer()
|
6
6
|
|
7
7
|
export const claptonChannel = consumer.subscriptions.create("Clapton::ClaptonChannel", {
|
8
|
-
connected() {
|
8
|
+
connected() {
|
9
|
+
window.actionCableConnected = true;
|
10
|
+
},
|
9
11
|
|
10
12
|
disconnected() {},
|
11
13
|
|
12
|
-
received(response) {
|
14
|
+
async received(response) {
|
13
15
|
const { data, errors } = response;
|
14
16
|
const component = document.querySelector(`[data-id="${data.component.id}"]`)
|
15
|
-
const
|
17
|
+
const module = await import(`${data.component.name}`);
|
18
|
+
const instance = new module[data.component.name](data.state, data.component.id, errors);
|
16
19
|
morphdom(component, instance.render, {
|
17
20
|
onBeforeElUpdated: (_fromEl, toEl) => {
|
18
21
|
toEl.setAttribute("data-set-event-handler", "true");
|