Ostatnio aktywny 1740947436

Rewizja adc3104f25962b3c68a84cd61bb7454d06087464

affirmations_v2.html Surowy Playground
1<!DOCTYPE html>
2<html>
3
4 <div id="app"></div>
5 <style>
6
7 #app, body {
8 height: 100%;
9 }
10 #edit-affirmations {
11 display: grid;
12 grid-template-rows: 80% 20%;
13 height: 80vh;
14 }
15
16 .affirmation {
17 width: 100%;
18 }
19 .half-half {
20 display: grid;
21 grid-template-columns: 50% 50%;
22 width: 100%;
23 }
24 .right-corner {
25 width: 25%;
26 justify-self: end;
27 }
28 .w-full { width: 100%; }
29 .grid { display: grid; }
30
31 #edit-affirmations textarea {
32 height: 80%;
33 }
34
35 </style>
36
37 <template id="mode-edit-affirmations">
38 <div id="edit-affirmations">
39 <textarea class="wide 80-tall" id="affirmation-list"></textarea>
40 <button id="save-affirmations">Save!</button>
41 </div>
42 </template>
43 <template id="mode-view-affirmations">
44 <div class="w-full grid">
45 <button id="go-to-edit-mode" class="right-corner"></button>
46 </div>
47 <div id="affirmation-list"></div>
48 <div class="half-half">
49 <button id="add-affirmation">another</button>
50 <button id="clear-affirmations">clear</button>
51 </div>
52 </template>
53 <template id="affirmation"><h3 class="affirmation"></h3></template>
54
55 <script src="hex.js"></script>
56 <script>
57 hex.arise(function() {
58 let affirmation_idx = 0;
59
60 let app = hex.id("app");
61 const get_affirmations = () => hex.recall("affirmations") || ["You need to add affirmations!"];
62 const next_affirmation = () => {
63 const affirmations = get_affirmations().filter(x => !(/^\s+$/.test(x)));
64 const ret = affirmations[affirmation_idx];
65 affirmation_idx = (affirmation_idx + 1) % affirmations.length;
66 return ret;
67 }
68
69 var affirmHeader = hex.spell("#affirmation", { value: ".affirmation" });
70
71 var modeRecite = hex.spell("#mode-view-affirmations", {
72 toEdit: ["#go-to-edit-mode", {t: "edit", on: {
73 click() {
74 hex.become(modeEdit, app, {affirmations: get_affirmations()});
75 }
76 } }],
77 affirmations: ["#affirmation-list", (el, affirmation) => affirmHeader(el, { value: affirmation })],
78 another: ["#add-affirmation",
79 { t: "another",
80 init() {
81 this._affirmations = [];
82 this._next = () => {
83 this._affirmations.push(next_affirmation());
84 this.affirmations(this._affirmations)
85 }
86 this._next();
87 },
88 on: { click() { this._next(); } }
89 }
90 ],
91 clear: ["#clear-affirmations", {t: "clear", on: { click() { this._affirmations = []; this.affirmations([]); } } }]
92 });
93
94 var modeEdit = hex.spell("#mode-edit-affirmations", {
95 affirmations: ["#affirmation-list", {
96 init(arg) {
97 this.affirmations = arg.affirmations.join("\n");
98 this._affirmations = arg.affirmations || get_affirmations();
99 },
100 on: { input(e) { this._affirmations = e.target.value.split("\n"); } }
101 }],
102
103 save: ["#save-affirmations",
104 { t:"save", on: { click() {
105 console.log(this);
106 hex.scrawl("affirmations", this._affirmations);
107 hex.become(modeRecite, app, {affirmations: get_affirmations()});
108 }}}
109 ],
110 });
111
112 hex.become(modeRecite, app, {affirmations: get_affirmations()});
113 });
114 </script>
115</html>
116
hex.js Surowy 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