als-document 0.1.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.
Files changed (3) hide show
  1. package/document.js +584 -0
  2. package/package.json +14 -0
  3. package/readme.md +196 -0
package/document.js ADDED
@@ -0,0 +1,584 @@
1
+ class Document {
2
+ static singlTags = ['comment','area','base','br','col','command','embed','hr','img','input','keygen','link','meta','param','source','track','wbr']
3
+ constructor(htmlText) {
4
+ if(typeof htmlText !== 'string') return
5
+ this.types = {}
6
+ this.domTree = []
7
+ this.added = []
8
+ this.domList = []
9
+ this.comments = []
10
+ this.scripts = {}
11
+ this.events = {}
12
+ this.htmlText = htmlText
13
+ this.doctype = ''
14
+ this.getDoctype()
15
+ this.removeComments()
16
+ this.removeScripts()
17
+ this.removeEvents()
18
+ this.parseTags()
19
+ this.addScripts()
20
+ this.addEvents()
21
+ this.addComments()
22
+ this.getPairs()
23
+ }
24
+ // Get domList
25
+ getDoctype() {
26
+ let doctype = this.htmlText.match(/\<\!DOCTYPE([\S\s]*?)\>/gm,'')
27
+ if(doctype !== null) {
28
+ this.doctype = doctype[0]
29
+ this.htmlText = this.htmlText.replace(/\<\!DOCTYPE([\S\s]*?)\>/gm,'')
30
+ }
31
+ }
32
+
33
+ removeComments() {
34
+ let comments = this.htmlText.match(/\<\!\-\-([\S\s]*?)\-\-\>/gm,'')
35
+ if(comments !== null) comments.forEach((comment,i) => {
36
+ let commentTag = `<comment comment-id="${i}">`
37
+ this.comments.push(comment)
38
+ this.htmlText = this.htmlText.replace(comment,commentTag)
39
+ });
40
+ }
41
+
42
+ addComments() {
43
+ this.domList.forEach((element,i) => {
44
+ if(element.tagName == 'comment') {
45
+ let id = this.domList[i].attributes['comment-id']
46
+ let comment = this.comments[id]
47
+ if(comment !== undefined) {
48
+ this.domList[i].comment = comment
49
+ delete this.comments[i]
50
+ }
51
+ }
52
+ });
53
+ }
54
+
55
+ removeScripts() {
56
+ let scripts = this.htmlText.match(/\<script(.*?)\>[\S\s]*?\<\/script\>/gm)
57
+ if(scripts !== null) scripts.forEach((script,i) => {
58
+ let scriptContent = script.replace(/\<script(.*?)\>/,'').replace('</script>','')
59
+ if(scriptContent.trim() !== '') {
60
+ let scriptName = `{script${i}}`
61
+ let newScript = script.replace(scriptContent,scriptName)
62
+ this.scripts[scriptName] = scriptContent
63
+ this.htmlText = this.htmlText.replace(script,newScript)
64
+ }
65
+ });
66
+ }
67
+
68
+ removeEvents() {
69
+ let events = ['abort','afterprint','animationend','animationiteration','animationstart','beforeprint','beforeunload','blur','canplay','canplaythrough','change','click','contextmenu','copy','cut','dblclick','drag','dragend','dragenter','dragleave','dragover','dragstart','drop','durationchange','ended','error','focus','focusin','focusout','fullscreenchange','fullscreenerror','hashchange','input','invalid','keydown','keypress','keyup','load','loadeddata','loadedmetadata','loadstart','message','mousedown','mouseenter','mouseleave','mousemove','mouseover','mouseout','mouseup','mousewheel','offline','online','open','pagehide','pageshow','paste','pause','play','playing','popstate','progress','ratechange','resize','reset','scroll','search','seeked','seeking','select','show','stalled','storage','submit','suspend','timeupdate','toggle','touchcancel','touchend','touchmove','touchstart','transitionend','unload','volumechange','waiting','wheel']
70
+ events.forEach(event => {
71
+ let r = new RegExp(`on${event}\\s?\\=\\s?"[\\S\\s]*?\\"`,'g')
72
+ let scripts = this.htmlText.match(r)
73
+ if(scripts !== null) scripts.forEach((script,i) => {
74
+ let scriptContent = script.replace(`on${event}`,'').replace('=','').replace(/\"/g,'')
75
+ if(scriptContent.trim() !== '') {
76
+ let scriptName = `{script${i}}`
77
+ let newScript = script.replace(scriptContent,scriptName)
78
+ this.events[scriptName] = scriptContent
79
+ this.htmlText = this.htmlText.replace(script,newScript)
80
+ }
81
+ });
82
+ });
83
+ }
84
+
85
+ addScripts() {
86
+ this.domList.forEach((element,i) => {
87
+ if(element.tagName == 'script' && !element.close) {
88
+ let text = this.domList[i+1].text
89
+ if(this.scripts[text] !== undefined) {
90
+ this.domList[i+1].text = this.scripts[text]
91
+ delete this.scripts[text]
92
+ }
93
+ }
94
+ });
95
+ }
96
+
97
+ addEvents() {
98
+ this.domList.forEach((element,i) => {
99
+ if(element.attributes !== undefined) {
100
+ for(let attName in element.attributes) {
101
+ let attValue = element.attributes[attName]
102
+ if(this.events[attValue] !== undefined) {
103
+ this.domList[i].attributes[attName] = this.events[attValue]
104
+ delete this.events[attValue]
105
+ }
106
+ }
107
+ }
108
+ });
109
+ }
110
+
111
+ parseTags() {
112
+ let outerHTML = this.htmlText
113
+ let outerHtmlForCut = outerHTML
114
+ let tags = outerHTML.match(/\<(\w*-?)*?(.*?)?([\S\s]*?)\>/gm)
115
+ let index = 0
116
+ if(tags !== null) tags.forEach((tag,i) => {
117
+ let node = outerHtmlForCut.split(tag)[0]
118
+ if(node.trim() !== '') {
119
+ this.domList.push({text:node,index})
120
+ index++
121
+ }
122
+ let obj = this.buildElementObj(tag)
123
+ let objName = obj.tagName+obj.order
124
+ obj.index = index
125
+ if(obj.order.length == 0) { // single tag
126
+ this.domList.push(obj)
127
+ } else this.domList.push({[objName]:obj,name:objName,index})
128
+ if(obj.close) {
129
+ let j = this.findOpen(objName)
130
+ if(j >=0) {
131
+ let closeTag = index
132
+ let openTagObj = this.domList[j][this.domList[j].name]
133
+ this.domList[j] = {...openTagObj,closeTag}
134
+ }
135
+ this.domList[obj.index] = obj
136
+ }
137
+ outerHtmlForCut = outerHtmlForCut.replace(node+tag,'')
138
+ index++
139
+ });
140
+ }
141
+ // Build element
142
+ buildElementObj(string,obj={}) {
143
+ let singlTags = Document.singlTags
144
+ if(string.match(/\<\/(\w*-?)*/) !== null) obj.close = true
145
+ else obj.close = false
146
+ obj.tagName = string.match(/\<\/?(\w*-?)*/,'gm')[0].replace(/\<\/?/,'')
147
+ if(!singlTags.includes(obj.tagName)) {
148
+ obj.tagName = obj.tagName.replace('/','')
149
+ let tagName = obj.tagName
150
+ this.getType(tagName,obj)
151
+ obj.order = this.types[tagName].count
152
+ } else obj.order = ''
153
+ obj.attributes = this.getAttributes(string)
154
+ obj = this.buildClass(obj)
155
+ if(obj.attributes.id !== undefined) {
156
+ obj.id = obj.attributes.id
157
+ delete obj.attributes.id
158
+ }
159
+ return obj
160
+ }
161
+
162
+ getType(tagName,obj) {
163
+ if(this.types[tagName] == undefined)
164
+ this.types[tagName] = {count:0,lastOperation:1}
165
+ else if(obj.close && this.types[tagName].lastOperation == 1)
166
+ this.types[tagName].lastOperation = 0
167
+ else if(obj.close && this.types[tagName].lastOperation == 0)
168
+ this.types[tagName].count--
169
+ else if(!obj.close && this.types[tagName].lastOperation == 0)
170
+ this.types[tagName].lastOperation = 1
171
+ else if(!obj.close && this.types[tagName].lastOperation == 1)
172
+ this.types[tagName].count++
173
+ }
174
+
175
+ getAttributes(string,attributes = {}) {
176
+ let matches = string.match(/\s(\/?\w*\-?)*((\S)*?\s?=[\S\s]*?\"[\S\s]*?\")?/g)
177
+ if(matches !== null) matches.forEach(attribute => {
178
+ attribute = attribute.trim()
179
+ if(attribute !== '') {
180
+ let attName = attribute.split('=')[0]
181
+ let attValue = attribute.replace(attName,'').replace('=','').replace(/\"/g,'')
182
+ if(attName !== '/') attributes[attName] = attValue.trim()
183
+ }
184
+ })
185
+ return attributes
186
+ }
187
+
188
+ buildClass(obj) {
189
+ if(obj.attributes.class !== undefined) {
190
+ obj.classList = obj.attributes.class.split(' ')
191
+ } else obj.classList = []
192
+ obj.classList.add = newClass => {
193
+ obj.classList.push(newClass)
194
+ obj.attributes.class += ' '+newClass
195
+ return obj
196
+ }
197
+ obj.classList.remove = clas => {
198
+ let index = obj.classList.indexOf(clas)
199
+ if(index >=0) {
200
+ obj.attributes.class = obj.attributes.class.replace(obj.classList[index],'')
201
+ obj.classList.splice(index,1)
202
+ }
203
+ return obj
204
+ }
205
+ return obj
206
+ }
207
+ // Build dom tree
208
+ getPairs(start=0,end=this.domList.length,domTree=this.domTree) {
209
+ for(let index=start; index<end; index++) {
210
+ let node = this.domList[index]
211
+ if(node.closeTag !== undefined && !this.added.includes(index)) {
212
+ if(this.firstTag == undefined) this.firstTag = index
213
+ this.buildTag(index,domTree)
214
+ break;
215
+ }
216
+ }
217
+ }
218
+
219
+ buildTag(openIndex,domTree,parent=this.domTree) {
220
+ this.added.push(openIndex)
221
+ let content = this.domList[openIndex]
222
+ content.children = []
223
+ content.innerText = ''
224
+ this.getChildNodes(openIndex,content.closeTag,content)
225
+ content.$ = (selector) => this.$(selector,content)
226
+ content.$$ = (selector) => this.$$(selector,content)
227
+ content.parent = parent
228
+ content = Document.buildMethods(content)
229
+ this.buildOperations(content)
230
+ if(content.innerText !== '') {
231
+ if(parent.innerText == undefined) parent.innerText = ''
232
+ parent.innerText += '|'+content.innerText
233
+ }
234
+ content.json = () => Document.removeMethods(content)
235
+ delete content.closeTag
236
+ delete content.close
237
+ delete content.index
238
+ delete content.order
239
+ domTree.push(content)
240
+ }
241
+
242
+ static buildMethods(content) {
243
+ content.children.forEach((child,index) => { // prev and next
244
+ if(index == 0) child.prev = null
245
+ else child.prev = content.children[index-1]
246
+ if(index == content.children.length-1) child.next = null
247
+ else child.next = content.children[index+1]
248
+ });
249
+ return content
250
+ }
251
+
252
+ static changeByIndex(array,value,item,before = true) {
253
+ let index = array.indexOf(value);
254
+ if(index > -1) {
255
+ if(item == undefined) array.splice(index, 1); // remove value
256
+ else if(item !== undefined) {
257
+ if(before) array.splice(index, 0, item); // add item before value
258
+ else array.splice(index+1, 0, item); // add item after value
259
+ }
260
+ }
261
+ }
262
+
263
+ static buildInnerText(element) {
264
+ element.innerText = ''
265
+ if(element.children !== undefined) element.children.forEach(child => {
266
+ if(child.text !== undefined && child.text !== '') element.innerText += child.text
267
+ if(child.innerText !== undefined && child.innerText !== '') element.innerText += '|'+child.innerText
268
+ });
269
+ }
270
+
271
+ buildOperations(content) {
272
+ content.remove = function() {
273
+ Document.changeByIndex(content.parent.children,content)
274
+ Document.buildInnerText(content.parent)
275
+ }
276
+ content.add = function(element,place) {
277
+ if(typeof element == 'string') element = Document.newElement(element)
278
+ else element.remove()
279
+ if(place == 1) content.children.unshift(element)
280
+ if(place == 2) content.children.push(element)
281
+ if(place == 1 || place == 2) build(content)
282
+
283
+ if(place == 0) Document.changeByIndex(content.parent.children,content,element,true)
284
+ if(place == 3) Document.changeByIndex(content.parent.children,content,element,false)
285
+ if(place == 0 || place == 3) build(content.parent)
286
+
287
+ function build(parent) {
288
+ element.parent = parent
289
+ element = Document.buildMethods(parent)
290
+ Document.buildInnerText(parent)
291
+ }
292
+ return element
293
+ }
294
+ content.add0 = element => content.add(element,0)
295
+ content.add1 = element => content.add(element,1)
296
+ content.add2 = element => content.add(element,2)
297
+ content.add3 = element => content.add(element,3)
298
+ }
299
+
300
+ static newElement(outerHtml) {
301
+ let document = new Document(outerHtml)
302
+ return document.domTree[0].json()
303
+ }
304
+
305
+ build(filePath,array=this.domTree,html = '',space='') {
306
+ let extraSpace = space+' '
307
+ let nl = `
308
+ `
309
+ array.forEach(element => {
310
+ if(element.text !== undefined) html += space+element.text+nl
311
+ else if(element.tagName == 'comment' ) {
312
+ html += space+element.comment + nl
313
+ } else {
314
+ let attributes = ''
315
+ for(let propName in element.attributes) {
316
+ let value = element.attributes[propName]
317
+ let attribute = ` ${propName}="${value}"`
318
+ if(attribute.length + attributes.length > 80) attribute = nl+space+attribute
319
+ attributes += attribute
320
+ }
321
+ let id = ''
322
+ if(element.id !== undefined) id = ` id="${element.id}"`
323
+ html += `${space}<${element.tagName}${id}${attributes}>${nl}`
324
+ if(element.children !== undefined)
325
+ if(element.children.length >0) html = this.build(filePath,element.children,html,extraSpace)
326
+ if(element.tagName !== undefined && !Document.singlTags.includes(element.tagName))
327
+ html += `${space}</${element.tagName}>${nl}`
328
+ }
329
+ });
330
+ if(array == this.domTree) {
331
+ html = this.doctype+nl+html
332
+ if(filePath !== undefined) Document.writeFile(filePath,html)
333
+ }
334
+ return html
335
+ }
336
+
337
+ getChildNodes(openIndex,closeIndex,content) {
338
+ for(let i = openIndex+1; i<closeIndex; i++) {
339
+ let node = this.domList[i]
340
+ if(!this.added.includes(i)) {
341
+ if(!node.close && node.text == undefined) this.buildTag(node.index,content.children,content)
342
+ else if(!node.close && node.text !== undefined) {
343
+ content.innerText += node.text
344
+ content.children.push(node);
345
+ delete node.index
346
+ }
347
+ this.added.push(i)
348
+ }
349
+ }
350
+ }
351
+
352
+ findOpen(key,array=this.domList) {
353
+ return array.findIndex(function(obj, index) {
354
+ if(obj[key] !== undefined && obj[key].close == false && obj[key].closeTag == undefined)
355
+ return true;
356
+ });
357
+ }
358
+ // querySelector
359
+ $(selector,obj) {return this.$$(selector,obj,true)}
360
+
361
+ $$(selector='',obj=this.domTree[0],first=false) {
362
+ if(typeof selector !== 'string') return
363
+ this.selector = selector
364
+ this.selectors = []
365
+ this.getSelectors(selector)
366
+ let array = this.findElements(obj)
367
+ if(first) return array[0]
368
+ else return this.buildCollection(array)
369
+ }
370
+
371
+ getSelectors() {
372
+ this.getPropSelctors() // remove all attributes from selector, build them, replace as [i] and put into selectors.attributes[]
373
+ let groups = this.selector.split(',')
374
+ groups.forEach(group => {
375
+ let result = {}
376
+ group = group.trim()
377
+ let family = group.split('>')
378
+ let prevBrother = group.split('+')
379
+ let nextBrother = group.split('~')
380
+ if(family.length > 1) {
381
+ result.parent = this.buildSingleSelector(family[0])
382
+ result.element = this.buildSingleSelector(family[1])
383
+ } else if(prevBrother.length > 1) {
384
+ result.prev = this.buildSingleSelector(prevBrother[0])
385
+ result.element = this.buildSingleSelector(prevBrother[1])
386
+ } else if(nextBrother.length > 1) {
387
+ result.next = this.buildSingleSelector(nextBrother[0])
388
+ result.element = this.buildSingleSelector(nextBrother[1])
389
+ } else result.element = this.buildSingleSelector(group)
390
+ this.selectors.push(result)
391
+ });
392
+ }
393
+
394
+ getPropSelctors() {
395
+ let signs = ['~','|','^','$','*']
396
+ let props = this.selector.match(/\[.*\]/g)
397
+ this.attributes = []
398
+ if(props !== null) props.forEach((prop,i) => {
399
+ this.selector = this.selector.replace(prop,`[${i}]`)
400
+ let attribute = prop.replace('[','').replace(']','')
401
+ let array = attribute.split('=')
402
+ let propName = array[0]
403
+ let propValue = (array[1] == undefined) ? '' : array[1].replace(/"/g,'')
404
+ let sign
405
+ if(signs.includes(propName.slice(-1))) {
406
+ sign = propName.slice(-1)
407
+ propName = propName.slice(0, -1)
408
+ }
409
+ this.attributes.push({propName,propValue,sign})
410
+ });
411
+ }
412
+
413
+ buildSingleSelector(selector,result={}) {
414
+ selector = selector.trim()
415
+ let props = selector.match(/\[.*\]/g)
416
+ if(props !== null) props.forEach(prop => {
417
+ selector = selector.replace(prop,'')
418
+ let index = prop.replace('[','').replace(']','')
419
+ result.attributes = this.attributes[index]
420
+ });
421
+ let id = selector.match(/#(\w*-?)*/)
422
+ if(id !== null) {
423
+ result.id = id[0].replace('#','')
424
+ selector = selector.replace(id[0],'')
425
+ }
426
+ let classes = selector.match(/\.(\w*-?)*/g)
427
+ if(classes !== null) {
428
+ result.classes = []
429
+ classes.forEach(clas => {
430
+ result.classes.push(clas.replace('.',''))
431
+ selector = selector.replace(clas,'')
432
+ });
433
+ }
434
+ let tag = selector.match(/(\w*-?)*/)
435
+ if(tag !== null) {
436
+ if(tag[0] !== '') {
437
+ result.tag = tag[0]
438
+ selector = selector.replace(tag[0],'')
439
+ }
440
+ }
441
+ return result
442
+ }
443
+
444
+ findElements(obj,array = []) {
445
+ array = this.checkSelectors(obj,array)
446
+ if(obj.children !== undefined) {
447
+ obj.children.forEach(element => {
448
+ this.findElements(element,array)
449
+ });
450
+ }
451
+ return array
452
+ }
453
+
454
+ checkSelectors(element,array) {
455
+ this.selectors.forEach(group => {
456
+ let addIt = 0
457
+ if(group.parent !== undefined) addIt += this.checkElement(element.parent,group.parent)
458
+ if(group.prev !== undefined) addIt += this.checkElement(element.prev,group.prev)
459
+ if(group.next !== undefined) addIt += this.checkElement(element.next,group.next)
460
+ if(group.element !== undefined) addIt += this.checkElement(element,group.element)
461
+ if(addIt == 0) array.push(element)
462
+ });
463
+ return array
464
+ }
465
+
466
+ checkElement(element,selectors,addIt = 0) {
467
+ if(element == undefined) return -1
468
+ if(selectors.tag !== undefined)
469
+ if(element.tagName !== selectors.tag) addIt--
470
+ if(selectors.id !== undefined)
471
+ if(element.id !== selectors.id) addIt--
472
+ if(selectors.classes !== undefined ) {
473
+ if(element.classList !== undefined) selectors.classes.forEach(clas => {
474
+ if(!element.classList.includes(clas)) addIt--
475
+ });
476
+ else addIt--
477
+ }
478
+ if(selectors.attributes !== undefined) addIt += this.checkAttributes(
479
+ element.attributes,
480
+ selectors.attributes.propName,
481
+ selectors.attributes.propValue,
482
+ selectors.attributes.sign
483
+ )
484
+ return addIt
485
+ }
486
+
487
+ checkAttributes(props,propName,propValue,sign,addIt = 0) {
488
+ if(props == undefined) return -1
489
+ else {
490
+ if(propValue == '' && props[propName] == undefined) addIt--
491
+ if(propValue.length>0 && props[propName] !== undefined) {
492
+ if(sign == undefined) {
493
+ if(props[propName] !== propValue) addIt--
494
+ } else if(sign == '~') {
495
+ let r = new RegExp(`\\b${propValue}`)
496
+ if(props[propName].match(r) == null) addIt--
497
+ } else if(sign == '|') {
498
+ if(!props[propName].startsWith(propValue) || props[propName] !== propValue) addIt--
499
+ } else if(sign == '^') {
500
+ if(!props[propName].startsWith(propValue)) addIt--
501
+ } else if(sign == '$') {
502
+ if(!props[propName].endsWith(propValue)) addIt--
503
+ } else if(sign == '*') {
504
+ if(!props[propName].includes(propValue)) addIt--
505
+ }
506
+ }
507
+ }
508
+ return addIt
509
+ }
510
+
511
+ // Collection array
512
+ buildCollection(collection) {
513
+ collection.each = function(fn) {return Document.each(this,fn)}
514
+ collection.parse = function(part,fn) {return Document.parse(this,part,fn)}
515
+ return collection
516
+ }
517
+
518
+ static each(collection,fn) {
519
+ for(let i = 0; i<collection.length; i++) {
520
+ fn(collection[i],i,collection)
521
+ }
522
+ return collection
523
+ }
524
+
525
+ static parse(collection,part,fn,array=[]) {
526
+ if(part !== undefined) {
527
+ collection.each((element,index,collection) => {
528
+ let content
529
+ if(element[part] !== undefined) content = element[part]
530
+ else if(element.attributes !== undefined)
531
+ if(element.attributes[part] !== undefined)
532
+ content = element.attributes[part]
533
+
534
+ if(content !== undefined) {
535
+ if(typeof content == 'string')
536
+ content = content.replace(/&nbsp;/g,' ')
537
+ if(fn !== undefined) {
538
+ if(fn(content)) array.push(content)
539
+ } else array.push(content)
540
+ }
541
+ })
542
+ } else {
543
+ collection.forEach(element => {
544
+ array.push(Document.removeMethods(element))
545
+ });
546
+ }
547
+ return array
548
+ }
549
+
550
+ static removeMethods(element) {
551
+ element = {...element}
552
+ let deleteThis = ['parent','next','prev','classList','json','$','$$','remove','add','add0','add1','add2','add3']
553
+ deleteThis.forEach(item => {
554
+ delete element[item]
555
+ });
556
+ if(element.children !== undefined) element.children.forEach((child,i) => {
557
+ element.children[i] = Document.removeMethods(child)
558
+ });
559
+ return element
560
+ }
561
+
562
+ static writeFile(path,obj,encoding = 'utf-8') {
563
+ let {writeFileSync} = require('fs')
564
+ path = Document.path(path)
565
+ if(typeof obj !== 'string') try {
566
+ obj = JSON.stringify(obj,null,4)
567
+ writeFileSync(path,obj,encoding)
568
+ } catch(e) {console.log(e)}
569
+ else writeFileSync(path,obj,encoding)
570
+ }
571
+
572
+ static readFile(path,encoding = 'utf-8') {
573
+ path = Document.path(path)
574
+ let {readFileSync} = require('fs')
575
+ return readFileSync(path,encoding)
576
+ }
577
+
578
+ static path(path) {
579
+ let {join} = require('path')
580
+ if(Array.isArray(path)) return join(...path)
581
+ else return path
582
+ }
583
+ }
584
+ module.exports = Document
package/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "als-document",
3
+ "version": "0.1.0",
4
+ "description": "virtual dom",
5
+ "main": "document.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [
10
+ "virtual DOM"
11
+ ],
12
+ "author": "Alex Sorkin",
13
+ "license": "ISC"
14
+ }
package/readme.md ADDED
@@ -0,0 +1,196 @@
1
+ # Als-Document
2
+
3
+ *If something wrong or not working properly, please write me to: sh.mashkanta@gmail.com*
4
+
5
+ Document is a class which gets html as string and return new object with DOM tree.
6
+ You can add or remove elements from DOM tree and modify each element.
7
+ You can select elements and collections and read and modify them with given instruments.
8
+
9
+
10
+ ## Write and Read files
11
+ Document have 2 static methods to read and write files.
12
+ The syntax:
13
+ ```javascript
14
+ Document.writeFile(filePath,obj,encoding = 'utf-8')
15
+ Document.readFile(filePath,encoding = 'utf-8')
16
+ ```
17
+
18
+ * ``filepath`` - filepath can be string (absolute path to file) or array for joining.
19
+ * ``obj`` - obj can be string or object for stringify.
20
+ * ``encoding`` - encoding for read or write file
21
+
22
+ Example:
23
+ ```javascript
24
+ let {Document} = require('als-document')
25
+ let html = Document.readFile([__dirname,'index.html'])
26
+ ```
27
+
28
+
29
+ ## Creating new object
30
+
31
+ Document constructor get single string parameter - the outerHTML for converting to virtual DOM tree.
32
+
33
+ ```javascript
34
+ let document = new Document(html) // html has to be string
35
+ document.domTree // includes virtual DOM tree as array of elements
36
+ ```
37
+
38
+
39
+ ## QuerySelector for single element
40
+ Then document object has created, you can select elements or collections.
41
+ For selecting single element, use ``$(selector)`` and for selecting collections ``$$(selector)``.
42
+
43
+ **Selecting element**
44
+
45
+ ```javascript
46
+ document.$('div') // select first div in document
47
+ document.$('div.some') // select first div element with some class
48
+ ```
49
+
50
+ At this time, selector supports this:
51
+ * Selects all elements - ``*``
52
+ * element - ``div``
53
+ * class - ``.some-class``
54
+ * id - ``#some-id``
55
+ * parent - ``div > p``
56
+ * next - ``div + p``
57
+ * previous - ``p ~ ul``
58
+ * attribute - ``[some-attribute="some value"]``
59
+ * ``[prop]``
60
+ * ``[prop~=value]``
61
+ * ``[prop|=value]``
62
+ * ``[prop^="value"]``
63
+ * ``[prop$="value"]``
64
+ * ``[prop*="value"]``
65
+
66
+
67
+ The folowing, **won't work**: ``div p``.
68
+
69
+
70
+ Each returned element, has the folowing:
71
+ ```javascript
72
+ {
73
+ parent, // parent element
74
+ prev, // previous element (null if no exists)
75
+ next, // next element (null if no exists)
76
+ innerText, // innner text of element and it's childNodes separated by |
77
+ children, // array of childNodes(elements and text nodes) - includes text element too
78
+ tagName, // tag name of element
79
+ id, // id of element if exists (not included in attributes)
80
+ attributes, // object of attributes (id not included)
81
+ classList, // array of classes and add and remove methods
82
+ $(selector),
83
+ $$(selector),
84
+ json(), // remove all methods and circular objects from object
85
+ remove(), // remove this element
86
+ add(element/outerHtml,place),
87
+ add0(element/outerHtml),
88
+ add1(element/outerHtml),
89
+ add2(element/outerHtml),
90
+ add3(element/outerHtml),
91
+ }
92
+ ```
93
+
94
+ Text node has the folowing:
95
+ ```javascript
96
+ {
97
+ text,
98
+ prev,
99
+ next
100
+ }
101
+ ```
102
+
103
+ Comment node:
104
+ ```javascript
105
+ tagName:comment,
106
+ comment // comment it self
107
+ ```
108
+
109
+ You can add or remove classes with classList methods.
110
+ Example:
111
+ ```javascript
112
+ let element = document.$('div')
113
+ element.classList.remove('some')
114
+ element.classList.add('another')
115
+ element.classList.add('onemore')
116
+ ```
117
+
118
+ Also you can change element's id:
119
+ ```javascript
120
+ let element = document.$('div')
121
+ element.id = 'new-id'
122
+ ```
123
+
124
+ ## Element methods
125
+
126
+ ```javascript
127
+ json() // remove all methods and circular objects from object
128
+ remove() // remove this element
129
+ add(element/outerHtml,place) // adding AdjacentHTML or AdjacentElement to place(0-3)
130
+ add0(element/outerHtml) // adding AdjacentHTML or AdjacentElement beforebegin
131
+ add1(element/outerHtml) // adding AdjacentHTML or AdjacentElement afterbegin
132
+ add2(element/outerHtml) // adding AdjacentHTML or AdjacentElement beforeend
133
+ add3(element/outerHtml) // adding AdjacentHTML or AdjacentElement afterend
134
+ ```
135
+
136
+ Example:
137
+ ```javascript
138
+ let document = new Document(html)
139
+ let a = document.$('a')
140
+ let div = document.$('div')
141
+ div.add2('<div id="test">Hello world</div>')
142
+ div.add3(a)
143
+ a.remove()
144
+ ```
145
+
146
+
147
+ Create new element with ``Document.newElement(outerHtml)``
148
+
149
+ ```javascript
150
+ Document.newElement('<div id="test">Hello world</div>')
151
+ ```
152
+
153
+
154
+ ## QuerySelector for Collection ``$$()``
155
+ To select few elements, use ``$$(selector)`` method.
156
+
157
+ ```javascript
158
+ document.$$('div') // return collection of all div elements
159
+ ```
160
+
161
+ The collection is array which has the elements and two methods: ``each`` and ``parse``.
162
+
163
+ ``each`` method gets callback function with 3 parameters: element it self, index of the element in collection and collection itself.
164
+
165
+ Here example:
166
+ ```javascript
167
+ let array = []
168
+ document.$$('div').each((element,index,collection) => {
169
+ if(element.innerText.includes('some text'))
170
+ array.push(element)
171
+ })
172
+ ```
173
+
174
+ ``parse`` method, gets two parameters: ``part`` and ``fn`` and return array with results.
175
+ * ``part`` is a part of element. It can be innerText, id, tagName or any property inside attributes.
176
+ * ``fn`` is a filter function which gets content of part. If return true, content will be included.
177
+
178
+ Example:
179
+ ```javascript
180
+ new Document(htmlText).$$('div')
181
+ .parse('innerText',
182
+ content=> (content.length > 0) ? true : false)
183
+ ```
184
+
185
+ ## Building html
186
+
187
+ For building html again, use ``build`` method.
188
+ Example:
189
+ ```javascript
190
+ let element = document.$('div')
191
+ element.classList.add('another')
192
+ element.classList.remove('some')
193
+ element.id = 'new-id'
194
+ document.build() // return new html text
195
+ document.build([__dirname,'new-index.html']) // will create a file with new html text
196
+ ```