From fe9a62edd23f5759e269cd78d95252ffdc2ced42 Mon Sep 17 00:00:00 2001 From: hippoz Date: Sun, 4 Oct 2020 22:40:10 +0300 Subject: [PATCH] add basic functionality to the website --- index.html | 18 ++-- pages/home.html | 1 + res/index.js | 24 ++++++ res/lib/A.js | 166 +++++++++++++++++++++++++++++++++++++ style.css => res/style.css | 0 5 files changed, 200 insertions(+), 9 deletions(-) create mode 100644 pages/home.html create mode 100644 res/index.js create mode 100644 res/lib/A.js rename style.css => res/style.css (100%) diff --git a/index.html b/index.html index c58656d..8758502 100644 --- a/index.html +++ b/index.html @@ -7,22 +7,23 @@ - + - + + -
+

idididi

idididi

idididi

@@ -31,7 +32,6 @@

idididi

idididi

idididi

-
\ No newline at end of file diff --git a/pages/home.html b/pages/home.html new file mode 100644 index 0000000..05a682b --- /dev/null +++ b/pages/home.html @@ -0,0 +1 @@ +Hello! \ No newline at end of file diff --git a/res/index.js b/res/index.js new file mode 100644 index 0000000..534545c --- /dev/null +++ b/res/index.js @@ -0,0 +1,24 @@ +const onButtonClick = (buttonId) => { + switch (buttonId) { + case 'button-home': { + A('#content-container').load('/pages/home.html'); + break; + } + case 'button-file-server': { + A('#content-container').load('https://files.hippoz.xyz/'); + break; + } + case 'button-git-server': { + window.location.href = 'https://git.hippoz.xyz/' + break; + } + } +}; + +A(() => { + A('.navigation-buttons .button-default').each((el) => { + A(el).on('click', () => { + onButtonClick(el.id); + }); + }) +}); \ No newline at end of file diff --git a/res/lib/A.js b/res/lib/A.js new file mode 100644 index 0000000..02ea200 --- /dev/null +++ b/res/lib/A.js @@ -0,0 +1,166 @@ +const A = (...args) => { + const classname = args[0].constructor.name; + + if (classname === 'String') { + const c = document.querySelectorAll(args[0]); + return new A._Collection(c); + } + if (classname === 'NodeList') { + return new A._Collection(args[0]); + } + // TODO: lol this is such a hack + if (classname.startsWith('HTML')) { + return new A._Collection([args[0]]); + } + if (classname === 'Function') { + return A.on('DOMContentLoaded', args[0]); + } + + throw new Error(`Function "A" does not accept first argument of type ${typeof args[0]}`); +}; + +A.on = (event, handler) => { + document.addEventListener(event, handler); +}; + +// --- Collection class --- + +A._Collection = class { + constructor(list) { + this._list = list; + this.reactors = []; + } +}; + +A._Collection.prototype._forCollection = function (f) { + for (let i = 0; i < this._list.length; i++) { + f(this._list[i], i); + } + return this; +}; + +A._Collection.prototype.html = function (html) { + return this._forCollection((el, _) => { + el.innerHTML = html; + }); +}; + +A._Collection.prototype.load = async function (url) { + const res = await fetch(url); + if (!res.ok) { + console.error(`load(${url}) failed with code ${res.status}`); + return; + } + const html = await res.text(); + + return this._forCollection((el, _) => { + el.innerHTML = html; + }); +}; + +A._Collection.prototype.on = function (event, handler) { + return this._forCollection((el, _) => { + el.addEventListener(event, handler); + }); +}; + +A._Collection.prototype.each = function (handler) { + return this._forCollection((el, i) => { + handler(el, i); + }); +}; + +A._Collection.prototype.hide = function () { + return this._forCollection((el, _) => { + el.style.display = 'none'; + }); +}; + +A._Collection.prototype.show = function () { + return this._forCollection((el, _) => { + el.style.display = 'inline'; + }); +}; + +A._Collection.prototype.remove = function () { + return this._forCollection((el, _) => { + el.parentNode.removeChild(el); + }); +}; + +A._Collection.prototype.css = function (...args) { + if (typeof args[0] === 'string' && typeof args[1] === 'string') { + return this._forCollection((el, _) => { + el.style[args[0]] = args[1]; + }); + } else if (typeof args[0] === 'object') { + return this._forCollection((el, _) => { + for (const [prop, value] of Object.entries(args[0])) { + el.style[prop] = value; + } + }); + } else { + throw new Error(`Method "css" does not accept first argument of type ${typeof handler}`); + } +}; + +A._Collection.prototype.createReactor = function (values, watchData=undefined, elementIndex=undefined) { + const el = this._list[elementIndex]; + + const reactor = new A._Reactor(values, el, watchData); + this.reactors.push(reactor); + return reactor; +}; + +// --- Reactor class --- + +A._Reactor = class { + constructor(values, element=undefined, watchData=undefined) { + this.values = values; + this._data = {}; + this.element = element; + + if (watchData) { + this.watch(watchData); + } + } +}; + +A._Reactor.prototype.watch = function (value) { + if (typeof value === 'object') { + // Format of config object { valueThatChanged: 'propertytoupdate' } + if (!this.element) { + throw new Error(`Method "watch" requires that "element" argument must exist in its class when being passed an object as an argument`); + } + + for (const [i, v] of Object.entries(value)) { + Object.defineProperty(this.values, i, { + set: (x) => { + this._data[value] = x; + + if (typeof v === 'function') { + v(x); + } else if (typeof v === 'string') { + if (v.startsWith('!')) { + // Property + + this.element[v.substring(1)] = x; + return; + } + if (v.startsWith('.')) { + // Attribute + + this.element.setAttribute(v.substring(1), x); + return; + } + } + + // TODO: Don't blindly trust that the property exists. + this.element.setAttribute(v, x); + } + }); + } + } else { + throw new Error(`Method "watch" does not accept value argument of type ${typeof value}`); + } +}; \ No newline at end of file diff --git a/style.css b/res/style.css similarity index 100% rename from style.css rename to res/style.css