als-layout 7.0.0 → 7.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/index.mjs CHANGED
@@ -1,83 +1,91 @@
1
1
  import { Document, SingleNode, Node } from 'als-document';
2
- export class Layout extends Document {
3
- constructor(html, host) { super(html, host); this.root = this.html; }
4
- get rawHtml() { return this.innerHTML }
5
- get clone() { return new this.constructor(new Document(this, this.URL), this.host) }
6
- lang(lang) { this.html.setAttribute('lang', lang); return this }
7
- link(href, attributes = { rel: "stylesheet", type: "text/css" }) {
8
- if (!href || typeof href !== 'string') throw new Error(`href attribute must be a string`)
9
- if (!this.root.querySelector(`link[rel=stylesheet][href^="${href}"]`))
10
- this.head.insert(2, new SingleNode('link', { href, ...attributes }))
11
- return this
12
- }
13
- keywords(keywords = []) {
14
- let el = this.root.$('meta[name=keywords]') || new SingleNode('meta', { name: 'keywords' })
15
- keywords = new Set([...(el.getAttribute('content') || '').split(','),...keywords.map(k => k.trim())].filter(Boolean))
16
- if (keywords.size) el.setAttribute('content', Array.from(keywords).join(','))
17
- if(keywords.size && !el.parent) this.head.insert(2, el)
18
- return this
19
- }
20
- style(styles) {
21
- if (typeof styles !== 'string') throw 'styles parameter should be string';
22
- let el = this.root.$('style') || this.head.insert(2, new Node('style'))
23
- el.innerHTML = el.innerHTML + '\n' + styles;
24
- return this
25
- }
26
- url(url, host = this.URL) {
27
- try {
28
- url = (host ? new URL(url, host) : new URL(url)).href.replace(/\/$/, '')
29
- this.meta({ property: 'og:url', content: url })
30
- const el = this.root.$('link[rel="canonical"]') || this.head.insert(2, new SingleNode('link', { rel: 'canonical', href: url }))
31
- el.setAttribute('href', url)
32
- } catch (error) { error.info = `url "${url}" with host "${host}" is not valid url`; throw error; }
33
- return this
34
- }
35
- meta(props) {
36
- const entries = Object.entries(props)
37
- const [name, value] = entries[0]
38
- const metaElement = this.root.querySelector(`meta[${name}="${value}"]`) || this.head.insert(2, new SingleNode('meta', props))
39
- entries.forEach(([name, v]) => metaElement.setAttribute(name, props[name]))
40
- return this
41
- }
42
- script(attrs = {}, innerHTML = '', head = true) {
43
- if (typeof attrs !== 'object' || attrs === null || Array.isArray(attrs)) attrs = {}
44
- if (attrs.src && this.root.querySelector(`script[src="${attrs.src}"]`)) return this
45
- if (Object.keys(attrs).length || innerHTML) {
46
- const script = new Node('script', attrs)
47
- if (innerHTML) script.innerHTML = innerHTML
48
- if (head) this.head.insert(2, script)
49
- else this.html.insert(2, script)
50
- }
51
- return this
52
- }
53
- description(description) {
54
- this.meta({ name: 'description', content: description })
55
- this.meta({ property: 'og:description', content: description })
56
- this.meta({ property: 'twitter:description', content: description })
57
- return this
58
- }
59
- favicon(href) {
60
- const el = this.root.$('link[rel=icon][type=image/x-icon]')
61
- if (el) el.setAttribute('href', href)
62
- else this.head.insert(2, new SingleNode('link', { rel: 'icon', href, type: 'image/x-icon' }))
63
- return this
64
- }
65
- viewport(viewport = 'width=device-width, initial-scale=1.0') {
66
- const el = this.root.$('meta[name="viewport"]')
67
- if (el) el.setAttribute('content', viewport)
68
- else this.head.insert(2, new SingleNode('meta', { name: 'viewport', content: viewport }))
69
- return this
70
- }
71
- image(image) {
72
- this.meta({ property: 'og:image', content: image })
73
- this.meta({ name: 'twitter:image', content: image })
74
- this.meta({ name: 'twitter:card', content: 'summary_large_image' })
75
- return this
76
- }
77
- title(title) {
78
- super.title // create title tag if not exists
79
- super.title = title
80
- this.meta({ property: 'og:title', content: title })
81
- return this
82
- }
2
+ export class Layout extends Document {
3
+ constructor(html, host) { super(html, host); this.root = this.html; }
4
+ get rawHtml() { return this.innerHTML }
5
+ get clone() { return new this.constructor(new Document(this, this.URL), this.URL) }
6
+ lang(lang) { this.html.setAttribute('lang', lang); return this }
7
+ link(href, attributes = { rel: "stylesheet", type: "text/css" }) {
8
+ if (!href || typeof href !== 'string') throw new Error(`href attribute must be a string`)
9
+ if (!this.root.querySelector(`link[rel=stylesheet][href^="${href}"]`))
10
+ this.head.insert(2, new SingleNode('link', { href, ...attributes }))
11
+ return this
12
+ }
13
+ keywords(keywords = []) {
14
+ let el = this.root.$('meta[name=keywords]') || new SingleNode('meta', { name: 'keywords' })
15
+ keywords = new Set([...(el.getAttribute('content') || '').split(','),...keywords.map(k => k.trim())].filter(Boolean))
16
+ if (keywords.size) el.setAttribute('content', Array.from(keywords).join(','))
17
+ if(keywords.size && !el.parent) this.head.insert(2, el)
18
+ return this
19
+ }
20
+ style(styles) {
21
+ if (typeof styles !== 'string') throw 'styles parameter should be string';
22
+ let el = this.root.$('style') || this.head.insert(2, new Node('style'))
23
+ el.innerHTML = el.innerHTML + '\n' + styles;
24
+ return this
25
+ }
26
+ url(url, host = this.URL) {
27
+ try {
28
+ this.urlObj = (host ? new URL(url, host) : new URL(url))
29
+ url = this.urlObj.href
30
+ this.meta({ property: 'og:url', content: url })
31
+ const el = this.root.$('link[rel="canonical"]') || this.head.insert(2, new SingleNode('link', { rel: 'canonical', href: url }))
32
+ el.setAttribute('href', url)
33
+ } catch (error) { error.info = `url "${url}" with host "${host}" is not valid url`; throw error; }
34
+ return this
35
+ }
36
+ meta(props) {
37
+ const entries = Object.entries(props)
38
+ const [name, value] = entries[0]
39
+ const metaElement = this.root.querySelector(`meta[${name}="${value}"]`) || this.head.insert(2, new SingleNode('meta', props))
40
+ entries.forEach(([name, v]) => metaElement.setAttribute(name, props[name]))
41
+ return this
42
+ }
43
+ script(attrs = {}, innerHTML = '', head = true) {
44
+ if (typeof attrs !== 'object' || attrs === null || Array.isArray(attrs)) attrs = {}
45
+ if (attrs.src && this.root.querySelector(`script[src="${attrs.src}"]`)) return this
46
+ if (Object.keys(attrs).length || innerHTML) {
47
+ const script = new Node('script', attrs)
48
+ if (innerHTML) script.innerHTML = innerHTML
49
+ if (head) this.head.insert(2, script)
50
+ else this.html.insert(2, script)
51
+ }
52
+ return this
53
+ }
54
+ description(description) {
55
+ this.meta({ name: 'description', content: description })
56
+ this.meta({ property: 'og:description', content: description })
57
+ this.meta({ name: 'twitter:description', content: description })
58
+ return this
59
+ }
60
+ favicon(href) {
61
+ const el = this.root.$('link[rel=icon][type=image/x-icon]')
62
+ if (el) el.setAttribute('href', href)
63
+ else this.head.insert(2, new SingleNode('link', { rel: 'icon', href, type: 'image/x-icon' }))
64
+ return this
65
+ }
66
+ viewport(viewport = 'width=device-width, initial-scale=1.0') {
67
+ const el = this.root.$('meta[name="viewport"]')
68
+ if (el) el.setAttribute('content', viewport)
69
+ else this.head.insert(2, new SingleNode('meta', { name: 'viewport', content: viewport }))
70
+ return this
71
+ }
72
+ image(image) {
73
+ this.meta({ property: 'og:image', content: image })
74
+ this.meta({ name: 'twitter:image', content: image })
75
+ this.meta({ name: 'twitter:card', content: 'summary_large_image' })
76
+ return this
77
+ }
78
+ title(title) {
79
+ super.title // create title tag if not exists
80
+ super.title = title
81
+ this.meta({ property: 'og:title', content: title })
82
+ return this
83
+ }
84
+ toDocument() {
85
+ if (typeof window === 'undefined' || typeof document === 'undefined') return this
86
+ document.querySelector('title')?.remove()
87
+ document.head.innerHTML = this.head.innerHTML
88
+ document.body.outerHTML = this.body.outerHTML
89
+ return this
90
+ }
83
91
  }
package/layout.js CHANGED
@@ -43,85 +43,93 @@ function cacheDoc(doc){
43
43
  const props=['isSingle','tagName','attributes']
44
44
  fu
45
45
  return { parseHTML,Node,Query,TextNode,SingleNode,buildFromCache,cacheDoc,Root,Document }
46
46
  })()
47
47
  const { Document, SingleNode, Node } = alsDocument
48
- class Layout extends Document {
49
- constructor(html, host) { super(html, host); this.root = this.html; }
50
- get rawHtml() { return this.innerHTML }
51
- get clone() { return new this.constructor(new Document(this, this.URL), this.host) }
52
- lang(lang) { this.html.setAttribute('lang', lang); return this }
53
- link(href, attributes = { rel: "stylesheet", type: "text/css" }) {
54
- if (!href || typeof href !== 'string') throw new Error(`href attribute must be a string`)
55
- if (!this.root.querySelector(`link[rel=stylesheet][href^="${href}"]`))
56
- this.head.insert(2, new SingleNode('link', { href, ...attributes }))
57
- return this
58
- }
59
- keywords(keywords = []) {
60
- let el = this.root.$('meta[name=keywords]') || new SingleNode('meta', { name: 'keywords' })
61
- keywords = new Set([...(el.getAttribute('content') || '').split(','),...keywords.map(k => k.trim())].filter(Boolean))
62
- if (keywords.size) el.setAttribute('content', Array.from(keywords).join(','))
63
- if(keywords.size && !el.parent) this.head.insert(2, el)
64
- return this
65
- }
66
- style(styles) {
67
- if (typeof styles !== 'string') throw 'styles parameter should be string';
68
- let el = this.root.$('style') || this.head.insert(2, new Node('style'))
69
- el.innerHTML = el.innerHTML + '\n' + styles;
70
- return this
71
- }
72
- url(url, host = this.URL) {
73
- try {
74
- url = (host ? new URL(url, host) : new URL(url)).href.replace(/\/$/, '')
75
- this.meta({ property: 'og:url', content: url })
76
- const el = this.root.$('link[rel="canonical"]') || this.head.insert(2, new SingleNode('link', { rel: 'canonical', href: url }))
77
- el.setAttribute('href', url)
78
- } catch (error) { error.info = `url "${url}" with host "${host}" is not valid url`; throw error; }
79
- return this
80
- }
81
- meta(props) {
82
- const entries = Object.entries(props)
83
- const [name, value] = entries[0]
84
- const metaElement = this.root.querySelector(`meta[${name}="${value}"]`) || this.head.insert(2, new SingleNode('meta', props))
85
- entries.forEach(([name, v]) => metaElement.setAttribute(name, props[name]))
86
- return this
87
- }
88
- script(attrs = {}, innerHTML = '', head = true) {
89
- if (typeof attrs !== 'object' || attrs === null || Array.isArray(attrs)) attrs = {}
90
- if (attrs.src && this.root.querySelector(`script[src="${attrs.src}"]`)) return this
91
- if (Object.keys(attrs).length || innerHTML) {
92
- const script = new Node('script', attrs)
93
- if (innerHTML) script.innerHTML = innerHTML
94
- if (head) this.head.insert(2, script)
95
- else this.html.insert(2, script)
96
- }
97
- return this
98
- }
99
- description(description) {
100
- this.meta({ name: 'description', content: description })
101
- this.meta({ property: 'og:description', content: description })
102
- this.meta({ property: 'twitter:description', content: description })
103
- return this
104
- }
105
- favicon(href) {
106
- const el = this.root.$('link[rel=icon][type=image/x-icon]')
107
- if (el) el.setAttribute('href', href)
108
- else this.head.insert(2, new SingleNode('link', { rel: 'icon', href, type: 'image/x-icon' }))
109
- return this
110
- }
111
- viewport(viewport = 'width=device-width, initial-scale=1.0') {
112
- const el = this.root.$('meta[name="viewport"]')
113
- if (el) el.setAttribute('content', viewport)
114
- else this.head.insert(2, new SingleNode('meta', { name: 'viewport', content: viewport }))
115
- return this
116
- }
117
- image(image) {
118
- this.meta({ property: 'og:image', content: image })
119
- this.meta({ name: 'twitter:image', content: image })
120
- this.meta({ name: 'twitter:card', content: 'summary_large_image' })
121
- return this
122
- }
123
- title(title) {
124
- super.title // create title tag if not exists
125
- super.title = title
126
- this.meta({ property: 'og:title', content: title })
127
- return this
128
- }
48
+ class Layout extends Document {
49
+ constructor(html, host) { super(html, host); this.root = this.html; }
50
+ get rawHtml() { return this.innerHTML }
51
+ get clone() { return new this.constructor(new Document(this, this.URL), this.URL) }
52
+ lang(lang) { this.html.setAttribute('lang', lang); return this }
53
+ link(href, attributes = { rel: "stylesheet", type: "text/css" }) {
54
+ if (!href || typeof href !== 'string') throw new Error(`href attribute must be a string`)
55
+ if (!this.root.querySelector(`link[rel=stylesheet][href^="${href}"]`))
56
+ this.head.insert(2, new SingleNode('link', { href, ...attributes }))
57
+ return this
58
+ }
59
+ keywords(keywords = []) {
60
+ let el = this.root.$('meta[name=keywords]') || new SingleNode('meta', { name: 'keywords' })
61
+ keywords = new Set([...(el.getAttribute('content') || '').split(','),...keywords.map(k => k.trim())].filter(Boolean))
62
+ if (keywords.size) el.setAttribute('content', Array.from(keywords).join(','))
63
+ if(keywords.size && !el.parent) this.head.insert(2, el)
64
+ return this
65
+ }
66
+ style(styles) {
67
+ if (typeof styles !== 'string') throw 'styles parameter should be string';
68
+ let el = this.root.$('style') || this.head.insert(2, new Node('style'))
69
+ el.innerHTML = el.innerHTML + '\n' + styles;
70
+ return this
71
+ }
72
+ url(url, host = this.URL) {
73
+ try {
74
+ this.urlObj = (host ? new URL(url, host) : new URL(url))
75
+ url = this.urlObj.href
76
+ this.meta({ property: 'og:url', content: url })
77
+ const el = this.root.$('link[rel="canonical"]') || this.head.insert(2, new SingleNode('link', { rel: 'canonical', href: url }))
78
+ el.setAttribute('href', url)
79
+ } catch (error) { error.info = `url "${url}" with host "${host}" is not valid url`; throw error; }
80
+ return this
81
+ }
82
+ meta(props) {
83
+ const entries = Object.entries(props)
84
+ const [name, value] = entries[0]
85
+ const metaElement = this.root.querySelector(`meta[${name}="${value}"]`) || this.head.insert(2, new SingleNode('meta', props))
86
+ entries.forEach(([name, v]) => metaElement.setAttribute(name, props[name]))
87
+ return this
88
+ }
89
+ script(attrs = {}, innerHTML = '', head = true) {
90
+ if (typeof attrs !== 'object' || attrs === null || Array.isArray(attrs)) attrs = {}
91
+ if (attrs.src && this.root.querySelector(`script[src="${attrs.src}"]`)) return this
92
+ if (Object.keys(attrs).length || innerHTML) {
93
+ const script = new Node('script', attrs)
94
+ if (innerHTML) script.innerHTML = innerHTML
95
+ if (head) this.head.insert(2, script)
96
+ else this.html.insert(2, script)
97
+ }
98
+ return this
99
+ }
100
+ description(description) {
101
+ this.meta({ name: 'description', content: description })
102
+ this.meta({ property: 'og:description', content: description })
103
+ this.meta({ name: 'twitter:description', content: description })
104
+ return this
105
+ }
106
+ favicon(href) {
107
+ const el = this.root.$('link[rel=icon][type=image/x-icon]')
108
+ if (el) el.setAttribute('href', href)
109
+ else this.head.insert(2, new SingleNode('link', { rel: 'icon', href, type: 'image/x-icon' }))
110
+ return this
111
+ }
112
+ viewport(viewport = 'width=device-width, initial-scale=1.0') {
113
+ const el = this.root.$('meta[name="viewport"]')
114
+ if (el) el.setAttribute('content', viewport)
115
+ else this.head.insert(2, new SingleNode('meta', { name: 'viewport', content: viewport }))
116
+ return this
117
+ }
118
+ image(image) {
119
+ this.meta({ property: 'og:image', content: image })
120
+ this.meta({ name: 'twitter:image', content: image })
121
+ this.meta({ name: 'twitter:card', content: 'summary_large_image' })
122
+ return this
123
+ }
124
+ title(title) {
125
+ super.title // create title tag if not exists
126
+ super.title = title
127
+ this.meta({ property: 'og:title', content: title })
128
+ return this
129
+ }
130
+ toDocument() {
131
+ if (typeof window === 'undefined' || typeof document === 'undefined') return this
132
+ document.querySelector('title')?.remove()
133
+ document.head.innerHTML = this.head.innerHTML
134
+ document.body.outerHTML = this.body.outerHTML
135
+ return this
136
+ }
129
137
  }
package/package.json CHANGED
@@ -1,12 +1,24 @@
1
1
  {
2
2
  "name": "als-layout",
3
- "version": "7.0.0",
4
- "main": "./main/layout.js",
3
+ "version": "7.1.0",
4
+ "main": "./src/layout.js",
5
5
  "module": "./index.mjs",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./index.mjs",
9
+ "require": "./src/layout.js"
10
+ }
11
+ },
12
+ "files": [
13
+ "index.mjs",
14
+ "layout.js",
15
+ "src/layout.js",
16
+ "readme.md"
17
+ ],
6
18
  "scripts": {
19
+ "build": "node build.js",
7
20
  "test": "node --test --experimental-test-coverage ./tests/**.*",
8
- "report": "node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info",
9
- "docs": "node ./scripts/build-readme.js"
21
+ "report": "node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
10
22
  },
11
23
  "keywords": [
12
24
  "html",