From adfc38603d3876f493322508a142913c9febca92 Mon Sep 17 00:00:00 2001 From: Lenin Compres Date: Sat, 26 Oct 2024 08:05:12 -0400 Subject: [PATCH] DOM updates Animations, loops and delays - interval and timeout - loop - let() - DOM.transition --- DOM.js | 70 +++++++++++++++++++++++++++++------ index.html | 2 +- src/pages.js | 101 +++++++++++++++++++++++++-------------------------- 3 files changed, 109 insertions(+), 64 deletions(-) diff --git a/DOM.js b/DOM.js index 84f04cb..ea04519 100644 --- a/DOM.js +++ b/DOM.js @@ -1,11 +1,11 @@ /** * Creates DOM structures from a JS object (structure) * @author Lenin Compres - * @version 1.2.1 + * @version 1.2.2 * @repository https://github.com/lenincompres/DOM.js */ - Element.prototype.get = function (station) { +Element.prototype.get = function (station) { let output; if (!station && this.tagName.toLocaleLowerCase() === "input") output = this.value; else if (!station || ["content", "inner", "innerhtml", "html"].includes(station)) output = this.innerHTML; @@ -22,6 +22,10 @@ if (output.length) return output; } +Element.prototype.let = function (station, be = () => undefined, ...args) { + return this.set(typeof be === "function" ? be(this.get(station)) : be, station, ...args); +} + Element.prototype.set = function (model, ...args) { if ([null, undefined].includes(model)) return this; let contentType = DOM.typify(model.content); @@ -83,17 +87,31 @@ Element.prototype.set = function (model, ...args) { else this[STATION] = e => model(e, this); return this; } + if (argsType.boolean === true && this.intervals && this.intervals[STATION]) { + DOM.transition(this, `${DOM.unCamelize(STATION)} 0s`); + clearInterval(this.intervals[STATION]); + } if (model.duration) { model.duration = parseInt(model.duration); + if (model.transition) DOM.transition(this, `${DOM.unCamelize(STATION)} ${model.duration}ms ${model.transition}`); + if (model.loop) { + this.set(model.loop[0], STATION); + let i = 1; + DOM.interval(this, () => { + this.set(model.loop[i], STATION); + i += 1; + if (i >= model.loop.length) i = 0; + }, model.duration, model.end, STATION); + return this; + } if (model.to !== undefined && model.from !== undefined) model.through = [model.from, model.to]; this.set(model.through[0], STATION); model.through.forEach((val, i) => setTimeout(() => this.set(val, STATION), i * model.duration)); - if (model.transition) this.set(`${this.get('transition')}, ${DOM.unCamelize(STATION)} ${model.duration}ms ${model.transition}`, 'transition'); return this; } if (model._bonds) model = model.bind(); else { - if (model.with && typeof model.with !== 'function') model.bind = model.with; + if (model.with && typeof model.with !== "function") model.bind = model.with; if (model.bind) { if (Array.isArray(model.bind)) model = DOM.bind(model.bind, model.as); else model = model.as ? model.bind.bind(model.as) : model.bind; @@ -286,6 +304,16 @@ Element.prototype.set = function (model, ...args) { if (!model[f]) return this; model[f](elem); }); + ["timeout"].forEach(f => { + if (!model[f]) return this; + let [func, t] = Array.isArray(model[f]) ? model[f] : [model[f], 1]; + setTimeout(() => func(elem), t); + }); + ["interval"].forEach(f => { + if (!model[f]) return this; + let [func, t, end] = Array.isArray(model[f]) ? model[f] : [model[f], 1]; + DOM.interval(this, func, t, end); + }); if (argsType.functions) argsType.functions.forEach(f => f(elem)); return elem; }; @@ -518,14 +546,13 @@ Object.prototype.binderSet = function (name, value) { // global static methods to handle the DOM class DOM { // returns value based on - static get(station, ...args) { - // checks if meant to get from an element - let argsType = DOM.typify(...args); - let elt = argsType.element ? argsType.element : argsType.p5Element; - if (elt) return elt.get(model); - // checks if the station belongs to the head + static get(station) { DOM.headTags.includes(station.toLowerCase()) ? document.head.get(station) : document.body.get(station); } + static + let (station, be) { + DOM.headTags.includes(station.toLowerCase()) ? document.head.let(station, be) : document.body.let(station, be); + } // create elements based on an object model static set(model = "", ...args) { if (!args.includes("css") && !window.DOM_RESETTED) { @@ -583,7 +610,7 @@ class DOM { tag = model.tag; delete model.tag; } - return document.createElement(tag).set(model); + return document.createElement(tag).set(model); } // returns a new binder static binder(value, ...args) { @@ -678,6 +705,25 @@ class DOM { } return qs.split("/"); } + static interval(elem, func, t, end, station) { + if (!elem.intervals) elem.intervals = {}; + else if (station && elem.intervals[station]) clearInterval(elem.intervals[station]); + let iId = setInterval(() => { + let go = typeof end === "function" ? end() : end || end === undefined; + if (!go) return clearInterval(iId); + func(elem); + isNaN(end) ? null : end -= 1; + }, t); + if (station) elem.intervals[station] = iId; + } + static transition(elem, trn) { // for animations (loop, duration) + let prop = trn.split(' ')[0].trim(); + let trns = elem.get("transition"); + if(trns) trns = trns.split(",").map(t => t.trim()).filter(t => t !== "NaN") + .map(t => t.startsWith(prop) ? trn : t); + else trns = [trn]; + elem.set(trns.join(", "), "transition"); + } static addID = (id, elt) => { if (!isNaN(id)) return console.error("ID's should not be numeric. id: " + id); if (elt.tagName) elt.setAttribute("id", id); @@ -743,7 +789,7 @@ class DOM { static metaNames = ["viewport", "keywords", "description", "author", "refresh", "application-name", "generator"]; static htmlEquivs = ["contentSecurityPolicy", "contentType", "defaultStyle", "content-security-policy", "content-type", "default-style", "refresh"]; static headTags = ["meta", "link", "title", "font", "icon", "image", ...DOM.metaNames, ...DOM.htmlEquivs]; - static reserveStations = ["tag", "id", "onready", "ready", "done", "ondone"]; + static reserveStations = ["tag", "id", "bind", "with", "as", "binders", "_bonds"]; static listeners = ["addevent", "addeventlistener", "eventlistener", "listener", "on"]; static getDocType = str => typeof str === "string" ? ({ css: "stylesheet", diff --git a/index.html b/index.html index 383c8c3..f7e29ea 100755 --- a/index.html +++ b/index.html @@ -14,10 +14,10 @@ gtag('js', new Date()); gtag('config', 'G-9S3H2NXER5'); + - \ No newline at end of file diff --git a/src/pages.js b/src/pages.js index 4f6092a..4f47a40 100755 --- a/src/pages.js +++ b/src/pages.js @@ -7,11 +7,12 @@ import CardScroll from "./CardScroll.js"; import news from "./news.js"; const projects = allProjects.filter(p => !p.hidden); -const activeProject = new Binder(); -const allTags = new Binder([]); const NONE = "∅"; -const activeTag = new Binder(NONE); -const showTag = (tag = NONE) => activeTag.value = activeTag.value === tag ? NONE : tag; +const _activeProject = new Binder(); +const _allTags = new Binder([]); +const _activeTag = new Binder(NONE); +const showTag = (tag = NONE) => _activeTag.value = tag; +const addTag = (tag) => !_allTags.value.includes(tag) ? (_allTags.value = [..._allTags.value, tag].sort(sortWords)) : null; const sortWords = (a, b) => a < b ? -1 : 1; Copy.add({ @@ -67,39 +68,39 @@ export const PAGES = { justifyContent: "center", display: "flex", flexWrap: "wrap", - content: allTags.bind(val => { - showTag(); - return { - a: [NONE, ...val].map(tag => ({ - backgroundColor: activeTag.bind({ - [tag]: STYLE.COLOR.LINK_DARK, - default: STYLE.COLOR.PALE - }), - color: activeTag.bind(val => val === tag ? STYLE.COLOR.PAGE : STYLE.COLOR.LINK), - boxShadow: STYLE.SHADOW.NORMAL, - borderRadius: "0.25em", - padding: "0.2em 0.68em", - margin: "0.3em 0.3em 0 0", - display: "inline-block", - text: tag, - onclick: e => showTag(tag) - })) - } - }), + content: _allTags.as(val => ({ + a: [NONE, ...val].map(tag => ({ + backgroundColor: _activeTag.as({ + [tag]: STYLE.COLOR.LINK_DARK, + default: STYLE.COLOR.PALE + }), + color: _activeTag.as(val => val === tag ? STYLE.COLOR.PAGE : STYLE.COLOR.LINK), + boxShadow: STYLE.SHADOW.NORMAL, + borderRadius: "0.25em", + padding: "0.2em 0.68em", + margin: "0.3em 0.3em 0 0", + display: "inline-block", + text: tag, + onclick: e => showTag(tag), + })) + })), span: { color: STYLE.COLOR.PALE, textShadow: STYLE.SHADOW.TEXT, - text: activeTag.bind(val => val !== NONE ? projects.filter(p => p.tags.includes(val)).length : projects.length), + text: _activeTag.as(val => val !== NONE ? projects.filter(p => p.tags.includes(val)).length : projects.length), }, - onready: queueDown, + onready: elt => queueDown(elt, { + left: ['-30px', '10px', 0], + opacity: [0, 1], + }), }, section: projects.map((project, i) => ({ model: STYLE.PAGE, fontSize: "1em", width: "23em", cursor: "pointer", - boxShadow: DOM.bind(activeProject, val => val === i ? STYLE.SHADOW.HIGHLIGHT : STYLE.SHADOW.NORMAL), - display: activeTag.bind(val => val === NONE || project.tags.includes(val) ? "block" : "none"), + boxShadow: _activeProject.as(val => val === i ? STYLE.SHADOW.HIGHLIGHT : STYLE.SHADOW.NORMAL), + display: _activeTag.as(val => val === NONE || project.tags.includes(val) ? "block" : "none"), main: { minHeight: "6.5em", div: { @@ -120,30 +121,28 @@ export const PAGES = { }, ul: { marginTop: "0.2em", - li: project.tags.sort(sortWords).map(tag => { - if (!allTags.value.includes(tag)) allTags.value = [...allTags.value, tag].sort(sortWords); - return { - borderRadius: "0.25em", - padding: "0.2em 0.4em", - marginRight: "0.2em", - backgroundColor: STYLE.COLOR.PALE, - color: STYLE.COLOR.LINK, - border: "solid 1px", - borderColor: activeTag.bind({ - [tag]: STYLE.COLOR.LINK, - default: STYLE.COLOR.PALE, - }), - display: "inline-block", - text: tag, - click: e => { - activeTag.value = activeTag.value === tag ? NONE : tag; - e.stopPropagation(); - } - } - }) + li: project.tags.sort(sortWords).map(tag => ({ + borderRadius: "0.25em", + padding: "0.2em 0.4em", + marginRight: "0.2em", + backgroundColor: STYLE.COLOR.PALE, + color: STYLE.COLOR.LINK, + border: "solid 1px", + borderColor: _activeTag.as({ + [tag]: STYLE.COLOR.LINK, + default: STYLE.COLOR.PALE, + }), + display: "inline-block", + text: tag, + click: e => { + _activeTag.value = _activeTag.value === tag ? NONE : tag; + e.stopPropagation(); + }, + ready: elt => addTag(tag), + })) }, - mouseover: e => activeProject.value = i, - mouseout: e => activeProject.value = false, + mouseover: e => _activeProject.value = i, + mouseout: e => _activeProject.value = false, click: e => { let link = project.link ? project.link : project.folder window.open(link, "_blank") @@ -152,7 +151,7 @@ export const PAGES = { })), onready: () => { showTag(); - activeTag.value = false; + _activeTag.value = false; } }, [Copy.KEY.contact]: {