affirmations.html
· 2.4 KiB · HTML
原始文件
Playground
<!DOCTYPE html>
<html>
<div id="app"></div>
<script src="hex.js"></script>
<template id="job-attr">
<dt><button class="key"></button></dt>
<dd><pre class="value"></pre></dd>
</template>
<template id="job-row">
<dl class="job-content"></dl>
<hr>
</template>
<script>
let kvPair = hex.spell("#job-attr", {
key: [".key", { init() { }, on: { click() {
navigator.clipboard.writeText(this.value)
} }}],
value: ".value", // mutable
});
let jobRow = hex.spell("#job-row", {
jobFields: [".job-content", (el, [key, value]) => kvPair(el, {key, value})],
});
hex.arise(function() {
function job(employerName, city, state, position, startDate, endDate,
contactName, email, phone) {
return {
employerName, city, state, position, startDate, endDate, contactName, email, phone
}
}
let jobs = [
job("Shift Paradigm", "Austin", "Texas", "Senior Software Developer", "06 - 2021", "04 - 2024 ",
"Michelle Hytry", "michelle.hytry@shiftparadigm.com", "512-717-4097"),
job("Linquest Corporation", "Colorado Springs", "Colorado", "Staff Software Engineer", "08 - 2019", "06 - 2021",
"Susan Kang", "susan.kang@linquest.com", "(719) 884-8400" ),
job("Qdoba Corporation", "Colorado Springs", "Colorado", "Line Cook", "06 - 2019", "08 - 2019",
"N/a", "N/a", "719-592-9701"),
job("Burrito Concepts", "Joplin", "Missouri", "Line Cook", "02 - 2019", "06 - 2019",
"N/a", "N/a", "417-782-5300"),
job("Greenshades Software", "Jacksonville", "Florida", "Software Developer", "11 - 2017", "12 - 2018",
"N/a", "hr@greenshades.com", "904-807-0160"),
job("Genesis Global Technologies", "Ft. Myers", "Florida", "Software Developer", "09 - 2014", "11 - 2017",
"Mona Hilton", "monah@genesisgt.com", "239-337-2667"),
];
let app_out = hex.q1("#app");
app_out.innerHTML = "";
window.J = [];
for (let j of jobs) {
window.J.push(jobRow(app_out, {
jobFields: Object.entries(j),
}));
}
});
</script>
</html>
| 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
· 5.1 KiB · JavaScript
原始文件
Playground
const hex = (function() {
const q = (el, sel) => !sel ? document.querySelectorAll(el) : el.querySelectorAll(sel);
const id = (sel) => document.getElementById(sel);
const q1 = (el, sel) => !sel ? document.querySelector(el) : el.querySelector(sel);
const isObj = (obj) => { var type = typeof obj; return type === 'object' && !!obj; };
const isSimple = (v) => {var type = typeof v; return type=== "number" || type === "string" || type === "boolean"; }
const arise = (fn) => document.addEventListener('DOMContentLoaded', fn, false);
const scrawl = (k, v) => localStorage.setItem(k, JSON.stringify(v));
const recall = (k) => JSON.parse(localStorage.getItem(k) || "null");
function setterFor(node) {
switch (node.tagName) {
case "INPUT":
return (val) => node.value = val;
default:
return (val) => { node.innerText = val; };
}
}
let templs = new Map();
function from(tempSel) {
let toClone;
if (templs.has(tempSel)) {
toClone = templs.get(tempSel);
} else {
let n = q1(tempSel);
if (n) {
templs.set(tempSel, n);
toClone = n;
} else {
throw tempSel + " failed";
}
}
return toClone.content.cloneNode(true);
}
function spell(template, config) {
return function(into, start) {
const basis = from(template)
const state = { vars: {}, dom: {}, setters: {} };
const interface = Object.create(spell);
const recursionGuard = new Set();
for (let [k, v] of Object.entries(config)) {
const makeProp = (el, initialValue) => {
state.setters[k] = setterFor(el);
Object.defineProperty(interface, k, {
get() { return state.vars[k] },
set(v) {
state.vars[k] = v;
state.setters[k]((v || "") + "");
}
});
interface[k] = initialValue;
}
if (typeof v === "string" && v) {
const el = q1(basis, v);
state.dom[k] = el;
makeProp(el, start[k]);
} else if (Array.isArray(v)) {
if (v.length <= 0) {
throw new Error("Empty array not valid!");
}
let el;
if (typeof v[0] === "string") {
el = q1(basis, v[0]);
state.dom[k] = el;
} else {
throw new Error(`Selector for ${k} must be a string!`);
}
if (v.length == 1 && (typeof v[0]) == "string") {
state.vars[k] = start[k];
makeProp(el, start[k]);
} else if (v.length == 2 && (typeof v[0]) === "string" && isSimple(v[1])) {
makeProp(el, start[k] || v[1]);
} else if (v.length == 2 && (typeof v[0]) === "string" && isObj(v[1])) {
makeProp(el, start[k]);
const obj = v[1];
if (obj.on) {
for (const [evt, fn] of Object.entries(obj.on)) {
let inner = fn.bind(interface);
let handler = function() {
if (recursionGuard.has(handler)) { return; }
try {
recursionGuard.add(handler);
inner(...arguments);
} finally {
recursionGuard.delete(handler);
}
};
el.addEventListener(evt, handler);
}
}
if (obj.init && typeof obj.init === "function") {
obj.init.call(interface, start);
}
} else if (v.length === 2 &&
(typeof v[0]) === "string" &&
(typeof v[1]) === "function"
&& Array.isArray(start[k])
) {
state.vars[k] = start[k].map((data) => v[1](el, data));
interface[k] = function(new_data) {
el.innerHTML = "";
state.vars[k] = new_data.map((data) => v[1](el, data));
}
} else {
throw new Error(`Invalid config: ${k}`);
}
}
}
interface._ = state;
into.appendChild(basis);
return interface;
}
}
return {q, q1, id, from, arise, scrawl, recall, spell};
})();
window.hex = hex;
| 1 | const 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 | |
| 130 | window.hex = hex; |
| 131 |