/** * Vvveb * * Copyright (C) 2021 Ziadin Givan * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * https://github.com/givanz/Vvveb */ let Input = { init: function(name) { }, onChange: function(event, node, input) { if (event && event.target) { const e = new CustomEvent('propertyChange', { detail: {value : input.value ?? this.value, input: this, origEvent:event} }); event.currentTarget.dispatchEvent(e); //event.data.element.trigger('propertyChange', [this.value, this, event]); } }, renderTemplate: function(name, data) { return tmpl("vvveb-input-" + name, data); }, setValue: function(value) { if (this.element[0] && value) { let input = this.element[0].querySelector('input'); if (input) { input.value = value; } } }, render: function(name, data) { let html = this.renderTemplate(name, data); this.element = generateElements(html); //bind events if (this.events) for (let i in this.events) { ev = this.events[i][0]; fun = this[ this.events[i][1] ]; el = this.events[i][2]; //this.element[0].querySelector(el).addEventListener(ev, function (ev, el, fun, target, event) { this.element[0].addEventListener(ev, function (ev, el, fun, target, event) { if (event.target.closest(el)) { //target, event, element, input return fun.call(event.target, event, target, this); } }.bind(this, ev, el, fun, this.element[0])); } return this.element[0]; } }; let TextInput = { ...Input, ...{ events: [ //event, listener, child element ["focusout", "onChange", "input"], ], init: function(data) { return this.render("textinput", data); }, } } let TextareaInput = { ...Input, ...{ events: [ ["keyup", "onChange", "textarea"], ], setValue: function(value) { if (this.element[0] && value) { let input = this.element[0].querySelector('textarea'); if (input) { input.value = value; } } }, init: function(data) { return this.render("textareainput", data); }, } } let CheckboxInput = { ...Input, ...{ events: [ ["change", "onCheck", "input"], ], onCheck: function(event, node, input) { input.value = this.checked; return input.onChange.call(this, event, node, input); }, setValue: function(value) { if (this.element[0]) { let input = this.element[0].querySelector('input'); if (input) { if (value) { input.checked = true; } else { input.checked = false; } } } }, init: function(data) { return this.render("checkboxinput", data); }, } } let SelectInput = { ...Input, ...{ events: [ ["change", "onChange", "select"], ], setValue: function(value) { if (this.element[0] && value) { let input = this.element[0].querySelector('select'); if (input) { input.value = value; } } }, init: function(data) { return this.render("select", data); }, } } let IconSelectInput = { ...Input, ...{ events: [ ["change", "onChange", "select"], ], setValue: function(value) { if (this.element[0] && value) { let input = this.element[0].querySelector('select'); if (input) { input.value = value; } } }, init: function(data) { return this.render("icon-select", data); }, } } let HtmlListSelectInput = { ...Input, ...{ data:{}, cache:{}, events: [ //["click", "onChange", "li"], ["change", "onListChange", "select"], ["keyup", "searchElement", "input.search"], ["click", "clearSearch", "button.clear-backspace"], ], clearSearch : function(event, element, input) { let search = element.querySelector("input.search"); if (search) { search.value = ""; input.searchElement(event, element, input); } search.dispatchEvent(new KeyboardEvent("keyup", { bubbles: true, cancelable: true, })); }, searchElement : function(event, element, input) { searchText = this.value; delay(() => { element.querySelectorAll("li").forEach((el, i) => { if (!searchText || el.title.indexOf(searchText) > -1) { el.style.display = ''; } else { el.style.display = 'none'; } }); }, 500); }, onElementClick: function(event, element, input) { let data = input.data; let svg = this.closest(data.insertElement); let value = svg.outerHTML ?? ""; input.value = value; let ret = input.onChange.call(this, event, element, input); return element; }, onListChange: function(event, element, input) { let url = input.data.url.replace('{value}', this.value); let elements = element.querySelector(".elements"); elements.innerHTML = `
Loading...
Loading...
`; //cache ajax requests if (input.cache[url] != undefined) { elements.innerHTML = input.cache[url]; } else { fetch(url) .then((response) => { if (!response.ok) { throw new Error(response) } return response.text() }) .then((text) => { input.cache[url] = text; elements.innerHTML = text; }) .catch(error => { console.log(error.statusText); displayToast("danger", "Error", "Error loading list"); }); } }, setValue: function(value) { let select = this.element[0].querySelector("select"); if (value && select) { select.value = value; } }, init: function(data) { this.data = data; this.events.push(["click", "onElementClick", data.clickElement]); let template = this.render("html-list-select", data); let select = template.querySelector("select"); this.onListChange.call(select, new Event('change'), template, this); return template; }, } } let LinkInput = { ...TextInput, ...{ events: [ ["change", "onChange", "input"], ], /* setValue: function(value) { //value = value.replace(/(? { if (value == el.value) { selected = el; } else { el.checked = false; el.removeAttribute("checked"); } }); selected.checked = true; selected.setAttribute("checked", "checked"); } }, init: function(data) { return this.render("radiobuttoninput", data); }, } } let ToggleInput = { ...Input, ...{ events: [ ["change", "onToggleChange", "input"], ], onToggleChange: function(event, node, input) { input.value = this.checked ? this.getAttribute("data-value-on") : this.getAttribute("data-value-off"); return input.onChange.call(this, event, node, input); }, setValue: function(value) { if (this.element[0]) { let input = this.element[0].querySelector('input'); if (input) { if (value == input.getAttribute("data-value-on")) { input.checked = true; input.setAttribute("checked", true); } else { input.checked = false; input.removeAttribute("checked"); } } } }, init: function(data) { return this.render("toggle", data); }, } } let ValueTextInput = { ...TextInput, ...{ events: [ ["focusout", "onChange", "input"], ], init: function(data) { return this.render("textinput", data); }, } } let GridLayoutInput = { ...TextInput, ...{ events: [ ["focusout", "onChange", "input"], ], init: function(data) { return this.render("textinput", data); }, } } let ProductsInput = { ...TextInput, ...{ events: [ ["focusout", "onChange", "input"], ], init: function(data) { return this.render("textinput", data); }, } } let GridInput = { ...Input, ...{ events: [ ["change", "onChange", "select" /*'select'*/], ["click", "onChange", "button" /*'select'*/], ], setValue: function(value) { if (this.element[0] && value) { let input = this.element[0].querySelector('select'); if (input) { input.value = value; input.querySelector("option[selected]").selected = true; } } }, init: function(data) { return this.render("grid", data); }, } } let TextValueInput = { ...Input, ...{ events: [ ["focusout", "onChange", "input"], ["click", "onChange", "button" /*'select'*/], ], setValue: function(value) { return false; }, init: function(data) { return this.render("textvalue", data); }, } } let ButtonInput = { ...Input, ...{ events: [ ["click", "onChange", "button" /*'select'*/], ], setValue: function(value) { if (this.element[0] && value) { let input = this.element[0].querySelector('button'); if (input) { input.value = value; } } }, init: function(data) { return this.render("button", data); }, } } let SectionInput = { ...Input, ...{ events: [ //["click", "onChange", "button" /*'select'*/], ], setValue: function(value) { return false; }, init: function(data) { return this.render("sectioninput", data); }, } } let PopOverInput = { ...Input, ...{ events: [ //["click", "onChange", "button" /*'select'*/], ], setValue: function(value) { return false; }, init: function(data) { return this.render("popoverinput", data); }, } } let ListInput = { ...Input, ...{ events: [ ["change", "onChange", "select"], ["click", "remove", ".delete-btn"], ["click", "add", ".btn-new"], ["click", "select", ".section-item"], ], remove: function(event, node, input) { let sectionItem = this.closest(".section-item"); let index = [...sectionItem.parentNode.children].indexOf(sectionItem);//sectionItem.index(); let data = input.data; if (data.removeElement) { let container = input.node; if (data.container) { container.querySelector(data.container); } container.querySelector(data.selector + ":nth-child(" + (index + 1) + ")").remove(); } sectionItem.remove(); event.action = "remove"; event.index = index; input.onChange(event, node, input, this); event.preventDefault(); return false; }, add: function(event, node, input) { let newElement = input.data.newElement ?? false; if (newElement) { let container = input.node; if (data.container) { container.querySelector(data.container); } container.append(generateElements(newElement)[0]); } event.action = "add"; input.onChange(event, node, input, this); return false; }, select: function(event, node, input) { let sectionItem = this.closest(".section-item"); if (sectionItem.parentNode) { let index = [...sectionItem.parentNode.children].indexOf(sectionItem);//sectionItem.index(); event.action = "select"; event.index = index; input.onChange(event, node, input, this); } return false; }, setValue: function(value) { }, init: function(data, node) { this.component = data.component; this.selector = data.selector; this.node = node; let elements = this.node.querySelectorAll(data.container + " " + this.selector); let options = []; elements.forEach(function (e, i) { let element = e; if (data.nameElement) { element = element.querySelector(data.nameElement); } let name = (data.name = "text" ? element.textContent.substr(0, 15) : element.id); options.push({ name: name, type: (data.prefix ?? "") + (i + 1) + (data.suffix ?? ""), }); }); data.options = options; data.elements = elements; this.data = data; let list = this.render("listinput", data); let items = list.querySelectorAll(".section-item"); let i = 0; for (const item of items) { const container = item.querySelector(".tree") ?? item; let properties = {}; if (data.elementProperties) { for (let prop in data.elementProperties) { properties[prop] = Object.assign({}, data.elementProperties[prop]); properties[prop].element = elements[i]; } } Vvveb.Components.renderProperties(null, properties, null, container); i++; } return list; }, } } let AutocompleteInput = { ...Input, ...{ events: [ ["autocomplete.change", "onAutocompleteChange", "input"], ["input", "onAutocompleteChange", "input"], ], onAutocompleteChange: function(event, node, input) { input.value = event.detail.value; return input.onChange.call(this, event, node, input); }, setValue: function(value) { if (this.element && value) { let input = this.element.querySelectorAll('input').forEach(e => e.value = value); } }, init: function(data) { this.element = this.render("textinput", data); let autocomplete = new _AutocompleteInput(this.element.querySelector("input"), data); return this.element; } } } let AutocompleteList = { ...Input, ...{ events: [ ["autocompletelist.change", "onAutocompleteChange", "input"], ], onAutocompleteChange: function(event, node, input) { input.value = event.detail; return input.onChange.call(this, event, node, input); }, setValue: function(value) { if (this.element && value) { let input = this.element.querySelectorAll('input').forEach(e => e.value = value); } }, init: function(data) { this.element = this.render("textinput", data); let autocomplete = new _AutocompleteList(this.element.querySelector("input"), data); return this.element; } } } let TagsInput = { ...Input, ...{ events: [ ["tagsinput.change", "onTagsInputChange", "input"], ], onTagsInputChange: function(event, node, input) { let tags = ""; for (const tag in event.detail[0]) { if (tags) tags += " "; tags += tag; } input.value = tags; return input.onChange.call(this, event, node, input); }, setValue: function(value) { if (this.autocomplete && value) { this.autocomplete.tagsInput.setValue(value.split(" ")); } }, init: function(data) { this.element = this.render("tagsinput", data); this.autocomplete = new _TagsInput(this.element.querySelector("input"), data); return this.element; } } } let NoticeInput = { ...Input, ...{ events: [ ], init: function(data) { return this.render("noticeinput", data); }, } }