homepage/res/lib/A.js
2020-10-04 22:55:27 +03:00

166 lines
No EOL
4.6 KiB
JavaScript

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}`);
}
};