Skip to content

Commit 85e869e

Browse files
committed
Merge branch 'hman61-doohtml-lite-v0.98.2-april-31-2025'
2 parents f706280 + 377f6cb commit 85e869e

File tree

5 files changed

+34
-49
lines changed

5 files changed

+34
-49
lines changed

frameworks/keyed/doohtml-lite/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ <h1>DooHTML - Lite</h1><span class="ver"></span>
4949
<div
5050
data-template="table"
5151
data-has-html="false"
52-
data-key="key"
52+
data-key="id"
5353
>
5454
</div>
5555

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
const Config={t:"DooHTML",o:"data-bind",l:"data-template",p:{i:-1,T:0,m:1},u:{BEG:"{{",END:"}}"},N:"data-key",A:"key"},version="v0.97.5",getItemValue=(e,t)=>t.includes(".")?t.split(".").reduce(((e,t)=>e&&void 0!==e[t]?e[t]:""),e):e[t]?e[t]:"",isTable=e=>["TABLE","TBODY","THEAD","TFOOT","TR","TH"].includes(e.tagName),render=(e,t,o=0)=>{0!==t.length?renderHTML(e,t,o):e.textContent=""},renderHTML=(e,t,o=0,a=null)=>{let l,n,d=t.length,s=e.place[0],c=a?o+d:d-o;c>d&&(c=d);let r=s.C.length;const p=(e,o)=>{for(let a=0;a<r;a++)n=getNode(e,s.C[a][1],0),n?"textContent"===s.C[a][2]?n.textContent=t[o][s.C[a][0]]:n.setAttribute(s.C[a][2],t[o][s.C[a][0]]):console.info("Field:"+s.C[a][0]+" does not exist")},i=s.h;for(let e=o;e<c;e++)l=s.D,p(l,e),s.appendChild(l.cloneNode(!0))[Config.A]=getItemValue(t[e],i)},getNode=(e,t,o)=>{let a=t[o];return e.childNodes[a]?getNode(e.childNodes[a],t,++o):e},append=(e,t,o=0)=>{renderHTML(e,t,o,t.length-o)},dooParse=e=>{let t=e.cloneNode(!0);t.removeAttribute(Config.o),t.removeAttribute("data-key");let o=t.outerHTML.replace(/\t/g,"").replace(/\n/g,""),a=o;["src","selected","checked","disabled","readonly"].forEach((e=>{o=o.replace(new RegExp(" "+e+'="{{(.+)}}"',"g")," doo-"+e+'="{{$1}}"')}));let l=a===o,n=document.createElement("template");n.innerHTML=o;let d=[];const s=(e,t,o)=>{let a=[],l=e;for(;l!==n.firstElementChild;){let e=l.previousSibling,t=0;for(;e;)t++,e=e.previousSibling;l=l.parentNode,l&&a.unshift(t)}d.push([t,a.slice(1),o])},c=document.createTreeWalker(n.content,NodeFilter.SHOW_TEXT,{acceptNode:()=>NodeFilter.FILTER_ACCEPT});let r=c.nextNode(),p=[];for(;r;){let e=r.wholeText.trim();if(0===e.indexOf("{{")&&e.lastIndexOf("}}")===e.length-2);else{let t=e.replace(/{{/g,"<span>{{").replace(/}}/g,"}}</span>");p.push({node:r.parentNode,L:e,v:t})}r=c.nextNode()}for(let e=0,t=p.length;e<t;e++)p[e].node.innerHTML=p[e].node.innerHTML.replace(p[e].L,p[e].v);let i=n.content.cloneNode(!0);const T=document.createTreeWalker(i,NodeFilter.SHOW_TEXT,{acceptNode:()=>NodeFilter.FILTER_ACCEPT});let m=T.nextNode();for(;m;){const e=m.nodeValue.match(/\{\{(.*?)\}\}/g);if(e){const t=m.parentNode;e.forEach((e=>{const o=e.replace(/\{\{|\}\}/g,"").trim(),a=document.createTextNode(o);m.textContent="";const l=t.appendChild(a);s(l,o,"textContent")}))}m=T.nextNode()}const f=document.createTreeWalker(i,NodeFilter.SHOW_ELEMENT,{acceptNode:()=>NodeFilter.FILTER_ACCEPT});for(m=f.nextNode();m;){for(const e of[...m.attributes])e.nodeValue.includes("{{")&&s(m,e.nodeValue.replace("{{","").replace("}}",""),e.name);m=f.nextNode()}let g=i.firstElementChild.outerHTML;return d.forEach((e=>{let t="{{"+e[0]+"}}";g=g.replace(new RegExp(t,"g"),"")})),i.outerHTML=g,{D:i.firstElementChild,H:l,C:d}},fetchTemplate=e=>new Promise(((t,o)=>{const a=new XMLHttpRequest;a.open("GET",e),a.onload=()=>t(a.responseText),a.onerror=()=>o(a.statusText),a.send()})),setReactiveDataNodes=e=>{const t=[],o=e=>{let t=0;for(;e.parentElement;)e=e.parentElement,t++;return t};e.innerHTML=e.innerHTML.replace(/\$\{(.+?)\}/gm,((t,o)=>isNaN(o)?e.getAttribute(o)||"":Config.u.BEG+e.R?.[o-1]+Config.u.END||""));const a=e.content.querySelectorAll(`[${Config.o}]`);a.forEach((t=>{t.hasAttribute("data-src")||t.setAttribute("data-src",e.hasAttribute("doo-dispatch")?"DooX":Config.o),t.removeAttribute("data-src")})),(e=>{[...e].map((e=>({I:e,level:o(e),F:e.getAttribute("data-src")?.startsWith("this.parent"),M:e.hasAttribute("data-norepeat")}))).sort(((e,t)=>t.level-e.level)).forEach((({I:e,level:o,F:a,M:l},n)=>{const d="|STYLE|LINK|".includes(`|${e.tagName}|`)?e:(e.parentElement&&"|DL|UL|TBODY|THEAD|TFOOT|TR|SELECT|SECTION|".includes(`|${e.parentElement.tagName}|`),e.parentElement),s=dooParse(e);Object.assign(d,{h:e.getAttribute(Config.o),D:s.D,H:s.H,C:s.C,name:n,level:o,F:a,M:l,O:isTable(d)}),"DATA"!==d.tagName&&"STYLE"!==d.tagName&&"LINK"!==d.tagName||e.parentElement?.replaceChild(d,e)||console.warn("Templates should only have one child node"),t.push(d)}))})(a),e.place=t},setNodeValues=(e,t)=>{for(let o=0;o<len;o++){const a=getNode(e,place.C[o][1],0);a?"textContent"===place.C[o][2]?a.textContent=data[t][place.C[o][0]]:a.setAttribute(place.C[o][2],data[t][place.C[o][0]]):console.info("Field:"+place.C[o][0]+" does not exist")}if(this.S){let e=place.querySelectorAll(place.D.tagName);for(let t=start;t<stop;t++){let o=e.item(t);const a=o||place.D;setNodeValues(a,t),o||(place.appendChild(a.cloneNode(!0))[Config.A]=getItemValue(data[t],this.h))}}else for(let e=start;e<stop;e++){const t=place.D;setNodeValues(t,e),place.appendChild(t.cloneNode(!0))[Config.A]=getItemValue(data[e],this.h)}},prefetchTemplate=async e=>{if(e&&(e.startsWith("./")||e.startsWith("../")||e.startsWith("http"))){return await fetchTemplate(e)}return null},createTemplate=async(e,t=[],o=null)=>{let a=o?await prefetchTemplate(o):"";a||(a=e.startsWith("<")?e:e.startsWith("#")?document.querySelector(e).outerHTML:document.querySelector("#"+e).outerHTML);const l=document.createElement("div");l.innerHTML=a,l.querySelector("template")&&(l.innerHTML=l.querySelector("template")?a:`<template><center><pre>The template you are trying to import does not have a &lt;template&gt; tag</pre><div style="color:red">${a}</div></center></template>`);const n=l.querySelector("template").cloneNode(!0),d=document.createElement("template");n.removeAttribute("id"),d.innerHTML=n.innerHTML,setReactiveDataNodes(d);const s=`[data-template="${e}"]`;return document.querySelector(s).parentElement.replaceChild(d.content,document.querySelector(s)),render(d.place[0],t,0),d};export{createTemplate,append,render,Config,version,prefetchTemplate};
1+
const Config={t:"DooHTML",o:"data-bind",l:"data-template",p:{T:-1,i:0,m:1},u:{BEG:"{{",END:"}}"},N:"data-key",A:"key"},version="v0.98.2",getItemValue=(e,t)=>t.includes(".")?t.split(".").reduce(((e,t)=>e&&void 0!==e[t]?e[t]:""),e):e[t]?e[t]:"",getNode=(e,t)=>t.reduce(((e,t)=>e?.childNodes[t]||null),e),isTable=e=>["TABLE","TBODY","THEAD","TFOOT","TR","TH"].includes(e.tagName),render=(e,t,o=0)=>{0!==t.length?renderHTML(e,t,o):e.textContent=""},renderHTML=(e,t,o=0,n=null)=>{let a=t.length;const l=e;let r=n?o+a:a-o;r>a&&(r=a);const d=l.D.length,c=(e,o)=>{for(let n=0;n<d;n++){const a=getNode(e,l.D[n][1]);a?"textContent"===l.D[n][2]?a.textContent=t[o][l.D[n][0]]:a.setAttribute(l.D[n][2],t[o][l.D[n][0]]):console.info("Field:"+l.D[n][0]+" does not exist")}},s=l[Config.A];for(let n=o;n<r;++n)c(e.C,n),l.appendChild(e.C.cloneNode(!0))[Config.A]=getItemValue(t[n],s)},append=(e,t,o=0)=>{renderHTML(e,t,o,t.length-o)},dooParse=e=>{let t=e.cloneNode(!0);t.removeAttribute(Config.o),t.removeAttribute("data-key");let o=t.outerHTML.replace(/\t/g,"").replace(/\n/g,""),n=o;["src","selected","checked","disabled","readonly"].forEach((e=>{o=o.replace(new RegExp(" "+e+'="{{(.+)}}"',"g")," doo-"+e+'="{{$1}}"')}));let a=n===o,l=document.createElement("template");l.innerHTML=o;let r=[];const d=(e,t,o)=>{let n=[],a=e;for(;a!==l.firstElementChild;){let e=a.previousSibling,t=0;for(;e;)t++,e=e.previousSibling;a=a.parentNode,a&&n.unshift(t)}r.push([t,n.slice(1),o])},c=document.createTreeWalker(l.content,NodeFilter.SHOW_TEXT,{acceptNode:()=>NodeFilter.FILTER_ACCEPT});let s=c.nextNode(),p=[];for(;s;){let e=s.wholeText.trim();if(0===e.indexOf("{{")&&e.lastIndexOf("}}")===e.length-2);else{let t=e.replace(/{{/g,"<span>{{").replace(/}}/g,"}}</span>");p.push({node:s.parentNode,L:e,h:t})}s=c.nextNode()}for(let e=0,t=p.length;e<t;e++)p[e].node.innerHTML=p[e].node.innerHTML.replace(p[e].L,p[e].h);let T=l.content.cloneNode(!0);const i=document.createTreeWalker(T,NodeFilter.SHOW_TEXT,{acceptNode:()=>NodeFilter.FILTER_ACCEPT});let m=i.nextNode();for(;m;){const e=m.nodeValue.match(/\{\{(.*?)\}\}/g);if(e){const t=m.parentNode;e.forEach((e=>{const o=e.replace(/\{\{|\}\}/g,"").trim(),n=document.createTextNode(o);m.textContent="";const a=t.appendChild(n);d(a,o,"textContent")}))}m=i.nextNode()}const f=document.createTreeWalker(T,NodeFilter.SHOW_ELEMENT,{acceptNode:()=>NodeFilter.FILTER_ACCEPT});for(m=f.nextNode();m;){for(const e of[...m.attributes])e.nodeValue.includes("{{")&&d(m,e.nodeValue.replace("{{","").replace("}}",""),e.name);m=f.nextNode()}let u=T.firstElementChild.outerHTML;return r.forEach((e=>{let t="{{"+e[0]+"}}";u=u.replace(new RegExp(t,"g"),"")})),T.outerHTML=u,{C:T.firstElementChild,v:a,D:r}},fetchTemplate=e=>new Promise(((t,o)=>{const n=new XMLHttpRequest;n.open("GET",e),n.onload=()=>t(n.responseText),n.onerror=()=>o(n.statusText),n.send()})),setReactiveDataNodes=e=>{const t=[],o=e=>{let t=0;for(;e.parentElement;)e=e.parentElement,t++;return t},n=e.content.querySelectorAll(`[${Config.o}]`);n.forEach((t=>{t.hasAttribute("data-src")||t.setAttribute("data-src",e.hasAttribute("doo-dispatch")?"DooX":Config.o),t.removeAttribute("data-src")})),(e=>{[...e].map((e=>({H:e,level:o(e),R:e.getAttribute("data-src")?.startsWith("this.parent"),F:e.hasAttribute("data-norepeat")}))).sort(((e,t)=>t.level-e.level)).forEach((({H:e,level:o,R:n,F:a},l)=>{const r="|STYLE|LINK|".includes(`|${e.tagName}|`)?e:(e.parentElement&&"|DL|UL|TBODY|THEAD|TFOOT|TR|SELECT|SECTION|".includes(`|${e.parentElement.tagName}|`),e.parentElement),d=dooParse(e);Object.assign(r,{C:d.C,v:d.v,D:d.D,name:l,level:o,R:n,F:a,I:isTable(r)}),"DATA"!==r.tagName&&"STYLE"!==r.tagName&&"LINK"!==r.tagName||e.parentElement?.replaceChild(r,e)||console.warn("Templates should only have one child node"),t.push(r)}))})(n),e.place=t},prefetchTemplate=async e=>{if(e&&(e.startsWith("./")||e.startsWith("../")||e.startsWith("http"))){return await fetchTemplate(e)}return null},createTemplate=async(e,t=[],o=null)=>{let n=o?await prefetchTemplate(o):"";n||(n=e.startsWith("<")?e:e.startsWith("#")?document.querySelector(e).outerHTML:document.querySelector("#"+e).outerHTML);const a=document.createElement("div");a.innerHTML=n,a.querySelector("template")&&(a.innerHTML=a.querySelector("template")?n:`<template><center><pre>The template you are trying to import does not have a &lt;template&gt; tag</pre><div style="color:red">${n}</div></center></template>`);const l=a.querySelector("template").cloneNode(!0),r=document.createElement("template");l.removeAttribute("id"),r.innerHTML=l.innerHTML,setReactiveDataNodes(r);const d=document.querySelector(`[data-template="${e}"]`);return r.place[0].textContent="",r.place[0][Config.A]=d.dataset[Config.A],d.parentElement.replaceChild(r.content,d),t.length>0&&render(r.place[0],t,0),r.place[0]};export{createTemplate,append,render,Config,version,prefetchTemplate};

frameworks/keyed/doohtml-lite/package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frameworks/keyed/doohtml-lite/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "js-framework-benchmark-doohtml",
3-
"version": "0.97.5",
3+
"version": "0.98.2",
44
"description": "DooHTML-lite JS-Benchmark",
55
"main": "main.js",
66
"js-framework-benchmark": {
@@ -14,7 +14,7 @@
1414
},
1515
"keywords": [],
1616
"author": "Henrik Javen",
17-
"license": "Apache-2.0",
17+
"license": "MIT",
1818
"homepage": "https://doohtml.com",
1919
"repository": {
2020
"type": "git",

frameworks/keyed/doohtml-lite/src/main.js

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
import {render, createTemplate, append, version} from '../lib/doohtml.mjs';
3+
import {render, createTemplate, append, version} from '../lib/doohtml.mjs'
44
const _random = max => Math.random() * max | 0
55

66
const adjectives = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean", "elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive", "cheap", "expensive", "fancy"]
@@ -31,14 +31,8 @@ class Main {
3131
}
3232

3333
async init() {
34-
this.tbody = await createTemplate('table', [])
35-
render(this.tbody, this.rows)
36-
this.firstDataBindNode = document.querySelector('#tbody')
37-
this.dooAfterRender()
38-
}
39-
40-
async dooAfterRender() {
41-
this.firstDataBindNode.addEventListener('click', e => {
34+
this.tbody = await createTemplate('table', this.rows)
35+
this.tbody.addEventListener('click', e => {
4236
e.preventDefault()
4337
if (e.target.parentElement.matches('.remove')) {
4438
this.delete(e.target.parentElement)
@@ -48,47 +42,38 @@ class Main {
4842
})
4943
}
5044

51-
getParentRow(elem) {
52-
while (elem) {
53-
if (elem.tagName === "TR") {return elem}
54-
elem = elem.parentNode
55-
}
56-
return undefined
57-
}
58-
5945
buildData(count = DEFAULT_SIZE) {
60-
const data = Array(count);
61-
for (let i = 0; i < count; i=i+1) {
62-
const label = `${adjectives[_random(lenA)]} ${colours[_random(lenB)]} ${nouns[_random(lenC)]}`
46+
const data = Array(count)
47+
for (let i = 0; i < count; i = i + 1) {
48+
const label = `${adjectives[_random(lenA)]} ${colours[_random(lenB)]} ${nouns[_random(lenC)]}`
6349
const id = this.ID++
6450
data[i] = { id, label }
6551
}
6652
return data
6753
}
6854

69-
getIndex(row) {
70-
let idx = this.rows.findIndex((item, i) => {
71-
if (item.id === row.key) {
55+
getIndex(key) {
56+
for (let i = 0; i < this.rows.length; i = i + 1) {
57+
if (this.rows[i].id === key) {
7258
return i
7359
}
74-
})
75-
return idx
60+
}
61+
return -1
7662
}
7763

7864
delete(elem) {
79-
let row = this.getParentRow(elem)
65+
const row = elem.closest('tr')
8066
if (row) {
81-
row.parentElement.removeChild(row)
82-
let idx = this.getIndex(row)
83-
if (idx !== undefined) {
67+
const key = row.key
68+
const idx = this.getIndex(key)
69+
if (key && idx > -1) {
8470
this.rows.splice(idx,1)
71+
row.remove()
8572
}
86-
8773
}
8874
}
8975

9076
run() {
91-
this.select(undefined)
9277
if (this.rows.length) this.clear()
9378
this.rows = this.buildData()
9479
render(this.tbody, this.rows)
@@ -101,16 +86,16 @@ class Main {
10186
}
10287

10388
runLots() {
104-
this.select(undefined)
10589
if (this.rows.length) this.clear()
10690
this.rows = this.buildData(DEFAULT_SIZE_RUN_LOTS)
10791
render(this.tbody, this.rows)
10892
}
10993

11094
update() {
111-
const len = this.rows.length
112-
for (let i = 0; i < len; i += 10) {
113-
this.firstDataBindNode.childNodes[i].querySelector('a').append(BANG)
95+
const len = this.tbody.children.length
96+
for (let i = 0; i<len; i = i + 10) {
97+
this.rows[i].label += BANG
98+
this.tbody.children[i].querySelector('a').append(BANG)
11499
}
115100
}
116101

@@ -121,31 +106,31 @@ class Main {
121106
}
122107

123108
if (elem) {
124-
const row = this.getParentRow(elem)
109+
const row = elem.closest('tr')
125110
if (row) {
126111
this.selectedRow = row
127112
row.className = DANGER
128113
}
129114
}
130115
}
131116

132-
133117
clear() {
134-
this.firstDataBindNode.textContent = null
118+
this.selectedRow = undefined
119+
this.tbody.textContent = null
135120
this.rows = []
136121
}
137122

138123
swapRows() {
139124
if (this.rows.length > SWAP_ROW) {
140-
let node1 = this.firstDataBindNode.firstChild.nextSibling,
141-
swapRow = this.firstDataBindNode.childNodes[SWAP_ROW],
125+
let node1 = this.tbody.firstChild.nextSibling,
126+
swapRow = this.tbody.children[SWAP_ROW],
142127
node999 = swapRow.nextSibling,
143128
row1 = this.rows[1]
144129

145-
this.rows[1] = this.rows[SWAP_ROW];
130+
this.rows[1] = this.rows[SWAP_ROW]
146131
this.rows[SWAP_ROW] = row1
147132

148-
this.firstDataBindNode.insertBefore(node1.parentNode.replaceChild(swapRow, node1), node999)
133+
this.tbody.insertBefore(node1.parentNode.replaceChild(swapRow, node1), node999)
149134
}
150135
}
151136

0 commit comments

Comments
 (0)