als-layout 0.4.9 → 1.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.js ADDED
@@ -0,0 +1,3 @@
1
+ const Layout = require('./lib/layout')
2
+
3
+ module.exports = Layout
@@ -0,0 +1,15 @@
1
+ const { buildFromCache, Root, parseHTML, cacheDoc } = require('als-document')
2
+
3
+ function buildRoot(item) {
4
+ const root =
5
+ (item instanceof Root) ? buildFromCache(cacheDoc(item))
6
+ : (typeof item === 'string') ? parseHTML(item)
7
+ : (typeof item === 'object') ? buildFromCache(item)
8
+ : new Root()
9
+
10
+ const firstNode = root.childNodes[0]
11
+ if(!firstNode || firstNode.tagName !== '!DOCTYPE') root.insert(1,/*html*/`<!DOCTYPE html>`)
12
+ return root
13
+ }
14
+
15
+ module.exports = buildRoot
@@ -0,0 +1,11 @@
1
+ const { SingleNode } = require('als-document')
2
+ function addMeta(props, layout) {
3
+ const entries = Object.entries(props)
4
+ const [name, value] = entries[0]
5
+ const selector = `meta[${name}="${value}"]`
6
+ const metaElement = layout.root.$(selector)
7
+ if (metaElement) entries.forEach(([name, v]) => metaElement.setAttribute(name, props[name]))
8
+ else layout.head.insert(2, new SingleNode('meta', props))
9
+ }
10
+
11
+ module.exports = addMeta
@@ -0,0 +1,8 @@
1
+ const { SingleNode } = require('als-document')
2
+
3
+ module.exports = function (charset = 'UTF-8', layout) {
4
+ const charsetElement = layout.head.$('meta[charset]')
5
+ if (charsetElement) charsetElement.setAttribute('charset', charset)
6
+ else layout.head.insert(2, new SingleNode('meta', { charset }))
7
+ return layout
8
+ }
@@ -0,0 +1,9 @@
1
+ const addMeta = require('./add-meta')
2
+
3
+ function addDescription(description, layout) {
4
+ addMeta({ name: 'description', content: description }, layout)
5
+ addMeta({ property: 'og:description', content: description }, layout)
6
+ addMeta({ property: 'twitter:description', content: description }, layout)
7
+ return layout
8
+ }
9
+ module.exports = addDescription
@@ -0,0 +1,10 @@
1
+ const { SingleNode } = require('als-document')
2
+
3
+ function addFavicon(href,layout) {
4
+ const faviconElement = layout.root.$('link[rel=icon][type=image/x-icon]')
5
+ if(faviconElement) faviconElement.setAttribute('href',href)
6
+ else layout.head.insert(2,new SingleNode('link',{rel:'icon',href,type:'image/x-icon'}))
7
+ return layout
8
+ }
9
+
10
+ module.exports = addFavicon
@@ -0,0 +1,9 @@
1
+ const addMeta = require('./add-meta')
2
+ function addImage(image,layout) {
3
+ addMeta({property:'og:image',content:image},layout)
4
+ addMeta({name:'twitter:image',content:image},layout)
5
+ addMeta({name:'twitter:card',content:'summary_large_image'},layout)
6
+ return layout
7
+ }
8
+
9
+ module.exports = addImage
@@ -0,0 +1,15 @@
1
+ const addKeywords = require('./keywords')
2
+ const addStyle = require('./style')
3
+ const addDescription = require('./description')
4
+ const addTitle = require('./title')
5
+ const addImage = require('./image')
6
+ const addUrl = require('./url')
7
+ const addFavicon = require('./favicon')
8
+ const addScript = require('./script')
9
+ const addLink = require('./link')
10
+ const charset = require('./charset')
11
+ const viewport = require('./viewport')
12
+ module.exports = {
13
+ addKeywords, addStyle, addDescription, addTitle, addImage,
14
+ addUrl, addFavicon, addScript,addLink,charset,viewport
15
+ }
@@ -0,0 +1,20 @@
1
+ const { SingleNode } = require('als-document')
2
+
3
+ function keywords(keywords = [], layout) {
4
+ const { root } = layout
5
+ let keywordsElement = root.$('meta[name=keywords]')
6
+ if (!keywordsElement) {
7
+ keywordsElement = new SingleNode('meta', { name: 'keywords' })
8
+ layout.head.insert(2, keywordsElement)
9
+ }
10
+ const content = keywordsElement.getAttribute('content')
11
+ const existingKeywords = content ? content.split(',') : []
12
+ keywords.forEach(keyword => {
13
+ keyword = keyword.trim()
14
+ if (!existingKeywords.includes(keyword)) existingKeywords.push(keyword)
15
+ });
16
+ keywordsElement.setAttribute('content', existingKeywords.join())
17
+ return layout
18
+ }
19
+
20
+ module.exports = keywords
@@ -0,0 +1,11 @@
1
+ const { SingleNode } = require('als-document')
2
+ function addLink(href, layout) {
3
+ let linkElement = layout.root.$(`link[rel=stylesheet][href="${href}"]`)
4
+ if (linkElement) return
5
+ linkElement = new SingleNode('link', { rel: 'stylesheet', href })
6
+ layout.head.insert(2, linkElement)
7
+ return layout
8
+ }
9
+
10
+
11
+ module.exports = addLink
@@ -0,0 +1,11 @@
1
+ const { Node } = require('als-document')
2
+ function addScript(attributes={}, innerHTML='', head = true, layout) {
3
+ if (attributes.src && layout.root.$(`script[src="${attributes.src}"]`)) return
4
+ const script = new Node('script', attributes)
5
+ script.innerHTML = innerHTML
6
+ if(head) layout.root.head.insert(2, script)
7
+ else layout.body.insert(3, script)
8
+ return layout
9
+ }
10
+
11
+ module.exports = addScript
@@ -0,0 +1,26 @@
1
+ const CssParser = require('als-css-parser');
2
+ const Simple = require('als-simple-css')
3
+ const { Node } = require('als-document')
4
+ function checkStyles(styles, minified) {
5
+ if (Array.isArray(styles)) styles = new Simple(styles).stylesheet(minified)
6
+ else if (minified) {
7
+ const cssParser = new CssParser(rawCss);
8
+ styles = cssParser.minified()
9
+ }
10
+ return styles
11
+ }
12
+
13
+ function addStyle(styles, minified=false,layout) {
14
+ styles = checkStyles(styles, minified)
15
+ let styleElement = layout.root.$('style')
16
+ if (!styleElement) {
17
+ styleElement = new Node('style')
18
+ layout.head.insert(2, styleElement)
19
+ }
20
+ if (!styleElement.innerHTML.includes(styles)) {
21
+ styleElement.innerHTML = styleElement.innerHTML + '\n' + styles
22
+ }
23
+ return layout
24
+ }
25
+
26
+ module.exports = addStyle
@@ -0,0 +1,11 @@
1
+ const addMeta = require('./add-meta')
2
+
3
+ function addTitle(title,layout) {
4
+ const element = layout.root.$('title')
5
+ if(element) element.innerHTML = title
6
+ else layout.head.insert(2,/*html*/`<title>${title}</title>`)
7
+ addMeta({property:'og:title',content:title},layout)
8
+ return layout
9
+ }
10
+
11
+ module.exports = addTitle
@@ -0,0 +1,17 @@
1
+ const addMeta = require('./add-meta')
2
+ const { SingleNode } = require('als-document')
3
+
4
+ function getUrl(url, host, layout) {
5
+ try {
6
+ url = new URL(url, host).href.replace(/\/$/, '')
7
+ addMeta({ 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(`url ${url} with host ${host} is not valid url`)
13
+ }
14
+ return layout
15
+ }
16
+
17
+ module.exports = getUrl
@@ -0,0 +1,8 @@
1
+ const { SingleNode } = require('als-document')
2
+
3
+ module.exports = function (viewport, layout) {
4
+ const element = layout.root.$('meta[name="viewport"]')
5
+ if (element) element.setAttribute('content', viewport)
6
+ else layout.head.insert(2, new SingleNode('meta', { name: 'viewport', content: viewport }))
7
+ return layout
8
+ }
package/lib/layout.js ADDED
@@ -0,0 +1,50 @@
1
+ const { cacheDoc } = require('als-document')
2
+ const {
3
+ addKeywords, addStyle, addDescription, addTitle, addImage,
4
+ addUrl, addFavicon, addScript, addLink, charset, viewport
5
+ } = require('./elements/index')
6
+ const buildRoot = require('./build-root')
7
+
8
+ class Layout {
9
+ constructor(layout, options = {}) {
10
+ this.options = options
11
+ this.root = buildRoot(layout)
12
+ this.body; this.head;
13
+ }
14
+
15
+ get html() {
16
+ const lang = this.options.lang || 'en'
17
+ if (!this.root.$('html')) this.root.insert(2,`<html></html>`)
18
+ const htmlElement = this.root.$('html')
19
+ if(lang && htmlElement.getAttribute('lang') !== lang) {
20
+ htmlElement.setAttribute('lang',lang)
21
+ }
22
+ return htmlElement
23
+ }
24
+ get body() {
25
+ if (!this.root.body) this.html.insert(2,`<body></body>`)
26
+ return this.root.body
27
+ }
28
+ get head() {
29
+ if (!this.root.head) this.html.insert(1,`<head></head>`)
30
+ return this.root.head
31
+ }
32
+
33
+ get rawHtml() { return this.root.innerHTML }
34
+ get cached() { return cacheDoc(this.root) }
35
+ get clone() { return new Layout(this.root, this.options) }
36
+
37
+ keywords(keywords = []) { return addKeywords(keywords, this) }
38
+ description(description) { return addDescription(description, this) }
39
+ title(title) { return addTitle(title, this) }
40
+ style(styles, minified) { return addStyle(styles, minified, this) }
41
+ image(image) { return addImage(image, this) }
42
+ url(url, host = this.options.host) { return addUrl(url, host, this) }
43
+ favicon(href) { return addFavicon(href, this) }
44
+ script(attributes, innerHTML, head = true) { return addScript(attributes, innerHTML, head, this) }
45
+ link(href) { return addLink(href, this) }
46
+ charset(newCharset = 'UTF-8') { return charset(newCharset, this) }
47
+ viewport(newViewport = 'width=device-width, initial-scale=1.0') { return viewport(newViewport, this) }
48
+ }
49
+
50
+ module.exports = Layout
package/package.json CHANGED
@@ -1,9 +1,20 @@
1
1
  {
2
2
  "name": "als-layout",
3
- "version": "0.4.9",
4
- "description": "Create html layout",
5
- "main": "layout.js",
3
+ "version": "1.1.0",
4
+ "description": "Html layout constructor",
5
+ "main": "index.js",
6
+ "directories": {
7
+ "lib": "lib"
8
+ },
9
+ "scripts": {
10
+ "test": "node ./tests/run-tests.js"
11
+ },
6
12
  "keywords": [],
7
- "author": "",
8
- "license": "ISC"
13
+ "author": "Alex Sorkin",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "als-css-parser": "^0.5.0",
17
+ "als-document": "^1.0.1-beta",
18
+ "als-simple-css": "^8.0.0"
19
+ }
9
20
  }
package/readme.md CHANGED
@@ -1,88 +1,66 @@
1
1
  # Als-layout
2
2
 
3
- * new in 0.4.5
4
- * rootUrl parameter
5
- * styles parameter
6
- * new in 0.4.1
7
- * Added spaces between properties on meta tags
8
- * new in 0.4:
9
- * minify
10
- * package optimization
11
- * can be used in node and in browser
12
- * new in 0.3: scripts and links now array
3
+ Html layout constructor.
13
4
 
14
- ## Syntax
15
- ```javascript
16
- // Create Layout object
17
- let layout = new Layout({
18
- title,body,description,image,
19
- lang='en',url,twiterName,
20
- scripts=[],links=[],
21
- favicon,footer='',header='',
22
- charset='UTF-8',styles='',
23
- rootUrl = ''
24
- })
25
- // Get updated layout
26
- let pageLayout = layout.get({
27
- title,body,description,image,
28
- lang,url,favicon,
29
- footer='',header='',
30
- scripts=[],links=[],
31
- charset=this.charset
32
- })
33
- ```
5
+ ## Change log
6
+ * clone - now it works
7
+ * script({},inner = '') default for inner for script is ''
8
+ * url - throwing error for not valid url
34
9
 
35
- ## Changing defaults
36
- Each Layout object has defaults, which you can change if needed.
37
- * defaults - defaults for options
38
- * meta - defaults for meta tags
39
- * tab - adding this before children tags
40
- * n - added at end of line
10
+ ## install
41
11
 
42
- ```javascript
43
- defaults = {lang:'en',scripts:[],links:[],footer:'',header:'',body:'',charset:'UTF-8'}
44
- meta = [
45
- {'http-equiv':"X-UA-Compatible", content:"IE=edge"},
46
- {name:"viewport",content:"width=device-width, initial-scale=1.0"},
47
- {property:"og:type", content:"website"},
48
- ]
49
- tab=' ' // then minify=true, tab=''
50
- n=` // then minify=true, n=''
51
- `
12
+ ```bash
13
+ npm i als-layout
52
14
  ```
53
15
 
54
- ### Example for changing defaults
16
+ ## Basic usage
55
17
 
56
- ```javascript
57
- let layout = new Layout()
58
- layout.meta[2].content = 'video.movie'
59
- layout.tab = ' '
60
- layout.defaults.lang = 'ru'
61
- layout.defaults.footer = '<div>Copyright for some...</div>'
62
- ```
18
+ ```js
19
+ const Layout = require('als-layout')
20
+ const layout = new Layout()
21
+ .charset() // default UTF-8
22
+ .viewport() // default width=device-width, initial-scale=1.0
23
+ .title('Test title') // adding/updating title and meta[og:title]
24
+ .favicon('/favicon.png') // adding/updating link[rel=icon][type=image/x-icon] with new href
25
+ .keywords(['some','keyword']) // adding/updating meta[name=keywords]. not adding existing keywords
26
+ .image('/main-image.png') // adding/updating meta - og:image,twitter:image,twitter:card
27
+ .description('Cool site') // adding/updating meta og:description,twitter:description and description tag
28
+ .url('/some', 'http://site.com') // adding/updating meta[og:url] and link[rel="canonical"]
29
+ .style([{body:{m:0,bgc:'whitesmoke'}}]) // adding as simple-css styles to existing/new style tag
30
+ .style('body {margin:0; backgroung-color:whitesmoke;}',true) // adding css styles to existing/new style tag. Second parameter is minified (default=false).
31
+ .link('/styles.css') // adding link[rel=stylesheet] if such href not exists
32
+ .script({src:'/app.js'},'', true) // set script with src to head if such src not exists
33
+ .script({}, 'console.log("hello world")', false) // set script with script code to footer
63
34
 
64
- ## Minify
65
- ```javascript
66
- let Layout = require('als-layout')
67
- Layout.minify = true // false by default. if true, return minified html
68
- ```
69
35
 
70
- ## scripts and links
36
+ layout.body // getter for body element (if not exists, created)
37
+ layout.head // getter for head element (if not exists, created)
38
+ layout.html // getter for html element (if not exists, created)
71
39
 
72
- ```javascript
73
- let scripts = [
74
- {inner='',src='',async,crossorigin,defer,integrity,referrerpolicy,type,footer=false,v}
75
- ]
76
- let links = [
77
- {href,rel='stylesheet',crossorigin,hreflang,media,referrerpolicy,sizes,type,v}
78
- ]
40
+ layout.rawHtml // raw html
41
+ layout.cached // cached DOM
42
+ layout.clone // new layout object clone for curent object
79
43
  ```
80
44
 
81
- ## styles
82
- You can add css styles as string which will be added inside as ``<style>/*your styles*/</style>`` inside head teag.
83
45
 
46
+ ## Advanced usage
47
+
48
+ ```js
49
+ const Layout = require('./lib/layout')
50
+
51
+ const raw = /*html*/`<html></html>`
52
+ const options = {
53
+ host:'http://example.com', // host for url method
54
+ lang:'fr' // for <html lang="fr"></html>
55
+ }
56
+ const layout = new Layout(raw,options)
57
+ console.log(layout.rawHtml)
58
+ // <!DOCTYPE html><html lang="fr"><head></head><body></body></html>
59
+
60
+ const homePage = layout.clone
61
+ homePage.title('Home page')
62
+ homePage.body.innerHTML = /*html*/`<h1>Home page</h1>`
63
+ console.log(homePage.rawHtml)
64
+ // <!DOCTYPE html><html lang="fr"><head><title>Home page</title><meta property="og:title" content="Home page"></head><body><h1>Home page</h1></body></html>
65
+ ```
84
66
 
85
- ## rootUrl
86
- rootUrl parameter is a url you want to add to different links.
87
- * adding rootUrl to meta url,meta image and favicon url
88
- * adding to all scripts, links which starts with "/"
@@ -0,0 +1,25 @@
1
+ const assert = require('assert');
2
+ const { describe, it } = require('node:test')
3
+ const buildRoot = require('../lib/build-root');
4
+ const { Root, cacheDoc } = require('als-document');
5
+
6
+ describe('Basic tests', function () {
7
+ it('should create an instance of Root if undefind', () => {
8
+ assert(buildRoot() instanceof Root)
9
+ });
10
+
11
+ it('should create an instance of Root from cached', () => {
12
+ const cached = cacheDoc(new Root())
13
+ assert(buildRoot(cached) instanceof Root)
14
+ });
15
+
16
+ it('should create an instance of Root from ready root', () => {
17
+ const root = new Root()
18
+ assert(buildRoot(root) !== root)
19
+ });
20
+
21
+ it('should add !DOCTYPE', () => {
22
+ const root = buildRoot()
23
+ assert(root.childNodes[0].tagName === '!DOCTYPE')
24
+ });
25
+ })
@@ -0,0 +1,47 @@
1
+ const assert = require('assert');
2
+ const { describe, it } = require('node:test')
3
+ const Layout = require('../lib/layout');
4
+ const { Root,cacheDoc } = require('als-document')
5
+
6
+ describe('Layout Initialization', () => {
7
+ it('should create an instance of Layout', () => {
8
+ const layout = new Layout();
9
+ assert(layout instanceof Layout, 'layout is not an instance of Layout');
10
+ });
11
+
12
+ it('should initialize default language as "en"', () => {
13
+ const layout = new Layout();
14
+ assert(layout.html.getAttribute('lang') === 'en', 'default language is not "en"');
15
+ });
16
+
17
+ it('should allow setting a custom language', () => {
18
+ const customLang = 'fr';
19
+ const layout = new Layout(undefined, { lang: customLang });
20
+ assert(layout.options.lang === customLang, `language is not set to ${customLang}`);
21
+ });
22
+
23
+ it('should initialize development mode as undefined or false', () => {
24
+ const layout = new Layout();
25
+ assert.strictEqual(layout.dev, undefined, 'dev is not undefined or false by default');
26
+ });
27
+
28
+ it('should initialize host as undefined', () => {
29
+ const layout = new Layout();
30
+ assert.strictEqual(layout.host, undefined, 'host is not undefined by default');
31
+ });
32
+
33
+ it('should allow setting a custom host', () => {
34
+ const customHost = 'http://localhost';
35
+ const layout = new Layout(undefined, { host: customHost });
36
+ assert.strictEqual(layout.options.host, customHost, `host is not set to ${customHost}`);
37
+ });
38
+
39
+ it('check method',() => {
40
+ const cached = cacheDoc(new Root())
41
+ const layout = new Layout(cached)
42
+ const root = layout.root
43
+ assert(root.$('html') !== null)
44
+ assert(root.$('head') !== null)
45
+ assert(root.$('body') !== null)
46
+ })
47
+ });
@@ -0,0 +1,101 @@
1
+ const assert = require('assert');
2
+ const Layout = require('../lib/layout');
3
+ const { describe, it,beforeEach } = require('node:test')
4
+ const Simple = require('als-simple-css')
5
+ describe('Elements Integration', () => {
6
+ let layout;
7
+
8
+ beforeEach(() => layout = new Layout());
9
+
10
+ it('should add charset correctly', () => {
11
+ const charset = 'test';
12
+ layout.charset(charset);
13
+ assert.strictEqual(layout.root.$('meta[charset]').getAttribute('charset'), charset, 'Charset not set correctly');
14
+ });
15
+
16
+ it('should add description correctly', () => {
17
+ const description = 'Test Description';
18
+ layout.description(description);
19
+ assert.strictEqual(layout.root.$('meta[name="description"]').getAttribute('content'), description, 'Description not set correctly');
20
+ assert.strictEqual(layout.root.$('meta[property="og:description"]').getAttribute('content'), description, 'Description not set correctly');
21
+ assert.strictEqual(layout.root.$('meta[property="twitter:description"]').getAttribute('content'), description, 'Description not set correctly');
22
+ });
23
+
24
+ it('should add favicon correctly', function () {
25
+ const faviconHref = 'favicon.ico';
26
+ layout.favicon(faviconHref);
27
+ assert.strictEqual(layout.root.$('link[rel="icon"]').getAttribute('href'), faviconHref, 'Favicon not set correctly');
28
+ });
29
+
30
+ it('should add image correctly', () => {
31
+ const imageUrl = 'test-image.jpg';
32
+ layout.image(imageUrl);
33
+ assert.strictEqual(layout.root.$('meta[property="og:image"]').getAttribute('content'), imageUrl, 'Image not set correctly');
34
+ assert.strictEqual(layout.root.$('meta[name="twitter:image"]').getAttribute('content'), imageUrl, 'Image not set correctly');
35
+ });
36
+
37
+ it('should add link correctly', () => {
38
+ const href = 'style.css';
39
+ layout.link(href);
40
+ assert.strictEqual(layout.root.$('link[rel="stylesheet"]').getAttribute('href'), href, 'Link not set correctly');
41
+ });
42
+
43
+ it('should add script correctly', () => {
44
+ const scriptContent = 'console.log("Hello, world!");';
45
+ layout.script({}, scriptContent);
46
+ assert.strictEqual(layout.root.$('script').innerHTML, scriptContent, 'Script content not set correctly');
47
+ });
48
+
49
+ it('should add title correctly', () => {
50
+ const title = 'Test Title';
51
+ layout.title(title);
52
+ assert(layout.root.$('title').innerHTML === title, 'Title not set correctly');
53
+ assert(layout.root.$('[property="og:title"]').getAttribute('content') === title, 'Title not set correctly');
54
+ });
55
+
56
+
57
+ it('should add url correctly', () => {
58
+ const url = 'http://localhost';
59
+ layout.url(url);
60
+ assert(layout.root.$('link[rel="canonical"]').getAttribute('href') === url, 'Canonical URL not set correctly');
61
+ });
62
+
63
+ it('should add keywords correctly', () => {
64
+ const keywords = ['keyword1', 'keyword2'];
65
+ layout.keywords(keywords);
66
+ assert(layout.root.$('meta[name="keywords"]').getAttribute('content') === keywords.join(), 'Keywords not set correctly');
67
+ });
68
+
69
+ it('should add viewport correctly', () => {
70
+ const viewportContent = 'width=device-width, initial-scale=1.0';
71
+ layout.viewport(viewportContent);
72
+ assert.strictEqual(layout.root.$('meta[name="viewport"]').getAttribute('content'), viewportContent, 'Viewport not set correctly');
73
+ });
74
+
75
+ it('should add style correctly', () => {
76
+ const styles = 'body { background-color: black; }';
77
+ layout.style(styles);
78
+ assert.strictEqual(layout.root.$('style').innerHTML.includes(styles), true, 'Styles not set correctly');
79
+ });
80
+
81
+ it('Should add simple styles',() => {
82
+ const styles = [{body:{bgc:'black'}}]
83
+ const css = new Simple(styles).stylesheet()
84
+ layout.style(styles);
85
+ assert(layout.root.$('style').innerHTML.includes(css), 'Styles not set correctly');
86
+ })
87
+
88
+ it('should add styles to existing style tag', () => {
89
+ assert(layout.root.$$('style').length === 0)
90
+ const styles1 = 'body { background-color: black; }';
91
+ const styles2 = 'body { margin: 0; }';
92
+ layout.style(styles1);
93
+ assert(layout.root.$$('style').length === 1)
94
+ layout.style(styles2);
95
+ assert(layout.root.$$('style').length === 1)
96
+ const inner = layout.root.$('style').innerHTML
97
+ assert(inner.includes(styles1));
98
+ assert(inner.includes(styles2));
99
+ });
100
+
101
+ });
@@ -0,0 +1,33 @@
1
+ const assert = require('assert');
2
+ const { describe, it, beforeEach } = require('node:test')
3
+ const Layout = require('../lib/layout');
4
+
5
+ describe('Layout Integrative tests', () => {
6
+ let layout;
7
+
8
+ beforeEach(() => layout = new Layout());
9
+
10
+ it('should integrate multiple elements correctly', () => {
11
+ layout.title('Test Title');
12
+ layout.description('Test Description');
13
+ layout.keywords(['keyword1', 'keyword2']);
14
+
15
+ assert(layout.root.$('title').innerHTML === 'Test Title', 'Title not integrated correctly');
16
+ assert(layout.root.$('meta[name="description"]').getAttribute('content') === 'Test Description', 'Description not integrated correctly');
17
+ assert(layout.root.$('meta[name="keywords"]').getAttribute('content') === 'keyword1,keyword2', 'Keywords not integrated correctly');
18
+ });
19
+
20
+ it('should update elements correctly when added multiple times', () => {
21
+ layout.title('First Title');
22
+ assert(layout.root.$('title').innerHTML === 'First Title', 'Title did not update correctly when added multiple times');
23
+ layout.title('Second Title');
24
+ assert(layout.root.$('title').innerHTML === 'Second Title', 'Title did not update correctly when added multiple times');
25
+ });
26
+
27
+ it('should remove elements correctly', () => {
28
+ layout.title('Test Title');
29
+ layout.root.$('title').remove();
30
+ assert(layout.root.$('title') === null, 'Title element was not removed correctly');
31
+ });
32
+
33
+ });
@@ -0,0 +1,6 @@
1
+ const { execSync } = require('child_process');
2
+ let [,, path] = process.argv;
3
+
4
+ execSync(`node --test ./tests/${path}.test.js`, { stdio: 'inherit' });
5
+
6
+ // Example: npm test mw.cookie
package/layout.js DELETED
@@ -1,115 +0,0 @@
1
- class Layout {
2
- static minify=false
3
- defaults = {lang:'en',scripts:[],links:[],footer:'',header:'',body:'',charset:'UTF-8',styles:''}
4
- meta = [
5
- {'http-equiv':"X-UA-Compatible", content:"IE=edge"},
6
- {name:"viewport",content:"width=device-width, initial-scale=1.0"},
7
- {property:"og:type", content:"website"},
8
- ]
9
- tab=' '
10
- n=`
11
- `
12
- constructor(options={}) {
13
- if(Layout.minify) this.tab = this.n = ''
14
- options = {...this.defaults,...options}
15
- for(let key in options) {
16
- this[key] = options[key]
17
- }
18
- }
19
-
20
- get(options={}) {
21
- for(let key in options) {
22
- if(key == 'scripts' || key == 'links') {
23
- if(!Array.isArray(options[key])) options[key] = []
24
- this[key] = [...this[key],...options[key]]
25
- }
26
- else this[key] = options[key]
27
- }
28
- return this.template()
29
- }
30
-
31
- template(n=this.n,tab=this.tab) {
32
- let {rootUrl='',favicon,title,header,body,footer,styles,htmlAtts=[],bodyAtts=[]} = this
33
- let {footerScripts,headerScripts} = this.buildScripts()
34
- let links = this.buildLinks()
35
- let template = /*html*/`<!DOCTYPE html>`+n
36
- template +=/*html*/`<html lang="${this.lang}" ${htmlAtts.join(' ')}>`+n
37
- template +=/*html*/`<head>`+n
38
- template += links ? links+n : ''
39
- template += styles ? /*html*/`<style>${styles}</style>`+n : ''
40
- template += headerScripts ? headerScripts : ''
41
- template += tab+/*html*/`<meta charset="${this.charset}">`+n
42
- template += this.buildMeta()+n
43
- template += favicon ? tab+/*html*/`<link rel="icon" href="${rootUrl}${favicon}" type="image/x-icon" >`+n : ''
44
- template += title ? tab+/*html*/`<title>${title || ''}</title>`+n : ''
45
- template +=/*html*/`</head>`+n
46
- template += /*html*/`<body ${ bodyAtts.join(' ')}>`+n
47
- template += header ? tab+header+n : ''
48
- template += tab+body+n
49
- template += footer ? tab+footer+n : ''
50
- template += footerScripts ? footerScripts : ''
51
- template += /*html*/`</body>`+n
52
- template += /*html*/`</html>`
53
- return template
54
- }
55
-
56
- buildMeta(n=this.n,tab=this.tab) {
57
- let meta = this.meta
58
- let {title,url,description,image,twiterName,rootUrl} = this
59
- if(rootUrl) {
60
- url = rootUrl+url
61
- image = rootUrl+image
62
- }
63
- if(description) {
64
- meta.push({name:"description",content:description})
65
- meta.push({property:"og:description",content:description})
66
- meta.push({name:"twitter:description",content:description})
67
- }
68
- if(image) {
69
- meta.push({property:"og:image", content:image})
70
- meta.push({name:"twitter:image", content:image})
71
- meta.push({name:"twitter:card", content:'summary_large_image'})
72
- } else {
73
- meta.push({name:"twitter:card", content:'article'})
74
- }
75
- if(twiterName) meta.push({name:"twitter:site",content:twiterName})
76
- if(title) meta.push({property:"og:title", content:title})
77
- if(url) meta.push({property:"og:url",content:url})
78
- return meta.map(obj => tab+
79
- /*html*/`<meta ${Object.keys(obj).map(propName => `${propName}="${obj[propName]}"`).join(' ')}>`
80
- ).join(n)
81
- }
82
-
83
- buildScripts() {
84
- let footerScripts = ''
85
- let headerScripts = ''
86
- let excludes = ['inner','v','footer']
87
- this.scripts.forEach(script => {
88
- let {inner='',v,src,footer} = script
89
- if(src && this.rootUrl)
90
- if(src.startsWith('/')) script.src = this.rootUrl+src
91
- if(src && v) script.src = script.src+'?'+v
92
- script = '<script '+Object.keys(script)
93
- .filter(p => !excludes.includes(p))
94
- .map(prop => `${prop}="${script[prop] || ''}"`).join(' ')
95
- +'>'+inner+`</script>`
96
- if(footer) footerScripts += this.tab+script+this.n
97
- else headerScripts += this.tab+script+this.n
98
- })
99
- return {footerScripts,headerScripts}
100
- }
101
-
102
- buildLinks() {
103
- return this.links.map(link => {
104
- let {href,v,rel} = link
105
- if(rel == undefined) link.rel = 'stylesheet'
106
- if(href && this.rootUrl)
107
- if(href.startsWith('/')) link.href = this.rootUrl+href
108
- if(href && v) link.href = href+'?'+v
109
- return this.tab+'<link '
110
- +Object.entries(link).map(([key,value]) => `${key}="${value}"`).join(' ')
111
- +'>'
112
- }).join(this.n)
113
- }
114
- }
115
- try {module.exports = Layout} catch{}