Последняя активность 1740947436

Версия 8810bae9a17d982f892f47e663699915ec6ce14f

affirmations.html Исходник Playground
1<!DOCTYPE html>
2<html>
3
4 <div id="app"></div>
5
6 <script src="hex.js"></script>
7
8 <template id="job-attr">
9 <dt><button class="key"></button></dt>
10 <dd><pre class="value"></pre></dd>
11 </template>
12
13 <template id="job-row">
14 <dl class="job-content"></dl>
15 <hr>
16 </template>
17
18
19 <script>
20 let kvPair = hex.spell("#job-attr", {
21 key: [".key", { init() { }, on: { click() {
22 navigator.clipboard.writeText(this.value)
23 } }}],
24 value: ".value", // mutable
25 });
26
27 let jobRow = hex.spell("#job-row", {
28 jobFields: [".job-content", (el, [key, value]) => kvPair(el, {key, value})],
29 });
30
31 hex.arise(function() {
32 function job(employerName, city, state, position, startDate, endDate,
33 contactName, email, phone) {
34 return {
35 employerName, city, state, position, startDate, endDate, contactName, email, phone
36 }
37 }
38 let jobs = [
39 job("Shift Paradigm", "Austin", "Texas", "Senior Software Developer", "06 - 2021", "04 - 2024 ",
40 "Michelle Hytry", "michelle.hytry@shiftparadigm.com", "512-717-4097"),
41 job("Linquest Corporation", "Colorado Springs", "Colorado", "Staff Software Engineer", "08 - 2019", "06 - 2021",
42 "Susan Kang", "susan.kang@linquest.com", "(719) 884-8400" ),
43 job("Qdoba Corporation", "Colorado Springs", "Colorado", "Line Cook", "06 - 2019", "08 - 2019",
44 "N/a", "N/a", "719-592-9701"),
45 job("Burrito Concepts", "Joplin", "Missouri", "Line Cook", "02 - 2019", "06 - 2019",
46 "N/a", "N/a", "417-782-5300"),
47 job("Greenshades Software", "Jacksonville", "Florida", "Software Developer", "11 - 2017", "12 - 2018",
48 "N/a", "hr@greenshades.com", "904-807-0160"),
49 job("Genesis Global Technologies", "Ft. Myers", "Florida", "Software Developer", "09 - 2014", "11 - 2017",
50 "Mona Hilton", "monah@genesisgt.com", "239-337-2667"),
51 ];
52 let app_out = hex.q1("#app");
53 app_out.innerHTML = "";
54 window.J = [];
55 for (let j of jobs) {
56 window.J.push(jobRow(app_out, {
57 jobFields: Object.entries(j),
58 }));
59 }
60 });
61 </script>
62</html>
63
hex.js Исходник Playground
1const hex = (function() {
2 const q = (el, sel) => !sel ? document.querySelectorAll(el) : el.querySelectorAll(sel);
3 const id = (sel) => document.getElementById(sel);
4 const q1 = (el, sel) => !sel ? document.querySelector(el) : el.querySelector(sel);
5 const isObj = (obj) => { var type = typeof obj; return type === 'object' && !!obj; };
6 const isSimple = (v) => {var type = typeof v; return type=== "number" || type === "string" || type === "boolean"; }
7 const arise = (fn) => document.addEventListener('DOMContentLoaded', fn, false);
8 const scrawl = (k, v) => localStorage.setItem(k, JSON.stringify(v));
9 const recall = (k) => JSON.parse(localStorage.getItem(k) || "null");
10
11 function setterFor(node) {
12 switch (node.tagName) {
13 case "INPUT":
14 return (val) => node.value = val;
15 default:
16 return (val) => { node.innerText = val; };
17 }
18 }
19
20 let templs = new Map();
21 function from(tempSel) {
22 let toClone;
23 if (templs.has(tempSel)) {
24 toClone = templs.get(tempSel);
25 } else {
26 let n = q1(tempSel);
27 if (n) {
28 templs.set(tempSel, n);
29 toClone = n;
30 } else {
31 throw tempSel + " failed";
32 }
33 }
34 return toClone.content.cloneNode(true);
35 }
36
37 function spell(template, config) {
38
39 return function(into, start) {
40 const basis = from(template)
41 const state = { vars: {}, dom: {}, setters: {} };
42 const interface = Object.create(spell);
43 const recursionGuard = new Set();
44
45 for (let [k, v] of Object.entries(config)) {
46 const makeProp = (el, initialValue) => {
47 state.setters[k] = setterFor(el);
48
49 Object.defineProperty(interface, k, {
50 get() { return state.vars[k] },
51 set(v) {
52 state.vars[k] = v;
53 state.setters[k]((v || "") + "");
54 }
55 });
56
57 interface[k] = initialValue;
58 }
59 if (typeof v === "string" && v) {
60 const el = q1(basis, v);
61 state.dom[k] = el;
62 makeProp(el, start[k]);
63 } else if (Array.isArray(v)) {
64 if (v.length <= 0) {
65 throw new Error("Empty array not valid!");
66 }
67 let el;
68 if (typeof v[0] === "string") {
69 el = q1(basis, v[0]);
70 state.dom[k] = el;
71 } else {
72 throw new Error(`Selector for ${k} must be a string!`);
73 }
74
75 if (v.length == 1 && (typeof v[0]) == "string") {
76 state.vars[k] = start[k];
77 makeProp(el, start[k]);
78 } else if (v.length == 2 && (typeof v[0]) === "string" && isSimple(v[1])) {
79 makeProp(el, start[k] || v[1]);
80 } else if (v.length == 2 && (typeof v[0]) === "string" && isObj(v[1])) {
81 makeProp(el, start[k]);
82 const obj = v[1];
83 if (obj.on) {
84 for (const [evt, fn] of Object.entries(obj.on)) {
85 let inner = fn.bind(interface);
86 let handler = function() {
87 if (recursionGuard.has(handler)) { return; }
88 try {
89 recursionGuard.add(handler);
90 inner(...arguments);
91 } finally {
92 recursionGuard.delete(handler);
93 }
94 };
95
96 el.addEventListener(evt, handler);
97 }
98 }
99 if (obj.init && typeof obj.init === "function") {
100 obj.init.call(interface, start);
101 }
102
103 } else if (v.length === 2 &&
104 (typeof v[0]) === "string" &&
105 (typeof v[1]) === "function"
106 && Array.isArray(start[k])
107 ) {
108 state.vars[k] = start[k].map((data) => v[1](el, data));
109 interface[k] = function(new_data) {
110 el.innerHTML = "";
111 state.vars[k] = new_data.map((data) => v[1](el, data));
112 }
113 } else {
114 throw new Error(`Invalid config: ${k}`);
115 }
116 }
117 }
118
119 interface._ = state;
120 into.appendChild(basis);
121 return interface;
122 }
123 }
124
125
126
127 return {q, q1, id, from, arise, scrawl, recall, spell};
128})();
129
130window.hex = hex;
131