als-layout 5.2.0 → 6.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.
- package/docs/0-change-log.md +8 -35
- package/docs/1-basic-usage.md +0 -10
- package/docs/2-cloning.md +16 -0
- package/docs/4-res-and-status.md +10 -0
- package/docs/{4-api.md → 5-api.md} +13 -4
- package/lib/elements/index.js +38 -0
- package/lib/elements/keywords.js +19 -0
- package/lib/elements/link.js +13 -0
- package/lib/elements/meta.js +12 -0
- package/lib/elements/url.js +18 -0
- package/lib/layout.js +30 -96
- package/package.json +4 -4
- package/readme.md +52 -55
- package/{build-readme.js → scripts/build-readme.js} +2 -2
- package/tests/integrative.test.js +1 -7
- package/lib/onload.js +0 -11
- /package/lib/{script.js → elements/script.js} +0 -0
- /package/lib/{style.js → elements/style.js} +0 -0
package/docs/0-change-log.md
CHANGED
|
@@ -1,37 +1,10 @@
|
|
|
1
|
-
## Change Log
|
|
2
|
-
* V5.2.0
|
|
3
|
-
* options object on clone, cloned too (remove the reference and deep cloning the object)
|
|
4
|
-
* V5.1.0
|
|
5
|
-
* status and end methods removed
|
|
6
|
-
* status and end methods added to als-view
|
|
7
|
-
* V5.0.0
|
|
8
|
-
* constructor changed
|
|
9
|
-
* options object parameter instead separated parameters
|
|
10
|
-
* options.logger
|
|
11
|
-
* bugs fixed
|
|
12
|
-
* some refactoring
|
|
13
|
-
* minifiying error catching
|
|
14
|
-
* status and end methods added
|
|
15
|
-
* V4.2.0
|
|
16
|
-
* link method changed
|
|
17
|
-
* `link(href, attributes = { rel: "stylesheet", type: "text/css" })`
|
|
18
|
-
* no version method
|
|
19
|
-
* no version parameter in image, link,script
|
|
20
|
-
* script
|
|
21
|
-
* script in footer added one after other in right order
|
|
1
|
+
## Change Log for V6
|
|
22
2
|
|
|
23
|
-
|
|
24
|
-
* Render removed
|
|
25
|
-
|
|
26
|
-
* V4.0.0
|
|
27
|
-
* All code rebuilded and refactored
|
|
28
|
-
* No als-simple-css for style
|
|
29
|
-
* No charset method
|
|
30
|
-
* minifying for style and inner scripts
|
|
31
|
-
* updated render version
|
|
32
|
-
* render as element's method instead layout's method
|
|
33
|
-
|
|
34
|
-
* V3.0.0
|
|
35
|
-
* render switched to als-render
|
|
36
|
-
* updated bug with meta tags after body
|
|
3
|
+
The code refactored.
|
|
37
4
|
|
|
5
|
+
### Removed
|
|
6
|
+
* no deepclone for options, using { ...Layout.options, ...options } instead
|
|
7
|
+
* no onload method
|
|
8
|
+
### Added
|
|
9
|
+
* status
|
|
10
|
+
* end(res)
|
package/docs/1-basic-usage.md
CHANGED
|
@@ -35,13 +35,3 @@ layout.rawHtml // raw HTML of the document
|
|
|
35
35
|
layout.clone // creates a new layout object clone for current object
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
### onload
|
|
39
|
-
|
|
40
|
-
By adding onload attribute, you can run scripts for each element after dom content has loaded.
|
|
41
|
-
|
|
42
|
-
Example how it works:
|
|
43
|
-
```js
|
|
44
|
-
const layout = new Layout().viewport().title('On load').onload()
|
|
45
|
-
layout.body.innerHTML = /*html*/`<div onload="this.innerHTML = 'new content'">original content</div>`
|
|
46
|
-
```
|
|
47
|
-
|
package/docs/2-cloning.md
CHANGED
|
@@ -17,3 +17,19 @@ const newLayout = layout.clone;
|
|
|
17
17
|
|
|
18
18
|
Cloning is particularly useful in scenarios where templates or base layouts are used repeatedly with slight variations, providing a robust and scalable solution for web page generation.
|
|
19
19
|
|
|
20
|
+
|
|
21
|
+
### propsToClone
|
|
22
|
+
|
|
23
|
+
You can add properties to add when cloning the object, by adding name of properties to `Layout.propsToClone` which is array.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
Layout.propsToClone.push('projectName')
|
|
29
|
+
|
|
30
|
+
const layout = new Layout()
|
|
31
|
+
layout.projectName = 'Cool project'
|
|
32
|
+
|
|
33
|
+
const cloned = layout.clone
|
|
34
|
+
console.log(cloned.projectName) // 'Cool project'
|
|
35
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Response with status
|
|
2
|
+
|
|
3
|
+
In version 6, added two methods:
|
|
4
|
+
1. `status(statusCode)` - adds the statusCode to `__status` property
|
|
5
|
+
2. `end(res)`
|
|
6
|
+
1. writes head with `__status, { 'Content-Type': 'text/html' }`
|
|
7
|
+
2. runs `res.end(this.rawHtml)`
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
The main idea, is to add quick way to response with layout.
|
|
@@ -23,16 +23,17 @@ Returns the inner HTML of the document.
|
|
|
23
23
|
|
|
24
24
|
Creates a clone of the current layout instance, preserving `options`.
|
|
25
25
|
|
|
26
|
+
|
|
27
|
+
#### `__status`
|
|
28
|
+
|
|
29
|
+
Stores the statusCode for `end` method.
|
|
30
|
+
|
|
26
31
|
### Methods
|
|
27
32
|
|
|
28
33
|
#### `lang(lang: string): this`
|
|
29
34
|
|
|
30
35
|
Sets the `lang` attribute on the `<html>` element.
|
|
31
36
|
|
|
32
|
-
#### `onload(): this`
|
|
33
|
-
|
|
34
|
-
Adds an `onload` script to the document. If called multiple times, the script is only added once.
|
|
35
|
-
|
|
36
37
|
#### `title(title: string): this`
|
|
37
38
|
|
|
38
39
|
Sets the document title and creates an Open Graph title meta tag.
|
|
@@ -86,3 +87,11 @@ Adds a `<script>` tag to the document.
|
|
|
86
87
|
#### `link(href: string, attributes: object = { rel: "stylesheet", type: "text/css" }): this`
|
|
87
88
|
|
|
88
89
|
Adds a `<link>` tag for external stylesheets.
|
|
90
|
+
|
|
91
|
+
#### `status(statusCode:number): this`
|
|
92
|
+
|
|
93
|
+
Adds the statusCode to `__status` property
|
|
94
|
+
|
|
95
|
+
#### `end(res):undefined`
|
|
96
|
+
|
|
97
|
+
Response with res(rawHtml)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const meta = require('./meta')
|
|
2
|
+
const script = require('./script')
|
|
3
|
+
const style = require('./style')
|
|
4
|
+
const addKeywords = require('./keywords')
|
|
5
|
+
const addLink = require('./link')
|
|
6
|
+
const addUrl = require('./url')
|
|
7
|
+
|
|
8
|
+
const { SingleNode } = require('als-document');
|
|
9
|
+
|
|
10
|
+
function getDescription(description,layout) {
|
|
11
|
+
meta({ name: 'description', content: description },layout)
|
|
12
|
+
meta({ property: 'og:description', content: description },layout)
|
|
13
|
+
meta({ property: 'twitter:description', content: description },layout)
|
|
14
|
+
return layout
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getFavicon(href,layout) {
|
|
18
|
+
const faviconElement = layout.root.$('link[rel=icon][type=image/x-icon]')
|
|
19
|
+
if (faviconElement) faviconElement.setAttribute('href', href)
|
|
20
|
+
else layout.head.insert(2, new SingleNode('link', { rel: 'icon', href, type: 'image/x-icon' }))
|
|
21
|
+
return layout
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getViewport(viewport = 'width=device-width, initial-scale=1.0',layout) {
|
|
25
|
+
const element = layout.root.$('meta[name="viewport"]')
|
|
26
|
+
if (element) element.setAttribute('content', viewport)
|
|
27
|
+
else layout.head.insert(2, new SingleNode('meta', { name: 'viewport', content: viewport }))
|
|
28
|
+
return layout
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getImage(image,layout) {
|
|
32
|
+
meta({ property: 'og:image', content: image },layout)
|
|
33
|
+
meta({ name: 'twitter:image', content: image },layout)
|
|
34
|
+
meta({ name: 'twitter:card', content: 'summary_large_image' },layout)
|
|
35
|
+
return layout
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = { meta, getDescription, getFavicon, getViewport, getImage, script, style, addKeywords, addLink, addUrl }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const { SingleNode } = require('als-document');
|
|
2
|
+
|
|
3
|
+
function keywords(keywords = [],layout) {
|
|
4
|
+
let keywordsElement = layout.root.$('meta[name=keywords]')
|
|
5
|
+
if (!keywordsElement) keywordsElement = new SingleNode('meta', { name: 'keywords' })
|
|
6
|
+
const content = keywordsElement.getAttribute('content')
|
|
7
|
+
const existingKeywords = content ? content.split(',') : []
|
|
8
|
+
keywords.forEach(keyword => {
|
|
9
|
+
keyword = keyword.trim()
|
|
10
|
+
if (!existingKeywords.includes(keyword)) existingKeywords.push(keyword)
|
|
11
|
+
});
|
|
12
|
+
if (existingKeywords.length) {
|
|
13
|
+
keywordsElement.setAttribute('content', existingKeywords.join())
|
|
14
|
+
layout.head.insert(2, keywordsElement)
|
|
15
|
+
}
|
|
16
|
+
return layout
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = keywords
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { SingleNode } = require('als-document');
|
|
2
|
+
|
|
3
|
+
function link(href, attributes = { rel: "stylesheet", type: "text/css" },layout) {
|
|
4
|
+
if (!href || typeof href !== 'string') return layout
|
|
5
|
+
const selector = `link[rel=stylesheet][href^="${href}"]`
|
|
6
|
+
let linkElement = layout.root.$(selector)
|
|
7
|
+
if (linkElement) return
|
|
8
|
+
linkElement = new SingleNode('link', { href, ...attributes })
|
|
9
|
+
layout.head.insert(2, linkElement)
|
|
10
|
+
return layout
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = link
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const { SingleNode } = require('als-document');
|
|
2
|
+
|
|
3
|
+
function meta(props,layout) {
|
|
4
|
+
const entries = Object.entries(props)
|
|
5
|
+
const [name, value] = entries[0]
|
|
6
|
+
const selector = `meta[${name}="${value}"]`
|
|
7
|
+
const metaElement = layout.root.$(selector)
|
|
8
|
+
if (metaElement) entries.forEach(([name, v]) => metaElement.setAttribute(name, props[name]))
|
|
9
|
+
else layout.head.insert(2, new SingleNode('meta', props))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = meta
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const meta = require('./meta');
|
|
2
|
+
const { SingleNode } = require('als-document');
|
|
3
|
+
|
|
4
|
+
function addUrl(url, host,layout) {
|
|
5
|
+
try {
|
|
6
|
+
url = (host ? new URL(url, host) : new URL(url)).href.replace(/\/$/, '')
|
|
7
|
+
meta({ property: 'og:url', content: url },layout)
|
|
8
|
+
const canonicalElement = layout.root.$('link[rel="canonical"]')
|
|
9
|
+
if (canonicalElement) canonicalElement.setAttribute('href', url)
|
|
10
|
+
else layout.head.insert(2, new SingleNode('link', { rel: 'canonical', href: url }))
|
|
11
|
+
} catch (error) {
|
|
12
|
+
console.log(error)
|
|
13
|
+
layout.logger.log(`url "${url}" with host "${host}" is not valid url`)
|
|
14
|
+
}
|
|
15
|
+
return layout
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = addUrl
|
package/lib/layout.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
const { Document
|
|
2
|
-
const script = require('./
|
|
3
|
-
const style = require('./style');
|
|
4
|
-
const onloadScript = require('./onload');
|
|
5
|
-
const deepClone = require('als-deep-clone')
|
|
1
|
+
const { Document } = require('als-document');
|
|
2
|
+
const { meta, getDescription, getFavicon, getViewport, getImage, script, style, addKeywords, addLink, addUrl } = require('./elements/index')
|
|
6
3
|
|
|
7
4
|
class Layout extends Document {
|
|
5
|
+
static propsToClone = [];
|
|
6
|
+
static options = { logger: console, host: '', minified: false }
|
|
7
|
+
|
|
8
8
|
constructor(html, options = {}) {
|
|
9
|
+
options = { ...Layout.options, ...options }
|
|
9
10
|
super(html, options.host);
|
|
10
11
|
this.options = options
|
|
11
12
|
this.logger = options.logger || console
|
|
@@ -13,104 +14,37 @@ class Layout extends Document {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
get rawHtml() { return this.innerHTML }
|
|
16
|
-
get clone() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const id = 'onload-script'
|
|
21
|
-
if(this.$('#'+id)) return
|
|
22
|
-
this.script({id}, onloadScript);
|
|
23
|
-
return this
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
title(title) {
|
|
27
|
-
super.title // create title tag if not exists
|
|
28
|
-
super.title = title
|
|
29
|
-
this.meta({ property: 'og:title', content: title })
|
|
30
|
-
return this
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
description(description) {
|
|
34
|
-
this.meta({ name: 'description', content: description })
|
|
35
|
-
this.meta({ property: 'og:description', content: description })
|
|
36
|
-
this.meta({ property: 'twitter:description', content: description })
|
|
37
|
-
return this
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
favicon(href) {
|
|
41
|
-
const faviconElement = this.root.$('link[rel=icon][type=image/x-icon]')
|
|
42
|
-
if (faviconElement) faviconElement.setAttribute('href', href)
|
|
43
|
-
else this.head.insert(2, new SingleNode('link', { rel: 'icon', href, type: 'image/x-icon' }))
|
|
44
|
-
return this
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
meta(props) {
|
|
48
|
-
const entries = Object.entries(props)
|
|
49
|
-
const [name, value] = entries[0]
|
|
50
|
-
const selector = `meta[${name}="${value}"]`
|
|
51
|
-
const metaElement = this.root.$(selector)
|
|
52
|
-
if (metaElement) entries.forEach(([name, v]) => metaElement.setAttribute(name, props[name]))
|
|
53
|
-
else this.head.insert(2, new SingleNode('meta', props))
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
keywords(keywords = []) {
|
|
57
|
-
let keywordsElement = this.root.$('meta[name=keywords]')
|
|
58
|
-
if (!keywordsElement) keywordsElement = new SingleNode('meta', { name: 'keywords' })
|
|
59
|
-
const content = keywordsElement.getAttribute('content')
|
|
60
|
-
const existingKeywords = content ? content.split(',') : []
|
|
61
|
-
keywords.forEach(keyword => {
|
|
62
|
-
keyword = keyword.trim()
|
|
63
|
-
if (!existingKeywords.includes(keyword)) existingKeywords.push(keyword)
|
|
64
|
-
});
|
|
65
|
-
if (existingKeywords.length) {
|
|
66
|
-
keywordsElement.setAttribute('content', existingKeywords.join())
|
|
67
|
-
this.head.insert(2, keywordsElement)
|
|
68
|
-
}
|
|
69
|
-
return this
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
viewport(viewport = 'width=device-width, initial-scale=1.0') {
|
|
73
|
-
const element = this.root.$('meta[name="viewport"]')
|
|
74
|
-
if (element) element.setAttribute('content', viewport)
|
|
75
|
-
else this.head.insert(2, new SingleNode('meta', { name: 'viewport', content: viewport }))
|
|
76
|
-
return this
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
image(image) {
|
|
80
|
-
this.meta({ property: 'og:image', content: image })
|
|
81
|
-
this.meta({ name: 'twitter:image', content: image })
|
|
82
|
-
this.meta({ name: 'twitter:card', content: 'summary_large_image' })
|
|
83
|
-
return this
|
|
17
|
+
get clone() {
|
|
18
|
+
const clone = new this.constructor(new Document(this, this.URL), this.options)
|
|
19
|
+
Layout.propsToClone.forEach(prop => clone[prop] = this[prop])
|
|
20
|
+
return clone
|
|
84
21
|
}
|
|
85
22
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
url = new URL(url, host).href.replace(/\/$/, '')
|
|
93
|
-
this.meta({ property: 'og:url', content: url })
|
|
94
|
-
const canonicalElement = this.root.$('link[rel="canonical"]')
|
|
95
|
-
if (canonicalElement) canonicalElement.setAttribute('href', url)
|
|
96
|
-
else this.head.insert(2, new SingleNode('link', { rel: 'canonical', href: url }))
|
|
97
|
-
} catch (error) {
|
|
98
|
-
this.logger.log(`url ${url} with host ${host} is not valid url`)
|
|
99
|
-
}
|
|
100
|
-
return this
|
|
23
|
+
__status = 200;
|
|
24
|
+
status(status) { this.__status = status; return this }
|
|
25
|
+
end(res) {
|
|
26
|
+
res.writeHead(this.__status, { 'Content-Type': 'text/html' })
|
|
27
|
+
res.end(this.rawHtml)
|
|
101
28
|
}
|
|
102
29
|
|
|
30
|
+
lang(lang) { this.html.setAttribute('lang', lang); return this }
|
|
31
|
+
link(href, attributes) { return addLink(href, attributes, this) }
|
|
32
|
+
keywords(keywords = []) { return addKeywords(keywords, this) }
|
|
33
|
+
style(styles, minified = this.options.minified) { return style(styles, minified, this) }
|
|
34
|
+
url(url, host = this.URL) { return addUrl(url, host, this) }
|
|
35
|
+
meta(props) { return meta(props, this) }
|
|
36
|
+
description(description) { return getDescription(description,this) }
|
|
37
|
+
favicon(href) { return getFavicon(href,this) }
|
|
38
|
+
viewport(viewport) { return getViewport(viewport,this) }
|
|
39
|
+
image(image) { return getImage(image,this) }
|
|
103
40
|
script(attrs = {}, innerHTML = '', head = true, minified = this.options.minified) {
|
|
104
|
-
return script(attrs,innerHTML,head,minified,this)
|
|
41
|
+
return script(attrs, innerHTML, head, minified, this)
|
|
105
42
|
}
|
|
106
43
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (linkElement) return
|
|
112
|
-
linkElement = new SingleNode('link', { href, ...attributes })
|
|
113
|
-
this.head.insert(2, linkElement)
|
|
44
|
+
title(title) {
|
|
45
|
+
super.title // create title tag if not exists
|
|
46
|
+
super.title = title
|
|
47
|
+
this.meta({ property: 'og:title', content: title })
|
|
114
48
|
return this
|
|
115
49
|
}
|
|
116
50
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "als-layout",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"test": "node --test --experimental-test-coverage",
|
|
7
|
-
"report": "node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
|
|
6
|
+
"test": "node --test --experimental-test-coverage ./tests/**.*",
|
|
7
|
+
"report": "node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info",
|
|
8
|
+
"docs":"node ./scripts/build-readme.js"
|
|
8
9
|
},
|
|
9
10
|
"keywords": [],
|
|
10
11
|
"author": "Alex Sorkin",
|
|
11
12
|
"license": "MIT",
|
|
12
13
|
"description": "Html layout constructor",
|
|
13
14
|
"dependencies": {
|
|
14
|
-
"als-deep-clone": "^1.0.0",
|
|
15
15
|
"als-document": "^1.4.0",
|
|
16
16
|
"uglify-js": "^3.19.2",
|
|
17
17
|
"uglifycss": "^0.0.29"
|
package/readme.md
CHANGED
|
@@ -17,45 +17,18 @@ npm i als-layout
|
|
|
17
17
|
```js
|
|
18
18
|
const Layout = require('als-layout')
|
|
19
19
|
```
|
|
20
|
-
|
|
21
|
-
## Change Log
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* some refactoring
|
|
33
|
-
* minifiying error catching
|
|
34
|
-
* status and end methods added
|
|
35
|
-
* V4.2.0
|
|
36
|
-
* link method changed
|
|
37
|
-
* `link(href, attributes = { rel: "stylesheet", type: "text/css" })`
|
|
38
|
-
* no version method
|
|
39
|
-
* no version parameter in image, link,script
|
|
40
|
-
* script
|
|
41
|
-
* script in footer added one after other in right order
|
|
42
|
-
|
|
43
|
-
* V4.1.0
|
|
44
|
-
* Render removed
|
|
45
|
-
|
|
46
|
-
* V4.0.0
|
|
47
|
-
* All code rebuilded and refactored
|
|
48
|
-
* No als-simple-css for style
|
|
49
|
-
* No charset method
|
|
50
|
-
* minifying for style and inner scripts
|
|
51
|
-
* updated render version
|
|
52
|
-
* render as element's method instead layout's method
|
|
53
|
-
|
|
54
|
-
* V3.0.0
|
|
55
|
-
* render switched to als-render
|
|
56
|
-
* updated bug with meta tags after body
|
|
57
|
-
|
|
58
|
-
|
|
20
|
+
|
|
21
|
+
## Change Log for V6
|
|
22
|
+
|
|
23
|
+
The code refactored.
|
|
24
|
+
|
|
25
|
+
### Removed
|
|
26
|
+
* no deepclone for options, using { ...Layout.options, ...options } instead
|
|
27
|
+
* no onload method
|
|
28
|
+
### Added
|
|
29
|
+
* status
|
|
30
|
+
* end(res)
|
|
31
|
+
|
|
59
32
|
## Basic Usage
|
|
60
33
|
|
|
61
34
|
### Initialization
|
|
@@ -93,17 +66,7 @@ layout.rawHtml // raw HTML of the document
|
|
|
93
66
|
layout.clone // creates a new layout object clone for current object
|
|
94
67
|
```
|
|
95
68
|
|
|
96
|
-
### onload
|
|
97
|
-
|
|
98
|
-
By adding onload attribute, you can run scripts for each element after dom content has loaded.
|
|
99
|
-
|
|
100
|
-
Example how it works:
|
|
101
|
-
```js
|
|
102
|
-
const layout = new Layout().viewport().title('On load').onload()
|
|
103
|
-
layout.body.innerHTML = /*html*/`<div onload="this.innerHTML = 'new content'">original content</div>`
|
|
104
|
-
```
|
|
105
69
|
|
|
106
|
-
|
|
107
70
|
## Cloning Functionality
|
|
108
71
|
|
|
109
72
|
### What is Cloning and Why is it Necessary?
|
|
@@ -123,7 +86,22 @@ const newLayout = layout.clone;
|
|
|
123
86
|
|
|
124
87
|
Cloning is particularly useful in scenarios where templates or base layouts are used repeatedly with slight variations, providing a robust and scalable solution for web page generation.
|
|
125
88
|
|
|
126
|
-
|
|
89
|
+
|
|
90
|
+
### propsToClone
|
|
91
|
+
|
|
92
|
+
You can add properties to add when cloning the object, by adding name of properties to `Layout.propsToClone` which is array.
|
|
93
|
+
|
|
94
|
+
Example:
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
Layout.propsToClone.push('projectName')
|
|
98
|
+
|
|
99
|
+
const layout = new Layout()
|
|
100
|
+
layout.projectName = 'Cool project'
|
|
101
|
+
|
|
102
|
+
const cloned = layout.clone
|
|
103
|
+
console.log(cloned.projectName) // 'Cool project'
|
|
104
|
+
```
|
|
127
105
|
## Advanced Usage
|
|
128
106
|
|
|
129
107
|
The `als-layout` library allows for sophisticated manipulation of web page layouts, providing robust tools for creating dynamic and complex web pages. Below is an advanced example demonstrating various capabilities of the library:
|
|
@@ -172,7 +150,17 @@ In this example:
|
|
|
172
150
|
|
|
173
151
|
This advanced example illustrates how `als-layout` can be used to handle complex scenarios and requirements in web development, enhancing the flexibility and power at your disposal.
|
|
174
152
|
|
|
175
|
-
|
|
153
|
+
|
|
154
|
+
## Response with status
|
|
155
|
+
|
|
156
|
+
In version 6, added two methods:
|
|
157
|
+
1. `status(statusCode)` - adds the statusCode to `__status` property
|
|
158
|
+
2. `end(res)`
|
|
159
|
+
1. writes head with `__status, { 'Content-Type': 'text/html' }`
|
|
160
|
+
2. runs `res.end(this.rawHtml)`
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
The main idea, is to add quick way to response with layout.
|
|
176
164
|
## API
|
|
177
165
|
|
|
178
166
|
### Constructor
|
|
@@ -198,16 +186,17 @@ Returns the inner HTML of the document.
|
|
|
198
186
|
|
|
199
187
|
Creates a clone of the current layout instance, preserving `options`.
|
|
200
188
|
|
|
189
|
+
|
|
190
|
+
#### `__status`
|
|
191
|
+
|
|
192
|
+
Stores the statusCode for `end` method.
|
|
193
|
+
|
|
201
194
|
### Methods
|
|
202
195
|
|
|
203
196
|
#### `lang(lang: string): this`
|
|
204
197
|
|
|
205
198
|
Sets the `lang` attribute on the `<html>` element.
|
|
206
199
|
|
|
207
|
-
#### `onload(): this`
|
|
208
|
-
|
|
209
|
-
Adds an `onload` script to the document. If called multiple times, the script is only added once.
|
|
210
|
-
|
|
211
200
|
#### `title(title: string): this`
|
|
212
201
|
|
|
213
202
|
Sets the document title and creates an Open Graph title meta tag.
|
|
@@ -261,3 +250,11 @@ Adds a `<script>` tag to the document.
|
|
|
261
250
|
#### `link(href: string, attributes: object = { rel: "stylesheet", type: "text/css" }): this`
|
|
262
251
|
|
|
263
252
|
Adds a `<link>` tag for external stylesheets.
|
|
253
|
+
|
|
254
|
+
#### `status(statusCode:number): this`
|
|
255
|
+
|
|
256
|
+
Adds the statusCode to `__status` property
|
|
257
|
+
|
|
258
|
+
#### `end(res):undefined`
|
|
259
|
+
|
|
260
|
+
Response with res(rawHtml)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const { readFileSync, writeFileSync, readdirSync } = require('fs')
|
|
2
2
|
const { join } = require('path')
|
|
3
3
|
|
|
4
|
-
const docsDir = join(__dirname, 'docs')
|
|
4
|
+
const docsDir = join(__dirname, '..','docs')
|
|
5
5
|
const files = readdirSync(docsDir)
|
|
6
6
|
const content = files.map(file => readFileSync(join(docsDir, file), 'utf-8')).join('\n');
|
|
7
|
-
writeFileSync(join(__dirname, 'readme.md'), content, 'utf-8')
|
|
7
|
+
writeFileSync(join(__dirname, '..','readme.md'), content, 'utf-8')
|
|
8
8
|
|
|
@@ -30,12 +30,6 @@ describe('Layout Integrative tests', () => {
|
|
|
30
30
|
assert(layout.root.$('title') === null, 'Title element was not removed correctly');
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
it('onload', () => {
|
|
34
|
-
layout.onload()
|
|
35
|
-
const script = layout.root.$('script')
|
|
36
|
-
assert(script.innerHTML.includes(`document.addEventListener('DOMContentLoaded'`))
|
|
37
|
-
})
|
|
38
|
-
|
|
39
33
|
});
|
|
40
34
|
|
|
41
35
|
describe('HTML Structure Initialization', () => {
|
|
@@ -81,7 +75,7 @@ describe('Clone Testing', () => {
|
|
|
81
75
|
|
|
82
76
|
it('should clone the layout correctly', () => {
|
|
83
77
|
const clone = layout.clone;
|
|
84
|
-
console.log(clone.constructor.name)
|
|
78
|
+
// console.log(clone.constructor.name)
|
|
85
79
|
assert(clone instanceof Layout, 'Clone should be an instance of Layout');
|
|
86
80
|
assert.notStrictEqual(clone, layout, 'Clone should not be the same instance as the original');
|
|
87
81
|
});
|
package/lib/onload.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const onloadScript = /*js*/`document.addEventListener('DOMContentLoaded', function() {
|
|
2
|
-
const elements = document.querySelectorAll('[onload]');
|
|
3
|
-
elements.forEach(element => {
|
|
4
|
-
const onloadCode = element.getAttribute('onload');
|
|
5
|
-
const func = Function('"use strict"; return function() { ' + onloadCode + ' }');
|
|
6
|
-
func().call(element);
|
|
7
|
-
element.removeAttribute('onload');
|
|
8
|
-
});
|
|
9
|
-
});`;
|
|
10
|
-
|
|
11
|
-
module.exports = onloadScript
|
|
File without changes
|
|
File without changes
|