pseudo-dom 0.3.0 → 0.5.0
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/README.md +1632 -111
- package/browser/pseudo-dom.js +23759 -1844
- package/browser/pseudo-dom.min.js +1 -1
- package/dist/classes/PseudoHTMLDocument.d.ts +33 -1
- package/dist/classes/PseudoHTMLDocument.js +80 -2
- package/dist/classes/PseudoHTMLDocument.min.js +1 -1
- package/dist/factories/createEvent.d.ts +28 -0
- package/dist/factories/createEvent.js +56 -0
- package/dist/factories/createEvent.min.js +1 -0
- package/dist/factories/eventDefaults.d.ts +31 -0
- package/dist/factories/eventDefaults.js +105 -0
- package/dist/factories/eventDefaults.min.js +1 -0
- package/dist/factories.d.ts +6 -0
- package/dist/factories.js +5 -1
- package/dist/factories.min.js +1 -1
- package/dist/functions/activeElement.d.ts +14 -0
- package/dist/functions/activeElement.js +33 -0
- package/dist/functions/activeElement.min.js +1 -0
- package/dist/functions/modifierState.d.ts +29 -0
- package/dist/functions/modifierState.js +41 -0
- package/dist/functions/modifierState.min.js +1 -0
- package/dist/main.d.ts +35 -1
- package/dist/main.js +81 -1
- package/dist/main.min.js +1 -1
- package/dist/services/AttrService.d.ts +6 -0
- package/dist/services/AttrService.js +24 -0
- package/dist/services/AttrService.min.js +1 -1
- package/dist/services/CommentService.d.ts +1 -0
- package/dist/services/CommentService.js +13 -0
- package/dist/services/CommentService.min.js +1 -0
- package/dist/services/CustomEventService.d.ts +37 -0
- package/dist/services/CustomEventService.js +35 -0
- package/dist/services/CustomEventService.min.js +1 -0
- package/dist/services/ElementService.d.ts +20 -0
- package/dist/services/ElementService.js +82 -15
- package/dist/services/ElementService.min.js +1 -1
- package/dist/services/EventService.d.ts +2 -0
- package/dist/services/EventService.js +7 -1
- package/dist/services/EventService.min.js +1 -1
- package/dist/services/FocusEventService.d.ts +32 -0
- package/dist/services/FocusEventService.js +35 -0
- package/dist/services/FocusEventService.min.js +1 -0
- package/dist/services/HTMLElementService.d.ts +20 -0
- package/dist/services/HTMLElementService.js +95 -0
- package/dist/services/HTMLElementService.min.js +1 -1
- package/dist/services/InputEventService.d.ts +41 -0
- package/dist/services/InputEventService.js +47 -0
- package/dist/services/InputEventService.min.js +1 -0
- package/dist/services/KeyboardEventService.d.ts +70 -0
- package/dist/services/KeyboardEventService.js +86 -0
- package/dist/services/KeyboardEventService.min.js +1 -0
- package/dist/services/MouseEventService.d.ts +80 -0
- package/dist/services/MouseEventService.js +108 -0
- package/dist/services/MouseEventService.min.js +1 -0
- package/dist/services/NodeService.d.ts +105 -8
- package/dist/services/NodeService.js +313 -17
- package/dist/services/NodeService.min.js +1 -1
- package/dist/services/PointerEventService.d.ts +51 -0
- package/dist/services/PointerEventService.js +67 -0
- package/dist/services/PointerEventService.min.js +1 -0
- package/dist/services/TextService.d.ts +1 -0
- package/dist/services/TextService.js +13 -0
- package/dist/services/TextService.min.js +1 -0
- package/dist/services/UIEventService.d.ts +43 -0
- package/dist/services/UIEventService.js +42 -0
- package/dist/services/UIEventService.min.js +1 -0
- package/dist/simulate.d.ts +32 -0
- package/dist/simulate.js +115 -0
- package/dist/simulate.min.js +1 -0
- package/package.json +3 -2
|
@@ -29,11 +29,21 @@ export declare class NodeService extends EventTargetService implements PseudoNod
|
|
|
29
29
|
static readonly DOCUMENT_TYPE_NODE = 10;
|
|
30
30
|
static readonly DOCUMENT_FRAGMENT_NODE = 11;
|
|
31
31
|
static readonly NOTATION_NODE = 12;
|
|
32
|
+
static readonly DOCUMENT_POSITION_DISCONNECTED = 1;
|
|
33
|
+
static readonly DOCUMENT_POSITION_PRECEDING = 2;
|
|
34
|
+
static readonly DOCUMENT_POSITION_FOLLOWING = 4;
|
|
35
|
+
static readonly DOCUMENT_POSITION_CONTAINS = 8;
|
|
36
|
+
static readonly DOCUMENT_POSITION_CONTAINED_BY = 16;
|
|
37
|
+
static readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 32;
|
|
38
|
+
private static nextNodeId;
|
|
32
39
|
children: PseudoNodeList | LinkedTreeList;
|
|
33
40
|
parent: PseudoNode | null;
|
|
34
41
|
protected nodeNameValue: string;
|
|
35
42
|
private nodeValueStore;
|
|
36
|
-
|
|
43
|
+
/** The document which made this node (createElement and the like), for when it is not in a tree yet. */
|
|
44
|
+
protected ownerDocumentStore: PseudoDocument | null;
|
|
45
|
+
/** A number for each node in the order they were made, used to give nodes which are in different trees a consistent order. */
|
|
46
|
+
private readonly nodeId;
|
|
37
47
|
/** The linker which holds this node in the children list of its parent, from which its siblings are found (null while it has no parent). */
|
|
38
48
|
protected listLinker: TreeLinker | null;
|
|
39
49
|
/**
|
|
@@ -63,6 +73,24 @@ export declare class NodeService extends EventTargetService implements PseudoNod
|
|
|
63
73
|
* @returns {PseudoNode} The added node
|
|
64
74
|
*/
|
|
65
75
|
appendChild(childNode: PseudoNode): PseudoNode;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this kind of node can have children (text, comments and attributes cannot).
|
|
78
|
+
* @returns {boolean}
|
|
79
|
+
*/
|
|
80
|
+
protected get acceptsChildren(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Make a copy of this node without its children, its parent or its listeners, which is what cloneNode starts from.
|
|
83
|
+
* Kinds of node which are made with arguments override this to give them.
|
|
84
|
+
* @returns {NodeService}
|
|
85
|
+
*/
|
|
86
|
+
protected cloneShallow(): NodeService;
|
|
87
|
+
/**
|
|
88
|
+
* Whether another node of the same type is equal to this one apart from its children, which isEqualNode compares
|
|
89
|
+
* afterwards. Kinds of node with more to compare (an element has attributes) override this.
|
|
90
|
+
* @param {NodeService} other The node to compare with
|
|
91
|
+
* @returns {boolean}
|
|
92
|
+
*/
|
|
93
|
+
protected equalsShallow(other: NodeService): boolean;
|
|
66
94
|
/**
|
|
67
95
|
* Called each time a node has been inserted as a child of this node, so that nodes which need to react to children
|
|
68
96
|
* (for example elements applying default events) can do so.
|
|
@@ -70,13 +98,19 @@ export declare class NodeService extends EventTargetService implements PseudoNod
|
|
|
70
98
|
*/
|
|
71
99
|
protected childInserted(child: NodeService): void;
|
|
72
100
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
101
|
+
* Make a copy of this node (without its parent, and without its event listeners). With deep the children are copied
|
|
102
|
+
* too, all the way down.
|
|
103
|
+
* @param {boolean} [deep=false] Copy the children as well
|
|
104
|
+
* @returns {PseudoNode}
|
|
75
105
|
*/
|
|
76
106
|
cloneNode(deep?: boolean): PseudoNode;
|
|
77
107
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
108
|
+
* Say where another node is in relation to this one, as the bits of NodeService.DOCUMENT_POSITION_*: 0 for this node
|
|
109
|
+
* itself, DISCONNECTED (with IMPLEMENTATION_SPECIFIC and a consistent PRECEDING or FOLLOWING) for a node in another tree,
|
|
110
|
+
* CONTAINS + PRECEDING when the other node is an ancestor, CONTAINED_BY + FOLLOWING when it is a descendant,
|
|
111
|
+
* otherwise PRECEDING or FOLLOWING by their order in the tree.
|
|
112
|
+
* @param {PseudoNode} otherNode The node to locate
|
|
113
|
+
* @returns {number}
|
|
80
114
|
*/
|
|
81
115
|
compareDocumentPosition(otherNode: PseudoNode): number;
|
|
82
116
|
/**
|
|
@@ -100,13 +134,18 @@ export declare class NodeService extends EventTargetService implements PseudoNod
|
|
|
100
134
|
insertBefore(newNode: PseudoNode, referenceNode?: PseudoNode | null): PseudoNode | PseudoDocumentFragment;
|
|
101
135
|
isDefaultNamespace(namespaceURI: string | null): boolean;
|
|
102
136
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
137
|
+
* Whether another node is the same as this one, by what they hold: the same type, name and value (an element also
|
|
138
|
+
* needs the same attributes), and children which are equal in the same order.
|
|
139
|
+
* @param {PseudoNode|null} otherNode The node to compare with
|
|
140
|
+
* @returns {boolean}
|
|
105
141
|
*/
|
|
106
|
-
isEqualNode(otherNode: PseudoNode): boolean;
|
|
142
|
+
isEqualNode(otherNode: PseudoNode | null): boolean;
|
|
107
143
|
isSameNode(otherNode: PseudoNode): boolean;
|
|
108
144
|
lookupPrefix(namespace: string): string | null;
|
|
109
145
|
lookupNamespaceURI(prefix: string): string | null;
|
|
146
|
+
/**
|
|
147
|
+
* Tidy the text below this node: neighbouring text nodes are joined into one and empty text nodes are removed.
|
|
148
|
+
*/
|
|
110
149
|
normalize(): void;
|
|
111
150
|
/**
|
|
112
151
|
* Remove a child from this node, it no longer has a parent or siblings afterwards.
|
|
@@ -124,3 +163,61 @@ export declare class NodeService extends EventTargetService implements PseudoNod
|
|
|
124
163
|
*/
|
|
125
164
|
replaceChild(newChild: PseudoNode, oldChild: PseudoNode): PseudoNode;
|
|
126
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Simulate the behaviour of the Text Class when there is no DOM available: the text in an element.
|
|
168
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
169
|
+
* @class
|
|
170
|
+
* @augments NodeService
|
|
171
|
+
* @property {string} data - The text
|
|
172
|
+
* @property {number} length - How many characters there are
|
|
173
|
+
* @property {string} wholeText - The text of this node and of the text nodes next to it
|
|
174
|
+
*/
|
|
175
|
+
export declare class TextService extends NodeService {
|
|
176
|
+
/**
|
|
177
|
+
* @param {string} [data=''] The text
|
|
178
|
+
* @constructor
|
|
179
|
+
*/
|
|
180
|
+
constructor(data?: string);
|
|
181
|
+
protected get acceptsChildren(): boolean;
|
|
182
|
+
get nodeName(): string;
|
|
183
|
+
get nodeType(): number;
|
|
184
|
+
get data(): string;
|
|
185
|
+
set data(data: string);
|
|
186
|
+
get length(): number;
|
|
187
|
+
get textContent(): string | null;
|
|
188
|
+
set textContent(text: string | null);
|
|
189
|
+
get wholeText(): string;
|
|
190
|
+
/**
|
|
191
|
+
* Break this text node in two at a position: this node keeps the text before it and a new node with the rest is put
|
|
192
|
+
* after this one.
|
|
193
|
+
* @param {number} offset How many characters stay in this node
|
|
194
|
+
* @returns {TextService} The new node
|
|
195
|
+
* @throws {Error} When the offset is beyond the end of the text
|
|
196
|
+
*/
|
|
197
|
+
splitText(offset: number): TextService;
|
|
198
|
+
protected cloneShallow(): NodeService;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Simulate the behaviour of the Comment Class when there is no DOM available: a note in the markup which is not shown.
|
|
202
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
203
|
+
* @class
|
|
204
|
+
* @augments NodeService
|
|
205
|
+
* @property {string} data - The comment
|
|
206
|
+
* @property {number} length - How many characters there are
|
|
207
|
+
*/
|
|
208
|
+
export declare class CommentService extends NodeService {
|
|
209
|
+
/**
|
|
210
|
+
* @param {string} [data=''] The comment
|
|
211
|
+
* @constructor
|
|
212
|
+
*/
|
|
213
|
+
constructor(data?: string);
|
|
214
|
+
protected get acceptsChildren(): boolean;
|
|
215
|
+
get nodeName(): string;
|
|
216
|
+
get nodeType(): number;
|
|
217
|
+
get data(): string;
|
|
218
|
+
set data(data: string);
|
|
219
|
+
get length(): number;
|
|
220
|
+
get textContent(): string | null;
|
|
221
|
+
set textContent(text: string | null);
|
|
222
|
+
protected cloneShallow(): NodeService;
|
|
223
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
require('core-js/modules/esnext.iterator.constructor.js')
|
|
4
|
+
require('core-js/modules/esnext.iterator.every.js')
|
|
5
|
+
require('core-js/modules/esnext.iterator.for-each.js')
|
|
3
6
|
const __importDefault = void 0 && (void 0).__importDefault || function (mod) {
|
|
4
7
|
return mod && mod.__esModule
|
|
5
8
|
? mod
|
|
@@ -10,7 +13,7 @@ const __importDefault = void 0 && (void 0).__importDefault || function (mod) {
|
|
|
10
13
|
Object.defineProperty(exports, '__esModule', {
|
|
11
14
|
value: true
|
|
12
15
|
})
|
|
13
|
-
exports.NodeService = void 0
|
|
16
|
+
exports.CommentService = exports.TextService = exports.NodeService = void 0
|
|
14
17
|
/**
|
|
15
18
|
* @file Substitute for the DOM Node Class.
|
|
16
19
|
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
@@ -35,8 +38,9 @@ class NodeService extends EventTargetService_1.default {
|
|
|
35
38
|
*/
|
|
36
39
|
constructor () {
|
|
37
40
|
super()
|
|
38
|
-
this.nodeValueStore =
|
|
39
|
-
this.
|
|
41
|
+
this.nodeValueStore = null
|
|
42
|
+
this.ownerDocumentStore = null
|
|
43
|
+
this.nodeId = NodeService.nextNodeId++
|
|
40
44
|
this.nodeNameValue = ''
|
|
41
45
|
this.children = (0, generateNodeList_1.default)()
|
|
42
46
|
this.parent = null
|
|
@@ -56,7 +60,8 @@ class NodeService extends EventTargetService_1.default {
|
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
get isConnected () {
|
|
59
|
-
|
|
63
|
+
// Connected means the tree the node is in has a document at the top
|
|
64
|
+
return this.getRootNode().nodeType === NodeService.DOCUMENT_NODE
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
get lastChild () {
|
|
@@ -84,7 +89,11 @@ class NodeService extends EventTargetService_1.default {
|
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
get ownerDocument () {
|
|
87
|
-
|
|
92
|
+
if (this.nodeType === NodeService.DOCUMENT_NODE) {
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
95
|
+
const root = this.getRootNode()
|
|
96
|
+
return root.nodeType === NodeService.DOCUMENT_NODE ? root : this.ownerDocumentStore
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
get parentNode () {
|
|
@@ -100,11 +109,34 @@ class NodeService extends EventTargetService_1.default {
|
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
get textContent () {
|
|
103
|
-
|
|
112
|
+
if (this.nodeType === NodeService.DOCUMENT_NODE || this.nodeType === NodeService.DOCUMENT_TYPE_NODE) {
|
|
113
|
+
return null
|
|
114
|
+
}
|
|
115
|
+
// The text of everything below, in order (comments and the like do not count)
|
|
116
|
+
let text = ''
|
|
117
|
+
Array.from(this.childNodes).forEach(child => {
|
|
118
|
+
if (child.nodeType === NodeService.TEXT_NODE) {
|
|
119
|
+
text += child.nodeValue
|
|
120
|
+
} else if (child.nodeType !== NodeService.COMMENT_NODE) {
|
|
121
|
+
text += child.textContent
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
return text
|
|
104
125
|
}
|
|
105
126
|
|
|
106
127
|
set textContent (text) {
|
|
107
|
-
this.
|
|
128
|
+
if (this.nodeType === NodeService.DOCUMENT_NODE || this.nodeType === NodeService.DOCUMENT_TYPE_NODE) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
// All the children are replaced by a single text node (or none for an empty text)
|
|
132
|
+
while (this.firstChild) {
|
|
133
|
+
this.removeChild(this.firstChild)
|
|
134
|
+
}
|
|
135
|
+
if (text !== null && typeof text !== 'undefined' && String(text) !== '') {
|
|
136
|
+
const textNode = new TextService(String(text))
|
|
137
|
+
textNode.ownerDocumentStore = this.ownerDocument
|
|
138
|
+
this.appendChild(textNode)
|
|
139
|
+
}
|
|
108
140
|
}
|
|
109
141
|
|
|
110
142
|
/**
|
|
@@ -116,6 +148,36 @@ class NodeService extends EventTargetService_1.default {
|
|
|
116
148
|
return this.insertBefore(childNode, null)
|
|
117
149
|
}
|
|
118
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Whether this kind of node can have children (text, comments and attributes cannot).
|
|
153
|
+
* @returns {boolean}
|
|
154
|
+
*/
|
|
155
|
+
get acceptsChildren () {
|
|
156
|
+
return true
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Make a copy of this node without its children, its parent or its listeners, which is what cloneNode starts from.
|
|
161
|
+
* Kinds of node which are made with arguments override this to give them.
|
|
162
|
+
* @returns {NodeService}
|
|
163
|
+
*/
|
|
164
|
+
cloneShallow () {
|
|
165
|
+
const copy = new this.constructor()
|
|
166
|
+
copy.nodeValue = this.nodeValue
|
|
167
|
+
copy.ownerDocumentStore = this.ownerDocumentStore
|
|
168
|
+
return copy
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Whether another node of the same type is equal to this one apart from its children, which isEqualNode compares
|
|
173
|
+
* afterwards. Kinds of node with more to compare (an element has attributes) override this.
|
|
174
|
+
* @param {NodeService} other The node to compare with
|
|
175
|
+
* @returns {boolean}
|
|
176
|
+
*/
|
|
177
|
+
equalsShallow (other) {
|
|
178
|
+
return this.nodeName === other.nodeName && this.nodeValue === other.nodeValue
|
|
179
|
+
}
|
|
180
|
+
|
|
119
181
|
/**
|
|
120
182
|
* Called each time a node has been inserted as a child of this node, so that nodes which need to react to children
|
|
121
183
|
* (for example elements applying default events) can do so.
|
|
@@ -123,19 +185,62 @@ class NodeService extends EventTargetService_1.default {
|
|
|
123
185
|
*/
|
|
124
186
|
childInserted (child) {}
|
|
125
187
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
188
|
+
* Make a copy of this node (without its parent, and without its event listeners). With deep the children are copied
|
|
189
|
+
* too, all the way down.
|
|
190
|
+
* @param {boolean} [deep=false] Copy the children as well
|
|
191
|
+
* @returns {PseudoNode}
|
|
128
192
|
*/
|
|
129
193
|
cloneNode (deep = false) {
|
|
130
|
-
|
|
194
|
+
const copy = this.cloneShallow()
|
|
195
|
+
if (deep) {
|
|
196
|
+
Array.from(this.childNodes).forEach(child => copy.appendChild(child.cloneNode(true)))
|
|
197
|
+
}
|
|
198
|
+
return copy
|
|
131
199
|
}
|
|
132
200
|
|
|
133
201
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
202
|
+
* Say where another node is in relation to this one, as the bits of NodeService.DOCUMENT_POSITION_*: 0 for this node
|
|
203
|
+
* itself, DISCONNECTED (with IMPLEMENTATION_SPECIFIC and a consistent PRECEDING or FOLLOWING) for a node in another tree,
|
|
204
|
+
* CONTAINS + PRECEDING when the other node is an ancestor, CONTAINED_BY + FOLLOWING when it is a descendant,
|
|
205
|
+
* otherwise PRECEDING or FOLLOWING by their order in the tree.
|
|
206
|
+
* @param {PseudoNode} otherNode The node to locate
|
|
207
|
+
* @returns {number}
|
|
136
208
|
*/
|
|
137
209
|
compareDocumentPosition (otherNode) {
|
|
138
|
-
|
|
210
|
+
if (otherNode === this) {
|
|
211
|
+
return 0
|
|
212
|
+
}
|
|
213
|
+
const pathFromRoot = node => {
|
|
214
|
+
const path = []
|
|
215
|
+
for (let current = node; current; current = current.parentNode) {
|
|
216
|
+
path.unshift(current)
|
|
217
|
+
}
|
|
218
|
+
return path
|
|
219
|
+
}
|
|
220
|
+
const mine = pathFromRoot(this)
|
|
221
|
+
const theirs = pathFromRoot(otherNode)
|
|
222
|
+
if (mine[0] !== theirs[0]) {
|
|
223
|
+
// Not in the same tree, so there is no real order: use a consistent one (the order the nodes were made in)
|
|
224
|
+
const before = otherNode.nodeId < this.nodeId ? NodeService.DOCUMENT_POSITION_PRECEDING : NodeService.DOCUMENT_POSITION_FOLLOWING
|
|
225
|
+
return NodeService.DOCUMENT_POSITION_DISCONNECTED | NodeService.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | before
|
|
226
|
+
}
|
|
227
|
+
if (theirs.length < mine.length && theirs.every((node, index) => mine[index] === node)) {
|
|
228
|
+
return NodeService.DOCUMENT_POSITION_CONTAINS | NodeService.DOCUMENT_POSITION_PRECEDING
|
|
229
|
+
}
|
|
230
|
+
if (mine.length < theirs.length && mine.every((node, index) => theirs[index] === node)) {
|
|
231
|
+
return NodeService.DOCUMENT_POSITION_CONTAINED_BY | NodeService.DOCUMENT_POSITION_FOLLOWING
|
|
232
|
+
}
|
|
233
|
+
// The paths part ways at siblings: whichever comes first among them is first in the tree
|
|
234
|
+
let depth = 0
|
|
235
|
+
while (mine[depth] === theirs[depth]) {
|
|
236
|
+
++depth
|
|
237
|
+
}
|
|
238
|
+
for (let sibling = mine[depth].nextSibling; sibling; sibling = sibling.nextSibling) {
|
|
239
|
+
if (sibling === theirs[depth]) {
|
|
240
|
+
return NodeService.DOCUMENT_POSITION_FOLLOWING
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return NodeService.DOCUMENT_POSITION_PRECEDING
|
|
139
244
|
}
|
|
140
245
|
|
|
141
246
|
/**
|
|
@@ -173,6 +278,9 @@ class NodeService extends EventTargetService_1.default {
|
|
|
173
278
|
* @throws {Error} When the reference node is not a child of this node, or the new node is this node or contains it
|
|
174
279
|
*/
|
|
175
280
|
insertBefore (newNode, referenceNode = null) {
|
|
281
|
+
if (!this.acceptsChildren) {
|
|
282
|
+
throw new Error('This kind of node cannot have children.')
|
|
283
|
+
}
|
|
176
284
|
if (referenceNode !== null && referenceNode.parentNode !== this) {
|
|
177
285
|
throw new Error('The node before which the new node is to be inserted is not a child of this node.')
|
|
178
286
|
}
|
|
@@ -210,11 +318,18 @@ class NodeService extends EventTargetService_1.default {
|
|
|
210
318
|
}
|
|
211
319
|
|
|
212
320
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
321
|
+
* Whether another node is the same as this one, by what they hold: the same type, name and value (an element also
|
|
322
|
+
* needs the same attributes), and children which are equal in the same order.
|
|
323
|
+
* @param {PseudoNode|null} otherNode The node to compare with
|
|
324
|
+
* @returns {boolean}
|
|
215
325
|
*/
|
|
216
326
|
isEqualNode (otherNode) {
|
|
217
|
-
|
|
327
|
+
if (!otherNode || otherNode.nodeType !== this.nodeType || !this.equalsShallow(otherNode)) {
|
|
328
|
+
return false
|
|
329
|
+
}
|
|
330
|
+
const mine = Array.from(this.childNodes)
|
|
331
|
+
const theirs = Array.from(otherNode.childNodes)
|
|
332
|
+
return mine.length === theirs.length && mine.every((child, index) => child.isEqualNode(theirs[index]))
|
|
218
333
|
}
|
|
219
334
|
|
|
220
335
|
isSameNode (otherNode) {
|
|
@@ -229,7 +344,34 @@ class NodeService extends EventTargetService_1.default {
|
|
|
229
344
|
return null
|
|
230
345
|
}
|
|
231
346
|
|
|
232
|
-
|
|
347
|
+
/**
|
|
348
|
+
* Tidy the text below this node: neighbouring text nodes are joined into one and empty text nodes are removed.
|
|
349
|
+
*/
|
|
350
|
+
normalize () {
|
|
351
|
+
let child = this.firstChild
|
|
352
|
+
while (child) {
|
|
353
|
+
if (child.nodeType === NodeService.TEXT_NODE) {
|
|
354
|
+
// Join the text nodes which follow into this one, and drop it when it is empty
|
|
355
|
+
let text = child.nodeValue
|
|
356
|
+
let following = child.nextSibling
|
|
357
|
+
while (following && following.nodeType === NodeService.TEXT_NODE) {
|
|
358
|
+
text += following.nodeValue
|
|
359
|
+
const after = following.nextSibling
|
|
360
|
+
this.removeChild(following)
|
|
361
|
+
following = after
|
|
362
|
+
}
|
|
363
|
+
child.nodeValue = text
|
|
364
|
+
if (text === '') {
|
|
365
|
+
this.removeChild(child)
|
|
366
|
+
}
|
|
367
|
+
child = following
|
|
368
|
+
} else {
|
|
369
|
+
child.normalize()
|
|
370
|
+
child = child.nextSibling
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
233
375
|
/**
|
|
234
376
|
* Remove a child from this node, it no longer has a parent or siblings afterwards.
|
|
235
377
|
* @param {PseudoNode} childElement The child node to remove
|
|
@@ -285,3 +427,157 @@ NodeService.DOCUMENT_NODE = 9
|
|
|
285
427
|
NodeService.DOCUMENT_TYPE_NODE = 10
|
|
286
428
|
NodeService.DOCUMENT_FRAGMENT_NODE = 11
|
|
287
429
|
NodeService.NOTATION_NODE = 12
|
|
430
|
+
NodeService.DOCUMENT_POSITION_DISCONNECTED = 1
|
|
431
|
+
NodeService.DOCUMENT_POSITION_PRECEDING = 2
|
|
432
|
+
NodeService.DOCUMENT_POSITION_FOLLOWING = 4
|
|
433
|
+
NodeService.DOCUMENT_POSITION_CONTAINS = 8
|
|
434
|
+
NodeService.DOCUMENT_POSITION_CONTAINED_BY = 16
|
|
435
|
+
NodeService.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 32
|
|
436
|
+
NodeService.nextNodeId = 1
|
|
437
|
+
/**
|
|
438
|
+
* Simulate the behaviour of the Text Class when there is no DOM available: the text in an element.
|
|
439
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
440
|
+
* @class
|
|
441
|
+
* @augments NodeService
|
|
442
|
+
* @property {string} data - The text
|
|
443
|
+
* @property {number} length - How many characters there are
|
|
444
|
+
* @property {string} wholeText - The text of this node and of the text nodes next to it
|
|
445
|
+
*/
|
|
446
|
+
class TextService extends NodeService {
|
|
447
|
+
/**
|
|
448
|
+
* @param {string} [data=''] The text
|
|
449
|
+
* @constructor
|
|
450
|
+
*/
|
|
451
|
+
constructor (data = '') {
|
|
452
|
+
super()
|
|
453
|
+
this.nodeValue = String(data)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
get acceptsChildren () {
|
|
457
|
+
return false
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
get nodeName () {
|
|
461
|
+
return '#text'
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
get nodeType () {
|
|
465
|
+
return NodeService.TEXT_NODE
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
get data () {
|
|
469
|
+
return this.nodeValue
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
set data (data) {
|
|
473
|
+
this.nodeValue = String(data)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
get length () {
|
|
477
|
+
return this.data.length
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
get textContent () {
|
|
481
|
+
return this.data
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
set textContent (text) {
|
|
485
|
+
this.data = text === null ? '' : String(text)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
get wholeText () {
|
|
489
|
+
let first = this
|
|
490
|
+
while (first.previousSibling && first.previousSibling.nodeType === NodeService.TEXT_NODE) {
|
|
491
|
+
first = first.previousSibling
|
|
492
|
+
}
|
|
493
|
+
let text = ''
|
|
494
|
+
for (let current = first; current && current.nodeType === NodeService.TEXT_NODE; current = current.nextSibling) {
|
|
495
|
+
text += current.nodeValue
|
|
496
|
+
}
|
|
497
|
+
return text
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Break this text node in two at a position: this node keeps the text before it and a new node with the rest is put
|
|
502
|
+
* after this one.
|
|
503
|
+
* @param {number} offset How many characters stay in this node
|
|
504
|
+
* @returns {TextService} The new node
|
|
505
|
+
* @throws {Error} When the offset is beyond the end of the text
|
|
506
|
+
*/
|
|
507
|
+
splitText (offset) {
|
|
508
|
+
if (offset < 0 || offset > this.length) {
|
|
509
|
+
throw new Error('The offset is beyond the end of the text.')
|
|
510
|
+
}
|
|
511
|
+
const rest = new TextService(this.data.slice(offset))
|
|
512
|
+
rest.ownerDocumentStore = this.ownerDocumentStore
|
|
513
|
+
this.data = this.data.slice(0, offset)
|
|
514
|
+
if (this.parentNode) {
|
|
515
|
+
this.parentNode.insertBefore(rest, this.nextSibling)
|
|
516
|
+
}
|
|
517
|
+
return rest
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
cloneShallow () {
|
|
521
|
+
const copy = new TextService(this.data)
|
|
522
|
+
copy.ownerDocumentStore = this.ownerDocumentStore
|
|
523
|
+
return copy
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
exports.TextService = TextService
|
|
527
|
+
/**
|
|
528
|
+
* Simulate the behaviour of the Comment Class when there is no DOM available: a note in the markup which is not shown.
|
|
529
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
530
|
+
* @class
|
|
531
|
+
* @augments NodeService
|
|
532
|
+
* @property {string} data - The comment
|
|
533
|
+
* @property {number} length - How many characters there are
|
|
534
|
+
*/
|
|
535
|
+
class CommentService extends NodeService {
|
|
536
|
+
/**
|
|
537
|
+
* @param {string} [data=''] The comment
|
|
538
|
+
* @constructor
|
|
539
|
+
*/
|
|
540
|
+
constructor (data = '') {
|
|
541
|
+
super()
|
|
542
|
+
this.nodeValue = String(data)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
get acceptsChildren () {
|
|
546
|
+
return false
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
get nodeName () {
|
|
550
|
+
return '#comment'
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
get nodeType () {
|
|
554
|
+
return NodeService.COMMENT_NODE
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
get data () {
|
|
558
|
+
return this.nodeValue
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
set data (data) {
|
|
562
|
+
this.nodeValue = String(data)
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
get length () {
|
|
566
|
+
return this.data.length
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
get textContent () {
|
|
570
|
+
return this.data
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
set textContent (text) {
|
|
574
|
+
this.data = text === null ? '' : String(text)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
cloneShallow () {
|
|
578
|
+
const copy = new CommentService(this.data)
|
|
579
|
+
copy.ownerDocumentStore = this.ownerDocumentStore
|
|
580
|
+
return copy
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
exports.CommentService = CommentService
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var __importDefault=function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.NodeService=void 0;const generateNodeList_1=__importDefault(require("../factories/generateNodeList")),TreeLinker_1=require("collect-your-stuff/dist/collections/linked-tree-list/TreeLinker"),EventTargetService_1=__importDefault(require("./EventTargetService"));class NodeService extends EventTargetService_1.default{constructor(){super(),this.nodeValueStore=
|
|
1
|
+
"use strict";require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.every.js"),require("core-js/modules/esnext.iterator.for-each.js");var __importDefault=function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.CommentService=exports.TextService=exports.NodeService=void 0;const generateNodeList_1=__importDefault(require("../factories/generateNodeList")),TreeLinker_1=require("collect-your-stuff/dist/collections/linked-tree-list/TreeLinker"),EventTargetService_1=__importDefault(require("./EventTargetService"));class NodeService extends EventTargetService_1.default{constructor(){super(),this.nodeValueStore=null,this.ownerDocumentStore=null,this.nodeId=NodeService.nextNodeId++,this.nodeNameValue="",this.children=(0,generateNodeList_1.default)(),this.parent=null,this.listLinker=null}get baseURI(){return window.location||"/"}get childNodes(){return this.children}get firstChild(){return this.children.first?this.children.first.data:null}get isConnected(){return this.getRootNode().nodeType===NodeService.DOCUMENT_NODE}get lastChild(){return this.children.last?this.children.last.data:null}get nextSibling(){return this.listLinker&&this.listLinker.next?this.listLinker.next.data:null}get nodeName(){return this.nodeNameValue||""}get nodeType(){return NodeService.DEFAULT_NODE}get nodeValue(){return this.nodeValueStore}set nodeValue(e){this.nodeValueStore=e}get ownerDocument(){if(this.nodeType===NodeService.DOCUMENT_NODE)return null;const e=this.getRootNode();return e.nodeType===NodeService.DOCUMENT_NODE?e:this.ownerDocumentStore}get parentNode(){return this.parent}get parentElement(){return this.parent&&this.parent.nodeType===NodeService.ELEMENT_NODE?this.parent:null}get previousSibling(){return this.listLinker&&this.listLinker.prev?this.listLinker.prev.data:null}get textContent(){if(this.nodeType===NodeService.DOCUMENT_NODE||this.nodeType===NodeService.DOCUMENT_TYPE_NODE)return null;let e="";return Array.from(this.childNodes).forEach(t=>{t.nodeType===NodeService.TEXT_NODE?e+=t.nodeValue:t.nodeType!==NodeService.COMMENT_NODE&&(e+=t.textContent)}),e}set textContent(e){if(this.nodeType!==NodeService.DOCUMENT_NODE&&this.nodeType!==NodeService.DOCUMENT_TYPE_NODE){for(;this.firstChild;)this.removeChild(this.firstChild);if(null!=e&&""!==String(e)){const t=new TextService(String(e));t.ownerDocumentStore=this.ownerDocument,this.appendChild(t)}}}appendChild(e){return this.insertBefore(e,null)}get acceptsChildren(){return!0}cloneShallow(){const e=new this.constructor;return e.nodeValue=this.nodeValue,e.ownerDocumentStore=this.ownerDocumentStore,e}equalsShallow(e){return this.nodeName===e.nodeName&&this.nodeValue===e.nodeValue}childInserted(e){}cloneNode(e=!1){const t=this.cloneShallow();return e&&Array.from(this.childNodes).forEach(e=>t.appendChild(e.cloneNode(!0))),t}compareDocumentPosition(e){if(e===this)return 0;const t=e=>{const t=[];for(let r=e;r;r=r.parentNode)t.unshift(r);return t},r=t(this),n=t(e);if(r[0]!==n[0]){const t=e.nodeId<this.nodeId?NodeService.DOCUMENT_POSITION_PRECEDING:NodeService.DOCUMENT_POSITION_FOLLOWING;return NodeService.DOCUMENT_POSITION_DISCONNECTED|NodeService.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC|t}if(n.length<r.length&&n.every((e,t)=>r[t]===e))return NodeService.DOCUMENT_POSITION_CONTAINS|NodeService.DOCUMENT_POSITION_PRECEDING;if(r.length<n.length&&r.every((e,t)=>n[t]===e))return NodeService.DOCUMENT_POSITION_CONTAINED_BY|NodeService.DOCUMENT_POSITION_FOLLOWING;let i=0;for(;r[i]===n[i];)++i;for(let e=r[i].nextSibling;e;e=e.nextSibling)if(e===n[i])return NodeService.DOCUMENT_POSITION_FOLLOWING;return NodeService.DOCUMENT_POSITION_PRECEDING}contains(e){let t=e;for(;t;){if(t===this)return!0;t=t.parentNode}return!1}getRootNode(e={composed:!1}){return this.parent?this.parent.getRootNode(e):this}hasChildNodes(){return this.children.length>0}insertBefore(e,t=null){if(!this.acceptsChildren)throw new Error("This kind of node cannot have children.");if(null!==t&&t.parentNode!==this)throw new Error("The node before which the new node is to be inserted is not a child of this node.");if(e===t)return e;if("function"==typeof e.contains&&e.contains(this))throw new Error("The new node cannot be inserted into itself or one of its own descendants.");if(e.nodeType===NodeService.DOCUMENT_FRAGMENT_NODE){for(;e.firstChild;)this.insertBefore(e.firstChild,t);return e}e.parentNode&&e.parentNode.removeChild(e);const r=new TreeLinker_1.TreeLinker({data:e});this.children.insertBefore(t?t.listLinker:null,r);const n=e;return n.parent=this,n.listLinker=r,this.childInserted(n),e}isDefaultNamespace(e){return null===e}isEqualNode(e){if(!e||e.nodeType!==this.nodeType||!this.equalsShallow(e))return!1;const t=Array.from(this.childNodes),r=Array.from(e.childNodes);return t.length===r.length&&t.every((e,t)=>e.isEqualNode(r[t]))}isSameNode(e){return this===e}lookupPrefix(e){return null}lookupNamespaceURI(e){return null}normalize(){let e=this.firstChild;for(;e;)if(e.nodeType===NodeService.TEXT_NODE){let t=e.nodeValue,r=e.nextSibling;for(;r&&r.nodeType===NodeService.TEXT_NODE;){t+=r.nodeValue;const e=r.nextSibling;this.removeChild(r),r=e}e.nodeValue=t,""===t&&this.removeChild(e),e=r}else e.normalize(),e=e.nextSibling}removeChild(e){if(!e||e.parentNode!==this)throw new Error("The node to be removed is not a child of this node.");const t=e;return this.children.remove(t.listLinker),t.parent=null,t.listLinker=null,e}replaceChild(e,t){if(!t||t.parentNode!==this)throw new Error("The node to be replaced is not a child of this node.");if(e===t)return t;let r=t.nextSibling;return r===e&&(r=e.nextSibling),this.removeChild(t),this.insertBefore(e,r),t}}exports.NodeService=NodeService,NodeService.DEFAULT_NODE=0,NodeService.ELEMENT_NODE=1,NodeService.ATTRIBUTE_NODE=2,NodeService.TEXT_NODE=3,NodeService.CDATA_SECTION_NODE=4,NodeService.ENTITY_REFERENCE_NODE=5,NodeService.ENTITY_NODE=6,NodeService.PROCESSING_INSTRUCTION_NODE=7,NodeService.COMMENT_NODE=8,NodeService.DOCUMENT_NODE=9,NodeService.DOCUMENT_TYPE_NODE=10,NodeService.DOCUMENT_FRAGMENT_NODE=11,NodeService.NOTATION_NODE=12,NodeService.DOCUMENT_POSITION_DISCONNECTED=1,NodeService.DOCUMENT_POSITION_PRECEDING=2,NodeService.DOCUMENT_POSITION_FOLLOWING=4,NodeService.DOCUMENT_POSITION_CONTAINS=8,NodeService.DOCUMENT_POSITION_CONTAINED_BY=16,NodeService.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC=32,NodeService.nextNodeId=1;class TextService extends NodeService{constructor(e=""){super(),this.nodeValue=String(e)}get acceptsChildren(){return!1}get nodeName(){return"#text"}get nodeType(){return NodeService.TEXT_NODE}get data(){return this.nodeValue}set data(e){this.nodeValue=String(e)}get length(){return this.data.length}get textContent(){return this.data}set textContent(e){this.data=null===e?"":String(e)}get wholeText(){let e=this;for(;e.previousSibling&&e.previousSibling.nodeType===NodeService.TEXT_NODE;)e=e.previousSibling;let t="";for(let r=e;r&&r.nodeType===NodeService.TEXT_NODE;r=r.nextSibling)t+=r.nodeValue;return t}splitText(e){if(e<0||e>this.length)throw new Error("The offset is beyond the end of the text.");const t=new TextService(this.data.slice(e));return t.ownerDocumentStore=this.ownerDocumentStore,this.data=this.data.slice(0,e),this.parentNode&&this.parentNode.insertBefore(t,this.nextSibling),t}cloneShallow(){const e=new TextService(this.data);return e.ownerDocumentStore=this.ownerDocumentStore,e}}exports.TextService=TextService;class CommentService extends NodeService{constructor(e=""){super(),this.nodeValue=String(e)}get acceptsChildren(){return!1}get nodeName(){return"#comment"}get nodeType(){return NodeService.COMMENT_NODE}get data(){return this.nodeValue}set data(e){this.nodeValue=String(e)}get length(){return this.data.length}get textContent(){return this.data}set textContent(e){this.data=null===e?"":String(e)}cloneShallow(){const e=new CommentService(this.data);return e.ownerDocumentStore=this.ownerDocumentStore,e}}exports.CommentService=CommentService;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Substitute for the DOM PointerEvent Class.
|
|
3
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { MouseEventInit, MouseEventService } from './MouseEventService';
|
|
7
|
+
/**
|
|
8
|
+
* The options for creating a pointer event, on top of the ones every mouse event has.
|
|
9
|
+
* @typedef {Object} PointerEventInit
|
|
10
|
+
* @property {number} [pointerId=0]
|
|
11
|
+
* @property {number} [width=1]
|
|
12
|
+
* @property {number} [height=1]
|
|
13
|
+
* @property {number} [pressure=0]
|
|
14
|
+
* @property {string} [pointerType=''] mouse, pen or touch
|
|
15
|
+
* @property {boolean} [isPrimary=false]
|
|
16
|
+
*/
|
|
17
|
+
export type PointerEventInit = MouseEventInit & {
|
|
18
|
+
pointerId?: number;
|
|
19
|
+
width?: number;
|
|
20
|
+
height?: number;
|
|
21
|
+
pressure?: number;
|
|
22
|
+
pointerType?: string;
|
|
23
|
+
isPrimary?: boolean;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Simulate the behaviour of the PointerEvent Class when there is no DOM available.
|
|
27
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
28
|
+
* @class
|
|
29
|
+
* @augments MouseEventService
|
|
30
|
+
* @property {number} pointerId
|
|
31
|
+
* @property {number} width
|
|
32
|
+
* @property {number} height
|
|
33
|
+
* @property {number} pressure
|
|
34
|
+
* @property {string} pointerType
|
|
35
|
+
* @property {boolean} isPrimary
|
|
36
|
+
*/
|
|
37
|
+
export declare class PointerEventService extends MouseEventService {
|
|
38
|
+
private readonly pointer;
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} [typeArg=''] The type of the event
|
|
41
|
+
* @param {PointerEventInit} [init={}] The options for the event
|
|
42
|
+
* @constructor
|
|
43
|
+
*/
|
|
44
|
+
constructor(typeArg?: string, init?: PointerEventInit);
|
|
45
|
+
get pointerId(): number;
|
|
46
|
+
get width(): number;
|
|
47
|
+
get height(): number;
|
|
48
|
+
get pressure(): number;
|
|
49
|
+
get pointerType(): string;
|
|
50
|
+
get isPrimary(): boolean;
|
|
51
|
+
}
|