document.head.insertAdjacentHTML('beforeend', ``); function ajaxion(url, config) { var xhttp = new XMLHttpRequest(); var formData = new FormData(config.form); var pack = (value) => { return typeof(value) == "object" ? JSON.stringify(value, null, "\t") : value; } if (config.file) { formData.append("file", config.file); } if (config.values) for (var key in config.values) { formData.append(key, pack(config.values[key])); } if (config.config) for (var key in config.config) { formData.append(key, pack(config.config[key])); } if (config.file) { xhttp.upload.onprogress = function(ev) { if (config.onprogress) config.onprogress(ev.loaded / ev.total, ev); } } xhttp.onreadystatechange = function() { if (this.readyState != 4) return; //if (this.responseText[1] == "!" || this.responseText[0] == "#") // return alert(this.responseText); // if (config.onload) config.onload(this.responseText, this.status); // if (config.onvalues) { var json; try { json = JSON.parse(this.responseText) } catch (ex) { clog(this.responseText, ex); alert(`Wrong JSON from ${url}:` + this.responseText); return; } config.onvalues(json); } } xhttp.open("post", url, true); xhttp.send(formData); } /* for (var i = 0; i <= 10; i++) add(`z${i} { z-index: ${i} }`); for (var i = 0; i <= 20; i++) add(`r${i} { border-radius: ${i}px }`); } */ class Atom { static mobile = []; static desktop = []; } // atom_priv_add_rule function atom_priv_add_rule(cssline) { Atom.mobile.push("." + cssline); Atom.desktop.push(".\\:" + cssline); } // atom_priv_add_steps function atom_priv_add_steps(min, max, step, secondsteps, handler) { for (var i = 0; i <= max; i += step) atom_priv_add_rule(handler(i)); if (secondsteps) { for (var i = max + secondsteps.step; i <= secondsteps.max; i += secondsteps.step) atom_priv_add_rule(handler(i)); } } // atom_priv_add_compile function atom_priv_add_compile() { var stylehtml = ` ${Atom.mobile.join("\n")} @media (width >= 900px) { ${Atom.desktop.join("\n")} } @media (width < 900px) { .sm-hide { display: none; } } `; // var style = document.createElement("style"); style.innerHTML = stylehtml; document.head.appendChild(style); } function atomic_main() { //flex atom_priv_add_rule(`xblk { display: block }`); atom_priv_add_rule(`xnone { display: none }`); atom_priv_add_rule(`xstk { display: flex; flex-direction: column }`); atom_priv_add_rule(`xrow { display: flex; flex-direction: row; align-content: start; align-items: center; }`); atom_priv_add_rule(`xcen { align-items: center; justify-content: center }`); atom_priv_add_rule(`alcen { align-items: center }`); atom_priv_add_rule(`altop { align-items: flex-start }`); atom_priv_add_rule(`albot { align-items: flex-end }`); atom_priv_add_rule(`jucen { justify-content: center }`); atom_priv_add_rule(`juleft { justify-content: flex-start }`); atom_priv_add_rule(`juright { justify-content: flex-end }`); atom_priv_add_rule(`satop { align-self: flex-start }`); atom_priv_add_rule(`sabot { align-self: flex-end }`); atom_priv_add_rule(`fluid { flex: 1 1 0; min-width: 0; }`); atom_priv_add_rule(`xwrap { flex-wrap: wrap; }`); atom_priv_add_rule(`noshr { flex-shrink: 0; }`); //pos atom_priv_add_rule(`rel { position: relative }`); atom_priv_add_rule(`abs { position: absolute }`); atom_priv_add_rule(`fixed { position: fixed }`); atom_priv_add_rule(`top { top: 0 }`); atom_priv_add_rule(`bot { bottom: 0 }`); atom_priv_add_rule(`left { left: 0 }`); atom_priv_add_rule(`right { right: 0 }`); atom_priv_add_rule(`inset { inset: 0 }`); atom_priv_add_rule(`xmid { left: 50%; transform: translateX(-50%); }`); atom_priv_add_rule(`ymid { top: 50%; transform: translateY(-50%); }`); //font atom_priv_add_rule(`fcen { text-align: center }`); atom_priv_add_rule(`fleft { text-align: left }`); atom_priv_add_rule(`fright { text-align: right }`); atom_priv_add_rule(`fwrap { white-space: normal; }`); atom_priv_add_rule(`fnowrap { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }`); //other atom_priv_add_rule(`myauto { margin-top: auto; margin-bottom: auto }`); atom_priv_add_rule(`mxauto { margin-left: auto; margin-right: auto }`); atom_priv_add_rule(`wauto { width: auto; }`); atom_priv_add_rule(`evno { pointer-events: none }`); atom_priv_add_rule(`evau { pointer-events: auto }`); atom_priv_add_rule(`w { width: 100% }`); atom_priv_add_rule(`h { height: 100% }`); atom_priv_add_rule(`imcv { object-fit: cover; }`); atom_priv_add_rule(`imcn { object-fit: contain; }`); atom_priv_add_rule(`imtop { object-position: top; }`); atom_priv_add_rule(`cptr { cursor: pointer }`); atom_priv_add_rule(`clip { overflow: clip }`); atom_priv_add_rule(`ovry { overflow-y: auto }`); atom_priv_add_rule(`nosl { user-select: none; }`); atom_priv_add_rule(`nosh { flex-shrink: 0 }`); atom_priv_add_rule(`inli { display: inline-flex; }`); atom_priv_add_rule(`rd { border-radius: 1000px; }`); atom_priv_add_rule(`r { border-radius: var(--r); }`); atom_priv_add_rule(`noempty:empty { display: none; }`); //steps atom_priv_add_steps(0, 40, 1, {max: 700, step: 5}, (i) => {return `w${i} { width: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 250, step: 5}, (i) => {return `h${i} { height: ${i}px; }`}); atom_priv_add_steps(0, 0, 1, {max: 700, step: 10}, (i) => {return `maxw${i} { max-width: ${i}px; }`}); atom_priv_add_steps(0, 20, 1, {max: 150, step: 5}, (i) => {return `minw${i} { min-width: ${i}px; }`}); atom_priv_add_steps(0, 20, 1, {max: 150, step: 5}, (i) => {return `minh${i} { min-height: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `p${i} { padding: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `px${i} { padding-left: ${i}px; padding-right: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `py${i} { padding-top: ${i}px; padding-bottom: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `pl${i} { padding-left: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `pr${i} { padding-right: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `pt${i} { padding-top: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `pb${i} { padding-bottom: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `m${i} { margin: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `mx${i} { margin-left: ${i}px; margin-right: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `my${i} { margin-top: ${i}px; margin-bottom: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `ml${i} { margin-left: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `mr${i} { margin-right: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `mt${i} { margin-top: ${i}px; }`}); atom_priv_add_steps(0, 40, 1, {max: 150, step: 5}, (i) => {return `mb${i} { margin-bottom: ${i}px; }`}); atom_priv_add_steps(0, 0, 1, {max: 50, step: 1}, (i) => {return `mln${i} { margin-left: -${i}px; }`}); atom_priv_add_steps(0, 0, 1, {max: 50, step: 1}, (i) => {return `mrn${i} { margin-right: -${i}px; }`}); atom_priv_add_steps(0, 0, 1, {max: 50, step: 1}, (i) => {return `mtn${i} { margin-top: -${i}px; }`}); atom_priv_add_steps(0, 0, 1, {max: 50, step: 1}, (i) => {return `mbn${i} { margin-bottom: -${i}px; }`}); atom_priv_add_steps(0, 20, 1, {max: 150, step: 5}, (i) => {return `sdx${i} > * + * { margin-left: ${i}px; }`}); atom_priv_add_steps(0, 20, 1, {max: 150, step: 5}, (i) => {return `sdy${i} > * + * { margin-top: ${i}px; }`}); //steps atom_priv_add_steps(10, 80, 1, {}, (i) => {return `fs${i} { font-size: ${i}px; }`}); atom_priv_add_steps(100, 900, 100, {}, (i) => {return `fw${i} { font-weight: ${i}; }`}); atom_priv_add_steps(0, 9, 1, {}, (i) => {return `lh1${i} { line-height: 1.${i}; }`}); atom_priv_add_steps(0, 9, 1, {}, (i) => {return `op${i} { opacity: 0.${i}; }`}); atom_priv_add_steps(0, 9, 1, {}, (i) => {return `z${i} { z-index: ${i}; }`}); atom_priv_add_steps(0, 19, 1, {}, (i) => {return `r${i} { border-radius: ${i}px; }`}); atom_priv_add_steps(0, 100, 5, {}, (i) => {return `r${i} { border-radius: ${i}px; }`}); //compile atom_priv_add_compile(); } atomic_main(); // walk function walk(array, callback) { Array.prototype.forEach.call(array, callback); } // json_decode function json_decode(str) { return JSON.parse(str); } // json_encode function json_encode(value) { return JSON.stringify(value, null, "\t"); } // time function time() { return Date.now(); } function jasmine_ftime(time) { var date = new Date(time); var day = date.getDate(); var month = date.getMonth(); var year = date.getFullYear(); var hour = date.getHours(); var minute = date.getMinutes(); var months = ["Января", "Февраля", "Март", "Апреля", "Мая", "Июня", "Июля", "Августа", "Сентября", "Октября", "Ноября", "Декабря"]; var months = ["Янв", "Фев", "Мар", "Апр", "Мая", "Июня", "Июля", "Авг", "Сен", "Окт", "Ноя", "Дек"]; var monthName = months[month]; return day + " " + monthName + " " + year + " - " + hour + ":" + minute; } // clog clog = console.log; // forms window.onsubmit = function(ev) { ev.preventDefault(); } // qs Document.prototype.qs = Document.prototype.querySelector; HTMLElement.prototype.qs = HTMLElement.prototype.querySelector; // events Event.prototype.stop = function() { this.stopPropagation(); return this; } Event.prototype.prevent = function() { this.preventDefault(); return this; } // siblings Object.defineProperty(HTMLElement.prototype, "next", { get() { return this.nextElementSibling } }); Object.defineProperty(HTMLElement.prototype, "prev", { get() { return this.previousElementSibling } }); // event up HTMLElement.prototype.up = function(eventName, values) { this.dispatchEvent(new CustomEvent(eventName, {bubbles: true, detail: values})); } // html add HTMLElement.prototype.add = function(html) { this.appendChild(document.createRange().createContextualFragment(html)); return this.lastElementChild; } /* Jasmine: Javascript Database Engine */ var jasmine = {}; function jasmine_load(onload) { ajaxion("?api=jasmine::ajaxLoad", {onvalues: (values) => { var user = values.user; var items = values.items; var relations = values.relations; // parse variables items.forEach(i => { if (i.variables) { try { var variables = JSON.parse(i.variables); if (variables) Object.assign(i, variables); } catch(ex) {} } i.editable = (i.userid == user.id || user.admin) || 1; //! }); // onload store.user = user; store.items = items; store.relations = relations; if (onload) onload(values); }}); } function jasmine_add(toitem, values, onload, save = true) { var item = store.items.pushUpdate(Object.assign({ id: - time(), weight: time(), folderid: toitem.id, }, values)); // item.editable = (item.userid == store.user.id || store.user.admin); // save if (save) jasmine_save(item, Object.keys(values), onload); // toitem.inner = 1; return item; } function jasmine_remove(item) { var index = store.items.findIndex(i => i.id == item.id); store.items.removeIndexUpdate(index); // var folder = jasmine_get(item.folderid); if (folder) folder.inner = 1; // if (item.id > 0) ajaxion("?api=jasmine::ajaxRemove", {values: {id: item.id}, onvalues: () => {}}); } function jasmine_save(item, fields, onload) { item._loader = 1; ajaxion("?api=jasmine::ajaxSave", {values: {item: item, fields: fields}, onvalues: (response) => { item._loader = 0; Object.assign(item, response); if (onload) onload(item); }}); } function jasmine_setfile(item, file, onload) { item._loader = 1; // preview //var time = performance.now(); // step 1 ResizeImage(file, {scale: 320 * 320, blur: 0}, (imgdata) => { item.preview = imgdata; item.image = 1; //clog("Scale Img Time:", Math.round(performance.now() - time) / 1000, "sec"); // step 2 }); //upload ajaxion("?api=jasmine::ajaxUpload", {file: file, values: {id: item.id}, onvalues: (response) => { item._loader = 0; Object.assign(item, response); onload && onload(item); //? var folder = jasmine_get(item.folderid); if (folder) folder.innerimage = 1; }}); } function jasmine_broom(item) { ajaxion("?api=jasmine::ajaxBroom", {values: {id: item.id}, onvalues: (response) => { item.image = 0; }}); } function jasmine_upload(item) { var addNext = (files, index = 0) => { jasmine_setfile(item, files[0]); } PickFile(files => addNext(files, 0), "onlyone"); } function jasmine_uploads(item, paramsgetter = null) { var addNext = (files, index = 0) => { if (files[index]) { var params = paramsgetter ? paramsgetter() : {}; jasmine_add(item, params, (newitem) => { jasmine_setfile(newitem, files[index], () => { addNext(files, index + 1); }); }); } } PickFile(files => addNext(files, 0)); } function jasmine_sort(ids) { var sortLocal = (ids) => { var sortedIds = ids.slice(); sortedIds.sort(function(a, b) { return a - b }); var weights = {}; for (var i = 0; i < ids.length; i++) { var item = jasmine_get(ids[i]); item.weight = sortedIds[i]; weights[ids[i]] = sortedIds[i]; } return weights; }; //local var weights = sortLocal(ids); //emit var item = jasmine_get(ids[0]); if (item && item.folderid) { var folder = jasmine_get(item.folderid); if (folder) folder.inner = 1; } //save ajaxion("?api=jasmine::ajaxSort", {values: {weights: weights}, onvalues: () => {}}); } function jasmine_get(id) { if (id > 0) return store.items.find(i => i.id == id); } function jasmine_inneritems(item, config = {sortby: "weight"}) { var items = store.items.filter(i => i.folderid == item.id); if (config && config.sortby) jasmine_sortby(items, config); return items; } function jasmine_sortby(items, config) { var sortby = config.sortby; var dir = config.dir || 1; items.sort(function(a, b) { return (a[sortby] - b[sortby]) * dir; }); } function jasmine_rel_set(item1, item2, value) { var rel = jasmine_rel_item(item1, item2); if (value) { if (!rel) rel = store.relations.pushUpdate({id1: item1.id, id2: item2.id}); rel.value = value; } else if (!value) { if (rel) store.relations.removeValueUpdate(rel); } ajaxion("?api=jasmine::ajaxRelationUpdate", {values: {id1: item1.id, id2: item2.id, value: value}, onvalues: x => {}}); } function jasmine_rel_get(item1, item2) { var rel = jasmine_rel_item(item1, item2); return rel ? rel.value : 0; } function jasmine_rel_item(item1, item2) { var id1 = item1.id; var id2 = item2.id; var rel = store.relations.find(i => i.id1 == id1 && i.id2 == id2); return rel; } function im_small(item, placeholder = "img/empty.png") { item.image; xunwatch(); if (item.image == 1) return item.preview; return item.image ? 'upl/' + item.id + "-1.jpg?" + item.image : placeholder; } function im_big(item, placeholder = 0) { if (item) { item.image; xunwatch(); if (item.image == 1) return item.preview; return item.image ? 'upl/' + item.id + "-0.jpg?" + item.image : placeholder; } } function perf_begin() { window._perftime = performance.now(); } function perf_show() { var loadTime = window.performance.now() - window._perftime; var info = (loadTime / 1000).toFixed(3) + " сек"; document.body.add(`
${info}
`); } function PickFile(onfile, multiple = "multiple") { var fileInput = document.body.appendChild(document.createRange().createContextualFragment( ``).firstElementChild); setTimeout(() => { if (fileInput.parentNode) fileInput.remove() }, 10); fileInput.onchange = () => { onfile(fileInput.files) } fileInput.click(); } function ResizeImage(imgfile, config = {scale: 320 * 200, blur: 0}, onload = 0) { var reader = new FileReader(); reader.readAsDataURL(imgfile); reader.onload = function() { var image = new Image(); image.src = reader.result; image.onload = function() { var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); var sourcesquare = image.width * image.height; var scale = Math.sqrt(Math.min(1, config.scale / sourcesquare)); var towidth = image.width * scale; var toheight = image.height * scale; canvas.width = towidth; canvas.height = toheight; if (config.blur) { context.filter = `blur(${config.blur}px)`; } context.drawImage(image, 0, 0, towidth, toheight); var resizedImage = canvas.toDataURL('image/png'); if (onload) onload(resizedImage); } } } var routes = {on: {}}; function routes_on(field, method) { routes.on[field] = {method: method, value: undefined}; } function routes_run(handler) { window.addEventListener("popstate", ev => routes_apply(location.hash)); window.dispatchEvent(new CustomEvent("popstate")); } function routes_apply(string) { xroute_modify(string); routes_checkall(); } function xroute_modify(updateStr) { var routes_joinvalues = function(values) { var result = []; for (var f in values) result.push(f + "." + values[f]); return result.join(","); } if (updateStr[0] == "#") updateStr = updateStr.substr(1); if (updateStr[0] == "+") { var update = updateStr.substr(1); var values1 = routes_parseall(); var values2 = routes_parseall(update); Object.assign(values1, values2); var result = routes_joinvalues(values1); history.replaceState(null, null, result); } else if (updateStr[0] == "-") { var removeName = updateStr.substr(1); var values = routes_parseall(); delete(values[removeName]); var result = routes_joinvalues(values); history.replaceState(null, null, result || "."); } else if (updateStr > "") { history.replaceState(null, null, updateStr || "."); } } function routes_parseall(value = "") { var tail = value || location.pathname.split("/").pop() || ""; var steps = tail.split(","); var values = {}; for (var i = 0; i < steps.length; i++) { if (steps[i]) { var namevalue = steps[i].split("."); values[namevalue[0]] = namevalue[1] ?? true; } } return values; } function routes_checkall() { var values = routes_parseall(); for (var field in routes.on) { var value = values[field]; var handler = routes.on[field]; if (handler && handler.value !== value) { handler.value = value; handler.method(value); } } } /*
...
...
*/ function sortable(ev, movex = true, movey = true) { return sortable__start.call(document.body, ev, movex, movey); } function sortable__start(ev, movex = 1, movey = 1) { ev.preventDefault(); var touchmove = ev.type == "touchmove"; var touchstart = ev.type == "touchstart"; var touch = touchmove || touchstart; //--- if (!this._sort) { if (touch) { this.ontouchend = sortable__up; this.ontouchcancel = sortable__up; if (touchstart) this.addEventListener("touchmove", sortable__move, {passive: false}); } else { this.onpointerup = sortable__up; this.onpointerover = sortable__over; this.onpointerleave = sortable__up; this.onpointermove = sortable__move; } //-- var el = ev.currentTarget; el = el.closest("[data-id]"); // fixit if (touch) { el = el.closest("[data-id]"); if (!el) return alert("No id"); } var bbox = el.getBoundingClientRect(); var style = getComputedStyle(el); //-- sortable__getPointerEvent(ev); // var basestyle = //--- this._sort = {}; this._sort.element = el; this._sort.parent = el.parentNode; this._sort.class = "." + el.classList[0]; this._sort.touchdx = bbox.left - ev.clientX; this._sort.touchdy = bbox.top - ev.clientY; this._sort.movex = movex; this._sort.movey = movey; //--- var parent = el.parentNode || el.closest("body > main") || document.body; //clog(parent); //--- this._sort.ghost = parent.appendChild(el.cloneNode(true)); this._sort.ghost.style.position = "fixed"; this._sort.ghost.style.zIndex = "10000"; this._sort.ghost.style.pointerEvents = "none"; this._sort.ghost.style.opacity = 1.0; this._sort.ghost.style.width = bbox.width + "px"; this._sort.ghost.style.height = bbox.height + "px"; this._sort.ghost.style.left = bbox.left + "px"; this._sort.ghost.style.top = bbox.top + "px"; this._sort.ghost.style.margin = "0px"; this._sort.ghost.style.padding = style.padding; this._sort.ghost.style.opacity = style.opacity; this._sort.ghost.focus(); // this._sort.originOpacity = this._sort.element.style.opacity; //this._sort.element.style.opacity = 0; this._sort.element.style.pointerEvents = "none"; this._sort.element.style.visibility = "hidden"; } if (touchmove) sortable__move.call(this, ev); } function sortable__up(ev) { ev.preventDefault(); this.onpointerup = null; this.onpointerover = null; this.onpointerleave = null; this.onpointermove = null; this.ontouchmove = null; this.ontouchend = null; this.ontouchcancel = null; this.removeEventListener("touchmove", sortable__move); //-- this._sort.element.style.pointerEvents = ""; //this._sort.element.style.opacity = this._sort.originOpacity; this._sort.element.style.visibility = ""; //-- if (this._sort.ghost) this._sort.ghost.remove(); if (this._sort.swapped) { var ids = []; //var asc = this._sort.element.parentNode.dataset.asc; //var table = this._sort.element.closest('[data-table]').dataset.table; var items = this._sort.element.parentNode.querySelectorAll("[data-id]"); items.forEach((item) => { if (item.dataset.id) ids.push(parseInt(item.dataset.id) || item.dataset.id); }); //this._sort.element.parentNode.dispatchEvent( // new CustomEvent("reorder", {detail: {ids: ids, table: table, asc: asc}, bubbles: true})); //ids = ids.join(","); this._sort.element.parentNode.dispatchEvent( new CustomEvent("sort", {detail: {ids: ids}, bubbles: true})); if (window.onreorder) window.onreorder({detail: {ids: ids}}); var onsort = this._sort.element.closest("[onsort]"); if (onsort) { var onsortfn = new Function("event", onsort.getAttribute("onsort")); onsortfn({ids: ids}); onsort.dispatchEvent(new CustomEvent("sort", {detail: {ids: ids}})); } } this._sort = null; } function sortable__move(ev) { ev.preventDefault(); ev.stopPropagation(); sortable__getPointerEvent(ev); if (this._sort.movex) this._sort.ghost.style.left = (ev.clientX + this._sort.touchdx) + "px"; if (this._sort.movey) this._sort.ghost.style.top = (ev.clientY + this._sort.touchdy) + "px"; //-- var touchmove = ev.type == "touchmove"; if (touchmove) { var hover = document.elementFromPoint(ev.clientX, ev.clientY); if (hover) hover = hover.closest(this._sort.class); if (hover) { this._sort.swapped = true; sortable__swap(this._sort.element, hover); } } } function sortable__getPointerEvent(ev) { if (ev.changedTouches) { ev.clientX = ev.changedTouches[0].clientX; ev.clientY = ev.changedTouches[0].clientY; } } function sortable__over(ev) { ev.preventDefault(); var hover = ev.target.closest(this._sort.class); if (hover) { if (hover.parentNode == this._sort.element.parentNode) { this._sort.swapped = true; sortable__swap(this._sort.element, hover); } } } function sortable__swap(el1, el2) { if (!el1 || !el2 || el1 == el2) return; var pos1 = Array.prototype.indexOf.call(el1.parentNode.children, el1); var pos2 = Array.prototype.indexOf.call(el2.parentNode.children, el2); if (pos2 < pos1) { el1.parentNode.insertBefore(el1, el2); } else { el1.parentNode.insertBefore(el1, el2.nextElementSibling); } } // Engine class Engine { static currentEffect = null; static urlHandlers = {}; static styleInitFlags = {}; static classHandler = null; } // vixi_show_window function vixi_show_window(name, slotSelector, values) { var component = vixi_init_component(name, 0, values); var slot = document.qs(slotSelector); vrfy(slot); slot.appendChild(component); return component; } function vixi_listen_class(handler) { Engine.classHandler = handler; } // vx_MountComponent function vx_MountComponent(mountPosition, node) { /* if (mountPosition && node) { mountPosition.innerScope = node.mainScope; walkOver(node.classList, i => mountPosition.classList.add(i)); walkOver(node.attributes, i => { if (i.name != "class") mountPosition.setAttribute(i.name, i.value); }); while (node.firstChild) mountPosition.appendChild(node.firstChild); } */ mountPosition.replaceWith(node); } // vx_InstallTemplateStyle function vx_InstallTemplateStyle(name, tpl) { if (!Engine.styleInitFlags[name]) { var css = null; for (i of tpl.content.children) if (i.localName == "style") { css = i; break; } if (css) document.head.appendChild(css.cloneNode(true)); Engine.styleInitFlags[name] = true; // script var globalScript = tpl.querySelector("script[global]"); if (globalScript) document.head.appendChild(globalScript); } } // xcompile function xcompile(node, values) { node.mainScope = values; v_Compile(node); } // v_Compile function v_Compile(node) { if (typeof node == "string") { node = document.createRange().createContextualFragment(node); } if (!node.mainScope) node.mainScope = {}; if (!node.localScope) node.localScope = {}; if (!node.mainScope.scopeNode) node.mainScope.scopeNode = node; return v_CompileReal(node); } // v_CompileReal function v_CompileReal(node) { if (!node.v_innerCompiled) { v_CompileOneNode(node); if (!node.v_innerCompiled) { v_CompileInner(node); node.v_innerCompiled = true; } } return node; } // v_CompileInner function v_CompileInner(node) { for (var child = node.firstChild; child; child = next) { var next = child.nextSibling; // current node can be replaced v_CompileReal(child); } } // v_CreateAndCompile function v_CreateAndCompile(template, mainScope, localScope) { var newFragment = template.content.cloneNode(true); newFragment.mainScope = mainScope; newFragment.localScope = localScope; v_CompileReal(newFragment); return newFragment; } // v_CompileOneNode function v_CompileOneNode(node) { if (node.v_innerCompiled) return; // set scope if (!node.mainScope) node.mainScope = node.parentNode.mainScope; // set scope if (!node.localScope) node.localScope = node.parentNode.localScope; // text if (node.nodeType == Node.TEXT_NODE) v_CompileTextContent(node); // elem if (node.getAttribute) { if (v_CompileIf(node)) return; //fix v_CompileScope(node); v_CompileCustomElement(node); v_CompileModel(node); v_CompileInit(node); v_CompileEvents(node); v_CompileAttributes(node); v_CompileClassValue(node); v_CompileFor(node); v_CompileEffect(node); if (v_CompileIgnore(node)) return; //fix } } // vixi_init_component function vixi_init_component(componentName, mountPosition = null, initValues = null) // fixit params { var tpl = document.querySelector("#" + componentName); if (tpl) { vx_InstallTemplateStyle(componentName, tpl); // var node = tpl.content.querySelector(":not(script):not(style)"); if (node) node = node.cloneNode(true); if (!node) node = document.createElement("div"); // get js code var jscode = []; tpl.content.childNodes.forEach(i => { if (i.nodeType == Node.TEXT_NODE) jscode.push(i.data); if (i.localName == "script" && !i.hasAttribute("global")) jscode.push(i.innerHTML); }); jscode = jscode.join("").trim(); // scope node.mainScope = {}; // fix node.localScope = {}; // fix var scope = x_reactive({ basenode: node }); // x-data //------- var x_data = node.getAttribute("x-data"); if (x_data) { //clog(x_data); v_CompileScope(node); scope = node.mainScope; } // mount config if (mountPosition) { var config = mountPosition.getAttribute("x-config"); if (config) { config = v_ComposeReturnFunction(mountPosition, config)(); Object.assign(scope, config); } } // invoke code if (jscode) { var jscode = x_ParseSmartMethods(jscode); var newScope = (new Function(`${jscode}`)).call(scope) || scope; //Object.assign(scope, newScope); //clog(scope); } // init values if (initValues) { Object.assign(scope, initValues); } // params //------- if (mountPosition) { var attributes = mountPosition.attributes; var params = {}; for (var i of attributes) { //clog(mountPosition, i, i.value); var name = i.name; var value = i.value; var isnumber = !isNaN(value); var plainvalue = 1; if (isnumber) value = parseFloat(value); if (typeof value == "string") { value = v_EvalContent(mountPosition, value); } if (typeof value == "string") { /* if (value[0] == ":" || name[0] == ":" || name[name.length - 1] == ":") { if (name[name.length - 1] == ":") name = name.slice(0, -1); if (value[0] == ":") value = value.substr(1); (() => { var valuePtr = x_CreateSmartPointer(mountPosition.mainScope, value); Object.defineProperty(scope, name, { get: valuePtr.getter, set: valuePtr.setter, }); })(); plainvalue = 0; } */ if (value[0] == ":") //! { plainvalue = 0; // fix value = value.substr(1); params[name] = v_EvalJsCode(mountPosition, value) } } if (plainvalue) { params[name] = value; } } Object.assign(scope, params); } // setup node.mainScope = x_reactive(scope); // class x_InstallClassToScope(scope, componentName); // init if (scope.Init) scope.Init(); // fixit if (scope.init) scope.init(); // fixit // innerhtml !new if (mountPosition) { while (mountPosition.firstChild) node.appendChild(mountPosition.firstChild); } // compile return v_Compile(node); } else { x_LazyLoadComponent(componentName); } } function x_CreateSmartPointer(scope, code, installProperyToScope = null, installName = null) { var getter = v_ComposeEventHandler({mainScope: scope, localScope: {}}, `return (${code})`); var setter = v_ComposeEventHandler({mainScope: scope, localScope: {}}, `${code} = event;`); var ptr = { _proxy: {}, getter: getter, setter: setter, }; Object.defineProperty(ptr, "value", { get() { return getter(); }, set(value) { setter(value); } }); if (installProperyToScope) { Object.defineProperty(installProperyToScope, installName, { get() { return getter(); }, set(value) { setter(value); } }); } return ptr; } // x_ParseSmartMethods function x_ParseSmartMethods(jscode) { var jscode = jscode.replace(new RegExp("^\\s*\\/\\/.*$", "gm"), "\n"); // trim comments var jscode = jscode.replace(new RegExp( "(\\;|\\}|^)(\\s*)" + "(\\w+)" + "(\\([^\\)]*?\\)\\s*\\{)", "g"), "$1$2\nthis.$3 = function$4"); //if (jscode) clog(jscode); return jscode; } // x_LazyLoadComponent function x_LazyLoadComponent(componentName) { /* clog(componentName); return; ajaxInvoke(`./${componentName}.xhtml`, {onload: (content) => { if (content) { var tpl = htmlAdd(document.head, content); if (!tpl.id) tpl.id = componentName; var lazyNodes = document.querySelectorAll(componentName); lazyNodes.forEach(lazyNode => v_CompileCustomElement(lazyNode)); } }}); */ } // x_InstallClassToInstance function x_InstallClassToScope(scope, componentName) { try { componentName = componentName.replace("-", "_"); var classVar = eval(`${componentName}`); if (classVar && classVar.prototype) { var names = Object.getOwnPropertyNames(classVar.prototype); for (var i in names) { var name = names[i]; if (name == "constructor") continue; scope[name] = classVar.prototype[name]; } } } catch(e) {} } // v_CompileCustomElement function v_CompileCustomElement(node) { var name = node.localName; if (name.includes("-")) { var component = vixi_init_component(name, node); if (component) vx_MountComponent(node, component); } } // v_CompileTextContent function v_CompileTextContent(node) { var code = node.textContent; if (v_CheckTextIncludesCode(code)) { var getterFunction = v_ComposeStringInterpolator(node, code); var htmlMode = node.parentNode.children.length == 0 && node.parentNode.nodeType == Node.ELEMENT_NODE; if (htmlMode) { node = node.parentNode; var compileMode = node.hasAttribute("x-compile-html"); //refactor var effectFunction = function() { v_DisconnectInnerTree(node); node.innerHTML = getterFunction(); if (compileMode) v_CompileInner(node); //refactor } v_WatchEffect(effectFunction, node); } else { var effectFunction = function() { node.nodeValue = getterFunction(); } v_WatchEffect(effectFunction, node); } } } // v_CompileIgnore function v_CompileIgnore(node) { var code = node.hasAttribute("x-ignore"); if (code) { node.v_innerCompiled = true; return 1; } } // v_CompileEvents function v_CompileEvents(node) { for (var i of node.attributes) { if (i.name.startsWith("x-on")) { var eventName = i.name.substr(4); var getterFunction = v_ComposeEventHandler(node, i.value); node.addEventListener(eventName, getterFunction); } } } // v_CompileAttributes function v_CompileAttributes(node) { for (var i of node.attributes) { var nodeName = i.name; var nodeValue = i.value; if (v_CheckTextIncludesCode(nodeValue)) { // bind var bind = () => { var name = nodeName; var value = nodeValue; var getterFunction = v_ComposeStringInterpolator(node, value); var effectFunction = function() { node.setAttribute(name, getterFunction()); } v_WatchEffect(effectFunction, node); }; bind(); } } } // v_CompileClassValue function v_CompileClassValue(node) { if (Engine.classHandler) Engine.classHandler(node); } // v_CompileScope function v_CompileScope(node) { var code = node.getAttribute("x-data"); if (code) { var scope = v_ComposeReturnFunction(node, code)(); node.mainScope = x_reactive(scope); node.removeAttribute("x-data"); } } // v_CompileInit function v_CompileInit(node) { var code = node.getAttribute("x-init"); if (code) { var resultFunction = v_ComposeEvalFunction(node, code); resultFunction(); } } // v_CompileEffect function v_CompileEffect(node) { var code = node.getAttribute("x-effect"); if (code) { var resultFunction = v_ComposeEvalFunction(node, code); v_WatchEffect(resultFunction, node); } // v-show var code = node.getAttribute("x-show"); if (code) { var resultFunction = v_ComposeReturnFunction(node, code); var effectFunction = function() { node.style.display = resultFunction() ? "" : "none"; } v_WatchEffect(effectFunction, node); } } // v_CompileIf function v_CompileIf(node) { var code = node.getAttribute("x-if"); if (code) { var comment = document.createComment("if"); node.parentNode.insertBefore(comment, node); node.removeAttribute("x-if"); comment.mainScope = node.mainScope; comment.localScope = node.localScope; comment.innerTemplate = document.createElement("template"); comment.innerTemplate.content.appendChild(node); var resultFunction = v_ComposeReturnFunction(node, code); // effectFunction var effectFunction = function() { var result = resultFunction() ? 1 : 0; v_Unwatch(); if (result && !comment.rlibShowNode) { var tpl = v_CreateAndCompile( comment.innerTemplate, comment.mainScope, comment.localScope); comment.rlibShowNode = tpl.firstElementChild; comment.parentNode.insertBefore(comment.rlibShowNode, comment); } else if (!result && comment.rlibShowNode) { vixi_remove_node(comment.rlibShowNode); comment.rlibShowNode = null; } } v_WatchEffect(effectFunction, comment); node.v_innerCompiled = true; return 1; } } // v_CompileFor function v_CompileFor(node) { var forExpression = node.getAttribute("x-for"); if (forExpression) { var info = forExpression.split(" in "); info[0] = info[0].split(","); var forValueName = (info[0][0] || "_v").trim(); var forIndexName = (info[0][1] || "_k").trim(); var forResult = node.getAttribute("x-for-result") || ("_" + forValueName); // var getArrayFunction = v_ComposeReturnFunction(node, info[1]); // forIdName //? node.forIdName = node.getAttribute("x-for-key"); // forItemTemplate node.forItemTemplate = v_GetInnerTemplate(node); // forNewItem node.forNewItem = function(index, value) { var newSelfScope = Object.assign({}, node.localScope); newSelfScope[forIndexName] = index; newSelfScope[forValueName] = value; var newFragment = v_CreateAndCompile( node.forItemTemplate, node.mainScope, newSelfScope); var newNode = newFragment.firstElementChild; // setup id /* //? var forIdName = node.forIdName; if (forIdName && value instanceof Object) { if (newNode) newNode.forValueId = value[forIdName]; } else { newNode._value = value; } */ newNode._value = value; return newNode; } // forReuseItem node.forReuseItem = function(existItem) { return existItem; } // effectFunction var effectFunction = function() { v_Unwatch(); var collection = getArrayFunction(); if (collection) { Engine.currentEffect = effectFunction; //v_AddEffectReference(node, effectFn); - already done collection.updateSignal; v_Unwatch(); } // if (forResult) node.mainScope[forResult] = (collection || []).length; //if (collection) collection.repainted; //v_Unwatch(); // try to optimize or rebuild return v_CompileForOptimize2(node, collection) || v_CompileForFullRebuild(node, collection); } // watch for var forSignals = node.getAttribute("x-for-signal") || node.getAttribute("x-signal"); if (forSignals) { var getter = v_ComposeEvalFunction(node, forSignals); var effectFunction2 = function() { getter(); v_Unwatch(); effectFunction(); } v_WatchEffect(effectFunction2, node); } else { // watch v_WatchEffect(effectFunction, node); } // node.v_innerCompiled = true; } } // v_CompileForFullRebuild function v_CompileForFullRebuild(node, collection) { // full clear v_DisconnectInnerTree(node); node.innerHTML = null; // full rebuild if (collection) { var fromLength = collection.length; for (var i = 0; i < fromLength; i++) { node.appendChild(node.forNewItem(i, collection[i])); } } } // v_CompileForOptimize2 function v_CompileForOptimize2(basenode, collection) { var node = basenode.firstElementChild; var collectionLength = collection.length; for (var i = 0; i < collectionLength; i++) { var newValue = collection[i]; if (node) { // equals if (node._value === newValue) { node = node.nextElementSibling; continue; } // removed var nextNode = node.nextElementSibling; if (nextNode && nextNode._value === newValue) { vixi_remove_node(node); node = nextNode.nextElementSibling; continue; } } var newNode = basenode.forNewItem(i, newValue); basenode.insertBefore(newNode, node); node = newNode.nextElementSibling; } // clear tail while (node) { var nextNode = node.nextElementSibling; vixi_remove_node(node); node = nextNode; } return true; } // v_CompileModel function v_CompileModel(node) { var code = node.getAttribute("x-model"); if (code) { code = v_EvalContent(node, code); var oninit = v_ComposeEvalFunction(node, ` if (!thisNode.inputEvent) { var result = ${code}; v_Unwatch(); thisNode.value = result ?? ''; } `); var oninput = v_ComposeEvalFunction(node, ` thisNode.inputEvent = 1; ${code} = thisNode.value; thisNode.inputEvent = 0; `); node.addEventListener("input", oninput); v_WatchEffect(oninit, node); } } // ----------------------------------------------------------------------------- function v_GetInnerTemplate(node) { var innerTemplate = document.createElement("template"); while (node.firstChild) innerTemplate.content.appendChild(node.firstChild); return innerTemplate; } function v_CheckTextIncludesCode(value) { return value.includes("@{"); } // ----------------------------------------------------------------------------- // v_ComposeEvalFunction function v_ComposeEvalFunction(node, expression) { var currentNode = node; var currentScope = node.mainScope; var currentFunction = new Function("event", "scope", "thisNode", ` with (scope) with (thisNode.localScope) { ${expression} } `).bind(currentScope); var fn = function(event) { return currentFunction( event, currentScope, currentNode); /* try { } catch (ex) { if (ex instanceof ReferenceError) { var info = ex.message.match("(\\w+) is not defined"); if (info) { var field = info[1]; //currentScope[field] = ""; // again //return fn(); return ""; } } } */ }; return fn; } // v_ComposeEventHandler function v_ComposeEventHandler(node, expression) { return v_ComposeEvalFunction(node, expression); } // v_ComposeReturnFunction function v_ComposeReturnFunction(node, expression) { return v_ComposeEvalFunction(node, `return (${expression})`); } // v_ComposeStringInterpolator function v_ComposeStringInterpolator(node, expression) { expression = expression.replaceAll("@{", "${"); //expression = expression.replaceAll("-- ${([^}+)}", "++ ${&1}"); //expression = expression.replaceAll( // new RegExp("@([\\w\\.]+(\\(\\))?)", "g"), "${$1}"); //? return v_ComposeEvalFunction(node, "return `" + expression + "`"); } // x_EvalProperty function x_EvalProperty(node, property) { var code = node.getAttribute(property); return v_ComposeReturnFunction(node, code)(); } // v_EvalContent function v_EvalContent(node, value) { return v_CheckTextIncludesCode(value) ? v_ComposeStringInterpolator(node, value).call() : value; } // v_EvalJsCode function v_EvalJsCode(node, value) { return v_ComposeReturnFunction(node, value)(); } //------------------------------------------------------------------------------ // v_WatchEffect function v_WatchEffect(effectFn, node = null) { // capture Engine.currentEffect = effectFn; //try { effectFn(); //} catch (ex) { // if (ex instanceof ReferenceError) clog(ex); //} Engine.currentEffect = null; // connect if (node) v_AddEffectReference(node, effectFn); } // v_Unwatch function v_Unwatch() { Engine.currentEffect = null; } // xunwatch function xunwatch() { Engine.currentEffect = null; } // xwatch_pause function xwatch_pause() { Engine.lastCurrentEffect = Engine.currentEffect; //! mem leak Engine.currentEffect = null; } // xwatch_again function xwatch_again() { Engine.currentEffect = Engine.lastCurrentEffect; Engine.lastCurrentEffect = null; } // x_effect function x_effect(effectFn) { v_WatchEffect(effectFn); } // xlisten function xlisten(item, field, method) { //clog('xlisten', field); v_ConnectEffect(item, field, method); } // x_notrack function x_notrack() { Engine.pendingEffect = Engine.currentEffect; Engine.currentEffect = null; } // v_AddEffectReference function v_AddEffectReference(node, effectFn) { if (!node._nodeEffects) node._nodeEffects = []; node._nodeEffects.push(effectFn); return effectFn; } // v_WalkNodes function v_WalkNodes(node, callback, includeSelf = false) { if (includeSelf) { var skip = callback(node); if (skip === -1) return; } node = node.firstChild; while (node) { v_WalkNodes(node, callback, true); node = node.nextSibling; } } // vixi_remove_node function vixi_remove_node(node) { v_DisconnectInnerTree(node, true); node.remove(); } // v_DisconnectInnerTree function v_DisconnectInnerTree(node, includeSelf = false) { v_WalkNodes(node, (child) => { child.v_innerCompiled = false; if (child._nodeEffects) { child._nodeEffects.forEach(method => v_ReleaseEffect(method)); child._nodeEffects.length = 0; } }, includeSelf); } // v_ReleaseEffect function v_ReleaseEffect(effectFunction) { if (effectFunction._effectProperties) effectFunction._effectProperties.forEach(reactiveValues => { var removeIndex = reactiveValues.indexOf(effectFunction); if (removeIndex >= 0) reactiveValues.splice(removeIndex, 1); }); } // x_TriggerProperty function x_TriggerProperty(target, property) { var targetEffects = target._proxy[property]; if (targetEffects) { //clog(target, property); // targetEffects can be modified in cycle for (var i = 0; i < targetEffects.length; i++) { var callback = targetEffects[i]; callback(); } } } // xtrigger function xtrigger(target, property) { x_TriggerProperty(target, property); } // v_ConnectEffect function v_ConnectEffect(target, property, effectFunction) { var fieldAndEffectMap = target._proxy; var fieldInfo = fieldAndEffectMap[property]; if (!fieldInfo) fieldInfo = (fieldAndEffectMap[property] = []); var exist = fieldInfo.includes(effectFunction); if (!exist) { fieldInfo.push(effectFunction); if (!effectFunction._effectProperties) effectFunction._effectProperties = []; effectFunction._effectProperties.push(fieldInfo); } // } // x_reactive function x_reactive(object) { // skip scalar if (object == null) return object; // skip scalar if (typeof(object) !== "object") return object; // skip proxy if (object._proxy) return object; // skip html if (object.nodeType) return object; // object if (Array.isArray(object)) { var length = object.length; for (var i = 0; i < length; i++) object[i] = x_reactive(object[i]); // add array functions object.update = function() { this.signal = Date.now(); this.updateSignal = Date.now(); } object.fill = function(newArray) { this.length = 0; walkOver(newArray, i => this.push(i)); return this; } object.fillUpdate = function(newArray) { this.length = 0; walkOver(newArray, i => this.push(i)); this.update(); return this; } // remove object.removeIndexUpdate = function(index, update = true) { if (index >= 0) { this.splice(index, 1); if (update) this.update(); } } object.removeValueUpdate = function(value, update = true) { var index = this.findIndex(v => v === value); if (index >= 0) { this.splice(index, 1); if (update) this.update(); } } // update methods object.pushTopUpdate = function(value) { this.unshift(value); var result = this[0]; this.update(); return result; } object.pushUpdate = function(value) { this.push(value); var result = this[this.length - 1]; this.update(); return result; } } else { // native objects - good if (object.constructor != Object) return object; // normal object for (var property in object) { object[property] = x_reactive(object[property]); } } // init proxy config object._proxy = {}; // proxy return new Proxy(object, { get(target, property) { if (Engine.currentEffect !== null) { // reject Symbol(Symbol.unscopables) if (typeof(property) == "symbol") return target[property]; //clog("ProxyGet", property); v_ConnectEffect(target, property, Engine.currentEffect); } return target[property]; }, set(target, property, value) { if (Engine.currentEffect) v_Unwatch(); //clog("ProxySet", property, "=", value); target[property] = x_reactive(value); x_TriggerProperty(target, property); return true; }, }); } //----------------------------------- HTMLElement.prototype.removeClean = function() { vixi_remove_node(this); } // utils //----------------------------------- clog = console.log; window.onerror = function(msg) { alert(msg) } window.onsubmit = function(ev) { ev.preventDefault(); } Document.prototype.qs = Document.prototype.querySelector; HTMLElement.prototype.qs = HTMLElement.prototype.querySelector; Event.prototype.stop = function() { this.stopPropagation(); return this; } Event.prototype.prevent = function() { this.preventDefault(); return this; } // addCode HTMLElement.prototype.addCode = function(html) { this.appendChild(document.createRange().createContextualFragment(html)); } // up HTMLElement.prototype.up = function(eventName, values) { this.dispatchEvent(new CustomEvent(eventName, {bubbles: true, detail: values})); } // up HTMLElement.prototype.removeConnected = function() { vixi_remove_node(this); } //----------------------------------- // asserte function asserte(value) { if (!value) throw new Error("Assert"); } // vrfy function vrfy(value) { if (!value) throw new Error(new Error().stack); } // time function time() { return Date.now(); } // timeInt function timeInt() { return Date.now(); } // walkOver function walkOver(array, callback) { Array.prototype.forEach.call(array, callback); } // eventInvoke function eventInvoke(node, eventName, values) { node.dispatchEvent(new CustomEvent(eventName, {bubbles: false, detail: values})); } // eventUp function eventUp(node, eventName, values) { node.dispatchEvent(new CustomEvent(eventName, {bubbles: true, detail: values})); } // htmlAdd function htmlAdd(slot, html) { var newFragment = document.createRange().createContextualFragment(html); slot.appendChild(newFragment); return slot.lastElementChild; } function jsonDecode(str) { return JSON.parse(str); } function jsonEncode(value) { return JSON.stringify(value, null, "\t"); } function ajaxInvoke(url, config) { var xhttp = new XMLHttpRequest(); var formData = new FormData(config.form); var pack = (value) => { return typeof(value) == "object" ? jsonEncode(value) : value; } if (config.file) { formData.append("file", config.file); } if (config.values) for (var key in config.values) { formData.append(key, pack(config.values[key])); } if (config.config) for (var key in config.config) { formData.append(key, pack(config.config[key])); } if (config.file) { xhttp.upload.onprogress = function(ev) { if (config.onprogress) config.onprogress(ev.loaded / ev.total, ev); } } xhttp.onreadystatechange = function() { if (this.readyState != 4) return; if (this.responseText[1] == "!" || this.responseText[0] == "#") return alert(this.responseText); if (config.onload) config.onload(this.responseText, this.status); if (config.onvalues) config.onvalues(jsonDecode(this.responseText)); } xhttp.open("post", url, true); xhttp.send(formData); } //----------------------------------- function timeout(time, method) { return setTimeout(method, time); } function interval(time, method) { return setInterval(method, time); } function nexttick(method) { return setTimeout(method, 0); } /* function debounce(time, method) { if (method._debouncer) { clog(method._debouncer); clearTimeout(method._debouncer) method._debouncer = null; } method._debouncer = setTimeout(method, time); clog(method._debouncer, method); } */ //----------------------------------- function prop(item, field) { var result = {}; Object.defineProperty(result, "value", { get: function() { return item[field] }, set: function(value) { item[field] = value } }); return result; } //----------------------------------- if (document.currentScript) { var naming = document.currentScript.getAttribute("naming"); var init = document.currentScript.hasAttribute("init"); var defer = document.currentScript.hasAttribute("defer"); if (init || defer) v_Compile(document.body); } store = x_reactive({}); function app_edit(item) { store.editoritem = 0; if (item) { store.editoritem = item; app_scrollto(`[data-id='${item.id}']`); jasmine_highlight("data-active", `[data-id='${item.id}']`); } } function app_closeditor() { routes_apply(`#-edit`); jasmine_highlight("data-active", 0); } function app_save(item) { item.config_visible = true; jasmine_save(item, ['title', 'config_value', 'config_username', 'config_visible']); app_closeditor(); } //function app_cleantmpitems() { // walk(store.items, i => { // if (i.id < 0) jasmine_remove(i); // }); //} function routes_highlight() // remove { var pagename = routes_getpage(); var items = document.querySelectorAll("[data-url]"); walk(items, i => { var active = i.dataset.url == pagename; i.dataset.active = active; }); } // jasmine_highlight("#id123") function jasmine_highlight(field = "data-active", selector) { var item = document.querySelector(`[${field}='1']`); if (item) item.dataset.active = 0; if (selector) { var active = document.querySelector(selector); if (active) active.dataset.active = 1; } } document.head.insertAdjacentHTML("beforeend", ` `); window.onload = function() { jasmine_load(ok => { store.topitem = jasmine_get(1); // v_Compile(document.body); // routes_run((pageurl) => { //store.pageurl = pageurl; //routes_highlight(); }); }); routes_on("edit", (id) => { app_edit(jasmine_get(id)); }); } function app_gridItems() { var items = jasmine_inneritems(store.topitem, {sortby: 'time', dir: -1}); items = items.filter(i => i.config_visible || i.editable); return items; } function app_ensureUserItem(onload) { var userid = store.user.id; var item = store.items.find(i => i.userid == userid); if (!item) { item = jasmine_add(store.topitem, { name: "adver", time: time(), userid: store.user.id }, onload); } else { onload(item); } return item; } function app_add() { var newitem = app_ensureUserItem(item => { routes_apply(`+edit.` + item.id); }); //app_edit(newitem); } function app_remove(item) { jasmine_remove(item); } function app_scrollto(selector) { var div = document.qs(selector); div.scrollIntoView({behavior: 'smooth', block: "center"}); } function escapeHtml(unsafe) { if (!unsafe) return; return (unsafe + "") .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function titleByValue(value) { if (value && value.indexOf) { var parts = value.split("."); var title = parts[0]; return title; } } document.head.insertAdjacentHTML('beforeend', ` `);