├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bundle └── render-basic │ ├── .babelrc │ ├── .eslintrc.js │ ├── examples │ ├── client.html │ ├── css │ │ └── main.css │ ├── img │ │ ├── fail.png │ │ └── ok.png │ ├── index.html │ └── source.html │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── index.js │ └── main.css │ └── webpack.config.js ├── index.js ├── package-lock.json ├── package.json └── src ├── DataManager.js ├── Elements.js ├── Hyperdata.js └── TextFormatting.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | bundle/*/dist/ 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /css 3 | /bundle 4 | .babelrc 5 | .eslintrc.js 6 | webpack.config.js -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 webdatarender 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Basic Render 2 | 3 | Read the documentation at WDR website: https://devgutt.github.io/wdr/basic-render.html 4 | 5 | -------------------------------------------------------------------------------- /bundle/render-basic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "useBuiltIns": "entry" 7 | } 8 | ] 9 | ] 10 | } -------------------------------------------------------------------------------- /bundle/render-basic/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "node": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended" 8 | ], 9 | "globals": { 10 | "Atomics": "readonly", 11 | "SharedArrayBuffer": "readonly" 12 | }, 13 | "parserOptions": { 14 | "ecmaVersion": 2018, 15 | "sourceType": "module" 16 | }, 17 | "rules": { 18 | "no-console" : "off", 19 | "no-unused-vars" : ["warn", { "varsIgnorePattern": "ignored" }] 20 | }, 21 | "settings": { 22 | "propWrapperFunctions": [ 23 | "forbidExtraProps", 24 | {"property": "freeze", "object": "Object"}, 25 | {"property": "myFavoriteWrapper"} 26 | ], 27 | "linkComponents": [ 28 | "Hyperlink", 29 | {"name": "Link", "linkAttribute": "to"} 30 | ] 31 | } 32 | }; -------------------------------------------------------------------------------- /bundle/render-basic/examples/client.html: -------------------------------------------------------------------------------- 1 | { 2 | "#title": "Client", 3 | "info": { 4 | "num": 120, 5 | "txt": "ATOME" 6 | }, 7 | "tst": [ 8 | "The number id **{{ info.num }}** and the number again {{ info.txt }} and {{ info.txt.ttt.hello.opa }}" 9 | ], 10 | "main": [ 11 | "The external number id **{{ [/examples/simple/source.html] info.num }}** and **{{ [/examples/simple/source.html] info.txt }}**", 12 | "The number id **{{ info.num }}** and the number again {{ info.txt }}", 13 | "The number id **{{ [/examples/simple/source.html] info.nested.hello }}**", 14 | "WDR Title **{{ [https://webdatarender.com] #title }}**", 15 | "WDR Last Update **{{ [https://webdatarender.com] updates.items.0.description }}**", 16 | "WDR Last last Update **{{ [https://webdatarender.com] updates.items.1.description }}**", 17 | "WDR Subscribe **{{ [https://webdatarender.com] subscribe }}**", 18 | "Evaluatly code **{{ [https://evaluatly.com] code.description }}**", 19 | "" 20 | ], 21 | "#sec": [ 22 | "The number id **{{ [/examples/simple/source.html] info.txt }}** and \nthis is another {{ [/examples/simple/source.html] info.txt }}", 23 | "The number id **{{ [http://nn] info.txt }}** this is another {{ [/examples/simple/source.html] info.txt }}", 24 | "The number id **{{ [http://nn] info.txt }}** and the number again {{ info.txt }}", 25 | "The number id **{{ [/examples/simple/source.html] info.#loopa }}** and the number again {{ info.txt }}", 26 | "The number id **{{ [/examples/simple/source.html] info.txt }}**", 27 | "The number id **{{ [/examples/simple/index.html] info.txt }}**", 28 | "" 29 | ], 30 | "#test": [ 31 | "--------------------------------------------------", 32 | "The number id **{{ info.num }}**", 33 | "The number id **{{info.num}}**", 34 | "The number id **{{ info.num }}**", 35 | "The number id **{{ info.num {{num}} }}**", 36 | "The number id **{{ [/examples/simple/source.html]info.num }}**", 37 | "The number id **{{ [/examples/simple/source.html] info.num }}**", 38 | "" 39 | ], 40 | 41 | 42 | "#render": { 43 | "_": "", 44 | "css": "css/main.css" 45 | } 46 | } -------------------------------------------------------------------------------- /bundle/render-basic/examples/css/main.css: -------------------------------------------------------------------------------- 1 | .section-1 h2 { 2 | color: darkviolet; 3 | } 4 | .content code { 5 | color: red; 6 | } 7 | -------------------------------------------------------------------------------- /bundle/render-basic/examples/img/fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devgutt/wdr-render-basic/d01c91b891250fcab9aecd9b99a44bb9ab883ead/bundle/render-basic/examples/img/fail.png -------------------------------------------------------------------------------- /bundle/render-basic/examples/img/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devgutt/wdr-render-basic/d01c91b891250fcab9aecd9b99a44bb9ab883ead/bundle/render-basic/examples/img/ok.png -------------------------------------------------------------------------------- /bundle/render-basic/examples/index.html: -------------------------------------------------------------------------------- 1 | { 2 | "#info": { 3 | "title": "Page's title", 4 | "updated": "Nov 24 2020" 5 | }, 6 | "img": "this is the ![logo](img/ok.png) and this is the [link](#)", 7 | "menu": ["[Home](#section-1) [Section 1](#section-1) [Section 2](#section-2) [Page 1](/about)"], 8 | "title": "Title h1", 9 | "subtitle": [ 10 | "_It is a long **established fact** that a reader will be distracted by the readable content of a page when looking at its layout._" 11 | ], 12 | "content": [ 13 | "It is a long **established fact** that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.", 14 | "There are many variations of `var x=1;` passages of Lorem Ipsum available, but the majority have suffered alteration in some `form`, by injected humour, or randomised words which don't look even slightly believable.", 15 | "If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text." 16 | ], 17 | "#ignore": "This tag is ignored", 18 | "img2": "![fail img](img/fail.png)", 19 | "hello": "world", 20 | "coding": "this is the code ```{\n \"key\": \"If you are going <b>to<\/b> use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text.\",\n \"key2\": \"value\"\n}``` oia o code.", 21 | "section-1": { 22 | "title": "Subtitle h2 👋", 23 | "subtitle": "Subtitle", 24 | "description": "Paragraph ~~delete~~...", 25 | "more": "[Link →](#)", 26 | "code": "{\n \"key\": \"If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text.\",\n \"key2\": \"value\"\n}", 27 | "num": 23, 28 | "bool": true, 29 | "subsection": { 30 | "title": "Subtitle h3", 31 | "description": "Subsection [description](#) passages of Lorem Ipsum available, but the majority.", 32 | "img": "img/ok.png", 33 | "moreimg": [ 34 | "![s](img/ok.png)", 35 | "![s](img/fail.png)", 36 | "![s](img/ok.png) ![s](img/fail.png)" 37 | ] 38 | }, 39 | "items": [ 40 | "item 1", 41 | "item 2", 42 | "item 3" 43 | ] 44 | }, 45 | "section-2": { 46 | "title": "Subtitle h2", 47 | "description": "This is the description...", 48 | "items": [ 49 | { 50 | "name": "**Item 1**", 51 | "description": "description ação...", 52 | "items": [ 53 | { 54 | "name": "**Item 1.1**", 55 | "description": "If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text.", 56 | "more": "[more](#)" 57 | }, 58 | { 59 | "name": "**Item 2.1**", 60 | "description": "If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text.." 61 | } 62 | ] 63 | }, 64 | { 65 | "name": "**Item 2**", 66 | "description": "description..." 67 | }, 68 | "thank you 🙏" 69 | ] 70 | }, 71 | "#render": { 72 | "_": "", 73 | "css": "css/main.css" 74 | } 75 | } -------------------------------------------------------------------------------- /bundle/render-basic/examples/source.html: -------------------------------------------------------------------------------- 1 | { 2 | "#title": "Source", 3 | "info": { 4 | "num": 42, 5 | "txt": "Universe", 6 | "nested": { 7 | "hello": "world" 8 | }, 9 | "description": [ 10 | "#1 This is **one** text.", 11 | "#2 This is *another* text.", 12 | "#3 Paragraph 3." 13 | ], 14 | "test": "console.log('Hi')" 15 | }, 16 | "main": [ 17 | "-----", 18 | "The number id **{{ info.num }}** and the number again {{ info.txt }} in {{ info.nested.hello }}", 19 | "one: {{info.description.1}}", 20 | "All: {{info.description}}", 21 | "All: {{info.test}}", 22 | "Version is {{ [https://webdatarender.com/basic-render.html] install.#version }}", 23 | "Title: {{ [https://evaluatly.com] hero.title }}", 24 | "Title: {{ [https://evaluatly.com] hero.description }}" 25 | ], 26 | 27 | 28 | "#render": { 29 | "_": "", 30 | "css": "css/main.css" 31 | } 32 | } -------------------------------------------------------------------------------- /bundle/render-basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wdr-render-basic-bundle", 3 | "version": "1.0.0", 4 | "description": "WDR basic render bundle", 5 | "author": "Gustavo Pires", 6 | "repository": "https://github.com/webdatarender/wdr-render-basic.git", 7 | "bugs": "https://github.com/webdatarender/wdr-render-basic/issues", 8 | "homepage": "https://webdatarender.com", 9 | "license": "MIT", 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "dev": "webpack", 13 | "prod": "NODE_ENV=prod webpack" 14 | }, 15 | "browserslist": [ 16 | "defaults" 17 | ], 18 | "dependencies": { 19 | "regenerator-runtime": "^0.13.7", 20 | "wdr-loader": "^1.0.2", 21 | "wdr-render-basic": "file:../.." 22 | }, 23 | "devDependencies": { 24 | "@babel/cli": "^7.10.1", 25 | "@babel/core": "^7.10.2", 26 | "@babel/preset-env": "^7.10.2", 27 | "babel-loader": "^8.0.6", 28 | "css-loader": "^3.6.0", 29 | "eslint": "^5.16.0", 30 | "eslint-loader": "^2.2.1", 31 | "mini-css-extract-plugin": "^0.9.0", 32 | "style-loader": "^1.1.3", 33 | "webpack": "^5.6.0", 34 | "webpack-cli": "^4.2.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bundle/render-basic/src/index.js: -------------------------------------------------------------------------------- 1 | import 'regenerator-runtime/runtime'; 2 | 3 | import loader from 'wdr-loader'; 4 | import render from 'wdr-render-basic'; 5 | 6 | import './main.css'; 7 | 8 | loader(data => { 9 | const dataManager = render.createDataManager(data); 10 | 11 | render.appendElement(document.head, [ 12 | render.createElement('meta', { charset: "utf-8" }), 13 | render.createElement('meta', { name: "viewport", content: "width=device-width", 'initial-scale': 1 }), 14 | render.createElement('title', {}, (data['#title'] || data['title'])) 15 | ]); 16 | 17 | if (data['#render'] && data['#render'].css) { 18 | render.appendElement(document.head, render.createElement('link', { rel: "stylesheet", href: data['#render'].css })); 19 | } 20 | 21 | const main = render.createElement('main', {}); 22 | render.appendElement(document.body, main); 23 | 24 | renderItem(dataManager, main, '', data, 0); 25 | }); 26 | 27 | function renderItem(dataManager, parent, key, value, level) { 28 | 29 | if (Array.isArray(value)) { 30 | 31 | const section = render.createElement('div', { class: key }); 32 | render.appendElement(parent, section); 33 | 34 | value.forEach(v => { 35 | if (typeof v == 'object') { 36 | const sectionItem = render.createElement('div', {}); 37 | render.appendElement(section, sectionItem); 38 | renderItem(dataManager, sectionItem, key, v, level); 39 | } else { 40 | renderItem(dataManager, section, null, v, level); 41 | } 42 | }) 43 | 44 | } else if (typeof value == 'object') { 45 | 46 | let p = parent; 47 | if (level == 1) { 48 | p = render.createElement('section', { class: key }); 49 | render.appendElement(parent, [render.createElement('a', { name: key }, ""), p]); 50 | } else if (level > 1) { 51 | p = render.createElement('div', { class: key }); 52 | render.appendElement(parent, p); 53 | } 54 | 55 | for (const k in value) { 56 | if (value.hasOwnProperty(k)) { 57 | if (k.startsWith('#')) continue; 58 | renderItem(dataManager, p, k, value[k], level + 1); 59 | } 60 | } 61 | 62 | } else { 63 | 64 | if (value !== undefined) { 65 | 66 | let e; 67 | if (key == 'title') { 68 | e = render.createElement(`h${level < 6 ? level : '6'}`, { class: key }); 69 | } else { 70 | e = render.createElement('p', { class: key }); 71 | } 72 | render.appendElement(parent, e); 73 | 74 | setValue(dataManager, e, value + ""); 75 | } 76 | 77 | } 78 | } 79 | 80 | function setValue(dataManager, el, str) { 81 | if (!str.includes('{{')) { 82 | el.innerHTML = render.textFormatting(str) 83 | } else { 84 | el.innerHTML = render.textFormatting(str.replace(/{{[^{}]+}}/g, "...")); 85 | render.processHyperdata(dataManager, str) 86 | .then(s => el.innerHTML = render.textFormatting(s)) 87 | .catch(error => { 88 | console.error(error); 89 | }); 90 | } 91 | } -------------------------------------------------------------------------------- /bundle/render-basic/src/main.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --font_color: #1A202C; 3 | --link_color: #3c4fe0; 4 | --back_item: rgba(0,0,0,0.05); 5 | --max_width: 800px; 6 | } 7 | 8 | html { 9 | box-sizing: border-box; 10 | } 11 | html, body { 12 | margin: 0; 13 | padding: 0; 14 | } 15 | *, *:before, *:after { 16 | box-sizing: inherit; 17 | } 18 | html { 19 | font-size: 18px; 20 | -moz-osx-font-smoothing: grayscale; 21 | -webkit-font-smoothing: antialiased; 22 | text-rendering: optimizeLegibility; 23 | text-size-adjust: 100%; 24 | } 25 | body { 26 | color: var(--font_color); 27 | font-weight: 400; 28 | background-color: #ffffff; 29 | -moz-osx-font-smoothing: grayscale; 30 | -webkit-font-smoothing: antialiased; 31 | text-rendering: optimizeLegibility; 32 | text-size-adjust: 100%; 33 | -webkit-tap-highlight-color: transparent; 34 | } 35 | body, button, input, select, textarea { 36 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; 37 | } 38 | code, pre { 39 | -moz-osx-font-smoothing: auto; 40 | -webkit-font-smoothing: auto; 41 | font-family: monospace; 42 | } 43 | a { 44 | color: var(--link_color); 45 | text-decoration: none; 46 | } 47 | a:hover { 48 | text-decoration: underline; 49 | } 50 | li { 51 | margin: 20px 0; 52 | } 53 | iframe { 54 | border: 0; 55 | } 56 | fieldset { 57 | border: none; 58 | } 59 | main { 60 | max-width: var(--max_width); 61 | margin: 0 auto; 62 | padding: 32px 16px; 63 | } 64 | h1, h2, h3, h4, h5, h6 { 65 | margin: 32px 0 16px; 66 | } 67 | p { 68 | margin: 16px 0; 69 | line-height: 1.4; 70 | } 71 | h1 { 72 | font-size: 3em; 73 | margin: 64px 0 32px; 74 | font-weight: 900; 75 | } 76 | pre { 77 | padding: 24px !important; 78 | overflow: scroll; 79 | } 80 | pre, .highlight { 81 | border-radius: 4px; 82 | background-color: var(--back_item); 83 | padding: 8px 24px; 84 | margin: 16px 0; 85 | } 86 | code { 87 | background: var(--back_item); 88 | padding: 0px 2px; 89 | border-radius: 3px; 90 | } 91 | -------------------------------------------------------------------------------- /bundle/render-basic/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const mode = process.env.NODE_ENV; 4 | 5 | let version = 'master'; 6 | if (mode == 'prod') { 7 | version = require('../../package.json').version; 8 | } 9 | console.log('version:', version); 10 | 11 | module.exports = { 12 | mode: mode == 'prod' ? 'production' : 'development', 13 | devtool: mode == 'prod' ? false : 'eval-cheap-module-source-map', 14 | output: { 15 | path: path.resolve(__dirname, 'dist'), 16 | filename: `render-basic-${mode == 'prod' ? version : 'dev'}.js` 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | enforce: "pre", 22 | test: /\.js$/, 23 | exclude: /(node_modules|wdr-loader|wdr-render-basic)/, 24 | loader: "eslint-loader" 25 | }, 26 | { 27 | test: /\.(js)$/, 28 | exclude: /(node_modules|bower_components)/, 29 | loader: "babel-loader", 30 | options: { presets: ["@babel/env"] } 31 | }, 32 | { 33 | test: /\.css$/i, 34 | use: [ 35 | 'style-loader', 36 | 'css-loader' 37 | ], 38 | } 39 | ] 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const el = require('./src/Elements'); 2 | 3 | module.exports = { 4 | createDataManager : require('./src/DataManager'), 5 | createElement: el.createElement, 6 | appendElement: el.appendElement, 7 | loadScript: el.loadScript, 8 | textFormatting : require('./src/TextFormatting'), 9 | processHyperdata: require('./src/Hyperdata') 10 | } 11 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wdr-render-basic", 3 | "version": "1.2.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wdr-render-basic", 3 | "version": "1.2.0", 4 | "description": "WDR basic render", 5 | "author": "Gustavo Pires", 6 | "main": "./index.js", 7 | "repository": "https://github.com/webdatarender/wdr-render-basic.git", 8 | "bugs": "https://github.com/webdatarender/wdr-render-basic/issues", 9 | "homepage": "https://webdatarender.com", 10 | "license": "MIT" 11 | } 12 | -------------------------------------------------------------------------------- /src/DataManager.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function createDataManager(data) { 4 | 5 | const DATA = {} 6 | 7 | async function getDataUrl(url) { 8 | 9 | if (url) { 10 | if (DATA[url] == undefined) { 11 | DATA[url] = fetch(url) 12 | .then(r => r.json()); 13 | } 14 | return DATA[url]; 15 | } 16 | } 17 | 18 | return { 19 | data, 20 | getDataUrl 21 | } 22 | } 23 | 24 | module.exports = createDataManager; 25 | -------------------------------------------------------------------------------- /src/Elements.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function createElement(type, attrs, children) { 4 | const e = createElementDoc(type); 5 | for (var attr in attrs) { 6 | const value = attrs[attr]; 7 | if (attr == 'style') { 8 | for (var st in value) { 9 | if (value[st] !== undefined) { 10 | e.style[st] = value[st]; 11 | } 12 | } 13 | } else if (attr == 'innerHTML') { 14 | e.innerHTML = value; 15 | } else { 16 | if (value !== undefined && value !== null) { 17 | e.setAttribute(attr, value); 18 | } 19 | } 20 | } 21 | if (children) { 22 | if (Array.isArray(children)) { 23 | children.forEach(item => { 24 | item && e.appendChild(item); 25 | }); 26 | } else { 27 | e.innerText = children; 28 | } 29 | } 30 | return e; 31 | } 32 | 33 | function createElementDoc(type) { 34 | switch (type) { 35 | case 'svg': 36 | case 'path': 37 | return document.createElementNS("http://www.w3.org/2000/svg", type); 38 | default: 39 | return document.createElement(type); 40 | } 41 | } 42 | 43 | function appendElement(parent, children) { 44 | if (Array.isArray(children)) { 45 | children.forEach(item => { 46 | item && parent.appendChild(item); 47 | }); 48 | } else { 49 | parent.appendChild(children); 50 | } 51 | } 52 | 53 | function loadScript(url, onload) { 54 | const script = document.createElement('script'); 55 | script.type = 'text/javascript'; 56 | script.async = true; 57 | document.head.appendChild(script); 58 | script.onload = onload; 59 | script.src = url; 60 | } 61 | 62 | module.exports = { 63 | createElement, 64 | appendElement, 65 | loadScript 66 | } 67 | -------------------------------------------------------------------------------- /src/Hyperdata.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | async function processHyperdata(dataManager, str) { 4 | const reg = /([\\]?){{\ *(?:\[([^{}]+)\]\ *)?([^{}]+)\ *}}/g; 5 | 6 | const ret = []; 7 | let match; 8 | let i = 0; 9 | while ((match = reg.exec(str)) !== null) { 10 | 11 | const opr = match[1]; 12 | 13 | ret.push(str.slice(i, match.index)); 14 | 15 | if (opr !== '\\') { 16 | const url = match[2]; 17 | const path = match[3]; 18 | try { 19 | ret.push(await getValue(dataManager, url, path)); 20 | } catch (error) { 21 | ret.push("[ERROR]"); 22 | } 23 | } else { 24 | ret.push((match[0] + "").slice(1)); 25 | } 26 | 27 | i = reg.lastIndex; 28 | } 29 | ret.push(str.slice(i)); 30 | 31 | return ret.join(""); 32 | } 33 | 34 | async function getValue(dataManager, url, path) { 35 | 36 | const data = url ? await dataManager.getDataUrl(url) : dataManager.data; 37 | const ret = path.split(".").reduce((acc, cur) => acc[(cur+"").trim()], data); 38 | return ret; 39 | } 40 | 41 | module.exports = processHyperdata; 42 | -------------------------------------------------------------------------------- /src/TextFormatting.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function textFormatting(str) { 4 | 5 | if (str === undefined) return ""; 6 | if (typeof str != 'string') return ""; 7 | 8 | const regTop = /(\*\*?|__?|~~|[<>\r\n])|\[([^[]*)\]\(([^(]*)\)|!\[([^[]*)\]\(([^(]*)\)|`([^`]+)`|```((?:.|\n)*)```|(#{1,6})\ (.*)/g; 9 | 10 | const closeTag = {}; 11 | const renderTag = tag => { 12 | if (!closeTag[tag]) { 13 | closeTag[tag] = true; 14 | return "<" + tag + ">"; 15 | } else { 16 | closeTag[tag] = false; 17 | return ""; 18 | } 19 | }; 20 | 21 | return str.replace(regTop, (m, cmd, linkName, linkUrl, imgAlt, imgPath, code, pre, titleNum, title) => { 22 | 23 | if (cmd) { 24 | if (cmd == '**' || cmd == '__') { 25 | return renderTag('strong'); 26 | } else if (cmd == '*' || cmd == '_') { 27 | return renderTag('em'); 28 | } else if (cmd == '~~') { 29 | return renderTag('del'); 30 | } else if (cmd == '>') { 31 | return ">"; 32 | } else if (cmd == '<') { 33 | return "<"; 34 | } else if (cmd == '\n') { 35 | return "
"; 36 | } else { 37 | return ""; 38 | } 39 | } else if (linkUrl) { 40 | return `${linkName || linkUrl}`; 41 | } else if (imgAlt) { 42 | return `${imgAlt}`; 43 | } else if (code) { 44 | return `${htmlEntities(code)}` 45 | } else if (pre) { 46 | return `
${htmlEntities(pre)}
` 47 | } else if (title) { 48 | return `${title}` 49 | } else { 50 | return ""; 51 | } 52 | }) 53 | } 54 | 55 | function htmlEntities(str) { 56 | return String(str).replace(/&/g, '&').replace(//g, '>'); 57 | } 58 | 59 | module.exports = textFormatting; 60 | 61 | --------------------------------------------------------------------------------