clapton 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConstNames,
|
|
3
|
+
ConstNamesPartial,
|
|
4
|
+
DiffDOMOptions,
|
|
5
|
+
DiffDOMOptionsPartial,
|
|
6
|
+
diffType,
|
|
7
|
+
elementNodeType,
|
|
8
|
+
textNodeType,
|
|
9
|
+
} from "./types"
|
|
10
|
+
import { applyDOM, undoDOM } from "./dom/index"
|
|
11
|
+
import { Diff } from "./helpers"
|
|
12
|
+
import { DiffFinder } from "./virtual/index"
|
|
13
|
+
export { nodeToObj, stringToObj } from "./virtual/index"
|
|
14
|
+
|
|
15
|
+
const DEFAULT_OPTIONS = {
|
|
16
|
+
debug: false,
|
|
17
|
+
diffcap: 10, // Limit for how many diffs are accepting when debugging. Inactive when debug is false.
|
|
18
|
+
maxDepth: false, // False or a numeral. If set to a numeral, limits the level of depth that the the diff mechanism looks for differences. If false, goes through the entire tree.
|
|
19
|
+
maxChildCount: 50, // False or a numeral. If set to a numeral, only does a simplified form of diffing of contents so that the number of diffs cannot be higher than the number of child nodes.
|
|
20
|
+
valueDiffing: true, // Whether to take into consideration the values of forms that differ from auto assigned values (when a user fills out a form).
|
|
21
|
+
// syntax: textDiff: function (node, currentValue, expectedValue, newValue)
|
|
22
|
+
textDiff(
|
|
23
|
+
node: textNodeType,
|
|
24
|
+
currentValue: string,
|
|
25
|
+
expectedValue: string,
|
|
26
|
+
newValue: string,
|
|
27
|
+
) {
|
|
28
|
+
node.data = newValue
|
|
29
|
+
return
|
|
30
|
+
},
|
|
31
|
+
// empty functions were benchmarked as running faster than both
|
|
32
|
+
// `f && f()` and `if (f) { f(); }`
|
|
33
|
+
preVirtualDiffApply() {}, // eslint-disable-line @typescript-eslint/no-empty-function
|
|
34
|
+
postVirtualDiffApply() {}, // eslint-disable-line @typescript-eslint/no-empty-function
|
|
35
|
+
preDiffApply() {}, // eslint-disable-line @typescript-eslint/no-empty-function
|
|
36
|
+
postDiffApply() {}, // eslint-disable-line @typescript-eslint/no-empty-function
|
|
37
|
+
filterOuterDiff: null,
|
|
38
|
+
compress: false, // Whether to work with compressed diffs
|
|
39
|
+
_const: false, // object with strings for every change types to be used in diffs.
|
|
40
|
+
document:
|
|
41
|
+
typeof window !== "undefined" && window.document
|
|
42
|
+
? window.document
|
|
43
|
+
: false,
|
|
44
|
+
components: [], // list of components used for converting from string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class DiffDOM {
|
|
48
|
+
options: DiffDOMOptions
|
|
49
|
+
constructor(options: DiffDOMOptionsPartial = {}) {
|
|
50
|
+
// IE11 doesn't have Object.assign and buble doesn't translate object spreaders
|
|
51
|
+
// by default, so this is the safest way of doing it currently.
|
|
52
|
+
Object.entries(DEFAULT_OPTIONS).forEach(([key, value]) => {
|
|
53
|
+
if (!Object.prototype.hasOwnProperty.call(options, key)) {
|
|
54
|
+
options[key] = value
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if (!options._const) {
|
|
59
|
+
const varNames = [
|
|
60
|
+
"addAttribute",
|
|
61
|
+
"modifyAttribute",
|
|
62
|
+
"removeAttribute",
|
|
63
|
+
"modifyTextElement",
|
|
64
|
+
"relocateGroup",
|
|
65
|
+
"removeElement",
|
|
66
|
+
"addElement",
|
|
67
|
+
"removeTextElement",
|
|
68
|
+
"addTextElement",
|
|
69
|
+
"replaceElement",
|
|
70
|
+
"modifyValue",
|
|
71
|
+
"modifyChecked",
|
|
72
|
+
"modifySelected",
|
|
73
|
+
"modifyComment",
|
|
74
|
+
"action",
|
|
75
|
+
"route",
|
|
76
|
+
"oldValue",
|
|
77
|
+
"newValue",
|
|
78
|
+
"element",
|
|
79
|
+
"group",
|
|
80
|
+
"groupLength",
|
|
81
|
+
"from",
|
|
82
|
+
"to",
|
|
83
|
+
"name",
|
|
84
|
+
"value",
|
|
85
|
+
"data",
|
|
86
|
+
"attributes",
|
|
87
|
+
"nodeName",
|
|
88
|
+
"childNodes",
|
|
89
|
+
"checked",
|
|
90
|
+
"selected",
|
|
91
|
+
]
|
|
92
|
+
const constNames: ConstNamesPartial = {}
|
|
93
|
+
if (options.compress) {
|
|
94
|
+
varNames.forEach(
|
|
95
|
+
(varName, index) => (constNames[varName] = index),
|
|
96
|
+
)
|
|
97
|
+
} else {
|
|
98
|
+
varNames.forEach((varName) => (constNames[varName] = varName))
|
|
99
|
+
}
|
|
100
|
+
options._const = constNames as ConstNames
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.options = options as DiffDOMOptions
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
apply(tree: Element, diffs: (Diff | diffType)[]) {
|
|
107
|
+
return applyDOM(tree, diffs, this.options)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
undo(tree: Element, diffs: (Diff | diffType)[]) {
|
|
111
|
+
return undoDOM(tree, diffs, this.options)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
diff(
|
|
115
|
+
t1Node: string | elementNodeType | Element,
|
|
116
|
+
t2Node: string | elementNodeType | Element,
|
|
117
|
+
) {
|
|
118
|
+
const finder = new DiffFinder(t1Node, t2Node, this.options)
|
|
119
|
+
return finder.init()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Diff } from "./helpers"
|
|
2
|
+
|
|
3
|
+
interface subsetType {
|
|
4
|
+
oldValue: number
|
|
5
|
+
newValue: number
|
|
6
|
+
length: number
|
|
7
|
+
delete?: true
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface elementNodeType {
|
|
11
|
+
nodeName: string
|
|
12
|
+
attributes?: { [key: string]: string }
|
|
13
|
+
childNodes?: nodeType[] // eslint-disable-line no-use-before-define
|
|
14
|
+
checked?: boolean
|
|
15
|
+
value?: string | number
|
|
16
|
+
selected?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface textNodeType {
|
|
20
|
+
nodeName: "#text" | "#comment"
|
|
21
|
+
data: string
|
|
22
|
+
childNodes?: never
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type nodeType = elementNodeType | textNodeType
|
|
26
|
+
|
|
27
|
+
interface elementDiffNodeType extends elementNodeType {
|
|
28
|
+
childNodes?: diffNodeType[] // eslint-disable-line no-use-before-define
|
|
29
|
+
// The following are only used during diffing.
|
|
30
|
+
subsets?: subsetType[]
|
|
31
|
+
subsetsAge?: number
|
|
32
|
+
outerDone?: boolean
|
|
33
|
+
innerDone?: boolean
|
|
34
|
+
valueDone?: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface textDiffNodeType extends textNodeType {
|
|
38
|
+
// The following are only used during diffing.
|
|
39
|
+
outerDone?: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type diffNodeType = elementDiffNodeType | textDiffNodeType
|
|
43
|
+
|
|
44
|
+
interface Document {
|
|
45
|
+
createElement: (arg: string) => Element
|
|
46
|
+
createElementNS: (namespaceURI: string, qualifiedName: string) => Element
|
|
47
|
+
createTextNode: (arg: string) => Text
|
|
48
|
+
createComment: (arg: string) => Comment
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
52
|
+
interface PreDiffApplyOptions {
|
|
53
|
+
diff: Diff
|
|
54
|
+
node: nodeType
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type PreDiffApply = (PreDiffApplyOptions) => boolean
|
|
58
|
+
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
60
|
+
interface PostDiffApplyOptions {
|
|
61
|
+
diff: Diff
|
|
62
|
+
node: nodeType
|
|
63
|
+
newNode: nodeType
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type PostDiffApply = (PostDiffApplyOptions) => void
|
|
67
|
+
|
|
68
|
+
interface ConstNames {
|
|
69
|
+
addAttribute: string | number
|
|
70
|
+
modifyAttribute: string | number
|
|
71
|
+
removeAttribute: string | number
|
|
72
|
+
modifyTextElement: string | number
|
|
73
|
+
relocateGroup: string | number
|
|
74
|
+
removeElement: string | number
|
|
75
|
+
addElement: string | number
|
|
76
|
+
removeTextElement: string | number
|
|
77
|
+
addTextElement: string | number
|
|
78
|
+
replaceElement: string | number
|
|
79
|
+
modifyValue: string | number
|
|
80
|
+
modifyChecked: string | number
|
|
81
|
+
modifySelected: string | number
|
|
82
|
+
modifyComment: string | number
|
|
83
|
+
action: string | number
|
|
84
|
+
route: string | number
|
|
85
|
+
oldValue: string | number
|
|
86
|
+
newValue: string | number
|
|
87
|
+
element: string | number
|
|
88
|
+
group: string | number
|
|
89
|
+
groupLength: string | number
|
|
90
|
+
from: string | number
|
|
91
|
+
to: string | number
|
|
92
|
+
name: string | number
|
|
93
|
+
value: string | number
|
|
94
|
+
data: string | number
|
|
95
|
+
attributes: string | number
|
|
96
|
+
nodeName: string | number
|
|
97
|
+
childNodes: string | number
|
|
98
|
+
checked: string | number
|
|
99
|
+
selected: string | number
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface DiffDOMOptions {
|
|
103
|
+
debug: boolean
|
|
104
|
+
diffcap: number // Limit for how many diffs are accepting when debugging. Inactive when debug is false.
|
|
105
|
+
maxDepth: number | false // False or a numeral. If set to a numeral, limits the level of depth that the the diff mechanism looks for differences. If false, goes through the entire tree.
|
|
106
|
+
maxChildCount: number // False or a numeral. If set to a numeral, only does a simplified form of diffing of contents so that the number of diffs cannot be higher than the number of child nodes.
|
|
107
|
+
valueDiffing: boolean // Whether to take into consideration the values of forms that differ from auto assigned values (when a user fills out a form).
|
|
108
|
+
caseSensitive: boolean // Whether to preserve the case of an input string. Important when including CML (XHTML, SVG, etc.)
|
|
109
|
+
// syntax: textDiff: function (node, currentValue, expectedValue, newValue)
|
|
110
|
+
textDiff: (
|
|
111
|
+
node: textNodeType | Text | Comment,
|
|
112
|
+
currentValue: string,
|
|
113
|
+
expectedValue: string,
|
|
114
|
+
newValue: string,
|
|
115
|
+
) => void
|
|
116
|
+
preVirtualDiffApply: PreDiffApply
|
|
117
|
+
postVirtualDiffApply: PostDiffApply
|
|
118
|
+
preDiffApply: PreDiffApply
|
|
119
|
+
postDiffApply: PostDiffApply
|
|
120
|
+
filterOuterDiff: null | ((t1, t2, diffs: Diff[]) => void | Diff[])
|
|
121
|
+
compress: boolean // Whether to work with compressed diffs
|
|
122
|
+
_const: ConstNames // object with strings for every change types to be used in diffs.
|
|
123
|
+
document: Document
|
|
124
|
+
components: string[]
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
type DiffDOMOptionsPartial = Partial<DiffDOMOptions>
|
|
128
|
+
|
|
129
|
+
type ConstNamesPartial = Partial<ConstNames>
|
|
130
|
+
|
|
131
|
+
type diffType = {
|
|
132
|
+
[key: string | number]:
|
|
133
|
+
| string
|
|
134
|
+
| number
|
|
135
|
+
| boolean
|
|
136
|
+
| number[]
|
|
137
|
+
| { [key: string]: string | { [key: string]: string } }
|
|
138
|
+
| elementNodeType
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
nodeType,
|
|
143
|
+
ConstNames,
|
|
144
|
+
ConstNamesPartial,
|
|
145
|
+
DiffDOMOptions,
|
|
146
|
+
DiffDOMOptionsPartial,
|
|
147
|
+
diffType,
|
|
148
|
+
diffNodeType,
|
|
149
|
+
elementDiffNodeType,
|
|
150
|
+
elementNodeType,
|
|
151
|
+
subsetType,
|
|
152
|
+
textDiffNodeType,
|
|
153
|
+
textNodeType,
|
|
154
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { DiffDOMOptions, elementNodeType, nodeType, subsetType } from "../types"
|
|
2
|
+
import { Diff } from "../helpers"
|
|
3
|
+
import { cleanNode } from "./helpers"
|
|
4
|
+
// ===== Apply a virtual diff =====
|
|
5
|
+
|
|
6
|
+
function getFromVirtualRoute(tree: elementNodeType, route: number[]) {
|
|
7
|
+
let node = tree
|
|
8
|
+
let parentNode
|
|
9
|
+
let nodeIndex
|
|
10
|
+
|
|
11
|
+
route = route.slice()
|
|
12
|
+
while (route.length > 0) {
|
|
13
|
+
nodeIndex = route.splice(0, 1)[0]
|
|
14
|
+
parentNode = node
|
|
15
|
+
node = node.childNodes ? node.childNodes[nodeIndex] : undefined
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
node,
|
|
19
|
+
parentNode,
|
|
20
|
+
nodeIndex,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function applyVirtualDiff(
|
|
25
|
+
tree: elementNodeType,
|
|
26
|
+
diff: Diff,
|
|
27
|
+
options: DiffDOMOptions, // {preVirtualDiffApply, postVirtualDiffApply, _const}
|
|
28
|
+
) {
|
|
29
|
+
let node, parentNode, nodeIndex
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
![options._const.addElement, options._const.addTextElement].includes(
|
|
33
|
+
diff[options._const.action],
|
|
34
|
+
)
|
|
35
|
+
) {
|
|
36
|
+
// For adding nodes, we calculate the route later on. It's different because it includes the position of the newly added item.
|
|
37
|
+
const routeInfo = getFromVirtualRoute(tree, diff[options._const.route])
|
|
38
|
+
node = routeInfo.node
|
|
39
|
+
parentNode = routeInfo.parentNode
|
|
40
|
+
nodeIndex = routeInfo.nodeIndex
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const newSubsets: subsetType[] = []
|
|
44
|
+
|
|
45
|
+
// pre-diff hook
|
|
46
|
+
const info = {
|
|
47
|
+
diff,
|
|
48
|
+
node,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (options.preVirtualDiffApply(info)) {
|
|
52
|
+
return true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let newNode
|
|
56
|
+
let nodeArray
|
|
57
|
+
let route
|
|
58
|
+
|
|
59
|
+
switch (diff[options._const.action]) {
|
|
60
|
+
case options._const.addAttribute:
|
|
61
|
+
if (!node.attributes) {
|
|
62
|
+
node.attributes = {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
node.attributes[diff[options._const.name]] =
|
|
66
|
+
diff[options._const.value]
|
|
67
|
+
|
|
68
|
+
if (diff[options._const.name] === "checked") {
|
|
69
|
+
node.checked = true
|
|
70
|
+
} else if (diff[options._const.name] === "selected") {
|
|
71
|
+
node.selected = true
|
|
72
|
+
} else if (
|
|
73
|
+
node.nodeName === "INPUT" &&
|
|
74
|
+
diff[options._const.name] === "value"
|
|
75
|
+
) {
|
|
76
|
+
node.value = diff[options._const.value]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
break
|
|
80
|
+
case options._const.modifyAttribute:
|
|
81
|
+
node.attributes[diff[options._const.name]] =
|
|
82
|
+
diff[options._const.newValue]
|
|
83
|
+
break
|
|
84
|
+
case options._const.removeAttribute:
|
|
85
|
+
delete node.attributes[diff[options._const.name]]
|
|
86
|
+
|
|
87
|
+
if (Object.keys(node.attributes).length === 0) {
|
|
88
|
+
delete node.attributes
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (diff[options._const.name] === "checked") {
|
|
92
|
+
node.checked = false
|
|
93
|
+
} else if (diff[options._const.name] === "selected") {
|
|
94
|
+
delete node.selected
|
|
95
|
+
} else if (
|
|
96
|
+
node.nodeName === "INPUT" &&
|
|
97
|
+
diff[options._const.name] === "value"
|
|
98
|
+
) {
|
|
99
|
+
delete node.value
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
break
|
|
103
|
+
case options._const.modifyTextElement:
|
|
104
|
+
node.data = diff[options._const.newValue]
|
|
105
|
+
if (parentNode.nodeName === "TEXTAREA") {
|
|
106
|
+
parentNode.value = diff[options._const.newValue]
|
|
107
|
+
}
|
|
108
|
+
break
|
|
109
|
+
case options._const.modifyValue:
|
|
110
|
+
node.value = diff[options._const.newValue]
|
|
111
|
+
break
|
|
112
|
+
case options._const.modifyComment:
|
|
113
|
+
node.data = diff[options._const.newValue]
|
|
114
|
+
break
|
|
115
|
+
case options._const.modifyChecked:
|
|
116
|
+
node.checked = diff[options._const.newValue]
|
|
117
|
+
break
|
|
118
|
+
case options._const.modifySelected:
|
|
119
|
+
node.selected = diff[options._const.newValue]
|
|
120
|
+
break
|
|
121
|
+
case options._const.replaceElement:
|
|
122
|
+
newNode = cleanNode(diff[options._const.newValue])
|
|
123
|
+
parentNode.childNodes[nodeIndex] = newNode
|
|
124
|
+
break
|
|
125
|
+
case options._const.relocateGroup:
|
|
126
|
+
nodeArray = node.childNodes
|
|
127
|
+
.splice(
|
|
128
|
+
diff[options._const.from],
|
|
129
|
+
diff[options._const.groupLength],
|
|
130
|
+
)
|
|
131
|
+
.reverse()
|
|
132
|
+
nodeArray.forEach((movedNode: nodeType) =>
|
|
133
|
+
node.childNodes.splice(diff[options._const.to], 0, movedNode),
|
|
134
|
+
)
|
|
135
|
+
if (node.subsets) {
|
|
136
|
+
node.subsets.forEach((map: subsetType) => {
|
|
137
|
+
if (
|
|
138
|
+
diff[options._const.from] < diff[options._const.to] &&
|
|
139
|
+
map.oldValue <= diff[options._const.to] &&
|
|
140
|
+
map.oldValue > diff[options._const.from]
|
|
141
|
+
) {
|
|
142
|
+
map.oldValue -= diff[options._const.groupLength]
|
|
143
|
+
const splitLength =
|
|
144
|
+
map.oldValue + map.length - diff[options._const.to]
|
|
145
|
+
if (splitLength > 0) {
|
|
146
|
+
// new insertion splits map.
|
|
147
|
+
newSubsets.push({
|
|
148
|
+
oldValue:
|
|
149
|
+
diff[options._const.to] +
|
|
150
|
+
diff[options._const.groupLength],
|
|
151
|
+
newValue:
|
|
152
|
+
map.newValue + map.length - splitLength,
|
|
153
|
+
length: splitLength,
|
|
154
|
+
})
|
|
155
|
+
map.length -= splitLength
|
|
156
|
+
}
|
|
157
|
+
} else if (
|
|
158
|
+
diff[options._const.from] > diff[options._const.to] &&
|
|
159
|
+
map.oldValue > diff[options._const.to] &&
|
|
160
|
+
map.oldValue < diff[options._const.from]
|
|
161
|
+
) {
|
|
162
|
+
map.oldValue += diff[options._const.groupLength]
|
|
163
|
+
const splitLength =
|
|
164
|
+
map.oldValue + map.length - diff[options._const.to]
|
|
165
|
+
if (splitLength > 0) {
|
|
166
|
+
// new insertion splits map.
|
|
167
|
+
newSubsets.push({
|
|
168
|
+
oldValue:
|
|
169
|
+
diff[options._const.to] +
|
|
170
|
+
diff[options._const.groupLength],
|
|
171
|
+
newValue:
|
|
172
|
+
map.newValue + map.length - splitLength,
|
|
173
|
+
length: splitLength,
|
|
174
|
+
})
|
|
175
|
+
map.length -= splitLength
|
|
176
|
+
}
|
|
177
|
+
} else if (map.oldValue === diff[options._const.from]) {
|
|
178
|
+
map.oldValue = diff[options._const.to]
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
break
|
|
184
|
+
case options._const.removeElement:
|
|
185
|
+
parentNode.childNodes.splice(nodeIndex, 1)
|
|
186
|
+
if (parentNode.subsets) {
|
|
187
|
+
parentNode.subsets.forEach((map: subsetType) => {
|
|
188
|
+
if (map.oldValue > nodeIndex) {
|
|
189
|
+
map.oldValue -= 1
|
|
190
|
+
} else if (map.oldValue === nodeIndex) {
|
|
191
|
+
map.delete = true
|
|
192
|
+
} else if (
|
|
193
|
+
map.oldValue < nodeIndex &&
|
|
194
|
+
map.oldValue + map.length > nodeIndex
|
|
195
|
+
) {
|
|
196
|
+
if (map.oldValue + map.length - 1 === nodeIndex) {
|
|
197
|
+
map.length--
|
|
198
|
+
} else {
|
|
199
|
+
newSubsets.push({
|
|
200
|
+
newValue:
|
|
201
|
+
map.newValue + nodeIndex - map.oldValue,
|
|
202
|
+
oldValue: nodeIndex,
|
|
203
|
+
length:
|
|
204
|
+
map.length - nodeIndex + map.oldValue - 1,
|
|
205
|
+
})
|
|
206
|
+
map.length = nodeIndex - map.oldValue
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
node = parentNode
|
|
212
|
+
break
|
|
213
|
+
case options._const.addElement: {
|
|
214
|
+
route = diff[options._const.route].slice()
|
|
215
|
+
const c: number = route.splice(route.length - 1, 1)[0]
|
|
216
|
+
node = getFromVirtualRoute(tree, route)?.node
|
|
217
|
+
newNode = cleanNode(diff[options._const.element])
|
|
218
|
+
|
|
219
|
+
if (!node.childNodes) {
|
|
220
|
+
node.childNodes = []
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (c >= node.childNodes.length) {
|
|
224
|
+
node.childNodes.push(newNode)
|
|
225
|
+
} else {
|
|
226
|
+
node.childNodes.splice(c, 0, newNode)
|
|
227
|
+
}
|
|
228
|
+
if (node.subsets) {
|
|
229
|
+
node.subsets.forEach((map: subsetType) => {
|
|
230
|
+
if (map.oldValue >= c) {
|
|
231
|
+
map.oldValue += 1
|
|
232
|
+
} else if (
|
|
233
|
+
map.oldValue < c &&
|
|
234
|
+
map.oldValue + map.length > c
|
|
235
|
+
) {
|
|
236
|
+
const splitLength = map.oldValue + map.length - c
|
|
237
|
+
newSubsets.push({
|
|
238
|
+
newValue: map.newValue + map.length - splitLength,
|
|
239
|
+
oldValue: c + 1,
|
|
240
|
+
length: splitLength,
|
|
241
|
+
})
|
|
242
|
+
map.length -= splitLength
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
break
|
|
247
|
+
}
|
|
248
|
+
case options._const.removeTextElement:
|
|
249
|
+
parentNode.childNodes.splice(nodeIndex, 1)
|
|
250
|
+
if (parentNode.nodeName === "TEXTAREA") {
|
|
251
|
+
delete parentNode.value
|
|
252
|
+
}
|
|
253
|
+
if (parentNode.subsets) {
|
|
254
|
+
parentNode.subsets.forEach((map: subsetType) => {
|
|
255
|
+
if (map.oldValue > nodeIndex) {
|
|
256
|
+
map.oldValue -= 1
|
|
257
|
+
} else if (map.oldValue === nodeIndex) {
|
|
258
|
+
map.delete = true
|
|
259
|
+
} else if (
|
|
260
|
+
map.oldValue < nodeIndex &&
|
|
261
|
+
map.oldValue + map.length > nodeIndex
|
|
262
|
+
) {
|
|
263
|
+
if (map.oldValue + map.length - 1 === nodeIndex) {
|
|
264
|
+
map.length--
|
|
265
|
+
} else {
|
|
266
|
+
newSubsets.push({
|
|
267
|
+
newValue:
|
|
268
|
+
map.newValue + nodeIndex - map.oldValue,
|
|
269
|
+
oldValue: nodeIndex,
|
|
270
|
+
length:
|
|
271
|
+
map.length - nodeIndex + map.oldValue - 1,
|
|
272
|
+
})
|
|
273
|
+
map.length = nodeIndex - map.oldValue
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
node = parentNode
|
|
279
|
+
break
|
|
280
|
+
case options._const.addTextElement: {
|
|
281
|
+
route = diff[options._const.route].slice()
|
|
282
|
+
const c: number = route.splice(route.length - 1, 1)[0]
|
|
283
|
+
newNode = {
|
|
284
|
+
nodeName: "#text",
|
|
285
|
+
data: diff[options._const.value],
|
|
286
|
+
}
|
|
287
|
+
node = getFromVirtualRoute(tree, route).node
|
|
288
|
+
if (!node.childNodes) {
|
|
289
|
+
node.childNodes = []
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (c >= node.childNodes.length) {
|
|
293
|
+
node.childNodes.push(newNode)
|
|
294
|
+
} else {
|
|
295
|
+
node.childNodes.splice(c, 0, newNode)
|
|
296
|
+
}
|
|
297
|
+
if (node.nodeName === "TEXTAREA") {
|
|
298
|
+
node.value = diff[options._const.newValue]
|
|
299
|
+
}
|
|
300
|
+
if (node.subsets) {
|
|
301
|
+
node.subsets.forEach((map: subsetType) => {
|
|
302
|
+
if (map.oldValue >= c) {
|
|
303
|
+
map.oldValue += 1
|
|
304
|
+
}
|
|
305
|
+
if (map.oldValue < c && map.oldValue + map.length > c) {
|
|
306
|
+
const splitLength = map.oldValue + map.length - c
|
|
307
|
+
newSubsets.push({
|
|
308
|
+
newValue: map.newValue + map.length - splitLength,
|
|
309
|
+
oldValue: c + 1,
|
|
310
|
+
length: splitLength,
|
|
311
|
+
})
|
|
312
|
+
map.length -= splitLength
|
|
313
|
+
}
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
break
|
|
317
|
+
}
|
|
318
|
+
default:
|
|
319
|
+
console.log("unknown action")
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (node.subsets) {
|
|
323
|
+
node.subsets = node.subsets.filter(
|
|
324
|
+
(map: subsetType) => !map.delete && map.oldValue !== map.newValue,
|
|
325
|
+
)
|
|
326
|
+
if (newSubsets.length) {
|
|
327
|
+
node.subsets = node.subsets.concat(newSubsets)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
options.postVirtualDiffApply({
|
|
332
|
+
node: info.node,
|
|
333
|
+
diff: info.diff,
|
|
334
|
+
newNode,
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export function applyVirtual(
|
|
341
|
+
tree: elementNodeType,
|
|
342
|
+
diffs: Diff[],
|
|
343
|
+
options: DiffDOMOptions,
|
|
344
|
+
) {
|
|
345
|
+
diffs.forEach((diff: Diff) => {
|
|
346
|
+
applyVirtualDiff(tree, diff, options)
|
|
347
|
+
})
|
|
348
|
+
return true
|
|
349
|
+
}
|