native-document 1.0.14 → 1.0.15
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.
- package/dist/native-document.dev.js +1262 -839
- package/dist/native-document.min.js +1 -1
- package/docs/anchor.md +216 -53
- package/docs/conditional-rendering.md +25 -24
- package/docs/core-concepts.md +20 -19
- package/docs/elements.md +21 -20
- package/docs/getting-started.md +28 -27
- package/docs/lifecycle-events.md +2 -2
- package/docs/list-rendering.md +607 -0
- package/docs/memory-management.md +1 -1
- package/docs/observables.md +15 -14
- package/docs/routing.md +22 -22
- package/docs/state-management.md +8 -8
- package/docs/validation.md +0 -2
- package/index.js +6 -1
- package/package.json +1 -1
- package/readme.md +5 -4
- package/src/data/MemoryManager.js +8 -20
- package/src/data/Observable.js +2 -180
- package/src/data/ObservableChecker.js +25 -24
- package/src/data/ObservableItem.js +158 -79
- package/src/data/observable-helpers/array.js +74 -0
- package/src/data/observable-helpers/batch.js +22 -0
- package/src/data/observable-helpers/computed.js +28 -0
- package/src/data/observable-helpers/object.js +111 -0
- package/src/elements/anchor.js +54 -9
- package/src/elements/control/for-each-array.js +280 -0
- package/src/elements/control/for-each.js +87 -110
- package/src/elements/index.js +1 -0
- package/src/elements/list.js +4 -0
- package/src/utils/helpers.js +44 -21
- package/src/wrappers/AttributesWrapper.js +5 -18
- package/src/wrappers/DocumentObserver.js +58 -29
- package/src/wrappers/ElementCreator.js +114 -0
- package/src/wrappers/HtmlElementEventsWrapper.js +52 -65
- package/src/wrappers/HtmlElementWrapper.js +11 -167
- package/src/wrappers/NdPrototype.js +109 -0
|
@@ -16,101 +16,180 @@ export default function ObservableItem(value) {
|
|
|
16
16
|
throw new NativeDocumentError('ObservableItem cannot be an Observable');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
this.$previousValue = value;
|
|
20
|
+
this.$currentValue = value;
|
|
21
|
+
this.$isCleanedUp = false;
|
|
22
|
+
|
|
23
|
+
this.$listeners = null;
|
|
24
|
+
this.$watchers = null;
|
|
25
|
+
|
|
26
|
+
this.$memoryId = MemoryManager.register(this);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Object.defineProperty(ObservableItem.prototype, '$value', {
|
|
30
|
+
get() {
|
|
31
|
+
return this.$currentValue;
|
|
32
|
+
},
|
|
33
|
+
set(value) {
|
|
34
|
+
this.set(value);
|
|
35
|
+
},
|
|
36
|
+
configurable: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
ObservableItem.prototype.triggerListeners = function(operations) {
|
|
40
|
+
const $listeners = this.$listeners;
|
|
41
|
+
const $previousValue = this.$previousValue;
|
|
42
|
+
const $currentValue = this.$currentValue;
|
|
43
|
+
|
|
44
|
+
operations = operations || {};
|
|
45
|
+
if($listeners?.length) {
|
|
46
|
+
for(let i = 0, length = $listeners.length; i < length; i++) {
|
|
47
|
+
$listeners[i]($currentValue, $previousValue, operations);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
24
51
|
|
|
25
|
-
|
|
52
|
+
ObservableItem.prototype.triggerWatchers = function() {
|
|
53
|
+
if(!this.$watchers) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
26
56
|
|
|
27
|
-
const $
|
|
57
|
+
const $watchers = this.$watchers;
|
|
58
|
+
const $previousValue = this.$previousValue;
|
|
59
|
+
const $currentValue = this.$currentValue;
|
|
28
60
|
|
|
29
|
-
|
|
30
|
-
$
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
DebugManager.error('Listener Undefined', 'Error in observable listener:', error);
|
|
35
|
-
this.unsubscribe(listener);
|
|
61
|
+
if($watchers.has($currentValue)) {
|
|
62
|
+
const watchValueList = $watchers.get($currentValue);
|
|
63
|
+
watchValueList.forEach(itemValue => {
|
|
64
|
+
if(itemValue.ifTrue.called) {
|
|
65
|
+
return;
|
|
36
66
|
}
|
|
67
|
+
itemValue.ifTrue.callback();
|
|
68
|
+
itemValue.else.called = false;
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
if($watchers.has($previousValue)) {
|
|
72
|
+
const watchValueList = $watchers.get($previousValue);
|
|
73
|
+
watchValueList.forEach(itemValue => {
|
|
74
|
+
if(itemValue.else.called) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
itemValue.else.callback();
|
|
78
|
+
itemValue.ifTrue.called = false;
|
|
37
79
|
});
|
|
80
|
+
}
|
|
81
|
+
};
|
|
38
82
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
83
|
+
ObservableItem.prototype.trigger = function(operations) {
|
|
84
|
+
this.triggerListeners(operations);
|
|
85
|
+
this.triggerWatchers();
|
|
86
|
+
}
|
|
42
87
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
88
|
+
/**
|
|
89
|
+
* @param {*} data
|
|
90
|
+
*/
|
|
91
|
+
ObservableItem.prototype.set = function(data) {
|
|
92
|
+
const newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
|
|
93
|
+
if(this.$currentValue === newValue) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.$previousValue = this.$currentValue;
|
|
97
|
+
this.$currentValue = newValue;
|
|
98
|
+
this.trigger();
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
ObservableItem.prototype.val = function() {
|
|
102
|
+
return this.$currentValue;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
ObservableItem.prototype.disconnectAll = function() {
|
|
106
|
+
this.$listeners?.splice(0);
|
|
107
|
+
this.$previousValue = null;
|
|
108
|
+
this.$currentValue = null;
|
|
109
|
+
if(this.$watchers) {
|
|
110
|
+
for (const [_, watchValueList] of this.$watchers) {
|
|
111
|
+
for (const itemValue of watchValueList) {
|
|
112
|
+
itemValue.ifTrue.callback = null;
|
|
113
|
+
itemValue.else.callback = null;
|
|
114
|
+
}
|
|
115
|
+
watchValueList.clear();
|
|
50
116
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
117
|
+
}
|
|
118
|
+
this.$watchers?.clear();
|
|
119
|
+
this.$listeners = null;
|
|
120
|
+
this.$watchers = null;
|
|
121
|
+
}
|
|
122
|
+
ObservableItem.prototype.cleanup = function() {
|
|
123
|
+
MemoryManager.unregister(this.$memoryId);
|
|
124
|
+
this.disconnectAll();
|
|
125
|
+
this.$isCleanedUp = true;
|
|
126
|
+
delete this.$value;
|
|
127
|
+
}
|
|
55
128
|
|
|
56
|
-
|
|
129
|
+
/**
|
|
130
|
+
*
|
|
131
|
+
* @param {Function} callback
|
|
132
|
+
* @returns {(function(): void)}
|
|
133
|
+
*/
|
|
134
|
+
ObservableItem.prototype.subscribe = function(callback) {
|
|
135
|
+
this.$listeners = this.$listeners ?? [];
|
|
136
|
+
if (this.$isCleanedUp) {
|
|
137
|
+
DebugManager.warn('Observable subscription', '⚠️ Attempted to subscribe to a cleaned up observable.');
|
|
138
|
+
return () => {};
|
|
139
|
+
}
|
|
140
|
+
if (typeof callback !== 'function') {
|
|
141
|
+
throw new NativeDocumentError('Callback must be a function');
|
|
142
|
+
}
|
|
57
143
|
|
|
58
|
-
this.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
};
|
|
144
|
+
this.$listeners.push(callback);
|
|
145
|
+
return () => this.unsubscribe(callback);
|
|
146
|
+
};
|
|
62
147
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
* @param {Function} callback
|
|
66
|
-
* @returns {(function(): void)}
|
|
67
|
-
*/
|
|
68
|
-
this.subscribe = (callback) => {
|
|
69
|
-
if ($isCleanedUp) {
|
|
70
|
-
DebugManager.warn('Observable subscription', '⚠️ Attempted to subscribe to a cleaned up observable.');
|
|
71
|
-
return () => {};
|
|
72
|
-
}
|
|
73
|
-
if (typeof callback !== 'function') {
|
|
74
|
-
throw new NativeDocumentError('Callback must be a function');
|
|
75
|
-
}
|
|
148
|
+
ObservableItem.prototype.on = function(value, callback, elseCallback) {
|
|
149
|
+
this.$watchers = this.$watchers ?? new Map();
|
|
76
150
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
151
|
+
let watchValueList = this.$watchers.get(value);
|
|
152
|
+
if(!watchValueList) {
|
|
153
|
+
watchValueList = new Set();
|
|
154
|
+
this.$watchers.set(value, watchValueList);
|
|
155
|
+
}
|
|
80
156
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
*/
|
|
85
|
-
this.unsubscribe = (callback) => {
|
|
86
|
-
const index = $listeners.indexOf(callback);
|
|
87
|
-
if (index > -1) {
|
|
88
|
-
$listeners.splice(index, 1);
|
|
89
|
-
}
|
|
157
|
+
let itemValue = {
|
|
158
|
+
ifTrue: { callback, called: false },
|
|
159
|
+
else: { callback: elseCallback, called: false }
|
|
90
160
|
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
161
|
+
watchValueList.add(itemValue);
|
|
162
|
+
return () => {
|
|
163
|
+
watchValueList?.delete(itemValue);
|
|
164
|
+
if(watchValueList.size === 0) {
|
|
165
|
+
this.$watchers?.delete(value);
|
|
166
|
+
}
|
|
167
|
+
watchValueList = null;
|
|
168
|
+
itemValue = null;
|
|
99
169
|
};
|
|
170
|
+
};
|
|
100
171
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Unsubscribe from an observable.
|
|
174
|
+
* @param {Function} callback
|
|
175
|
+
*/
|
|
176
|
+
ObservableItem.prototype.unsubscribe = function(callback) {
|
|
177
|
+
const index = this.$listeners.indexOf(callback);
|
|
178
|
+
if (index > -1) {
|
|
179
|
+
this.$listeners.splice(index, 1);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
111
182
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Create an Observable checker instance
|
|
185
|
+
* @param callback
|
|
186
|
+
* @returns {ObservableChecker}
|
|
187
|
+
*/
|
|
188
|
+
ObservableItem.prototype.check = function(callback) {
|
|
189
|
+
return new ObservableChecker(this, callback)
|
|
190
|
+
};
|
|
191
|
+
ObservableItem.prototype.get = ObservableItem.prototype.check;
|
|
115
192
|
|
|
193
|
+
ObservableItem.prototype.toString = function() {
|
|
194
|
+
return '{{#ObItem::(' +this.$memoryId+ ')}}';
|
|
116
195
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import NativeDocumentError from "../../errors/NativeDocumentError";
|
|
2
|
+
import {Observable} from "../Observable";
|
|
3
|
+
import ObservableItem from "../ObservableItem";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const methods = ['push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice'];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param {Array} target
|
|
11
|
+
* @returns {ObservableItem}
|
|
12
|
+
*/
|
|
13
|
+
Observable.array = function(target) {
|
|
14
|
+
if(!Array.isArray(target)) {
|
|
15
|
+
throw new NativeDocumentError('Observable.array : target must be an array');
|
|
16
|
+
}
|
|
17
|
+
const observer = Observable(target);
|
|
18
|
+
|
|
19
|
+
methods.forEach((method) => {
|
|
20
|
+
observer[method] = function(...values) {
|
|
21
|
+
const result = observer.val()[method](...values);
|
|
22
|
+
observer.trigger({ action: method, args: values, result });
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
observer.clear = function() {
|
|
28
|
+
observer.$value.length = 0;
|
|
29
|
+
observer.trigger({ action: 'clear' });
|
|
30
|
+
return true;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
observer.remove = function(index) {
|
|
34
|
+
const deleted = observer.$value.splice(index, 1);
|
|
35
|
+
if(deleted.length === 0) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
observer.trigger({ action: 'remove', args: [index], result: deleted[0] });
|
|
39
|
+
return deleted;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
observer.swap = function(indexA, indexB) {
|
|
43
|
+
const value = observer.$value;
|
|
44
|
+
const length = value.length;
|
|
45
|
+
if(length < indexA || length < indexB) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if(indexB < indexA) {
|
|
49
|
+
const temp = indexA;
|
|
50
|
+
indexA = indexB;
|
|
51
|
+
indexB = temp;
|
|
52
|
+
}
|
|
53
|
+
const elementA = value[indexA];
|
|
54
|
+
const elementB = value[indexB]
|
|
55
|
+
|
|
56
|
+
value[indexA] = elementB;
|
|
57
|
+
value[indexB] = elementA;
|
|
58
|
+
observer.trigger({ action: 'swap', args: [indexA, indexB], result: [elementA, elementB] });
|
|
59
|
+
return true;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
observer.length = function() {
|
|
63
|
+
return observer.$value.length;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const overrideMethods = ['map', 'filter', 'reduce', 'some', 'every', 'find', 'findIndex', 'concat'];
|
|
67
|
+
overrideMethods.forEach((method) => {
|
|
68
|
+
observer[method] = function(...args) {
|
|
69
|
+
return observer.val()[method](...args);
|
|
70
|
+
};
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return observer;
|
|
74
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Validator from "../../utils/validator";
|
|
2
|
+
import {Observable} from "../Observable";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {Function} callback
|
|
7
|
+
* @returns {Function}
|
|
8
|
+
*/
|
|
9
|
+
Observable.batch = function(callback) {
|
|
10
|
+
const $observer = Observable(0);
|
|
11
|
+
const batch = function() {
|
|
12
|
+
if(Validator.isAsyncFunction(callback)) {
|
|
13
|
+
return (callback(...arguments)).then(() => {
|
|
14
|
+
$observer.trigger();
|
|
15
|
+
}).catch(error => { throw error; });
|
|
16
|
+
}
|
|
17
|
+
callback(...arguments);
|
|
18
|
+
$observer.trigger();
|
|
19
|
+
};
|
|
20
|
+
batch.$observer = $observer;
|
|
21
|
+
return batch;
|
|
22
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import ObservableItem from "../ObservableItem";
|
|
2
|
+
import Validator from "../../utils/validator";
|
|
3
|
+
import NativeDocumentError from "../../errors/NativeDocumentError";
|
|
4
|
+
import {Observable} from "../Observable";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {Function} callback
|
|
9
|
+
* @param {Array|Function} dependencies
|
|
10
|
+
* @returns {ObservableItem}
|
|
11
|
+
*/
|
|
12
|
+
Observable.computed = function(callback, dependencies = []) {
|
|
13
|
+
const initialValue = callback();
|
|
14
|
+
const observable = new ObservableItem(initialValue);
|
|
15
|
+
const updatedValue = () => observable.set(callback());
|
|
16
|
+
|
|
17
|
+
if(Validator.isFunction(dependencies)) {
|
|
18
|
+
if(!Validator.isObservable(dependencies.$observer)) {
|
|
19
|
+
throw new NativeDocumentError('Observable.computed : dependencies must be valid batch function');
|
|
20
|
+
}
|
|
21
|
+
dependencies.$observer.subscribe(updatedValue);
|
|
22
|
+
return observable;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
dependencies.forEach(dependency => dependency.subscribe(updatedValue));
|
|
26
|
+
|
|
27
|
+
return observable;
|
|
28
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import Validator from "../../utils/validator";
|
|
2
|
+
import {Observable} from "../Observable";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {Object} value
|
|
7
|
+
* @returns {Proxy}
|
|
8
|
+
*/
|
|
9
|
+
Observable.init = function(value) {
|
|
10
|
+
const data = {};
|
|
11
|
+
for(const key in value) {
|
|
12
|
+
const itemValue = value[key];
|
|
13
|
+
if(Validator.isJson(itemValue)) {
|
|
14
|
+
data[key] = Observable.init(itemValue);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
else if(Validator.isArray(itemValue)) {
|
|
18
|
+
data[key] = Observable.array(itemValue);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
data[key] = Observable(itemValue);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const $val = function() {
|
|
25
|
+
const result = {};
|
|
26
|
+
for(const key in data) {
|
|
27
|
+
const dataItem = data[key];
|
|
28
|
+
if(Validator.isObservable(dataItem)) {
|
|
29
|
+
result[key] = dataItem.val();
|
|
30
|
+
} else if(Validator.isProxy(dataItem)) {
|
|
31
|
+
result[key] = dataItem.$value;
|
|
32
|
+
} else {
|
|
33
|
+
result[key] = dataItem;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
const $clone = function() {
|
|
39
|
+
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return new Proxy(data, {
|
|
43
|
+
get(target, property) {
|
|
44
|
+
if(property === '__isProxy__') {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if(property === '$value') {
|
|
48
|
+
return $val();
|
|
49
|
+
}
|
|
50
|
+
if(property === '$clone') {
|
|
51
|
+
return $clone;
|
|
52
|
+
}
|
|
53
|
+
if(target[property] !== undefined) {
|
|
54
|
+
return target[property];
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
},
|
|
58
|
+
set(target, prop, newValue) {
|
|
59
|
+
if(target[prop] !== undefined) {
|
|
60
|
+
target[prop].set(newValue);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get the value of an observable or an object of observables.
|
|
68
|
+
* @param {ObservableItem|Object<ObservableItem>} data
|
|
69
|
+
* @returns {{}|*|null}
|
|
70
|
+
*/
|
|
71
|
+
Observable.value = function(data) {
|
|
72
|
+
if(Validator.isObservable(data)) {
|
|
73
|
+
return data.val();
|
|
74
|
+
}
|
|
75
|
+
if(Validator.isProxy(data)) {
|
|
76
|
+
return data.$value;
|
|
77
|
+
}
|
|
78
|
+
if(Validator.isArray(data)) {
|
|
79
|
+
const result = [];
|
|
80
|
+
data.forEach(item => {
|
|
81
|
+
result.push(Observable.value(item));
|
|
82
|
+
});
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
return data;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
Observable.update = function($target, data) {
|
|
90
|
+
for(const key in data) {
|
|
91
|
+
const targetItem = $target[key];
|
|
92
|
+
const newValue = data[key];
|
|
93
|
+
|
|
94
|
+
if(Validator.isObservable(targetItem)) {
|
|
95
|
+
if(Validator.isArray(newValue)) {
|
|
96
|
+
Observable.update(targetItem, newValue);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
targetItem.set(newValue);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if(Validator.isProxy(targetItem)) {
|
|
103
|
+
Observable.update(targetItem, newValue);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
$target[key] = newValue;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
Observable.object = Observable.init;
|
|
111
|
+
Observable.json = Observable.init;
|
package/src/elements/anchor.js
CHANGED
|
@@ -33,6 +33,14 @@ export default function Anchor(name) {
|
|
|
33
33
|
parent.insertBefore(getChildAsNode(child), target);
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
element.appendElement = function(child, before = null) {
|
|
37
|
+
if(anchorEnd.parentNode === element) {
|
|
38
|
+
anchorEnd.parentNode.nativeInsertBefore(child, before || anchorEnd);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
anchorEnd.parentNode?.insertBefore(child, before || anchorEnd);
|
|
42
|
+
};
|
|
43
|
+
|
|
36
44
|
element.appendChild = function(child, before = null) {
|
|
37
45
|
const parent = anchorEnd.parentNode;
|
|
38
46
|
if(!parent) {
|
|
@@ -41,28 +49,65 @@ export default function Anchor(name) {
|
|
|
41
49
|
}
|
|
42
50
|
before = before ?? anchorEnd;
|
|
43
51
|
if(Validator.isArray(child)) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
const fragment = document.createDocumentFragment();
|
|
53
|
+
for(let i = 0, length = child.length; i < length; i++) {
|
|
54
|
+
fragment.appendChild(getChildAsNode(child[i]));
|
|
55
|
+
}
|
|
56
|
+
insertBefore(parent, fragment, before);
|
|
47
57
|
return element;
|
|
48
58
|
}
|
|
49
59
|
insertBefore(parent, child, before);
|
|
50
60
|
};
|
|
51
61
|
|
|
52
|
-
element.
|
|
53
|
-
|
|
62
|
+
element.removeChildren = function() {
|
|
63
|
+
const parent = anchorEnd.parentNode;
|
|
64
|
+
if(parent === element) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if(parent.firstChild === anchorStart && parent.lastChild === anchorEnd) {
|
|
68
|
+
parent.replaceChildren(anchorStart, anchorEnd);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let itemToRemove = anchorStart.nextSibling, tempItem;
|
|
73
|
+
const fragment = document.createDocumentFragment();
|
|
74
|
+
while(itemToRemove && itemToRemove !== anchorEnd) {
|
|
75
|
+
tempItem = itemToRemove.nextSibling;
|
|
76
|
+
fragment.append(itemToRemove);
|
|
77
|
+
itemToRemove = tempItem;
|
|
78
|
+
}
|
|
79
|
+
fragment.replaceChildren();
|
|
80
|
+
}
|
|
81
|
+
element.remove = function() {
|
|
82
|
+
const parent = anchorEnd.parentNode;
|
|
83
|
+
if(parent === element) {
|
|
54
84
|
return;
|
|
55
85
|
}
|
|
56
86
|
let itemToRemove = anchorStart.nextSibling, tempItem;
|
|
57
87
|
while(itemToRemove !== anchorEnd) {
|
|
58
88
|
tempItem = itemToRemove.nextSibling;
|
|
59
|
-
|
|
89
|
+
element.nativeAppendChild(itemToRemove);
|
|
60
90
|
itemToRemove = tempItem;
|
|
61
91
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
element.removeWithAnchors = function() {
|
|
95
|
+
element.removeChildren();
|
|
96
|
+
anchorStart.remove();
|
|
97
|
+
anchorEnd.remove();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
element.replaceContent = function(child) {
|
|
101
|
+
const parent = anchorEnd.parentNode;
|
|
102
|
+
if(!parent) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if(parent.firstChild === anchorStart && parent.lastChild === anchorEnd) {
|
|
106
|
+
parent.replaceChildren(anchorStart, child, anchorEnd);
|
|
107
|
+
return;
|
|
65
108
|
}
|
|
109
|
+
element.removeChildren();
|
|
110
|
+
parent.insertBefore(child, anchorEnd);
|
|
66
111
|
};
|
|
67
112
|
|
|
68
113
|
element.insertBefore = function(child, anchor = null) {
|