-
Notifications
You must be signed in to change notification settings - Fork 0
/
pagesnippets2.min.js
8 lines (8 loc) · 8.6 KB
/
pagesnippets2.min.js
1
2
3
4
5
6
7
8
/**
* PageSnippets - dynamically load and produce HTML or XML.
* @version 2.1
* @copyright Copyright 2023 Christoph Zager
* @link https://github.com/suppenhuhn79/pagesnippets
* @license Apache-2.0 - See the full license text at http://www.apache.org/licenses/LICENSE-2.0
*/
let pageSnippets=new function(){const e="https://github.com/suppenhuhn79/pagesnippets",t="http://www.w3.org/1999/xhtml";let n=new XMLSerializer,r=new Map;function a(e,t=!1){return e.constructor===Array&&(e=e.join("/")),("/"+e+(!0===t?"/":"")).replace(/\/+/g,"/")}function o(e,t,r){let a=n.serializeToString(e);return a.substring(0,a.indexOf(">")+1)+"\t@"+t+"\n"+r}function i(e){return e.replace(/\sxmlns(=|:[^=]+=)"[^"]+"/gi,"").trim()}this.locale="default",this.import=function(n){return new Promise(((a,l)=>{Array.from(r.values()).filter((e=>e.source===n)).length>0?(console.debug('PageSnippet "'+n+'" is already imported.'),a()):fetch(n).then((s=>{function c(e){let t="";if(/^(http[s]?:\/\/|\/)/.test(e))t=e;else{let r=n.replace(/[^./]+\.[\S]+$/,"");e=e.replace(/^\.\//,""),t=r.concat(e).replace(/[^/]+\/\.\.\//g,"")}return t}function u(t,r,a){let l=[];for(let s of t.children){let t=o(s,n,a);if(s.namespaceURI===e)if("snippet"===s.localName)p(s,r,t);else if("snippet-group"===s.localName){let e=s.getAttribute("name");u(s,r+"/"+e,t)}else""===r&&"stylesheet"===s.localName?f(s):""===r&&"script"===s.localName?l.push(s):console.warn("Element not allowed here.\n"+i(t));else console.warn("Unexpected element.\n"+i(t))}""===r&&g(l)}function p(e,a,o){let l=a+"/"+e.getAttribute("name");r.set(l,{source:n,key:l,namespace:e.firstElementChild.namespaceURI||t,data:e.firstElementChild}),e.childElementCount>1&&console.warn("Only one child element allowed.\n"+i(o))}function f(e){let t=c(e.getAttribute("src"));if(null===document.querySelector('link[rel="stylesheet"][href="'+t+'"]')){let e=document.createElement("link");e.setAttribute("rel","stylesheet"),e.setAttribute("href",t),document.head.appendChild(e)}}function g(e){function t(t){"error"===t.type?console.error('Error while loading "'+t.target.src+'"\n'+i(o(t.target,n,""))):g(e.slice(1))}if(e.length>0){let n=c(e[0].getAttribute("src"));if(null===document.querySelector('script[src="'+n+'"]')){let e=document.createElement("script");e.addEventListener("load",t),e.addEventListener("error",t),e.setAttribute("src",n),document.head.appendChild(e)}else g(e.slice(1))}else a()}if(200===s.status)s.text().then((t=>{let r;try{r=(new DOMParser).parseFromString(t,"text/xml")}finally{if(r.documentElement.namespaceURI===e&&"pagesnippets"===r.documentElement.localName)u(r.firstElementChild,"","");else{let e=new Error('"'+n+'" is not a PageSnippets XML-document.');console.error(e),l(e)}}}));else{let e=new ReferenceError("Server returned "+s.status+" ("+s.statusText+") when trying to fetch "+s.url);console.error(e),l(e)}}),(e=>{console.log("FETCH ERROR"),l(new Error(e))}))}))},this.produce=function(n,l={},s=""){function c(e,t,n="."){let r;if(e&&t){let a=t.split(n);r=1===a.length?e[a[0]]:c(e[a[0]],a.splice(1).join(n),n)}return r}function u(e,t,n){let r=e,a=/\{\{(.*?)\}\}/g,o=a.exec(e);for(;o;){let i=c(t,o[1])??"";if("number"==typeof i){let e=n?.attributes.getNamedItem("number-format")?.value;if(e){let t=/^\+?[^.]+/.exec(e)?.[0]??"0",n=/\.(.*)$/.exec(e)?.[1]??"",a=Math.max(n.replace(/[^0]/g,"").length,1),l=i.toLocaleString(void 0,{roundingPriority:"lessPrecision",roundingMode:"trunc",useGrouping:e.includes(","),signDisplay:e.includes("+")?"always":"auto",trailingZeroDisplay:/\.#/.test(e)?"stripIfInteger":"auto",minimumIntegerDigits:Math.max(t.replace(/[^0]/g,"").length,1),minimumFractionDigits:a,maximumFractionDigits:Math.max(n.length,a)});r=r.replace(o[0],l)}else r=r.replace(o[0],i.toString())}else if(i instanceof Date){let e=n?.attributes.getNamedItem("date-format")?.value;if(e){for(let t of e.matchAll(/D{1,4}|d{1,2}|M{1,4}|m{1,2}|y{4}|y{2}|h{1,2}|n{2}|s{2}/g)){let n=t[0],r=n.length,a="";switch(n){case"d":case"dd":a=i.getDate().toString();break;case"D":case"DD":case"DDD":case"DDDD":a=i.toLocaleDateString(pageSnippets.locale,{weekday:"long"}),r<4&&(a=a.substring(0,r));break;case"m":case"mm":a=(i.getMonth()+1).toString();break;case"M":case"MM":case"MMM":case"MMMM":a=i.toLocaleDateString(pageSnippets.locale,{month:"long"}),r<4&&(a=a.substring(0,r));break;case"yy":a=i.getFullYear().toString().substring(2,4);break;case"yyyy":a=i.getFullYear().toString();break;case"h":case"hh":a=i.getHours().toString();break;case"nn":a=i.getMinutes().toString();break;case"ss":a=i.getSeconds().toString();break;default:a=""}e=e.replace(n,a.padStart(r,"0"))}r=r.replace(o[0],e)}else r=r.replace(o[0],i.toJSON())}else r=r.replace(o[0],i.toString());o=a.exec(e)}return r}function p(n,r,a,l){for(let s of n.childNodes)switch(s.nodeType){case 1:let n=o(s,y,l);if(s.namespaceURI===e)switch(s.localName){case"call-function":d(s,r,a,n);break;case"choose":b(s,r,a,n);break;case"for-each":m(s,r,a,n);break;case"for-empty":h(s,r,a,n);break;case"if":w(s,r,a,n);break;case"insert-snippet":S(s,r,a,n);break;case"text":r.appendChild(document.createTextNode(u(s.firstChild.data,a,s)));break;default:console.warn("Element not allowed here.\n"+i(n))}else{let e=document.createElementNS(s.namespaceURI||t,s.tagName);f(s,e,a,n),p(s,e,a,n),g(s,e,a,n),r.appendChild(e)}break;case 3:!1===/^\s*$/.test(s.textContent)&&r.appendChild(document.createTextNode(u(s.textContent,a,s.parentElement)));break}}function f(t,n,r,a){for(let o of t.attributes)if(o.namespaceURI===e)if(/^on\S+/.test(o.localName)){let e=c(r,o.value);"function"==typeof e?n[o.localName]=e:console.warn('Event handler "'+o.value+'" is not a function.\n'+i(a))}else"postproduction"!==o.localName&&console.warn('Attribute "'+o.name+'" is not allowed here.\n'+i(a));else n.setAttributeNS(o.namespaceURI,o.localName,u(o.value,r))}function g(t,n,r,a){let o=t.getAttributeNS(e,"postproduction");if(o){n.removeAttributeNS(e,"postproduction");let t=c(r,o);if("function"!=typeof t)throw new ReferenceError('Post-production reference "'+o+'" is not a function.\n'+i(a));t(n,r)}}function d(t,n,r,a){let o=t.getAttributeNS(e,"name")||t.getAttribute("name");if("function"!=typeof r[o])throw new ReferenceError('Reference to call "'+o+'" is not a function.\n'+i(a));r[o](n,r)}function m(t,n,r,a){let o=t.getAttributeNS(e,"list")||t.getAttribute("list"),l=c(r,o);if(l?.constructor!==Array)throw new TypeError('"'+o+'" is '+(l?.constructor.name??"undefined")+", expected Array.\n"+i(a));{let e=0,o=l.length;for(let i of l){let l=["string","number","boolean"].includes(typeof i)||i.constructor===Array?{_value:i}:Object.assign({},i);l._position=e+=1,l._count=o,p(t,n,Object.assign({},r,l),a)}}}function h(t,n,r,a){let o=c(r,t.getAttributeNS(e,"list")||t.getAttribute("list"));o?.constructor===Array&&0!==o.length||p(t,n,r,a)}function b(t,n,r,a){const l="strict";let s=(RegExp("^strict$|^lax$").exec(t.getAttribute("mode")||l)||[""])[0];""===s&&(console.warn('Invalid choose-mode "'+t.getAttribute("mode")+'", using "strict".\n'+i(a)),s=l);let c=!1;for(let u of t.children){let t=o(u,y,a);if(u.namespaceURI===e&&"if"===u.localName){let e=w(u,n,r,t);if(c=c||e,c&&s===l)break}else u.namespaceURI===e&&"else"===u.localName?!1===c&&p(u,n,r,t):console.warn("Element not allowed here.\n"+i(t))}}function w(t,n,r,a){let o,l=t.getAttributeNS(e,"test")||t.getAttribute("test"),s="return ("+l.replace(/'?\{\{/g,"this.").replace(/\}\}'?/g,"")+")";try{o=Function(s).call(r)}catch(e){throw new e.constructor('Cannot evaluate expression "'+l+'": '+e.message+".\n"+i(a))}return!0===o&&p(t,n,r,a),o}function S(t,n,o,l){let s=a(u(t.getAttributeNS(e,"name")||t.getAttribute("name"),o));if(!r.has(s))throw new ReferenceError('Unknown snippet "'+s+'".\n'+i(l));n.appendChild(pageSnippets.produce(s,o,l))}if(!1===["string","undefined"].includes(typeof s))throw new TypeError("Prohibited usage of _parentSnippetRef");let y;if(n=a(n),this.getSnippet(n)){let e=r.get(n);if(s.includes(e.source+":"+n))throw new Error("Recursive snippet nesting.\n"+i(s));let t=o(e.data,e.source+":"+n,s),a=document.createElementNS(e.namespace,e.data.localName);return y=e.source+":"+n,f(e.data,a,l,t),p(e.data,a,l,t),g(e.data,a,l,t),a}},this.hasSnippet=function(e){return r.has(e)},this.getSnippet=function(e){if(r.has(e))return r.get(a(e));throw new ReferenceError('No such snippet: "'+e+'".')},this.getSnippets=function(e="",t=!1){let n=[],o=new RegExp("^("+a(e,!0)+"[^/]+)$");if(e=a(e,!0),n=n.concat(Array.from(r.keys()).filter((e=>o.test(e)))),!0===t)for(let t of this.getSnippetGroups(e))n=n.concat(this.getSnippets(t,!0));return n},this.getSnippetGroups=function(e="",t=!1){let n=new RegExp("^("+a(e,!0)+"[^/]+/)"),o=new Set;for(let e of r.keys()){let r=n.exec(e);r&&!1===o.has(r[1])&&(o.add(r[1]),!0===t&&this.getSnippetGroups(r[1],t).forEach((e=>o.add(e))))}return Array.from(o)}};