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.
@@ -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