426 lines
11 KiB
JavaScript
426 lines
11 KiB
JavaScript
/*
|
|
* Find.js
|
|
*
|
|
* Copyright 2026 Lida <lida@lida-laptol>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*
|
|
*
|
|
*/
|
|
|
|
class FindObjectMap {
|
|
constructor(_root, app, num) {
|
|
this.root = _root;
|
|
if (typeof this.root !== "object") {
|
|
PrivateFind.error("Неизвестный root!");
|
|
}
|
|
this._app = app;
|
|
this._num = num;
|
|
return this;
|
|
}
|
|
select(q) {
|
|
const o = this.root.querySelector(q);
|
|
if (typeof o === "undefined") {
|
|
PrivateFind.error("Нет обьектов для селектора!");
|
|
return undefined;
|
|
}
|
|
return new FindObjectMap(o, this._app, this._num + 1);
|
|
}
|
|
read() {
|
|
return this.root.innerHTML;
|
|
}
|
|
text(t) {
|
|
if (arguments.length == 0) {
|
|
return this.root.textContent;
|
|
}
|
|
this.root.textContent = t;
|
|
return this;
|
|
}
|
|
html(t) {
|
|
if (arguments.length == 0) {
|
|
return this.root.innerHTML;
|
|
}
|
|
this.root.innerHTML = t;
|
|
return this;
|
|
}
|
|
value(t) {
|
|
if (arguments.length == 0) {
|
|
return this.root.value;
|
|
}
|
|
this.root.value = t;
|
|
return this;
|
|
}
|
|
id(q) {
|
|
const o = this.root.querySelector("#" + q);
|
|
if (typeof o === "undefined") {
|
|
PrivateFind.error("No objects of selector");
|
|
return undefined;
|
|
}
|
|
return new FindObjectMap(o, this._app, this._num + 1);
|
|
}
|
|
tag(q) {
|
|
const o = this.root.getElementsByTagName(q);
|
|
if (typeof o === "undefined") {
|
|
PrivateFind.error("No objects of selector");
|
|
return undefined;
|
|
}
|
|
return new FindObjectMap(o, this._app, this._num + 1);
|
|
}
|
|
attach(event, func) {
|
|
this.root.addEventListener(event, () => {
|
|
func(this._app);
|
|
});
|
|
return this;
|
|
}
|
|
merge() {
|
|
if (this._num != 0) {
|
|
PrivateFind.error(
|
|
"Вы можете создавать " +
|
|
"merge-обьект только из корневого map(), " +
|
|
"но уровень вложенности данного map() равен " +
|
|
String(this._num) + "!"
|
|
);
|
|
return this;
|
|
}
|
|
const addr = this._app.getNumberOfGroupFromId(this._app.__id);
|
|
this._app.groups[addr].html = new Array(this.read());
|
|
return this;
|
|
}
|
|
app() {
|
|
return this._app;
|
|
}
|
|
main() {
|
|
return new FindObjectMap(this._app.root, this._app, 0);
|
|
}
|
|
}
|
|
|
|
const tags = {
|
|
"mobile" : `<meta name="viewport" content="width=device-width, initial-scale=1"></meta>`
|
|
}
|
|
|
|
export default class {
|
|
|
|
/* Public section */
|
|
|
|
constructor(root) {
|
|
this.root = root;
|
|
this.iter = 0;
|
|
this.groups = new Array();
|
|
this.groups_count = 0;
|
|
this._map = new FindObjectMap(this.root, this, 0);
|
|
return this;
|
|
}
|
|
|
|
static tags(name) {
|
|
return tags[name];
|
|
}
|
|
|
|
static attach(x, f) {
|
|
return `${x}="${f.replace("\"", """)}"`;
|
|
}
|
|
|
|
static css(text) {
|
|
return `<link rel="stylesheet" href="${text.replace("\"", """)}"></link>`;
|
|
}
|
|
|
|
static search(name) {
|
|
return document.getElementById(name);
|
|
}
|
|
|
|
main(el) {
|
|
this.root = el;
|
|
this._map.root = el;
|
|
return this;
|
|
}
|
|
|
|
group(id_, html_, meta_) {
|
|
let id = undefined;
|
|
let html = undefined;
|
|
if (arguments.length == 1) {
|
|
id = this.__id;
|
|
html = id_;
|
|
} else {
|
|
id = id_;
|
|
html = html_;
|
|
}
|
|
let l = false;
|
|
if (typeof meta_ !== "undefined") {
|
|
l = true;
|
|
}
|
|
const addr = this.getNumberOfGroupFromId(id, false);
|
|
let meta = undefined;
|
|
if (addr == -1) {
|
|
meta = meta_;
|
|
} else {
|
|
meta = l ? meta_ : this.groups[addr].meta;
|
|
}
|
|
if (typeof meta !== "object") {
|
|
meta = new Array();
|
|
}
|
|
if (addr != -1) {
|
|
this.groups[addr] = {
|
|
id: id,
|
|
html: html,
|
|
meta: meta,
|
|
title: document.title
|
|
};
|
|
return this;
|
|
}
|
|
|
|
if (!Array.isArray(html)) {
|
|
PrivateFind.findTypeError(html, "object");
|
|
return this;
|
|
}
|
|
for (let i = 0; i < html.length; i ++) {
|
|
if (typeof html[i] !== "string") {
|
|
PrivateFind.findTypeError(html[i], "string");
|
|
}
|
|
}
|
|
this.groups[this.groups_count] = {
|
|
id: id,
|
|
html: html,
|
|
meta: meta
|
|
};
|
|
this.groups_count ++;
|
|
return this;
|
|
}
|
|
|
|
delete(groupid_, elementid_) {
|
|
let groupid = undefined;
|
|
let elementid = undefined;
|
|
if (arguments.length == 1) {
|
|
groupid = this.__id;
|
|
elementid = groupid_;
|
|
} else {
|
|
groupid = groupid_;
|
|
elementid = elementid_;
|
|
}
|
|
|
|
const addr = this.getNumberOfGroupFromId(groupid);
|
|
const len = this.groups[addr]
|
|
.html.length;
|
|
if (elementid < 0 || elementid >= len) {
|
|
PrivateFind.error("You can't remove element " + elementid + "!");
|
|
}
|
|
|
|
elementid ++;
|
|
const max = (elementid >= len) ? elementid : len;
|
|
const lp = this.groups[addr]
|
|
.html;
|
|
this.groups[addr]
|
|
.html =
|
|
lp.slice(0, elementid - 1)
|
|
.concat(lp.slice(elementid, max));
|
|
return this;
|
|
}
|
|
|
|
correct(groupid_, elementid_, telement_) {
|
|
let groupid = undefined;
|
|
let elementid = undefined;
|
|
let telement = undefined;
|
|
if (arguments.length == 2) {
|
|
groupid = this.__id;
|
|
elementid = groupid_;
|
|
telement = elementid_;
|
|
} else {
|
|
groupid = groupid_;
|
|
elementid = elementid_;
|
|
telement = telement_;
|
|
}
|
|
|
|
this.groups[this.getNumberOfGroupFromId(groupid)]
|
|
.html[elementid] = telement;
|
|
return this;
|
|
}
|
|
|
|
add(id_, html_) {
|
|
let id = undefined;
|
|
let html = undefined;
|
|
if (arguments.length == 1) {
|
|
id = this.__id;
|
|
html = id_;
|
|
} else {
|
|
id = id_;
|
|
html = html_;
|
|
}
|
|
|
|
if (this.groups.length == 0 || this.getNumberOfGroupFromId(id, false) == -1) {
|
|
this.group(id, html);
|
|
return this;
|
|
}
|
|
|
|
const addr = this.getNumberOfGroupFromId(id);
|
|
this.groups[addr]
|
|
.html = this
|
|
.groups[addr]
|
|
.html
|
|
.concat(html);
|
|
return this;
|
|
}
|
|
|
|
title(id_, html_) {
|
|
let id = undefined;
|
|
let html = undefined;
|
|
if (arguments.length == 1) {
|
|
id = this.__id;
|
|
html = id_;
|
|
} else {
|
|
id = id_;
|
|
html = html_;
|
|
}
|
|
if (this.groups.length === 0 || this.getNumberOfGroupFromId(id, false) === -1) {
|
|
this.group(id, []);
|
|
}
|
|
const title = html;
|
|
const addr = this.getNumberOfGroupFromId(id);
|
|
this.groups[addr].title = String(title);
|
|
return this;
|
|
}
|
|
|
|
meta(id_, html_) {
|
|
let id = undefined;
|
|
let html = undefined;
|
|
if (arguments.length == 1) {
|
|
id = this.__id;
|
|
html = id_;
|
|
} else {
|
|
id = id_;
|
|
html = html_;
|
|
}
|
|
|
|
if (this.groups.length == 0 || this.getNumberOfGroupFromId(id, false) == -1) {
|
|
this.group(id, [], html);
|
|
return this;
|
|
}
|
|
|
|
const addr = this.getNumberOfGroupFromId(id);
|
|
this.groups[addr]
|
|
.meta = this
|
|
.groups[addr]
|
|
.meta
|
|
.concat(html);
|
|
return this;
|
|
}
|
|
|
|
select(id) {
|
|
this.__id = id;
|
|
return this;
|
|
}
|
|
|
|
draw() {
|
|
if (typeof this.__id === "undefined") {
|
|
PrivateFind.error("Use select, before draw. Or you can use render.");
|
|
}
|
|
let group = this.groups[PrivateFind.arrayFindElement(this.groups, this.__id)];
|
|
if (typeof group !== "object") {
|
|
PrivateFind.findTypeError(group, "object");
|
|
return this;
|
|
}
|
|
if (typeof group.html !== "object") {
|
|
PrivateFind.findTypeError(group.html, "object");
|
|
return this;
|
|
}
|
|
this.root.innerHTML = "";
|
|
if (typeof group.title !== "undefined" && document.title !== group.title) {
|
|
document.title = group.title;
|
|
}
|
|
if (
|
|
typeof group.meta === "object" &&
|
|
Array.isArray(group.meta) &&
|
|
group.meta.length > 0 && this.iter === 0
|
|
) {
|
|
for (let i = 0; i < group.meta.length; i ++) {
|
|
if (typeof group.meta[i] === "string") {
|
|
this.root.innerHTML += group.meta[i];
|
|
}
|
|
}
|
|
}
|
|
for (let i = 0; i < group.html.length; i ++) {
|
|
if (typeof group.html[i] === "string") {
|
|
this.root.innerHTML += group.html[i];
|
|
}
|
|
}
|
|
this.iter ++;
|
|
return this;
|
|
}
|
|
|
|
render(id_) {
|
|
let id = undefined;
|
|
if (arguments.length == 0) {
|
|
id = this.__id;
|
|
} else {
|
|
id = id_;
|
|
}
|
|
|
|
const sv = this.__id;
|
|
this.select(id);
|
|
this.draw();
|
|
this.__id = sv;
|
|
return this;
|
|
}
|
|
|
|
map() {
|
|
return this._map;
|
|
}
|
|
|
|
getNumberOfGroupFromId(groupid, type) {
|
|
let l = false;
|
|
if (typeof type === undefined || (typeof type === "boolean" && type == true)) l = true;
|
|
const addr = PrivateFind.arrayFindElement(this.groups, groupid);
|
|
let group = this.groups[addr];
|
|
if (typeof group !== "object") {
|
|
if (l) PrivateFind.findTypeError(group, "object");
|
|
return -1;
|
|
}
|
|
let element = group.html;
|
|
if (typeof element !== "object") {
|
|
if (l) PrivateFind.findTypeError(element, "object");
|
|
return -1;
|
|
}
|
|
return addr;
|
|
}
|
|
}
|
|
|
|
class FindError extends Error {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'Find Framework Error';
|
|
}
|
|
}
|
|
|
|
class PrivateFind {
|
|
|
|
/* Private section */
|
|
|
|
static arrayFindElement(groups, id) {
|
|
for (let i = 0; i < groups.length; i ++) {
|
|
if (groups[i].id === id) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static error(text) {
|
|
throw new FindError(text);
|
|
}
|
|
|
|
static findTypeError(obj, tp) {
|
|
throw new TypeError(`Вы пытаетесь передать ${typeof obj}, в то время как ожидается ${tp}!`);
|
|
}
|
|
|
|
}
|