als-document 0.5.0 → 0.6.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/document/document.js +192 -0
- package/document/test.js +678 -0
- package/document.js +372 -142
- package/document.min.js +1 -0
- package/index.js +6 -0
- package/package.json +3 -3
- package/parser/parser.js +89 -40
- package/parser/test.js +7 -7
- package/query/query.js +1 -1
- package/query/readme.md +5 -2
- package/readme.md +242 -68
- package/selector/selector.js +14 -13
- package/selector/test.js +1 -1
- package/test/test.js +3 -1
- package/parser/readme.md +0 -121
- package/selector/readme.md +0 -74
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
let HtmlSelector = require('../selector/selector')
|
|
2
|
+
let HtmlParser = require('../parser/parser')
|
|
3
|
+
|
|
4
|
+
class Document extends HtmlSelector {
|
|
5
|
+
constructor(html) {
|
|
6
|
+
super(html)
|
|
7
|
+
this.elements.forEach((element) => {this.addMethods(element)});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
addMethods(element) {
|
|
11
|
+
if(element.type == 'tag' && element.status !== 'close') {
|
|
12
|
+
this.insert(element)
|
|
13
|
+
this.buildAttribs(element)
|
|
14
|
+
this.classlistMethods(element)
|
|
15
|
+
this.style(element)
|
|
16
|
+
this.id(element)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
id(element,self=this) {
|
|
21
|
+
if(element.id !== undefined)
|
|
22
|
+
if(!!Object.getOwnPropertyDescriptor(element, 'id')['get']) return
|
|
23
|
+
if(element.id == null || element.id !== undefined) {
|
|
24
|
+
if(typeof element.id == 'string') delete element.id
|
|
25
|
+
Object.defineProperty(element, 'id', {
|
|
26
|
+
get() {return this.attribs.id ? this.attribs.id : null},
|
|
27
|
+
set(value) {
|
|
28
|
+
this.attribs.id = value
|
|
29
|
+
self.changeElementText(this)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
style(element,obj={},self=this) {
|
|
36
|
+
if(element.style !== undefined) obj = {...element.style}
|
|
37
|
+
const convertProp = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
|
|
38
|
+
const handler = {
|
|
39
|
+
get(target,prop,receiver) {
|
|
40
|
+
if(prop === 'target') return target
|
|
41
|
+
return Reflect.get(...arguments);
|
|
42
|
+
},
|
|
43
|
+
set(obj, prop, value) {
|
|
44
|
+
obj[prop] = value
|
|
45
|
+
element.attribs.style = Object.keys(obj).map(key => `${convertProp(key)}:${obj[key]};`).join('')
|
|
46
|
+
self.changeElementText(this)
|
|
47
|
+
},
|
|
48
|
+
deleteProperty(obj, prop) {
|
|
49
|
+
if (prop in obj) {
|
|
50
|
+
delete obj[prop];
|
|
51
|
+
element.attribs.style = Object.keys(obj).map(key => `${convertProp(key)}:${obj[key]};`).join('')
|
|
52
|
+
}
|
|
53
|
+
self.changeElementText(this)
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
element.style = new Proxy(obj, handler);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
classlistMethods(element,self=this) {
|
|
60
|
+
if(element.classList == undefined) element.classList = []
|
|
61
|
+
element.classList.add = function(newClass) {
|
|
62
|
+
if(element.attribs.class == undefined) element.attribs.class = ''
|
|
63
|
+
this.push(newClass)
|
|
64
|
+
element.attribs.class += ' '+newClass
|
|
65
|
+
self.changeElementText(this)
|
|
66
|
+
}
|
|
67
|
+
element.classList.remove = function(clsToRemove) {
|
|
68
|
+
this.splice(this.indexOf(clsToRemove),1)
|
|
69
|
+
element.attribs.class = this.filter(c => c !== undefined).join(' ')
|
|
70
|
+
self.changeElementText(this)
|
|
71
|
+
}
|
|
72
|
+
element.classList.toggle = function(clsToToggle) {
|
|
73
|
+
if(this.includes(clsToToggle)) this.remove(clsToToggle)
|
|
74
|
+
else this.add(clsToToggle)
|
|
75
|
+
self.changeElementText(this)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
buildAttribs(element,self=this) {
|
|
80
|
+
if(!element.attr) element.attr = function(name,value) {
|
|
81
|
+
let notForRemove = ['class','style','id']
|
|
82
|
+
let notForChange = ['style','id']
|
|
83
|
+
if(name && value === undefined) return this.attribs[name]
|
|
84
|
+
else if(name && value === null && !notForRemove.includes(name)) {
|
|
85
|
+
delete this.attribs[name]
|
|
86
|
+
} else if(name && value !== undefined && value !== null && !notForChange.includes(name)) {
|
|
87
|
+
this.attribs[name] = value
|
|
88
|
+
if(name == 'class') {
|
|
89
|
+
this.classList = value.split(' ').filter(c => c !== ' ')
|
|
90
|
+
self.classlistMethods(this)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
self.changeElementText(this)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
insert(element) {
|
|
98
|
+
let self = this
|
|
99
|
+
element.insert = function(newElement,pos=0) {
|
|
100
|
+
let elements
|
|
101
|
+
let $elements = this.$elements
|
|
102
|
+
if(typeof newElement == 'string') {
|
|
103
|
+
newElement = new HtmlParser(newElement)
|
|
104
|
+
newElement.elements.forEach(el => {
|
|
105
|
+
self.html.getElements(el)
|
|
106
|
+
self.makeSelectable(el);
|
|
107
|
+
self.addMethods(el);
|
|
108
|
+
});
|
|
109
|
+
elements = newElement.elements
|
|
110
|
+
newElement = newElement.root.children[0]
|
|
111
|
+
} else {
|
|
112
|
+
let {index,endIndex} = newElement
|
|
113
|
+
let count = isNaN(endIndex - index) ? 1 : endIndex - index+1
|
|
114
|
+
elements = $elements.splice(index,count)
|
|
115
|
+
let {parent,childIndex} = newElement
|
|
116
|
+
parent.children.splice(childIndex,1)
|
|
117
|
+
}
|
|
118
|
+
self.rebildElements($elements)
|
|
119
|
+
self.addElement(this,$elements,newElement,elements,pos)
|
|
120
|
+
}
|
|
121
|
+
element.remove = function() {
|
|
122
|
+
let {$elements,elements,parent,childIndex,index} = this
|
|
123
|
+
$elements.splice(index,elements.length)
|
|
124
|
+
parent.children.splice(childIndex,1)
|
|
125
|
+
parent.endIndex = parent.endIndex-elements.length
|
|
126
|
+
self.rebildElements($elements)
|
|
127
|
+
}
|
|
128
|
+
Object.defineProperty(element, 'before', { set(newEl) {this.insert(newEl,0)}})
|
|
129
|
+
Object.defineProperty(element, 'after', { set(newEl) {this.insert(newEl,3)}})
|
|
130
|
+
Object.defineProperty(element, 'last', { set(newEl) {this.insert(newEl,2)}})
|
|
131
|
+
Object.defineProperty(element, 'first', { set(newEl) {this.insert(newEl,1)}})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
addElement(element,$elements,newElement,elements,pos) {
|
|
135
|
+
let {parent,level,index,endIndex} = element
|
|
136
|
+
if(pos == 0) { // beforebegin
|
|
137
|
+
$elements.splice(index,0,...elements) // add elements to $elements
|
|
138
|
+
parent.children.splice(element.childIndex,0,newElement) // add as child before
|
|
139
|
+
} else if(pos == 3) { // afterend
|
|
140
|
+
$elements.splice(endIndex+1,0,...elements) // add elements to $elements
|
|
141
|
+
parent.children.splice(element.childIndex+1,0,newElement) // add element as child after
|
|
142
|
+
} else if(pos == 1 || pos == 2) {
|
|
143
|
+
level = level+1
|
|
144
|
+
parent = element
|
|
145
|
+
if(pos == 1) { // afterbegin
|
|
146
|
+
$elements.splice(index+1,0,...elements) // add elements to $elements
|
|
147
|
+
element.children.unshift(newElement) // add element as first child
|
|
148
|
+
} else if(pos == 2) { // beforeend
|
|
149
|
+
$elements.splice(endIndex-1,0,...elements) // add elements to $elements
|
|
150
|
+
element.children.push(newElement) // add element as last child
|
|
151
|
+
}
|
|
152
|
+
element.endIndex = element.endIndex + elements.length
|
|
153
|
+
}
|
|
154
|
+
this.rebildElements($elements)
|
|
155
|
+
this.rebuildChild(elements[0],parent,element.html,level)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
rebildElements($elements) {
|
|
159
|
+
for(let i=0; i<$elements.length; i++) {
|
|
160
|
+
let {endIndex,index} = $elements[i]
|
|
161
|
+
if(endIndex) {
|
|
162
|
+
let gap = endIndex - index
|
|
163
|
+
$elements[i].endIndex = i + gap
|
|
164
|
+
}
|
|
165
|
+
$elements[i].index = i
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
rebuildChild(child,parent,html,level) {
|
|
170
|
+
if(child.endIndex !== undefined) { // add level to close tag
|
|
171
|
+
child.elements[child.elements.length-1].level = level
|
|
172
|
+
}
|
|
173
|
+
html.getElements(child,html) // bind element to this.$elements
|
|
174
|
+
child.parent = parent
|
|
175
|
+
child.level = level
|
|
176
|
+
if(child.children)
|
|
177
|
+
if(child.children.length > 0)
|
|
178
|
+
child.children.forEach(grandChild => {
|
|
179
|
+
this.rebuildChild(grandChild,child,html,level+1)
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
changeElementText(element) {
|
|
184
|
+
let {type,status,attribs,tag} = element
|
|
185
|
+
if(type == 'tag' && status !== 'close') {
|
|
186
|
+
let atts = Object.keys(attribs)
|
|
187
|
+
atts = atts.length>0 ? ' '+atts.map(name => `${name}${attribs[name] ? `="${attribs[name]}"`: ''}`).join(' ') : ''
|
|
188
|
+
element.text = `<${tag}${atts}>`
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
module.exports = Document
|