@cocreate/elements
Advanced tools
Comparing version 1.38.0 to 1.38.1
{ | ||
"name": "@cocreate/elements", | ||
"version": "1.38.0", | ||
"version": "1.38.1", | ||
"description": "Fetch content into any html element by using html5 attributes to query data stored in CoCreate headless CMS. If data is changed it will instantly reflect in html tags as changes are broadcasted in realtime", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
290
src/form.js
@@ -1,11 +0,10 @@ | ||
import Observer from '@cocreate/observer'; | ||
import { getAttributeNames, ObjectId } from '@cocreate/utils'; | ||
import Action from '@cocreate/actions'; | ||
import elementPrototype from '@cocreate/element-prototype'; | ||
import Observer from "@cocreate/observer"; | ||
import { getAttributeNames, ObjectId } from "@cocreate/utils"; | ||
import Action from "@cocreate/actions"; | ||
import elementPrototype from "@cocreate/element-prototype"; | ||
/** | ||
* Initializes form elements. If no parameter is provided, or null is passed, it queries and initializes all form elements. | ||
* Initializes form elements. If no parameter is provided, or null is passed, it queries and initializes all form elements. | ||
* It can also initialize a single form element or an array of form elements. | ||
* | ||
* | ||
* @param {(Element|Element[]|null)} [elements] - Optional. A single form element, an array of form elements, or null. | ||
@@ -17,173 +16,190 @@ * - If null or omitted, the function queries and initializes all form elements. | ||
function init(elements) { | ||
if (!elements) | ||
elements = document.querySelectorAll('form'); | ||
else if (!Array.isArray(elements)) | ||
elements = [elements] | ||
if (!elements) elements = document.querySelectorAll("form"); | ||
else if (!Array.isArray(elements)) elements = [elements]; | ||
for (let element of elements) { | ||
Observer.init({ | ||
name: 'CoCreateFormElements', | ||
observe: ['addedNodes'], | ||
selector: '[storage], [database], [array], [index], [object], [key]', | ||
callback: function (mutation) { | ||
if (element == mutation.target.form) | ||
setAttribute(element, [mutation.target]) | ||
} | ||
}); | ||
for (let element of elements) { | ||
Observer.init({ | ||
name: "CoCreateFormElements", | ||
observe: ["addedNodes"], | ||
selector: | ||
"[storage], [database], [array], [index], [object], [key]", | ||
callback: function (mutation) { | ||
if (element == mutation.target.form) | ||
setAttribute(element, [mutation.target]); | ||
} | ||
}); | ||
runObjectId(element); | ||
setAttribute(element); | ||
disableAutoFill(element); | ||
setValue(element) | ||
element.addEventListener('submit', function (event) { | ||
if (!element.hasAttribute('action')) { | ||
event.preventDefault(); | ||
} | ||
}); | ||
} | ||
runObjectId(element); | ||
setAttribute(element); | ||
disableAutoFill(element); | ||
setValue(element); | ||
element.addEventListener("submit", function (event) { | ||
if (!element.hasAttribute("action")) { | ||
event.preventDefault(); | ||
} | ||
}); | ||
} | ||
} | ||
/** | ||
* @param form | ||
*/ | ||
* @param form | ||
*/ | ||
function runObjectId(form) { | ||
let elements = Array.from(form.querySelectorAll("[object='ObjectId()']")); | ||
let elements = Array.from(form.querySelectorAll("[object='ObjectId()']")); | ||
if (form.getAttribute('object') === "ObjectId()") { | ||
elements.push(form); | ||
} | ||
for (let i = 0; i < elements.length; i++) { | ||
let array = elements[i].getAttribute('array') | ||
if (!array) | ||
continue | ||
elements[i].setAttribute('object', ObjectId().toString()) | ||
} | ||
if (form.getAttribute("object") === "ObjectId()") { | ||
elements.push(form); | ||
} | ||
for (let i = 0; i < elements.length; i++) { | ||
let array = elements[i].getAttribute("array"); | ||
if (!array) continue; | ||
elements[i].setAttribute("object", ObjectId().toString()); | ||
} | ||
} | ||
/** | ||
* @param form | ||
*/ | ||
* @param form | ||
*/ | ||
function setAttribute(form, elements) { | ||
if (!elements) | ||
elements = form.querySelectorAll('[storage], [database], [array], [index], [object], [key]'); | ||
if (!elements) | ||
elements = form.querySelectorAll( | ||
"[storage], [database], [array], [index], [object], [key]" | ||
); | ||
for (let attribute of form.attributes) { | ||
let variable = window.CoCreateConfig.attributes[attribute.name] | ||
for (let attribute of form.attributes) { | ||
let variable = window.CoCreateConfig.attributes[attribute.name]; | ||
// Set the attribute of all elements in the variable | ||
if (variable) { | ||
for (let el of elements) { | ||
// Set the value of the attribute. | ||
// TODO: skip-attribute naming convention, perhaps skip by defualt if storage, database, array not the same and use attribute to apply for cases where one _id will be used across 2 arrays | ||
if (!el.getAttribute(attribute.name) && !el.hasAttribute('skip-attribute')) { | ||
el.setAttribute(attribute.name, attribute.value); | ||
} | ||
} | ||
} | ||
} | ||
// Set the attribute of all elements in the variable | ||
if (variable) { | ||
for (let el of elements) { | ||
// Set the value of the attribute. | ||
// TODO: skip-attribute naming convention, perhaps skip by defualt if storage, database, array not the same and use attribute to apply for cases where one _id will be used across 2 arrays | ||
if ( | ||
!el.getAttribute(attribute.name) && | ||
!el.hasAttribute("skip-attribute") | ||
) { | ||
el.setAttribute(attribute.name, attribute.value); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* @param element | ||
*/ | ||
* @param element | ||
*/ | ||
function disableAutoFill(element) { | ||
// Clear the text area and set the autocomplete attribute to off. | ||
if (element.tagName == "TEXTAREA") { | ||
element.value = ""; | ||
element.setAttribute("autocomplete", "off"); | ||
} | ||
// Set the autocomplete attribute to off. | ||
if (!element.hasAttribute("autocomplete")) { | ||
element.setAttribute('autocomplete', "off"); | ||
} | ||
// Clear the text area and set the autocomplete attribute to off. | ||
if (element.tagName == "TEXTAREA") { | ||
element.value = ""; | ||
element.setAttribute("autocomplete", "off"); | ||
} | ||
// Set the autocomplete attribute to off. | ||
if (!element.hasAttribute("autocomplete")) { | ||
element.setAttribute("autocomplete", "off"); | ||
} | ||
} | ||
/** | ||
* @param form | ||
*/ | ||
* @param form | ||
*/ | ||
function reset(form) { | ||
// Convert the form elements collection to an array | ||
const formElementsArray = Array.from(form.elements); | ||
// Convert the form elements collection to an array | ||
const formElementsArray = Array.from(form.elements); | ||
// Query for additional elements with [object] or [key] attributes that are not already part of form controls | ||
const customElements = Array.from(form.querySelectorAll('[object], [key]:not(input):not(select):not(textarea):not(button)')); | ||
// Query for additional elements with [object] or [key] attributes that are not already part of form controls | ||
const customElements = Array.from( | ||
form.querySelectorAll( | ||
"[object], [key]:not(input):not(select):not(textarea):not(button)" | ||
) | ||
); | ||
// Merge form elements and custom elements using the spread operator | ||
const allElements = [...formElementsArray, ...customElements]; | ||
// Merge form elements and custom elements using the spread operator | ||
const allElements = [...formElementsArray, ...customElements]; | ||
// Store the elements and their values in a map for restoration | ||
const elementStates = new Map(); | ||
// Store the elements and their values in a map for restoration | ||
const elementStates = new Map(); | ||
// Iterate over all elements and store their current state based on the 'reset' attribute | ||
for (const element of allElements) { | ||
if (['BUTTON', 'FIELDSET'].includes(element.tagName)) | ||
continue | ||
// Get the reset attribute value, if any | ||
const resetType = element.getAttribute('reset'); | ||
if (element.hasAttribute('object') && (!resetType || resetType === 'object')) | ||
element.setAttribute('object', ''); | ||
if (resetType === 'false' || resetType === 'object') | ||
elementStates.set(element, element.getValue() || element.value || element.getAttribute('value')); | ||
if (!resetType || resetType !== 'object') | ||
element.setValue('') | ||
} | ||
// Iterate over all elements and store their current state based on the 'reset' attribute | ||
for (const element of allElements) { | ||
if (["BUTTON", "FIELDSET"].includes(element.tagName)) continue; | ||
// Get the reset attribute value, if any | ||
const resetType = element.getAttribute("reset"); | ||
if ( | ||
element.hasAttribute("object") && | ||
(!resetType || resetType === "object") | ||
) | ||
element.setAttribute("object", ""); | ||
if (resetType === "false" || resetType === "object") | ||
elementStates.set( | ||
element, | ||
element.getValue() || | ||
element.value || | ||
element.getAttribute("value") | ||
); | ||
if (!resetType || resetType === "value") element.setValue(""); | ||
} | ||
if (form.hasAttribute('object')) | ||
form.setAttribute('object', ''); | ||
if (form.hasAttribute("object")) form.setAttribute("object", ""); | ||
// Perform the default form reset | ||
form.reset(); | ||
// Perform the default form reset | ||
form.reset(); | ||
// Restore values based on the 'reset' attribute | ||
elementStates.forEach((value, element) => { | ||
element.setValue(value) | ||
}); | ||
// Restore values based on the 'reset' attribute | ||
elementStates.forEach((value, element) => { | ||
element.setValue(value); | ||
}); | ||
// Dispatch a custom reset event | ||
document.dispatchEvent(new CustomEvent('reset', { | ||
detail: {} | ||
})); | ||
// Dispatch a custom reset event | ||
document.dispatchEvent( | ||
new CustomEvent("reset", { | ||
detail: {} | ||
}) | ||
); | ||
} | ||
function setValue(form) { | ||
form.setValue = (value) => { | ||
if (typeof value !== "object") | ||
elementPrototype.setValue(form, value); | ||
else { | ||
const inputs = form.querySelectorAll('[name], [key]'); | ||
inputs.forEach(element => { | ||
const key = element.getAttribute('key') || element.getAttribute('name'); | ||
if (value[key]) { | ||
element.setValue(value[key]); | ||
} | ||
}); | ||
} | ||
} | ||
form.setValue = (value) => { | ||
if (typeof value !== "object") elementPrototype.setValue(form, value); | ||
else { | ||
const inputs = form.querySelectorAll("[name], [key]"); | ||
inputs.forEach((element) => { | ||
const key = | ||
element.getAttribute("key") || element.getAttribute("name"); | ||
if (value[key]) { | ||
element.setValue(value[key]); | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
Observer.init({ | ||
name: 'CoCreateForm', | ||
observe: ['addedNodes'], | ||
selector: 'form', | ||
callback: mutation => init(mutation.target) | ||
name: "CoCreateForm", | ||
observe: ["addedNodes"], | ||
selector: "form", | ||
callback: (mutation) => init(mutation.target) | ||
}); | ||
Observer.init({ | ||
name: 'CoCreateForm', | ||
observe: ['attributes'], | ||
attributeName: getAttributeNames(['storage', 'database', 'array', 'object', 'index']), | ||
selector: 'form', | ||
callback: mutation => mutation.target.tagName === "FORM" && | ||
setAttribute(mutation.target) | ||
name: "CoCreateForm", | ||
observe: ["attributes"], | ||
attributeName: getAttributeNames([ | ||
"storage", | ||
"database", | ||
"array", | ||
"object", | ||
"index" | ||
]), | ||
selector: "form", | ||
callback: (mutation) => | ||
mutation.target.tagName === "FORM" && setAttribute(mutation.target) | ||
}); | ||
Action.init({ | ||
name: "reset", | ||
endEvent: "reset", | ||
callback: (action) => { | ||
if (action.form) | ||
reset(action.form); | ||
} | ||
name: "reset", | ||
endEvent: "reset", | ||
callback: (action) => { | ||
if (action.form) reset(action.form); | ||
} | ||
}); | ||
@@ -190,0 +206,0 @@ |
2411
src/index.js
@@ -25,11 +25,19 @@ /******************************************************************************** | ||
import Observer from '@cocreate/observer'; | ||
import Actions from '@cocreate/actions'; | ||
import CRUD from '@cocreate/crud-client'; | ||
import { dotNotationToObject, queryElements, queryData, sortData, getAttributes, getAttributeNames, checkValue } from '@cocreate/utils'; | ||
import filter from '@cocreate/filter'; | ||
import { render, renderValue, renderedNodes } from '@cocreate/render'; | ||
import '@cocreate/element-prototype'; | ||
import './fetchSrc'; | ||
import { reset } from './form' | ||
import Observer from "@cocreate/observer"; | ||
import Actions from "@cocreate/actions"; | ||
import CRUD from "@cocreate/crud-client"; | ||
import { | ||
dotNotationToObject, | ||
queryElements, | ||
queryData, | ||
sortData, | ||
getAttributes, | ||
getAttributeNames, | ||
checkValue | ||
} from "@cocreate/utils"; | ||
import filter from "@cocreate/filter"; | ||
import { render, renderValue, renderedNodes } from "@cocreate/render"; | ||
import "@cocreate/element-prototype"; | ||
import "./fetchSrc"; | ||
import { reset } from "./form"; | ||
@@ -43,5 +51,5 @@ const selector = "[storage], [database], [array], [render-json]"; | ||
/** | ||
* Initializes elements with specific CRUD attributes. If no parameter is provided, it queries and initializes all elements | ||
* Initializes elements with specific CRUD attributes. If no parameter is provided, it queries and initializes all elements | ||
* that have certain CRUD-related attributes. It can also initialize a single element or an array of elements. | ||
* | ||
* | ||
* Attributes used for initialization are: | ||
@@ -52,1375 +60,1451 @@ * - storage: Specifies the storage mechanism. | ||
* - render-json: Determines how JSON data is rendered. | ||
* | ||
* @param {(Element|Element[])} [elements] - Optional. A single element or an array of elements to initialize. | ||
* If omitted, the function queries and initializes all elements containing | ||
* | ||
* @param {(Element|Element[])} [elements] - Optional. A single element or an array of elements to initialize. | ||
* If omitted, the function queries and initializes all elements containing | ||
* any of these CRUD attributes: "storage", "database", "array", "render-json". | ||
*/ | ||
async function init(element) { | ||
if (element && !(element instanceof HTMLCollection) && !(element instanceof NodeList) && !Array.isArray(element)) | ||
element = [element] | ||
else if (!element) { | ||
element = document.querySelectorAll(selector) | ||
initSocket(); | ||
} | ||
if ( | ||
element && | ||
!(element instanceof HTMLCollection) && | ||
!(element instanceof NodeList) && | ||
!Array.isArray(element) | ||
) | ||
element = [element]; | ||
else if (!element) { | ||
element = document.querySelectorAll(selector); | ||
initSocket(); | ||
} | ||
let dataObjects = new Map(); | ||
for (let i = 0; i < element.length; i++) { | ||
if (elements.has(element[i]) || element[i].tagName === 'FORM' || element[i].getAttribute('crud') === 'false') | ||
continue | ||
let dataObjects = new Map(); | ||
for (let i = 0; i < element.length; i++) { | ||
if ( | ||
elements.has(element[i]) || | ||
element[i].tagName === "FORM" || | ||
element[i].getAttribute("crud") === "false" | ||
) | ||
continue; | ||
let data = await initElement(element[i]); | ||
if (data) { | ||
let dataKey = initDataKey(element[i], data) | ||
dataObjects.set(dataKey.string, data) | ||
} | ||
} | ||
let data = await initElement(element[i]); | ||
if (data) { | ||
let dataKey = initDataKey(element[i], data); | ||
dataObjects.set(dataKey.string, data); | ||
} | ||
} | ||
if (dataObjects && dataObjects.size > 0) { | ||
for (let key of dataObjects.keys()) { | ||
let { data, elements } = keys.get(key) | ||
read(Array.from(elements.keys()), data, { string: key }); | ||
} | ||
} | ||
if (dataObjects && dataObjects.size > 0) { | ||
for (let key of dataObjects.keys()) { | ||
let { data, elements } = keys.get(key); | ||
read(Array.from(elements.keys()), data, { string: key }); | ||
} | ||
} | ||
// const evt = new CustomEvent('elementsInitialized', { bubbles: true }); | ||
// document.dispatchEvent(evt); | ||
// const evt = new CustomEvent('elementsInitialized', { bubbles: true }); | ||
// document.dispatchEvent(evt); | ||
} | ||
async function initElement(el) { | ||
let data = getObject(el); | ||
if (!data || !data.type) | ||
return | ||
let data = getObject(el); | ||
if (!data || !data.type) return; | ||
if (data.object && data.object !== 'pending' && !(/^[0-9a-fA-F]{24}$/.test(data.object))) | ||
return | ||
if ( | ||
data.object && | ||
data.object !== "pending" && | ||
!/^[0-9a-fA-F]{24}$/.test(data.object) | ||
) | ||
return; | ||
if (!elements.has(el)) { | ||
elements.set(el, '') | ||
if (!elements.has(el)) { | ||
elements.set(el, ""); | ||
if (!el.elementsInputEvent) { | ||
el.elementsInputEvent = true; | ||
if (!el.elementsInputEvent) { | ||
el.elementsInputEvent = true; | ||
if (['INPUT', 'TEXTAREA', 'SELECT'].includes(el.tagName) | ||
|| (el.hasAttribute('contenteditable') && el.getAttribute('contenteditable') !== 'false') | ||
|| el.contenteditable) { | ||
if ( | ||
["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName) || | ||
(el.hasAttribute("contenteditable") && | ||
el.getAttribute("contenteditable") !== "false") || | ||
el.contenteditable | ||
) { | ||
if (el.tagName == "IFRAME") { | ||
// ToDo: saving on contenteditable elements when an objectId does not exist in order to crud or crdt | ||
el = el.contentDocument.documentElement; | ||
el.setAttribute("contenteditable", "true"); | ||
} | ||
if (el.tagName == 'IFRAME') { | ||
// ToDo: saving on contenteditable elements when an objectId does not exist in order to crud or crdt | ||
el = el.contentDocument.documentElement | ||
el.setAttribute('contenteditable', 'true') | ||
el.addEventListener("input", function (e) { | ||
if (el.pendingObject) return; | ||
} | ||
const { object, key, isRealtime, isCrdt } = | ||
getAttributes(el); | ||
if (!isRealtime || isRealtime === "false" || key === "_id") | ||
return; | ||
if (isCrdt == "true" && object && object !== "pending") | ||
return; | ||
if (e.detail && e.detail.skip == true) return; | ||
if (data.type !== "object" && data[data.type] === "pending") | ||
return; | ||
el.addEventListener('input', function (e) { | ||
if (el.pendingObject) return | ||
save(el); | ||
}); | ||
} | ||
} | ||
} | ||
// let attributes = ['filter-key', 'filter-search', 'filter-sort-key', 'filter-on', 'filter-limit'] | ||
// if (el.getFilter || attributes.some(attr => el.hasAttribute(attr))) { | ||
const { object, key, isRealtime, isCrdt } = getAttributes(el); | ||
if (!isRealtime || isRealtime === "false" || key === "_id") return; | ||
if (isCrdt == "true" && object && object !== 'pending') return | ||
if (e.detail && e.detail.skip == true) return; | ||
if (data.type !== 'object' && data[data.type] === 'pending') return | ||
await filter.init(); | ||
if (el.getFilter) { | ||
data.$filter = await el.getFilter(); | ||
save(el); | ||
}); | ||
} | ||
} | ||
} | ||
// let attributes = ['filter-key', 'filter-search', 'filter-sort-key', 'filter-on', 'filter-limit'] | ||
// if (el.getFilter || attributes.some(attr => el.hasAttribute(attr))) { | ||
el.setFilter = (filter) => { | ||
data.$filter = filter; | ||
el.hasRead = false; | ||
// let dataKey = initDataKey(el, data) | ||
read(el, data); | ||
}; | ||
} | ||
await filter.init() | ||
if (el.getFilter) { | ||
data.$filter = await el.getFilter(); | ||
el.setFilter = (filter) => { | ||
data.$filter = filter | ||
el.hasRead = false | ||
// let dataKey = initDataKey(el, data) | ||
read(el, data) | ||
} | ||
} | ||
return data; | ||
return data; | ||
} | ||
function getObject(element) { | ||
const data = getAttributes(element); | ||
const crudType = ['storage', 'database', 'array', 'index', 'object'] | ||
const data = getAttributes(element); | ||
const crudType = ["storage", "database", "array", "index", "object"]; | ||
for (let i = 0; i < crudType.length; i++) { | ||
if (!checkValue(data[crudType[i]])) | ||
return | ||
for (let i = 0; i < crudType.length; i++) { | ||
if (!checkValue(data[crudType[i]])) return; | ||
if (data[crudType[i]] && data[crudType[i]].includes(",")) { | ||
const array = data[crudType[i]].split(','); | ||
data[crudType[i]] = [] | ||
if (data[crudType[i]] && data[crudType[i]].includes(",")) { | ||
const array = data[crudType[i]].split(","); | ||
data[crudType[i]] = []; | ||
for (let j = 0; j < array.length; j++) { | ||
array[j].trim() | ||
if (crudType[i] === 'object') { | ||
data[crudType[i]].push({ _id: array[j] }) | ||
} else { | ||
data[crudType[i]].push(array[j]) | ||
} | ||
} | ||
} | ||
} | ||
for (let j = 0; j < array.length; j++) { | ||
array[j].trim(); | ||
if (crudType[i] === "object") { | ||
data[crudType[i]].push({ _id: array[j] }); | ||
} else { | ||
data[crudType[i]].push(array[j]); | ||
} | ||
} | ||
} | ||
} | ||
if (data.object || data.object === '' || data.key || data.key === '') { | ||
if (!data.array || data.array && !data.array.length) return | ||
data.type = 'object' | ||
} else if (data.index || data.index === '') { | ||
if (!data.array || data.array && !data.array.length) return | ||
data.type = 'index' | ||
} else if (data.array || data.array === '') | ||
data.type = 'array' | ||
else if (data.database || data.database === '') | ||
data.type = 'database' | ||
else if (data.storage || data.storage === '') | ||
data.type = 'storage' | ||
else if (data.data) | ||
data.type = 'data' | ||
if (data.object || data.object === "" || data.key || data.key === "") { | ||
if (!data.array || (data.array && !data.array.length)) return; | ||
data.type = "object"; | ||
} else if (data.index || data.index === "") { | ||
if (!data.array || (data.array && !data.array.length)) return; | ||
data.type = "index"; | ||
} else if (data.array || data.array === "") data.type = "array"; | ||
else if (data.database || data.database === "") data.type = "database"; | ||
else if (data.storage || data.storage === "") data.type = "storage"; | ||
else if (data.data) data.type = "data"; | ||
delete data.isRealtime | ||
return data | ||
delete data.isRealtime; | ||
return data; | ||
} | ||
function initDataKey(element, data) { | ||
let dataKey = getDataKey(data) | ||
if (keys.has(dataKey.string)) | ||
keys.get(dataKey.string).elements.set(element, '') | ||
else | ||
keys.set(dataKey.string, { elements: new Map([[element, '']]), data, dataKey }); | ||
let dataKey = getDataKey(data); | ||
if (keys.has(dataKey.string)) | ||
keys.get(dataKey.string).elements.set(element, ""); | ||
else | ||
keys.set(dataKey.string, { | ||
elements: new Map([[element, ""]]), | ||
data, | ||
dataKey | ||
}); | ||
elements.set(element, dataKey.string) | ||
elements.set(element, dataKey.string); | ||
if (element.parentElement) { | ||
let form = element.parentElement.closest('form') | ||
if (form) { | ||
if (!form.save) | ||
form.save = () => save(form) | ||
if (element.parentElement) { | ||
let form = element.parentElement.closest("form"); | ||
if (form) { | ||
if (!form.save) form.save = () => save(form); | ||
if (!form.getData) | ||
form.getData = () => getData(form) | ||
if (!form.getData) form.getData = () => getData(form); | ||
let formObject = forms.get(form) | ||
if (formObject) { | ||
formObject.elements.set(element, data) | ||
if (formObject.types.has(data.type)) | ||
formObject.types.get(data.type).set(element, data) | ||
else | ||
formObject.types.set(data.type, new Map([[element, data]])); | ||
} else | ||
forms.set(form, { elements: new Map([[element, data]]), types: new Map([[data.type, new Map([[element, data]])]]) }); | ||
} | ||
} | ||
let formObject = forms.get(form); | ||
if (formObject) { | ||
formObject.elements.set(element, data); | ||
if (formObject.types.has(data.type)) | ||
formObject.types.get(data.type).set(element, data); | ||
else | ||
formObject.types.set(data.type, new Map([[element, data]])); | ||
} else | ||
forms.set(form, { | ||
elements: new Map([[element, data]]), | ||
types: new Map([[data.type, new Map([[element, data]])]]) | ||
}); | ||
} | ||
} | ||
if (!element.read) | ||
element.read = () => read(element) | ||
if (!element.save) | ||
element.save = () => save(element) | ||
if (!element.read) element.read = () => read(element); | ||
if (!element.save) element.save = () => save(element); | ||
return dataKey | ||
return dataKey; | ||
} | ||
async function read(element, data, dataKey) { | ||
if (!dataKey) | ||
dataKey = { string: elements.get(element) } | ||
if (!data) { | ||
let existingData = keys.get(dataKey.string) | ||
if (existingData && existingData.dataKey && existingData.dataKey.object) | ||
data = { ...existingData.dataKey.object } | ||
} | ||
if (!dataKey) dataKey = { string: elements.get(element) }; | ||
if (!data) { | ||
let existingData = keys.get(dataKey.string); | ||
if (existingData && existingData.dataKey && existingData.dataKey.object) | ||
data = { ...existingData.dataKey.object }; | ||
} | ||
if (!dataKey || !data.type) | ||
return | ||
if (!data.$filter && (!data[data.type] || !data[data.type].length)) | ||
return | ||
if (!dataKey || !data.type) return; | ||
if (!data.$filter && (!data[data.type] || !data[data.type].length)) return; | ||
if (!(element instanceof HTMLCollection) && !Array.isArray(element)) | ||
element = [element] | ||
if (!(element instanceof HTMLCollection) && !Array.isArray(element)) | ||
element = [element]; | ||
let delay = debounce.get(dataKey.string) | ||
if (!delay) | ||
debounce.set(dataKey.string, delay = {}) | ||
let delay = debounce.get(dataKey.string); | ||
if (!delay) debounce.set(dataKey.string, (delay = {})); | ||
if (!delay.elements) | ||
delay.elements = new Map() | ||
if (!delay.elements) delay.elements = new Map(); | ||
for (let el of element) { | ||
const isRead = el.getAttribute('read'); | ||
if (isRead !== 'false' && !el.hasRead && (!data.$filter || data.$filter && data.$filter.isFilter !== false)) { | ||
el.hasRead = true | ||
delay.elements.set(el, true) | ||
} else { | ||
// console.log('read skipped', el) | ||
} | ||
} | ||
for (let el of element) { | ||
const isRead = el.getAttribute("read"); | ||
if ( | ||
isRead !== "false" && | ||
!el.hasRead && | ||
(!data.$filter || (data.$filter && data.$filter.isFilter !== false)) | ||
) { | ||
el.hasRead = true; | ||
delay.elements.set(el, true); | ||
} else { | ||
// console.log('read skipped', el) | ||
} | ||
} | ||
if (!delay.elements.size) | ||
return | ||
if (!delay.elements.size) return; | ||
clearTimeout(delay.timer); | ||
delay.timer = setTimeout(function () { | ||
// TODO: should server support string and string array for type object, methods create, read, delete | ||
if (!data.$filter && data.type === 'object') { | ||
if (!data.object) | ||
return | ||
else if (typeof data.object === 'string') | ||
data.object = { _id: data.object } | ||
else if (Array.isArray(data.object)) { | ||
if (data.object.length) | ||
data.object = { _id: data.object[0]._id } | ||
} else if (!data.object._id.match(/^[0-9a-fA-F]{24}$/)) | ||
return | ||
// if (data.object._id.startsWith('$')) | ||
// return | ||
} | ||
clearTimeout(delay.timer); | ||
delay.timer = setTimeout(function () { | ||
// TODO: should server support string and string array for type object, methods create, read, delete | ||
if (!data.$filter && data.type === "object") { | ||
if (!data.object) return; | ||
else if (typeof data.object === "string") | ||
data.object = { _id: data.object }; | ||
else if (Array.isArray(data.object)) { | ||
if (data.object.length) | ||
data.object = { _id: data.object[0]._id }; | ||
} else if (!data.object._id.match(/^[0-9a-fA-F]{24}$/)) return; | ||
// if (data.object._id.startsWith('$')) | ||
// return | ||
} | ||
// if (data.object && !Array.isArray(data.object) && data.object._id.startsWith('$')) | ||
// return | ||
// if (data.object && !Array.isArray(data.object) && data.object._id.startsWith('$')) | ||
// return | ||
// if (data.$filter && data.$filter.query) { | ||
// if (!Object.keys(data.$filter.query).length) | ||
// return | ||
// } | ||
// if (data.$filter && data.$filter.query) { | ||
// if (!Object.keys(data.$filter.query).length) | ||
// return | ||
// } | ||
data.method = data.type + '.read' | ||
data.method = data.type + ".read"; | ||
CRUD.send(data).then((Data) => { | ||
debounce.delete(dataKey.string) | ||
let els = Array.from(delay.elements.keys()) | ||
clearTimeout(delay.timer); | ||
delete delay.elements | ||
delete delay.timer | ||
CRUD.send(data).then((Data) => { | ||
debounce.delete(dataKey.string); | ||
let els = Array.from(delay.elements.keys()); | ||
clearTimeout(delay.timer); | ||
delete delay.elements; | ||
delete delay.timer; | ||
setData(els, Data); | ||
}) | ||
}, 500); | ||
setData(els, Data); | ||
}); | ||
}, 500); | ||
} | ||
function get$in(query, mergedValues = []) { | ||
for (let key of Object.keys(query)) { | ||
if (key === '$and' || key === '$or' || key === '$nor') { | ||
for (let i = 0; i < query[key].length; i++) { | ||
sort$in(query[key][i], mergedValues) | ||
} | ||
} else if (typeof query[key] === 'object' && !Array.isArray(query[key])) { | ||
if (query[key].$in) | ||
mergedValues = [...mergedValues, ...query[key].$in]; | ||
} | ||
} | ||
return mergedValues | ||
for (let key of Object.keys(query)) { | ||
if (key === "$and" || key === "$or" || key === "$nor") { | ||
for (let i = 0; i < query[key].length; i++) { | ||
sort$in(query[key][i], mergedValues); | ||
} | ||
} else if ( | ||
typeof query[key] === "object" && | ||
!Array.isArray(query[key]) | ||
) { | ||
if (query[key].$in) | ||
mergedValues = [...mergedValues, ...query[key].$in]; | ||
} | ||
} | ||
return mergedValues; | ||
} | ||
function sort$in(data, query) { | ||
let mergedValues = get$in(query); | ||
let mergedValues = get$in(query); | ||
if (mergedValues.length) { | ||
const sorted = mergedValues | ||
.map(name => data.find(career => career.name === name)) | ||
.filter(career => career !== undefined); | ||
return sorted | ||
} | ||
if (mergedValues.length) { | ||
const sorted = mergedValues | ||
.map((name) => data.find((career) => career.name === name)) | ||
.filter((career) => career !== undefined); | ||
return sorted; | ||
} | ||
} | ||
async function setData(element, data) { | ||
if (!element) { | ||
element = getDataElements(data) | ||
if (!element.length) return | ||
} | ||
if (!(element instanceof HTMLCollection) && !Array.isArray(element)) | ||
element = [element] | ||
if (!element) { | ||
element = getDataElements(data); | ||
if (!element.length) return; | ||
} | ||
if (!(element instanceof HTMLCollection) && !Array.isArray(element)) | ||
element = [element]; | ||
let type = data.type | ||
if (!type && data.method) { | ||
type = data.method.split('.')[0] | ||
} else if (type == 'key') | ||
type = 'object' | ||
let type = data.type; | ||
if (!type && data.method) { | ||
type = data.method.split(".")[0]; | ||
} else if (type == "key") type = "object"; | ||
if (data.$filter && data.$filter.query) { | ||
let sortedData = sort$in(data[type], data.$filter.query) | ||
if (sortedData && sortedData.length) | ||
data[type] = sortedData | ||
} | ||
if (data.$filter && data.$filter.query) { | ||
let sortedData = sort$in(data[type], data.$filter.query); | ||
if (sortedData && sortedData.length) data[type] = sortedData; | ||
} | ||
for (let el of element) { | ||
// if rendered in server side skip | ||
if (el.hasAttribute('rendered')) | ||
return el.removeAttribute('rendered'); | ||
if (el.hasAttribute('render-json')) { | ||
// TODO find the json template in the text or attributes | ||
// if found add the node as an element, if the element has crud attributes also add as the element | ||
// for (let attribute of el.attributes) { | ||
// if (attribute.value.match(/{{(.*?)}}/)) { | ||
// let value = await renderValue(attribute, data[type][0], attribute.value) | ||
// if (value) | ||
// attribute.value = value | ||
// } | ||
// } | ||
// if (el.innerHTML.match(/{{(.*?)}}/)) { | ||
// let value = renderValue(el, data[type], el.innerHTML) | ||
// if (value) | ||
// el.innerHTML = value | ||
// } | ||
for (let el of element) { | ||
// if rendered in server side skip | ||
if (el.hasAttribute("rendered")) return el.removeAttribute("rendered"); | ||
if (el.hasAttribute("render-json")) { | ||
// TODO find the json template in the text or attributes | ||
// if found add the node as an element, if the element has crud attributes also add as the element | ||
// for (let attribute of el.attributes) { | ||
// if (attribute.value.match(/{{(.*?)}}/)) { | ||
// let value = await renderValue(attribute, data[type][0], attribute.value) | ||
// if (value) | ||
// attribute.value = value | ||
// } | ||
// } | ||
// if (el.innerHTML.match(/{{(.*?)}}/)) { | ||
// let value = renderValue(el, data[type], el.innerHTML) | ||
// if (value) | ||
// el.innerHTML = value | ||
// } | ||
// if (el.textContent.match(/{{(.*?)}}/)) { | ||
// let value = renderValue(el, undefined, el.textContent) | ||
// if (value) | ||
// attribute.value = value | ||
// } | ||
// if (el.textContent.match(/{{(.*?)}}/)) { | ||
// let value = renderValue(el, undefined, el.textContent) | ||
// if (value) | ||
// attribute.value = value | ||
// } | ||
// let Data = JSON.parse(match[1]); | ||
// Data.method = object.read | ||
// CRUD.send(Data) | ||
console.log('render-json', '') | ||
// let Data = JSON.parse(match[1]); | ||
// Data.method = object.read | ||
// CRUD.send(Data) | ||
console.log("render-json", ""); | ||
} | ||
} | ||
let action = el.getAttribute("actions"); | ||
if (action && ["database", "array", "object", "key"].includes(action)) | ||
continue; | ||
let action = el.getAttribute('actions') | ||
if (action && ['database', 'array', 'object', 'key'].includes(action)) continue; | ||
const { key, isRead, isUpdate, isListen, isCrdt } = getAttributes(el); | ||
if (el.getFilter || el.renderValue) | ||
await filterData(el, data, type, key); | ||
else { | ||
if (!data[type] || !data[type].length) continue; | ||
const { key, isRead, isUpdate, isListen, isCrdt } = getAttributes(el); | ||
if (el.getFilter || el.renderValue) | ||
await filterData(el, data, type, key) | ||
else { | ||
if (!data[type] || !data[type].length) | ||
continue; | ||
if (key && checkValue(key)) { | ||
let value; | ||
if (key.includes("$length")) { | ||
value = CRUD.getValueFromObject( | ||
data[type][0], | ||
key.replace(/\.\$length$/, "") | ||
); | ||
if (value) value = value.length; | ||
else value = 0; | ||
} else { | ||
let $update = data[type][0].$update; | ||
if ($update) { | ||
delete data[type][0].$update; | ||
data[type][0] = { ...data[type][0], ...$update }; | ||
} | ||
value = CRUD.getValueFromObject(data[type][0], key); | ||
} | ||
if (key && checkValue(key)) { | ||
let value | ||
if (key.includes('$length')) { | ||
value = CRUD.getValueFromObject(data[type][0], key.replace(/\.\$length$/, '')) | ||
if (value) | ||
value = value.length | ||
else | ||
value = 0 | ||
} else { | ||
let $update = data[type][0].$update | ||
if ($update) { | ||
delete data[type][0].$update | ||
data[type][0] = { ...data[type][0], ...$update } | ||
} | ||
value = CRUD.getValueFromObject(data[type][0], key) | ||
} | ||
if (!data[type].length) continue; | ||
if (isRead === "false" || isCrdt === "true") continue; | ||
if (isUpdate === "false" || isListen === "false" && !data.method.endsWith('.read')) continue; | ||
// TODO: object.update data returned from server will not include $operator | ||
el.setValue(value); | ||
} | ||
} | ||
} | ||
if (!data[type].length) continue; | ||
if (isRead === "false" || isCrdt === "true") continue; | ||
if ( | ||
isUpdate === "false" || | ||
(isListen === "false" && !data.method.endsWith(".read")) | ||
) | ||
continue; | ||
// TODO: object.update data returned from server will not include $operator | ||
el.setValue(value); | ||
} | ||
} | ||
} | ||
} | ||
async function filterData(element, data, type, key) { | ||
let operator = '', value | ||
let operator = "", | ||
value; | ||
if (key && !key.includes('$length') && key !== '{}') { | ||
if (!data || !type) return | ||
if (key && !key.includes("$length") && key !== "{}") { | ||
if (!data || !type) return; | ||
if (key.startsWith('$')) { | ||
operator = key.split('.')[0] || '' | ||
} | ||
if (key.startsWith("$")) { | ||
operator = key.split(".")[0] || ""; | ||
} | ||
let property = key.replace(operator + '.', '') | ||
let property = key.replace(operator + ".", ""); | ||
if (Array.isArray(data[type])) { | ||
let Data = [], isObject | ||
for (let doc of data[type]) { | ||
if (!doc.$storage) | ||
continue | ||
// TODO: should have been handled by getDataElements() | ||
if (type === 'object') { | ||
let _id = element.getAttribute('object') | ||
if (_id && doc._id !== _id) | ||
continue | ||
let $update = doc.$update | ||
if ($update) { | ||
delete doc.$update | ||
doc = { ...doc, ...$update } | ||
} | ||
if (Array.isArray(data[type])) { | ||
let Data = [], | ||
isObject; | ||
for (let doc of data[type]) { | ||
if (!doc.$storage) continue; | ||
// TODO: should have been handled by getDataElements() | ||
if (type === "object") { | ||
let _id = element.getAttribute("object"); | ||
if (_id && doc._id !== _id) continue; | ||
let $update = doc.$update; | ||
if ($update) { | ||
delete doc.$update; | ||
doc = { ...doc, ...$update }; | ||
} | ||
} | ||
if (doc[property]) { | ||
if (Array.isArray(doc[property])) | ||
Data.push(...doc[property]); | ||
else { | ||
isObject = true; | ||
Data.push(doc[property]); | ||
} | ||
} else continue; | ||
} | ||
} | ||
if (doc[property]) { | ||
if (Array.isArray(doc[property])) | ||
Data.push(...doc[property]) | ||
else { | ||
isObject = true | ||
Data.push(doc[property]) | ||
} | ||
} else | ||
continue | ||
} | ||
// if (isObject && Data.length === 1) { | ||
// data = { [property]: Data[0] } | ||
// } else | ||
if (!operator) data = Data; | ||
else if (operator === "$sum") { | ||
value = Data.reduce((accumulator, currentValue) => { | ||
return accumulator + currentValue; | ||
}, 0); | ||
} | ||
} else { | ||
data = { [property]: data[type][property] }; | ||
} | ||
} | ||
// if (isObject && Data.length === 1) { | ||
// data = { [property]: Data[0] } | ||
// } else | ||
if (!operator) | ||
data = Data | ||
else if (operator === '$sum') { | ||
value = Data.reduce((accumulator, currentValue) => { | ||
return accumulator + currentValue; | ||
}, 0); | ||
} | ||
} else { | ||
data = { [property]: data[type][property] } | ||
} | ||
} | ||
let isRendered = element.querySelector("[render-clone]"); | ||
if (operator) { | ||
element.setValue(value); | ||
} else if ( | ||
element.renderValue && | ||
data.method && | ||
data.method.endsWith(".read") && | ||
data.$filter && | ||
(data.$filter.overwrite || !isRendered) | ||
) { | ||
await element.renderValue(data); | ||
} else if ( | ||
(data.$filter && data.$filter.loadmore) || | ||
(data.method && data.method.endsWith(".read") && isRendered) | ||
) { | ||
await loadMore(element, data, type); | ||
} else if ( | ||
element.getFilter && | ||
data.method && | ||
!data.method.endsWith(".read") | ||
) { | ||
await checkFilters(element, data, type); | ||
} else if (element.renderValue) { | ||
await element.renderValue(data); | ||
} else if (key === "$length") { | ||
element.setValue(data[type].length); | ||
} else if (key && key.includes("$length")) { | ||
let value = CRUD.getValueFromObject( | ||
data[type][0], | ||
key.replace(/\.\$length$/, "") | ||
); | ||
element.setValue(value.length); | ||
} else if (key === "{}") { | ||
element.setValue(data[type]); | ||
} else if (data) element.setValue(data); | ||
let isRendered = element.querySelector('[render-clone]'); | ||
if (operator) { | ||
element.setValue(value); | ||
} else if (element.renderValue && data.method && data.method.endsWith('.read') && data.$filter && (data.$filter.overwrite || !isRendered)) { | ||
await element.renderValue(data); | ||
} else if (data.$filter && data.$filter.loadmore || data.method && data.method.endsWith('.read') && isRendered) { | ||
await loadMore(element, data, type) | ||
} else if (element.getFilter && data.method && !data.method.endsWith('.read')) { | ||
await checkFilters(element, data, type) | ||
} else if (element.renderValue) { | ||
await element.renderValue(data); | ||
} else if (key === '$length') { | ||
element.setValue(data[type].length); | ||
} else if (key && key.includes('$length')) { | ||
let value = CRUD.getValueFromObject(data[type][0], key.replace(/\.\$length$/, '')) | ||
element.setValue(value.length); | ||
} else if (key === '{}') { | ||
element.setValue(data[type]) | ||
} else if (data) | ||
element.setValue(data) | ||
if (data.$filter) { | ||
let filterElement = filter.filters.get(element); | ||
if (filterElement) filterElement.index = data.$filter.index; | ||
} | ||
if (data.$filter) { | ||
let filterElement = filter.filters.get(element) | ||
if (filterElement) | ||
filterElement.index = data.$filter.index | ||
} | ||
if (!data[type] || !Array.isArray(data[type]) || !data[type].length) return; | ||
if (!data[type] || !Array.isArray(data[type]) || !data[type].length) | ||
return | ||
const evt = new CustomEvent('fetchedData', { bubbles: true }); | ||
element.dispatchEvent(evt); | ||
const evt = new CustomEvent("fetchedData", { bubbles: true }); | ||
element.dispatchEvent(evt); | ||
} | ||
async function loadMore(element, data, type, sort) { | ||
let Data = { ...data }; | ||
let renderedData = await element.getData(); | ||
if (!renderedData || !renderedData[type]) { | ||
return; | ||
} | ||
for (let i = 0; i < Data[type].length; i++) { | ||
let index; | ||
if (type === 'object') { | ||
index = renderedData[type].findIndex(obj => obj._id === Data[type][i]._id); | ||
} else { | ||
index = renderedData[type].findIndex(obj => obj.name === Data[type][i].name); | ||
} | ||
let Data = { ...data }; | ||
let renderedData = await element.getData(); | ||
if (!renderedData || !renderedData[type]) { | ||
return; | ||
} | ||
for (let i = 0; i < Data[type].length; i++) { | ||
let index; | ||
if (type === "object") { | ||
index = renderedData[type].findIndex( | ||
(obj) => obj._id === Data[type][i]._id | ||
); | ||
} else { | ||
index = renderedData[type].findIndex( | ||
(obj) => obj.name === Data[type][i].name | ||
); | ||
} | ||
if (index >= 0) { | ||
Data[type].splice(i, 1); | ||
i--; // Adjust the index to account for the removed item | ||
} | ||
} | ||
if (Data[type].length > 0) { | ||
await element.renderValue(Data); | ||
} | ||
if (index >= 0) { | ||
Data[type].splice(i, 1); | ||
i--; // Adjust the index to account for the removed item | ||
} | ||
} | ||
if (Data[type].length > 0) { | ||
await element.renderValue(Data); | ||
} | ||
} | ||
async function checkFilters(element, data, type) { | ||
let Data | ||
if (!element.getData) { | ||
// TODO: fix: getObject as this is related to render or form, but filter could exist on an input which does not have getObject | ||
// TODO: generate an object of current element key: value to use with filter. because filter is used object is not defined | ||
Data = getObject(element) | ||
if (Array.isArray(Data[type])) | ||
Data = Data[type][0] | ||
} else | ||
Data = await element.getData() | ||
let Data; | ||
if (!element.getData) { | ||
// TODO: fix: getObject as this is related to render or form, but filter could exist on an input which does not have getObject | ||
// TODO: generate an object of current element key: value to use with filter. because filter is used object is not defined | ||
Data = getObject(element); | ||
if (Array.isArray(Data[type])) Data = Data[type][0]; | ||
} else Data = await element.getData(); | ||
if (!Data) return | ||
if (!Data) return; | ||
let newData | ||
if (type) { | ||
Data = Data[type] | ||
newData = data[type] | ||
} else | ||
newData = data | ||
let newData; | ||
if (type) { | ||
Data = Data[type]; | ||
newData = data[type]; | ||
} else newData = data; | ||
let filter = await element.getFilter() | ||
if (filter && filter.query) { | ||
for (let i = 0; i < newData.length; i++) { | ||
let isMatch = queryData(newData[i], filter.query) | ||
if (!isMatch) | ||
newData.slice(i, 1) | ||
} | ||
let filter = await element.getFilter(); | ||
if (filter && filter.query) { | ||
for (let i = 0; i < newData.length; i++) { | ||
let isMatch = queryData(newData[i], filter.query); | ||
if (!isMatch) newData.slice(i, 1); | ||
} | ||
} | ||
} | ||
if (!newData || !newData.length) return; | ||
if (!newData || !newData.length) | ||
return | ||
if (Array.isArray(Data)) { | ||
if (Array.isArray(newData)) { | ||
for (let i = 0; i < newData.length; i++) { | ||
checkIndex(element, data, Data, newData[i], type, filter); | ||
} | ||
} else { | ||
checkIndex(element, data, Data, newData, type, filter); | ||
} | ||
} else { | ||
let primaryKey; | ||
if (type === "object") { | ||
primaryKey = "_id"; | ||
} else { | ||
primaryKey = "name"; | ||
} | ||
if (Array.isArray(Data)) { | ||
if (Array.isArray(newData)) { | ||
for (let i = 0; i < newData.length; i++) { | ||
checkIndex(element, data, Data, newData[i], type, filter) | ||
} | ||
} else { | ||
checkIndex(element, data, Data, newData, type, filter) | ||
} | ||
} else { | ||
let primaryKey | ||
if (type === 'object') { | ||
primaryKey = '_id'; | ||
} else { | ||
primaryKey = 'name'; | ||
} | ||
if (Array.isArray(newData)) { | ||
for (let i = 0; i < newData.length; i++) { | ||
if ( | ||
typeof Data === "string" && | ||
Data === newData[i][primaryKey] | ||
) { | ||
Data = newData[i]; | ||
} else if (Data[primaryKey] === newData[i][primaryKey]) { | ||
Data = dotNotationToObject(newData[i], Data); | ||
} | ||
} | ||
} else if (typeof Data === "string" && Data === newData[primaryKey]) { | ||
Data = newData; | ||
} else if (Data[primaryKey] === newData[primaryKey]) { | ||
Data = dotNotationToObject(newData, Data); | ||
} | ||
if (Array.isArray(newData)) { | ||
for (let i = 0; i < newData.length; i++) { | ||
if (typeof Data === 'string' && Data === newData[i][primaryKey]) { | ||
Data = newData[i] | ||
} else if (Data[primaryKey] === newData[i][primaryKey]) { | ||
Data = dotNotationToObject(newData[i], Data) | ||
} | ||
} | ||
} else if (typeof Data === 'string' && Data === newData[primaryKey]) { | ||
Data = newData | ||
} else if (Data[primaryKey] === newData[primaryKey]) { | ||
Data = dotNotationToObject(newData, Data) | ||
} | ||
if (element.renderValue) | ||
element.renderValue(data); | ||
// render({ element, data, key: type }); | ||
else if (data) | ||
element.setValue(data) | ||
} | ||
if (element.renderValue) element.renderValue(data); | ||
// render({ element, data, key: type }); | ||
else if (data) element.setValue(data); | ||
} | ||
} | ||
function checkIndex(element, data, Data, newData, type, filter) { | ||
let index | ||
if (type === 'object') { | ||
index = Data.findIndex(obj => obj._id === newData._id); | ||
} else { | ||
index = Data.findIndex(obj => obj.name === newData.name); | ||
} | ||
let index; | ||
if (type === "object") { | ||
index = Data.findIndex((obj) => obj._id === newData._id); | ||
} else { | ||
index = Data.findIndex((obj) => obj.name === newData.name); | ||
} | ||
if (!data.$filter) | ||
data.$filter = {} | ||
if (!data.$filter) data.$filter = {}; | ||
if (data.method.endsWith('.delete')) { | ||
if (!index && index !== 0) | ||
return | ||
data.$filter.remove = true | ||
} else { | ||
if (data.method.endsWith('.create')) { | ||
if (index === -1) { | ||
data.$filter.create = true | ||
if (filter && filter.sort) | ||
newData.isNewData = true | ||
else | ||
index = Data.length | ||
Data.push(newData) | ||
} | ||
} else { | ||
data.$filter.update = true | ||
data.$filter.currentIndex = index | ||
Data[index] = dotNotationToObject(newData, Data[index]) | ||
if (filter && filter.sort) { | ||
Data[index].isNewData = true | ||
} | ||
} | ||
if (data.method.endsWith(".delete")) { | ||
if (!index && index !== 0) return; | ||
data.$filter.remove = true; | ||
} else { | ||
if (data.method.endsWith(".create")) { | ||
if (index === -1) { | ||
data.$filter.create = true; | ||
if (filter && filter.sort) newData.isNewData = true; | ||
else index = Data.length; | ||
Data.push(newData); | ||
} | ||
} else { | ||
data.$filter.update = true; | ||
data.$filter.currentIndex = index; | ||
Data[index] = dotNotationToObject(newData, Data[index]); | ||
if (filter && filter.sort) { | ||
Data[index].isNewData = true; | ||
} | ||
} | ||
if (filter && filter.sort) { | ||
Data = sortData(Data, filter.sort) | ||
index = Data.findIndex(obj => obj.isNewData); | ||
} | ||
if (filter && filter.sort) { | ||
Data = sortData(Data, filter.sort); | ||
index = Data.findIndex((obj) => obj.isNewData); | ||
} | ||
} | ||
} | ||
if (index >= 0) { | ||
if (data.$filter.currentIndex === index) | ||
delete data.$filter.currentIndex | ||
data.$filter.index = index | ||
if (element.renderValue) | ||
element.renderValue(data); | ||
else if (data) | ||
element.setValue(data) | ||
} | ||
if (index >= 0) { | ||
if (data.$filter.currentIndex === index) | ||
delete data.$filter.currentIndex; | ||
data.$filter.index = index; | ||
if (element.renderValue) element.renderValue(data); | ||
else if (data) element.setValue(data); | ||
} | ||
} | ||
function getDataKey(data) { | ||
let dataKey = {}; | ||
let attributes = ["host", "organization_id", "apikey", "method", "type", "storage", "database", "array", "index", "object", "key", "updateKey", "$filter", "upsert", "namespace", "room", "broadcast", "broadcastSender", "broadcastBrowser"]; | ||
let dataKey = {}; | ||
let attributes = [ | ||
"host", | ||
"organization_id", | ||
"apikey", | ||
"method", | ||
"type", | ||
"storage", | ||
"database", | ||
"array", | ||
"index", | ||
"object", | ||
"key", | ||
"updateKey", | ||
"$filter", | ||
"upsert", | ||
"namespace", | ||
"room", | ||
"broadcast", | ||
"broadcastSender", | ||
"broadcastBrowser" | ||
]; | ||
for (let attribute of attributes) { | ||
if (attribute === 'key' && data.type === 'object') | ||
continue | ||
let value = data[attribute]; | ||
if (value) { | ||
if (Array.isArray(value)) { | ||
dataKey[attribute] = [...value]; | ||
if (typeof value[0] === 'string') | ||
dataKey[attribute].sort(); // Sort the values alphabetically | ||
} else { | ||
dataKey[attribute] = value; | ||
} | ||
} | ||
} | ||
for (let attribute of attributes) { | ||
if (attribute === "key" && data.type === "object") continue; | ||
let value = data[attribute]; | ||
if (value) { | ||
if (Array.isArray(value)) { | ||
dataKey[attribute] = [...value]; | ||
if (typeof value[0] === "string") dataKey[attribute].sort(); // Sort the values alphabetically | ||
} else { | ||
dataKey[attribute] = value; | ||
} | ||
} | ||
} | ||
const object = Object.fromEntries(Object.entries(dataKey).sort(([a], [b]) => a.localeCompare(b))); | ||
const string = JSON.stringify(object); | ||
const object = Object.fromEntries( | ||
Object.entries(dataKey).sort(([a], [b]) => a.localeCompare(b)) | ||
); | ||
const string = JSON.stringify(object); | ||
return { string, object }; | ||
return { string, object }; | ||
} | ||
function getDataElements(data) { | ||
let element = [] | ||
let matchingKeys = getDataKeys(data) | ||
for (let i = 0; i < matchingKeys.length; i++) { | ||
let matchingElements = keys.get(matchingKeys[i]) | ||
if (matchingElements && matchingElements.elements && matchingElements.elements.size) | ||
element.push(...matchingElements.elements.keys()) | ||
} | ||
return element | ||
let element = []; | ||
let matchingKeys = getDataKeys(data); | ||
for (let i = 0; i < matchingKeys.length; i++) { | ||
let matchingElements = keys.get(matchingKeys[i]); | ||
if ( | ||
matchingElements && | ||
matchingElements.elements && | ||
matchingElements.elements.size | ||
) | ||
element.push(...matchingElements.elements.keys()); | ||
} | ||
return element; | ||
} | ||
// TODO: Correctly check for matches | ||
// TODO: Correctly check for matches | ||
function getDataKeys(data) { | ||
const matchingKeyStrings = []; | ||
const targetKeys = ["type", "storage", "database", "array", "index", "object", '$filter']; | ||
const matchingKeyStrings = []; | ||
const targetKeys = [ | ||
"type", | ||
"storage", | ||
"database", | ||
"array", | ||
"index", | ||
"object", | ||
"$filter" | ||
]; | ||
for (const [keyString, sortedKey] of keys.entries()) { | ||
let hasMatch = true; | ||
for (const [keyString, sortedKey] of keys.entries()) { | ||
let hasMatch = true; | ||
for (const key of targetKeys) { | ||
if (!data.$filter && key === '$filter' && sortedKey.data.hasOwnProperty(key)) | ||
hasMatch = true | ||
else if (data.hasOwnProperty(key)) { | ||
if (!sortedKey.data.hasOwnProperty(key)) { | ||
hasMatch = false; | ||
break; | ||
} | ||
if (Array.isArray(sortedKey.data[key]) && Array.isArray(data[key])) { | ||
// if key is object check _id | ||
if (key === 'object' && sortedKey.data.$filter) | ||
hasMatch = true | ||
else { | ||
const matches = sortedKey.data[key].some(value => { | ||
if (key === 'object') { | ||
return data[key].some(obj => { | ||
return obj._id === value._id | ||
}); | ||
} else { | ||
return data[key].includes(value) | ||
} | ||
}); | ||
for (const key of targetKeys) { | ||
if ( | ||
!data.$filter && | ||
key === "$filter" && | ||
sortedKey.data.hasOwnProperty(key) | ||
) | ||
hasMatch = true; | ||
else if (data.hasOwnProperty(key)) { | ||
if (!sortedKey.data.hasOwnProperty(key)) { | ||
hasMatch = false; | ||
break; | ||
} | ||
if ( | ||
Array.isArray(sortedKey.data[key]) && | ||
Array.isArray(data[key]) | ||
) { | ||
// if key is object check _id | ||
if (key === "object" && sortedKey.data.$filter) | ||
hasMatch = true; | ||
else { | ||
const matches = sortedKey.data[key].some((value) => { | ||
if (key === "object") { | ||
return data[key].some((obj) => { | ||
return obj._id === value._id; | ||
}); | ||
} else { | ||
return data[key].includes(value); | ||
} | ||
}); | ||
if (!matches) { | ||
hasMatch = false; | ||
break; | ||
} | ||
if (!matches) { | ||
hasMatch = false; | ||
break; | ||
} | ||
} | ||
} else if (sortedKey.data[key] !== data[key]) { | ||
hasMatch = false; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
if (hasMatch) { | ||
matchingKeyStrings.push(keyString); | ||
} | ||
} | ||
} else if (sortedKey.data[key] !== data[key]) { | ||
hasMatch = false; | ||
break; | ||
} | ||
} | ||
} | ||
if (hasMatch) { | ||
matchingKeyStrings.push(keyString); | ||
} | ||
} | ||
return matchingKeyStrings; | ||
return matchingKeyStrings; | ||
} | ||
async function getData(form) { | ||
let dataKeys = new Map() | ||
let formObject = forms.get(form) | ||
if (!formObject) { | ||
let elements = form.querySelectorAll(selector) | ||
await init(elements) | ||
return await getData(form) | ||
} | ||
let dataKeys = new Map(); | ||
let formObject = forms.get(form); | ||
if (!formObject) { | ||
let elements = form.querySelectorAll(selector); | ||
await init(elements); | ||
return await getData(form); | ||
} | ||
for (let type of formObject.types.values()) { | ||
for (let [element, data] of type.entries()) { | ||
if (!element.hasAttribute('key') || element.getAttribute('save') === 'false') | ||
continue | ||
for (let type of formObject.types.values()) { | ||
for (let [element, data] of type.entries()) { | ||
if ( | ||
!element.hasAttribute("key") || | ||
element.getAttribute("save") === "false" | ||
) | ||
continue; | ||
if (element.hasAttribute('actions')) { | ||
let attribute = element.getAttribute('actions') | ||
if (attribute.includes('save', 'delete')) | ||
continue | ||
} | ||
let Data = { ...data } | ||
let dataKey = elements.get(element) | ||
let value = await element.getValue() | ||
if (element.hasAttribute("actions")) { | ||
let attribute = element.getAttribute("actions"); | ||
if (attribute.includes("save", "delete")) continue; | ||
} | ||
let Data = { ...data }; | ||
let dataKey = elements.get(element); | ||
let value = await element.getValue(); | ||
// console.log(type, value, data) | ||
if (!Data[Data.type] && Data.key) { | ||
if (!value) | ||
continue | ||
else if (Array.isArray(value) && !value.length) | ||
continue | ||
// console.log(type, value, data) | ||
if (!Data[Data.type] && Data.key) { | ||
if (!value) continue; | ||
else if (Array.isArray(value) && !value.length) continue; | ||
Data.method = Data.type + '.create' | ||
if (Data.type === 'object') { | ||
if (!Data.object) | ||
Data.object = {} | ||
else if (typeof Data.object === 'string') | ||
Data.object = { _id: Data.object } | ||
Data.method = Data.type + ".create"; | ||
if (Data.type === "object") { | ||
if (!Data.object) Data.object = {}; | ||
else if (typeof Data.object === "string") | ||
Data.object = { _id: Data.object }; | ||
if (Data.key) { | ||
if (Data.key == "{}") { | ||
if (Array.isArray(value)) { | ||
Data.object = value; | ||
} else Data.object = { ...Data.object, ...value }; | ||
} else Data.object[Data.key] = value; | ||
} | ||
if (Data.isUpsert && Data.$filter) | ||
Data.method = "object.update"; | ||
} else Data[Data.type] = value; | ||
} else if (Data[Data.type] && Data.key) { | ||
let attributes = element.attributes; | ||
if (Data.key.startsWith("$")) { | ||
for (let i = 0; i < attributes.length; i++) { | ||
let operators = [ | ||
"$rename", | ||
"$inc", | ||
"$push", | ||
"$each", | ||
"$splice", | ||
"$unset", | ||
"$delete", | ||
"$slice", | ||
"$pop", | ||
"$shift", | ||
"$addToSet", | ||
"$pull" | ||
]; | ||
if (operators.includes(attributes[i].name)) { | ||
Data.key = attributes[i].name + "." + Data.key; | ||
break; | ||
} | ||
} | ||
} | ||
if (Data.key) { | ||
if (Data.key == '{}') { | ||
if (Array.isArray(value)) { | ||
Data.object = value | ||
} else | ||
Data.object = { ...Data.object, ...value } | ||
} else | ||
Data.object[Data.key] = value | ||
} | ||
if (Data.isUpsert && Data.$filter) | ||
Data.method = 'object.update' | ||
if ((Data.type = "object")) { | ||
if (Data.key == "{}") { | ||
if (!value) continue; | ||
else if (Array.isArray(value) && !value.length) | ||
continue; | ||
} | ||
} else | ||
Data[Data.type] = value | ||
if (typeof Data[Data.type] === "string") | ||
if (Data.key == "{}") { | ||
// TODO: handle if array length more than 1 | ||
if (Array.isArray(value)) | ||
Data[Data.type] = { | ||
_id: Data[Data.type], | ||
...value[0] | ||
}; | ||
else | ||
Data[Data.type] = { | ||
_id: Data[Data.type], | ||
...value | ||
}; | ||
} else | ||
Data[Data.type] = { | ||
_id: Data[Data.type], | ||
[Data.key]: value | ||
}; | ||
else if (Array.isArray(Data[Data.type])) | ||
if (Data.key == "{}") | ||
Data[Data.type][0] = { | ||
...Data[Data.type][0], | ||
...value | ||
}; | ||
else { | ||
Data[Data.type][0][Data.key] = value; | ||
if (!Data[Data.type][0]._id) | ||
Data.method = Data.type + ".create"; | ||
} | ||
else if (typeof Data[Data.type] === "object") | ||
if (Data.key == "{}") | ||
Data[Data.type] = { ...Data[Data.type], ...value }; | ||
else { | ||
Data[Data.type][Data.key] = value; | ||
if (!Data[Data.type]._id) | ||
Data.method = Data.type + ".create"; | ||
} | ||
} else { | ||
Data[Data.type] = { [Data[Data.type]]: value }; | ||
} | ||
} else if (Data[Data.type] && Data.key) { | ||
let attributes = element.attributes | ||
if (Data.key.startsWith('$')) { | ||
for (let i = 0; i < attributes.length; i++) { | ||
let operators = ['$rename', '$inc', '$push', '$each', '$splice', '$unset', '$delete', '$slice', '$pop', '$shift', '$addToSet', '$pull'] | ||
if (operators.includes(attributes[i].name)) { | ||
Data.key = attributes[i].name + '.' + Data.key | ||
break; | ||
} | ||
} | ||
} | ||
if (Data.isUpdate || Data.isUpdate === "") { | ||
if (!Data.key) return; | ||
delete Data.isUpdate; | ||
Data.updateKey = { [Data.key]: value }; | ||
Data.method = Data.type + ".update"; | ||
} else if (Data.isDelete || Data.isDelete === "") { | ||
delete Data.isDelete; | ||
if (Data.type == "object" && Data.key) { | ||
Data.method = Data.type + ".update"; | ||
// TODO: Data.type can be a string _id or an array for string _id needs to be converted to object | ||
if (typeof Data[Data.type] === "string") | ||
Data[Data.type] = { | ||
_id: Data[Data.type], | ||
[Data.key]: undefined | ||
}; | ||
else if (Array.isArray(Data[Data.type])) { | ||
console.log( | ||
"Data.type is an array function incomplete" | ||
); | ||
} else if (typeof Data[Data.type] === "object") | ||
Data[Data.type][Data.key] = undefined; | ||
} else { | ||
Data.method = Data.type + ".delete"; | ||
} | ||
} else if (Data.type !== "object" && Data[Data.type] === "") { | ||
// if (!Data.key) | ||
// Data.method = Data.type + '.read' | ||
// else if (Data.key === 'name') | ||
// Data.method = Data.type + '.create' | ||
} else if (Data.type !== "object" && Data[Data.type]) { | ||
// if (Data.key) | ||
// Data.method = Data.type + '.update' | ||
} | ||
} | ||
if (Data.type = 'object') { | ||
if (Data.key == '{}') { | ||
if (!value) | ||
continue | ||
else if (Array.isArray(value) && !value.length) | ||
continue | ||
} | ||
//dataKey should be used to group | ||
let key = dataKey + Data.method; | ||
if (dataKeys.has(key)) { | ||
let storedData = dataKeys.get(key)[Data.type]; | ||
dataKeys.get(key)[Data.type] = { | ||
...storedData, | ||
...Data[Data.type] | ||
}; | ||
} else { | ||
dataKeys.set(key, Data); | ||
} | ||
} | ||
} | ||
if (typeof Data[Data.type] === 'string') | ||
if (Data.key == '{}') { | ||
// TODO: handle if array length more than 1 | ||
if (Array.isArray(value)) | ||
Data[Data.type] = { _id: Data[Data.type], ...value[0] } | ||
else | ||
Data[Data.type] = { _id: Data[Data.type], ...value } | ||
} else | ||
Data[Data.type] = { _id: Data[Data.type], [Data.key]: value } | ||
else if (Array.isArray(Data[Data.type])) | ||
if (Data.key == '{}') | ||
Data[Data.type][0] = { ...Data[Data.type][0], ...value } | ||
else { | ||
Data[Data.type][0][Data.key] = value | ||
if (!Data[Data.type][0]._id) | ||
Data.method = Data.type + '.create' | ||
} | ||
else if (typeof Data[Data.type] === 'object') | ||
if (Data.key == '{}') | ||
Data[Data.type] = { ...Data[Data.type], ...value } | ||
else { | ||
Data[Data.type][Data.key] = value | ||
if (!Data[Data.type]._id) | ||
Data.method = Data.type + '.create' | ||
} | ||
} else { | ||
Data[Data.type] = { [Data[Data.type]]: value } | ||
} | ||
// TODO: group by methods so we can make one crud request per method | ||
let dataArray = Array.from(dataKeys.values()); | ||
if (Data.isUpdate || Data.isUpdate === '') { | ||
if (!Data.key) return | ||
delete Data.isUpdate | ||
Data.updateKey = { [Data.key]: value } | ||
Data.method = Data.type + '.update' | ||
} else if (Data.isDelete || Data.isDelete === '') { | ||
delete Data.isDelete | ||
if (Data.type == 'object' && Data.key) { | ||
Data.method = Data.type + '.update' | ||
// TODO: Data.type can be a string _id or an array for string _id needs to be converted to object | ||
if (typeof Data[Data.type] === 'string') | ||
Data[Data.type] = { _id: Data[Data.type], [Data.key]: undefined } | ||
else if (Array.isArray(Data[Data.type])) { | ||
console.log('Data.type is an array function incomplete') | ||
} else if (typeof Data[Data.type] === 'object') | ||
Data[Data.type][Data.key] = undefined | ||
} else { | ||
Data.method = Data.type + '.delete' | ||
} | ||
} else if (Data.type !== 'object' && Data[Data.type] === '') { | ||
// if (!Data.key) | ||
// Data.method = Data.type + '.read' | ||
// else if (Data.key === 'name') | ||
// Data.method = Data.type + '.create' | ||
} else if (Data.type !== 'object' && Data[Data.type]) { | ||
// if (Data.key) | ||
// Data.method = Data.type + '.update' | ||
} | ||
} | ||
//dataKey should be used to group | ||
let key = dataKey + Data.method | ||
if (dataKeys.has(key)) { | ||
let storedData = dataKeys.get(key)[Data.type] | ||
dataKeys.get(key)[Data.type] = { ...storedData, ...Data[Data.type] } | ||
} else { | ||
dataKeys.set(key, Data) | ||
} | ||
} | ||
} | ||
// TODO: group by methods so we can make one crud request per method | ||
let dataArray = Array.from(dataKeys.values()) | ||
return dataArray | ||
return dataArray; | ||
} | ||
async function save(element) { | ||
if (!element) return; | ||
let data, value | ||
let upsert = element.getAttribute('upsert') | ||
if (upsert && upsert !== 'false') | ||
upsert = true | ||
if (element.tagName === "FORM") { | ||
data = await element.getData() | ||
} else { | ||
let isSave = element.getAttribute('save') | ||
if (isSave === 'false') return | ||
if (!element) return; | ||
let data, value; | ||
let upsert = element.getAttribute("upsert"); | ||
if (upsert && upsert !== "false") upsert = true; | ||
if (element.tagName === "FORM") { | ||
data = await element.getData(); | ||
} else { | ||
let isSave = element.getAttribute("save"); | ||
if (isSave === "false") return; | ||
let form = element.closest('form'); | ||
if (form) | ||
return save(form); | ||
let form = element.closest("form"); | ||
if (form) return save(form); | ||
let dataKey = elements.get(element) | ||
data = { ...keys.get(dataKey).dataKey.object } | ||
let dataKey = elements.get(element); | ||
data = { ...keys.get(dataKey).dataKey.object }; | ||
value = await element.getValue(); | ||
let key = element.getAttribute('key') | ||
value = await element.getValue(); | ||
let key = element.getAttribute("key"); | ||
if (typeof data[data.type] === 'string') | ||
if (key == '{}') | ||
data[data.type] = { _id: data[data.type], ...value } | ||
else | ||
data[data.type] = { _id: data[data.type], [key]: value } | ||
else if (typeof data[data.type] === 'object') | ||
if (key == '{}') | ||
data[data.type] = { ...data[data.type], ...value } | ||
else | ||
data[data.type][key] = value | ||
if (typeof data[data.type] === "string") | ||
if (key == "{}") | ||
data[data.type] = { _id: data[data.type], ...value }; | ||
else data[data.type] = { _id: data[data.type], [key]: value }; | ||
else if (typeof data[data.type] === "object") | ||
if (key == "{}") data[data.type] = { ...data[data.type], ...value }; | ||
else data[data.type][key] = value; | ||
if (/\.([0-9]*)/g.test(data.key)) { | ||
let splice = element.getAttribute('splice') | ||
let slice = element.getAttribute('slice') | ||
let update = element.getAttribute('update') | ||
if (/\.([0-9]*)/g.test(data.key)) { | ||
let splice = element.getAttribute("splice"); | ||
let slice = element.getAttribute("slice"); | ||
let update = element.getAttribute("update"); | ||
if (splice || splice === "") { | ||
data[data.type][key] = { $splice: value } | ||
} else if (slice) { | ||
data[data.type][key] = '$delete' | ||
} else if (update) { | ||
value = data.key.replace(/\[.*?\]/, '[' + value + ']') | ||
data.updateKey[key] = value | ||
data[data.type][key] = { $update: value } // $update is string use the value as the key name | ||
if (splice || splice === "") { | ||
data[data.type][key] = { $splice: value }; | ||
} else if (slice) { | ||
data[data.type][key] = "$delete"; | ||
} else if (update) { | ||
value = data.key.replace(/\[.*?\]/, "[" + value + "]"); | ||
data.updateKey[key] = value; | ||
data[data.type][key] = { $update: value }; // $update is string use the value as the key name | ||
// data[data.type][key] = { $update: {[value]: value} } // $update is an object use the key as the value to use for the new key | ||
} | ||
// data[data.type][key] = { $update: {[value]: value} } // $update is an object use the key as the value to use for the new key | ||
} | ||
} | ||
} | ||
data = [data]; | ||
} | ||
data = [data] | ||
} | ||
let Data = []; | ||
for (let i = 0; i < data.length; i++) { | ||
if (data[i].type === "object") { | ||
if (typeof data[i].object === "string") { | ||
if (!data[i]._id) data[i].method = "object.create"; | ||
else { | ||
data[i].method = "object.update"; | ||
if (upsert) data[i].upsert = true; | ||
} | ||
} else if (Array.isArray(data[i].object)) { | ||
if (!data[i].object[0]._id) data[i].method = "object.create"; | ||
else { | ||
data[i].method = "object.update"; | ||
if (upsert) data[i].upsert = true; | ||
} | ||
} else if (typeof data[i].object === "object") { | ||
if (!data[i].object._id) data[i].method = "object.create"; | ||
else { | ||
data[i].method = "object.update"; | ||
if (upsert) data[i].upsert = true; | ||
} | ||
} | ||
} | ||
if (data[i].isUpsert) { | ||
data[i].upsert = true; | ||
delete data[i].isUpsert; | ||
} | ||
let Data = [] | ||
for (let i = 0; i < data.length; i++) { | ||
if (data[i].type === 'object') { | ||
if (typeof data[i].object === 'string') { | ||
if (!data[i]._id) | ||
data[i].method = 'object.create' | ||
else { | ||
data[i].method = 'object.update' | ||
if (upsert) | ||
data[i].upsert = true | ||
} | ||
} else if (Array.isArray(data[i].object)) { | ||
if (!data[i].object[0]._id) | ||
data[i].method = 'object.create' | ||
else { | ||
data[i].method = 'object.update' | ||
if (upsert) | ||
data[i].upsert = true | ||
} | ||
} else if (typeof data[i].object === 'object') { | ||
if (!data[i].object._id) | ||
data[i].method = 'object.create' | ||
else { | ||
data[i].method = 'object.update' | ||
if (upsert) | ||
data[i].upsert = true | ||
} | ||
} | ||
} | ||
if (data[i].method && data[i].method.endsWith(".create")) { | ||
element.setAttribute(data[i].type, "pending"); | ||
} else if ( | ||
data[i].method && | ||
data[i].method.endsWith(".update") && | ||
data[i].type == "object" && | ||
typeof value == "string" && | ||
window.CoCreate.crdt && | ||
!"crdt" | ||
) { | ||
return window.CoCreate.crdt.replaceText({ | ||
array: data[i].array, | ||
key: data[i].key, | ||
object: data[i].object._id, | ||
value | ||
}); | ||
} | ||
if (data[i].isUpsert) { | ||
data[i].upsert = true | ||
delete data[i].isUpsert | ||
} | ||
data[i] = await CRUD.send(data[i]); | ||
if (data[i].method && data[i].method.endsWith('.create')) { | ||
element.setAttribute(data[i].type, 'pending'); | ||
} else if (data[i].method && data[i].method.endsWith('.update') && data[i].type == 'object' && typeof value == 'string' && window.CoCreate.crdt && !'crdt') { | ||
return window.CoCreate.crdt.replaceText({ | ||
array: data[i].array, | ||
key: data[i].key, | ||
object: data[i].object._id, | ||
value | ||
}); | ||
} | ||
Data.push(data[i]); | ||
if ( | ||
data[i] && | ||
(data[i].method.endsWith(".create") || | ||
(data[i].type !== "object" && | ||
data[i].method.endsWith(".update"))) | ||
) { | ||
setTypeValue(element, data[i]); | ||
} else if (data[i]) | ||
document.dispatchEvent( | ||
new CustomEvent("saved", { | ||
detail: data[i] | ||
}) | ||
); | ||
} | ||
data[i] = await CRUD.send(data[i]); | ||
Data.push(data[i]) | ||
if (data[i] && (data[i].method.endsWith('.create') || data[i].type !== 'object' && data[i].method.endsWith('.update'))) { | ||
setTypeValue(element, data[i]) | ||
} else if (data[i]) | ||
document.dispatchEvent(new CustomEvent('saved', { | ||
detail: data[i] | ||
})); | ||
} | ||
return Data | ||
return Data; | ||
} | ||
function setTypeValue(element, data) { | ||
// TODO: if an array name is updated, the attibute array="" needs to be updated. | ||
// TODO: if an array name is updated, the attibute array="" needs to be updated. | ||
if (!data) return; | ||
if (!data) return; | ||
let form | ||
if (element.tagName === "FORM") | ||
form = element | ||
else if (element.parentElement) | ||
form = element.parentElement.closest('form') | ||
let form; | ||
if (element.tagName === "FORM") form = element; | ||
else if (element.parentElement) | ||
form = element.parentElement.closest("form"); | ||
if (!form) { | ||
if (data.type === 'object') { | ||
element.setAttribute('object', data.object[0]._id) | ||
} else { | ||
element.setAttribute(data.type, data[data.type].name) | ||
} | ||
} else { | ||
let formObject = forms.get(form) | ||
if (form.getAttribute('object') === 'pending') | ||
form.setAttribute('object', data.object[0]._id) | ||
if (!form) { | ||
if (data.type === "object") { | ||
element.setAttribute("object", data.object[0]._id); | ||
} else { | ||
element.setAttribute(data.type, data[data.type].name); | ||
} | ||
} else { | ||
let formObject = forms.get(form); | ||
if (form.getAttribute("object") === "pending") | ||
form.setAttribute("object", data.object[0]._id); | ||
let elements = formObject.types.get(data.type) | ||
let elements = formObject.types.get(data.type); | ||
for (let [el, Data] of elements.entries()) { | ||
if (data.type === 'object') { | ||
if (!Data.object || Data.object === 'pending') { | ||
Data.object = data.object[0]._id | ||
el.setAttribute('object', data.object[0]._id) | ||
} | ||
} else if (!Data[data.type]) { | ||
Data[data.type] = data[data.type].name | ||
el.setAttribute(data.type, data[data.type].name) | ||
} | ||
} | ||
setData(Array.from(elements.keys()), data) | ||
for (let [el, Data] of elements.entries()) { | ||
if (data.type === "object") { | ||
if (!Data.object || Data.object === "pending") { | ||
Data.object = data.object[0]._id; | ||
el.setAttribute("object", data.object[0]._id); | ||
} | ||
} else if (!Data[data.type]) { | ||
Data[data.type] = data[data.type].name; | ||
el.setAttribute(data.type, data[data.type].name); | ||
} | ||
} | ||
setData(Array.from(elements.keys()), data); | ||
// const state_ids = new Map(); | ||
// const state_ids = new Map(); | ||
// let state_id = form.getAttribute('state_id'); | ||
// if (state_id) { | ||
// // Set state_ids to state_ids if array is not set | ||
// if (form.getAttribute('array') == array) | ||
// state_ids.set(state_id, ''); | ||
// } | ||
// let state_id = form.getAttribute('state_id'); | ||
// if (state_id) { | ||
// // Set state_ids to state_ids if array is not set | ||
// if (form.getAttribute('array') == array) | ||
// state_ids.set(state_id, ''); | ||
// } | ||
// let objectId = el.getAttribute('object'); | ||
// let key = el.getAttribute('key') | ||
// // set object and state_id attributes to the object id if the object id is pending | ||
// if (key && (objectId == '' || objectId == 'pending')) { | ||
// el.setAttribute('object', id); | ||
// // Set the id attribute of the element | ||
// if (key == '_id') | ||
// el.setValue(id) | ||
// let state_id = el.getAttribute('state_id'); | ||
// // Set the state id to the state_ids. | ||
// if (state_id) { | ||
// state_ids.set(state_id, ''); | ||
// } | ||
// let objectId = el.getAttribute('object'); | ||
// let key = el.getAttribute('key') | ||
// // set object and state_id attributes to the object id if the object id is pending | ||
// if (key && (objectId == '' || objectId == 'pending')) { | ||
// el.setAttribute('object', id); | ||
// // Set the id attribute of the element | ||
// if (key == '_id') | ||
// el.setValue(id) | ||
// let state_id = el.getAttribute('state_id'); | ||
// // Set the state id to the state_ids. | ||
// if (state_id) { | ||
// state_ids.set(state_id, ''); | ||
// } | ||
// if (el.hasAttribute('state-object')) { | ||
// let stateObjectId = el.getAttribute('state-object'); | ||
// // Set the state object id if not set. | ||
// if (stateObjectId == '') { | ||
// el.setAttribute('state-object', id); | ||
// let state_id = el.getAttribute('state_id'); | ||
// // Set the state id to the state_ids. | ||
// if (state_id) { | ||
// state_ids.set(state_id, ''); | ||
// } | ||
// } | ||
// } | ||
// if (el.hasAttribute('state-object')) { | ||
// let stateObjectId = el.getAttribute('state-object'); | ||
// // Set the state object id if not set. | ||
// if (stateObjectId == '') { | ||
// el.setAttribute('state-object', id); | ||
// let state_id = el.getAttribute('state_id'); | ||
// // Set the state id to the state_ids. | ||
// if (state_id) { | ||
// state_ids.set(state_id, ''); | ||
// } | ||
// } | ||
// } | ||
// // Set the object attribute of all state_ids to the object attribute of all state_ids | ||
// if (state_ids.size > 0) { | ||
// for (let key of state_ids.keys()) { | ||
// let stateEls = document.querySelectorAll(`[state_id="${key}"]`) | ||
// for (let stateEl of stateEls) { | ||
// // if (stateEl.getAttribute('array') == array){ | ||
// // Set the object id attribute to the stateEl s object if it is not set. | ||
// if (stateEl.getAttribute('object') == '') { | ||
// stateEl.setAttribute('object', id); | ||
// } | ||
// // } | ||
// } | ||
// } | ||
// } | ||
// } | ||
} | ||
// // Set the object attribute of all state_ids to the object attribute of all state_ids | ||
// if (state_ids.size > 0) { | ||
// for (let key of state_ids.keys()) { | ||
// let stateEls = document.querySelectorAll(`[state_id="${key}"]`) | ||
// for (let stateEl of stateEls) { | ||
// // if (stateEl.getAttribute('array') == array){ | ||
// // Set the object id attribute to the stateEl s object if it is not set. | ||
// if (stateEl.getAttribute('object') == '') { | ||
// stateEl.setAttribute('object', id); | ||
// } | ||
// // } | ||
// } | ||
// } | ||
// } | ||
// } | ||
} | ||
document.dispatchEvent(new CustomEvent('saved', { | ||
detail: data | ||
})); | ||
document.dispatchEvent( | ||
new CustomEvent("saved", { | ||
detail: data | ||
}) | ||
); | ||
} | ||
async function remove(element) { | ||
if (element && !(element instanceof HTMLCollection) && !Array.isArray(element)) | ||
element = [element] | ||
for (let i = 0; i < element.length; i++) { | ||
if (element[i].tagName === 'FORM') { | ||
let form = forms.get(element[i]) | ||
if (!form) return | ||
if ( | ||
element && | ||
!(element instanceof HTMLCollection) && | ||
!Array.isArray(element) | ||
) | ||
element = [element]; | ||
for (let i = 0; i < element.length; i++) { | ||
if (element[i].tagName === "FORM") { | ||
let form = forms.get(element[i]); | ||
if (!form) return; | ||
form = form.elements | ||
for (let el of form.keys()) { | ||
let key = elements.get(el) | ||
if (key) { | ||
keys.get(key).elements.delete(el) | ||
elements.delete(el) | ||
// debounce.delete(key) | ||
} | ||
} | ||
let key = elements.get(element[i]) | ||
if (key) { | ||
keys.get(key).elements.delete(element[i]) | ||
if (!keys.get(key).elements.size) | ||
keys.delete(key) | ||
} | ||
elements.delete(element[i]) | ||
forms.delete(element[i]) | ||
} else { | ||
form = form.elements; | ||
for (let el of form.keys()) { | ||
let key = elements.get(el); | ||
if (key) { | ||
keys.get(key).elements.delete(el); | ||
elements.delete(el); | ||
// debounce.delete(key) | ||
} | ||
} | ||
let key = elements.get(element[i]); | ||
if (key) { | ||
keys.get(key).elements.delete(element[i]); | ||
if (!keys.get(key).elements.size) keys.delete(key); | ||
} | ||
elements.delete(element[i]); | ||
forms.delete(element[i]); | ||
} else { | ||
let key = elements.get(element[i]); | ||
if (key) { | ||
if (element[i].getFilter) filter.filters.delete(element[i]); | ||
keys.get(key).elements.delete(element[i]); | ||
elements.delete(element[i]); | ||
if (!keys.get(key).elements.size) keys.delete(key); | ||
let key = elements.get(element[i]) | ||
if (key) { | ||
if (element[i].getFilter) | ||
filter.filters.delete(element[i]) | ||
keys.get(key).elements.delete(element[i]) | ||
elements.delete(element[i]) | ||
if (!keys.get(key).elements.size) | ||
keys.delete(key) | ||
// debounce.delete(key) | ||
let form = element[i].closest('form') | ||
form = forms.get(form) | ||
if (form) { | ||
form.elements.delete(element[i]) | ||
if (!form.elements.size) | ||
forms.delete(form) | ||
} | ||
} else | ||
elements.delete(element[i]) | ||
} | ||
} | ||
// debounce.delete(key) | ||
let form = element[i].closest("form"); | ||
form = forms.get(form); | ||
if (form) { | ||
form.elements.delete(element[i]); | ||
if (!form.elements.size) forms.delete(form); | ||
} | ||
} else elements.delete(element[i]); | ||
} | ||
} | ||
} | ||
function initSocket() { | ||
const type = ["storage", "database", "array", "index", "object", 'filter']; | ||
const method = ['create', 'update', 'delete']; | ||
const type = ["storage", "database", "array", "index", "object", "filter"]; | ||
const method = ["create", "update", "delete"]; | ||
for (let i = 0; i < type.length; i++) { | ||
for (let j = 0; j < method.length; j++) { | ||
const action = type[i] + '.' + method[j]; | ||
for (let i = 0; i < type.length; i++) { | ||
for (let j = 0; j < method.length; j++) { | ||
const action = type[i] + "." + method[j]; | ||
CRUD.listen(action, function (data) { | ||
if (data.resolved && data.status === 'received' && CRUD.socket.clientId === data.clientId) | ||
return | ||
if (data.rendered) | ||
return | ||
CRUD.listen(action, function (data) { | ||
if ( | ||
data.resolved && | ||
data.status === "received" && | ||
CRUD.socket.clientId === data.clientId | ||
) | ||
return; | ||
if (data.rendered) return; | ||
data.rendered = true | ||
data.rendered = true; | ||
setData(null, data); | ||
}); | ||
} | ||
} | ||
setData(null, data); | ||
}); | ||
} | ||
} | ||
} | ||
Observer.init({ | ||
name: 'render', | ||
observe: ['addedNodes'], | ||
selector: '[render-clone]', | ||
callback: function (mutation) { | ||
if (!mutation.parentElement.hasAttribute('dnd')) | ||
return | ||
let delayTimer = debounce.get(mutation) | ||
clearTimeout(delayTimer); | ||
debounce.delete(mutation.target) | ||
name: "render", | ||
observe: ["addedNodes"], | ||
selector: "[render-clone]", | ||
callback: function (mutation) { | ||
if (!mutation.parentElement.hasAttribute("dnd")) return; | ||
let delayTimer = debounce.get(mutation); | ||
clearTimeout(delayTimer); | ||
debounce.delete(mutation.target); | ||
let renderedNode = renderedNodes.get(mutation.target) | ||
if (!renderedNode) return | ||
let renderedNode = renderedNodes.get(mutation.target); | ||
if (!renderedNode) return; | ||
if (!mutation.movedFrom) return | ||
let draggedEl = mutation.target | ||
let draggedFrom = mutation.movedFrom.parentElement | ||
let droppedEl = mutation.target.nextElementSibling || mutation.target.previousElementSibling | ||
let droppedIn = mutation.parentElement | ||
if (!mutation.movedFrom) return; | ||
let draggedEl = mutation.target; | ||
let draggedFrom = mutation.movedFrom.parentElement; | ||
let droppedEl = | ||
mutation.target.nextElementSibling || | ||
mutation.target.previousElementSibling; | ||
let droppedIn = mutation.parentElement; | ||
if (!draggedFrom || !droppedIn) return | ||
dndCrud(draggedEl, draggedFrom, droppedEl, droppedIn) | ||
} | ||
}) | ||
if (!draggedFrom || !droppedIn) return; | ||
dndCrud(draggedEl, draggedFrom, droppedEl, droppedIn); | ||
} | ||
}); | ||
// TODO: has the potential to work on most of the crud elements specifically if the value is an object or an array | ||
async function dndCrud(draggedEl, draggedFrom, droppedEl, droppedIn) { | ||
let from = await dndCrudData(draggedEl, draggedFrom, 'remove') | ||
let to = await dndCrudData(droppedEl, droppedIn, 'add') | ||
let from = await dndCrudData(draggedEl, draggedFrom, "remove"); | ||
let to = await dndCrudData(droppedEl, droppedIn, "add"); | ||
if (from && to && !draggedFrom.isSameNode(droppedIn)) { | ||
let element = getDataElements(from.data) | ||
if (!element.length) return | ||
if (from && to && !draggedFrom.isSameNode(droppedIn)) { | ||
let element = getDataElements(from.data); | ||
if (!element.length) return; | ||
let match = element.find(obj => obj === droppedIn); | ||
if (!match) { | ||
if (from.keyPath.includes('.')) { | ||
let test = { [from.keyPath]: undefined } | ||
let match = element.find((obj) => obj === droppedIn); | ||
if (!match) { | ||
if (from.keyPath.includes(".")) { | ||
let test = { [from.keyPath]: undefined }; | ||
from.newData = dotNotationToObject(test, from.newData) | ||
dndCrudSend(from.newData, 'update') | ||
} else { | ||
const index = from.keyPath.match(/\[(\d+)\]/) | ||
let removeData = from.newData[from.newData.type].splice(index, 1)[0]; | ||
if (removeData) { | ||
removeData.type = from.newData.type | ||
removeData[removeData.type] = removeData | ||
dndCrudSend(removeData, 'delete') | ||
} | ||
from.newData = dotNotationToObject(test, from.newData); | ||
dndCrudSend(from.newData, "update"); | ||
} else { | ||
const index = from.keyPath.match(/\[(\d+)\]/); | ||
let removeData = from.newData[from.newData.type].splice( | ||
index, | ||
1 | ||
)[0]; | ||
if (removeData) { | ||
removeData.type = from.newData.type; | ||
removeData[removeData.type] = removeData; | ||
dndCrudSend(removeData, "delete"); | ||
} | ||
if (from.newData[from.newData.type].length) | ||
dndCrudSend(from.newData, 'update') | ||
if (from.newData[from.newData.type].length) | ||
dndCrudSend(from.newData, "update"); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
if (to) | ||
dndCrudSend(to.newData, 'update') | ||
if (to) dndCrudSend(to.newData, "update"); | ||
} | ||
async function dndCrudData(element, parent, operator) { | ||
if (!elements.has(parent)) return | ||
let data = await parent.getData() | ||
let newData = getObject(parent) | ||
if (!elements.has(parent)) return; | ||
let data = await parent.getData(); | ||
let newData = getObject(parent); | ||
let { Data, sortName, sortDirection, keyPath, clones, index } = dndNewData(element, data) | ||
newData[newData.type] = [] | ||
let { Data, sortName, sortDirection, keyPath, clones, index } = dndNewData( | ||
element, | ||
data | ||
); | ||
newData[newData.type] = []; | ||
if (sortName) { | ||
for (let i = 0; i < clones.length; i++) { | ||
if (i > index) { | ||
let previousData = data[data.type][index] | ||
if (operator === 'add') | ||
Data[sortName] = i + 1 | ||
else if (operator === 'remove') | ||
Data[sortName] = i - 1 | ||
if (sortName) { | ||
for (let i = 0; i < clones.length; i++) { | ||
if (i > index) { | ||
let previousData = data[data.type][index]; | ||
if (operator === "add") Data[sortName] = i + 1; | ||
else if (operator === "remove") Data[sortName] = i - 1; | ||
newData[newData.type].push({ ...previousData, ...Data }) | ||
} | ||
} | ||
newData[newData.type].push({ ...previousData, ...Data }); | ||
} | ||
} | ||
} else { | ||
newData[newData.type] = [{ ...data[data.type][index], ...Data }]; | ||
} | ||
} else { | ||
newData[newData.type] = [{ ...data[data.type][index], ...Data }] | ||
} | ||
return { data, newData, keyPath, clones, index } | ||
return { data, newData, keyPath, clones, index }; | ||
} | ||
function dndNewData(element, data) { | ||
let Data = {} | ||
if (data.$filter.query) { | ||
dndNewDataUpdate(Data, data.$filter.query) | ||
} | ||
let Data = {}; | ||
if (data.$filter.query) { | ||
dndNewDataUpdate(Data, data.$filter.query); | ||
} | ||
let sortName, sortDirection | ||
let sort = data.$filter.sort | ||
if (sort && sort.length) { | ||
// for (let i = 0; i < sort.length; i++) { | ||
for (let i = sort.length - 1; i >= 0; i--) { | ||
if (typeof data[sort.key] === 'number') { | ||
sortName = sort.key | ||
sortDirection = sort.direction | ||
break | ||
} | ||
} | ||
} | ||
let sortName, sortDirection; | ||
let sort = data.$filter.sort; | ||
if (sort && sort.length) { | ||
// for (let i = 0; i < sort.length; i++) { | ||
for (let i = sort.length - 1; i >= 0; i--) { | ||
if (typeof data[sort.key] === "number") { | ||
sortName = sort.key; | ||
sortDirection = sort.direction; | ||
break; | ||
} | ||
} | ||
} | ||
let keyPath, clonesMap, clones, index | ||
let keyPath, clonesMap, clones, index; | ||
let renderedNode = renderedNodes.get(element) | ||
if (renderedNode) { | ||
keyPath = renderedNode.keyPath | ||
clonesMap = renderedNode.template.clones | ||
clones = Array.from(clonesMap.values()); | ||
index = clones.indexOf(element); | ||
} | ||
let renderedNode = renderedNodes.get(element); | ||
if (renderedNode) { | ||
keyPath = renderedNode.keyPath; | ||
clonesMap = renderedNode.template.clones; | ||
clones = Array.from(clonesMap.values()); | ||
index = clones.indexOf(element); | ||
} | ||
return { Data, sortName, sortDirection, keyPath, clones, index } | ||
return { Data, sortName, sortDirection, keyPath, clones, index }; | ||
} | ||
function dndNewDataUpdate(Data, query) { | ||
for (let key of Object.keys(query)) { | ||
if (key === '$and' || key === '$or' || key === '$nor') { | ||
for (let i = 0; i < query[key].length; i++) { | ||
dndNewDataUpdate(Data, query[key][i]) | ||
} | ||
} else if (typeof query[key] === 'object' && !Array.isArray(query[key])) { | ||
if (query[key].$eq) | ||
Data[key] = query[key].$eq | ||
if (query[key].$ne) | ||
Data[key] = query[key].$ne | ||
} else { | ||
Data[key] = query[key] | ||
} | ||
} | ||
for (let key of Object.keys(query)) { | ||
if (key === "$and" || key === "$or" || key === "$nor") { | ||
for (let i = 0; i < query[key].length; i++) { | ||
dndNewDataUpdate(Data, query[key][i]); | ||
} | ||
} else if ( | ||
typeof query[key] === "object" && | ||
!Array.isArray(query[key]) | ||
) { | ||
if (query[key].$eq) Data[key] = query[key].$eq; | ||
if (query[key].$ne) Data[key] = query[key].$ne; | ||
} else { | ||
Data[key] = query[key]; | ||
} | ||
} | ||
} | ||
function dndCrudSend(data, crudType) { | ||
if (CRUD) { | ||
let action = data.type; | ||
action = action.charAt(0).toUpperCase() + action.slice(1); | ||
CRUD[crudType + action](data) | ||
} else | ||
console.log('dnd reordered data set as crud is unavailable') | ||
if (CRUD) { | ||
let action = data.type; | ||
action = action.charAt(0).toUpperCase() + action.slice(1); | ||
CRUD[crudType + action](data); | ||
} else console.log("dnd reordered data set as crud is unavailable"); | ||
} | ||
Observer.init({ | ||
name: 'CoCreateElementsChildList', | ||
observe: ['childList'], | ||
selector: selector, | ||
callback: function (mutation) { | ||
init(mutation.addedNodes); | ||
} | ||
name: "CoCreateElementsChildList", | ||
observe: ["childList"], | ||
selector: selector, | ||
callback: function (mutation) { | ||
init(mutation.addedNodes); | ||
} | ||
}); | ||
Observer.init({ | ||
name: 'CoCreateElementsRemovedNodes', | ||
observe: ['removedNodes'], | ||
selector: selector, | ||
callback: function (mutation) { | ||
// if (mutation.target.parentElement) return | ||
// if (mutation.target.parentElement) { | ||
// let delayTimer = setTimeout(function () { | ||
// debounce.delete(mutation.target) | ||
// remove(mutation.target) | ||
// }, 3000); | ||
// debounce.set(mutation.target, delayTimer) | ||
// } else | ||
if (mutation.target.hasAttribute('render-clone')) | ||
return | ||
remove(mutation.target) | ||
} | ||
name: "CoCreateElementsRemovedNodes", | ||
observe: ["removedNodes"], | ||
selector: selector, | ||
callback: function (mutation) { | ||
// if (mutation.target.parentElement) return | ||
// if (mutation.target.parentElement) { | ||
// let delayTimer = setTimeout(function () { | ||
// debounce.delete(mutation.target) | ||
// remove(mutation.target) | ||
// }, 3000); | ||
// debounce.set(mutation.target, delayTimer) | ||
// } else | ||
if (mutation.target.hasAttribute("render-clone")) return; | ||
remove(mutation.target); | ||
} | ||
}); | ||
Observer.init({ | ||
name: 'CoCreateElementsAttributes', | ||
observe: ['attributes'], | ||
attributeName: ['storage', 'database', 'array', 'index', 'object', 'key'], | ||
// target: selector, // blocks mutations when applied | ||
callback: function (mutation) { | ||
let currentValue = mutation.target.getAttribute(mutation.attributeName) | ||
if (currentValue !== mutation.oldValue) { | ||
remove(mutation.target) | ||
if (mutation.target.tagName === 'FORM') | ||
return | ||
init([mutation.target]) | ||
} | ||
} | ||
name: "CoCreateElementsAttributes", | ||
observe: ["attributes"], | ||
attributeName: ["storage", "database", "array", "index", "object", "key"], | ||
// target: selector, // blocks mutations when applied | ||
callback: function (mutation) { | ||
let currentValue = mutation.target.getAttribute(mutation.attributeName); | ||
if (currentValue !== mutation.oldValue) { | ||
remove(mutation.target); | ||
if (mutation.target.tagName === "FORM") return; | ||
init([mutation.target]); | ||
} | ||
} | ||
}); | ||
Actions.init([ | ||
{ | ||
name: "save", | ||
endEvent: "saved", | ||
callback: (action) => { | ||
if (action.form) | ||
save(action.form); | ||
} | ||
}, | ||
{ | ||
name: "delete", | ||
endEvent: "deleted", | ||
callback: async (action) => { | ||
let elements = queryElements({ element: action.element, prefix: 'delete' }); | ||
if (elements === false) | ||
elements = [action.element] | ||
{ | ||
name: "save", | ||
endEvent: "saved", | ||
callback: (action) => { | ||
if (action.form) save(action.form); | ||
} | ||
}, | ||
{ | ||
name: "delete", | ||
endEvent: "deleted", | ||
callback: async (action) => { | ||
let elements = queryElements({ | ||
element: action.element, | ||
prefix: "delete" | ||
}); | ||
if (elements === false) elements = [action.element]; | ||
for (let i = 0; i < elements.length; i++) { | ||
const data = getObject(elements[i]); | ||
if (!data) return | ||
data.method = data.type + '.delete' | ||
for (let i = 0; i < elements.length; i++) { | ||
const data = getObject(elements[i]); | ||
if (!data) return; | ||
data.method = data.type + ".delete"; | ||
if (elements[i].renderValue) { | ||
let selected = elements[i].querySelectorAll('.selected') | ||
data[data.type] = [] | ||
for (let j = 0; j < selected.length; j++) { | ||
let attribute = selected[j].getAttribute(data.type) | ||
if (attribute) { | ||
attribute = attribute.split(',') | ||
for (let k = 0; k < attribute.length; k++) { | ||
if (data.type === 'object') | ||
data[data.type].push({ _id: attribute[k] }) | ||
else { | ||
data[data.type].push(attribute[k]) | ||
} | ||
} | ||
} | ||
} | ||
} else if (data.type === 'object' && typeof data[data.type] === 'string') | ||
data[data.type] = { _id: data[data.type] } | ||
if (elements[i].renderValue) { | ||
let selected = elements[i].querySelectorAll(".selected"); | ||
data[data.type] = []; | ||
for (let j = 0; j < selected.length; j++) { | ||
let attribute = selected[j].getAttribute(data.type); | ||
if (attribute) { | ||
attribute = attribute.split(","); | ||
for (let k = 0; k < attribute.length; k++) { | ||
if (data.type === "object") | ||
data[data.type].push({ _id: attribute[k] }); | ||
else { | ||
data[data.type].push(attribute[k]); | ||
} | ||
} | ||
} | ||
} | ||
} else if ( | ||
data.type === "object" && | ||
typeof data[data.type] === "string" | ||
) | ||
data[data.type] = { _id: data[data.type] }; | ||
let response = await CRUD.send(data) | ||
document.dispatchEvent(new CustomEvent('deleted', { | ||
detail: response | ||
})); | ||
} | ||
} | ||
} | ||
let response = await CRUD.send(data); | ||
document.dispatchEvent( | ||
new CustomEvent("deleted", { | ||
detail: response | ||
}) | ||
); | ||
} | ||
} | ||
} | ||
]); | ||
@@ -1430,2 +1514,15 @@ | ||
export default { init, read, save, getData, getObject, reset, elements, keys, forms, debounce, getAttributes, setTypeValue }; | ||
export default { | ||
init, | ||
read, | ||
save, | ||
getData, | ||
getObject, | ||
reset, | ||
elements, | ||
keys, | ||
forms, | ||
debounce, | ||
getAttributes, | ||
setTypeValue | ||
}; |
Sorry, the diff of this file is too big to display
1873
222812