Frontend updates
This commit is contained in:
parent
c96bdfddb0
commit
8981fec28d
@ -1,109 +1,175 @@
|
|||||||
_wrapperVersion = "1.0.0"
|
_wrapperVersion = '1.0.0';
|
||||||
_minApiVersion = "1.0.0"
|
_minApiVersion = '1.0.0';
|
||||||
_maxApiVersion = "1.0.0"
|
_maxApiVersion = '1.0.0';
|
||||||
|
|
||||||
|
_defaultTTL = 60000;
|
||||||
|
|
||||||
_apiConfig = {
|
_apiConfig = {
|
||||||
"basePath": "/api/v1/"
|
basePath: '/api/v1/'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!window.localStorage) {
|
||||||
|
console.warn('Local Storage is not available, some features may not work');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic driver functions
|
// Generic driver functions
|
||||||
let _api = {
|
let _api = {
|
||||||
"get": async function(path) {
|
get: async function (path) {
|
||||||
const options = {
|
const options = {
|
||||||
headers: new Headers({'content-type': 'application/json'})
|
headers: new Headers({ 'content-type': 'application/json' })
|
||||||
};
|
};
|
||||||
const response = await fetch(_apiConfig.basePath + path, options)
|
const response = await fetch(_apiConfig.basePath + path, options);
|
||||||
// Handle the response
|
// Handle the response
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
_testPageFail(response.statusText)
|
_testPageFail(response.statusText);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const result = await response.json()
|
const result = await response.json();
|
||||||
// Handle the result, was json valid?
|
// Handle the result, was json valid?
|
||||||
if (!result) {
|
if (!result) {
|
||||||
_testPageFail("Invalid JSON response")
|
_testPageFail('Invalid JSON response');
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
"post": async function(path, data) {
|
post: async function (path, data) {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: new Headers({'content-type': 'application/json'}),
|
headers: new Headers({ 'content-type': 'application/json' }),
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
};
|
};
|
||||||
const response = await fetch(_apiConfig.basePath + path, options)
|
const response = await fetch(_apiConfig.basePath + path, options);
|
||||||
// Handle the response
|
// Handle the response
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
_testPageFail(response.statusText)
|
_testPageFail(response.statusText);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const result = await response.json()
|
const result = await response.json();
|
||||||
// Handle the result, was json valid?
|
// Handle the result, was json valid?
|
||||||
if (!result) {
|
if (!result) {
|
||||||
_testPageFail("Invalid JSON response")
|
_testPageFail('Invalid JSON response');
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
"getAsync": function(path, callback) {
|
getAsync: function (path, callback) {
|
||||||
const options = {
|
const options = {
|
||||||
headers: new Headers({'content-type': 'application/json'})
|
headers: new Headers({ 'content-type': 'application/json' })
|
||||||
};
|
};
|
||||||
fetch(_apiConfig.basePath + path, options).then(response => response.json()).then(data => callback(data)).catch(error => _testPageFail(error))
|
fetch(_apiConfig.basePath + path, options)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => callback(data))
|
||||||
|
.catch((error) => _testPageFail(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getApiDescriptionByTable(tableName) {
|
||||||
|
const keyDesc = `desc:${tableName}`;
|
||||||
|
const keyTime = `${keyDesc}:time`;
|
||||||
|
const keyTTL = `${keyDesc}:ttl`;
|
||||||
|
|
||||||
|
// Retrieve cached data
|
||||||
|
const description = JSON.parse(localStorage.getItem(keyDesc));
|
||||||
|
const timeCreated = parseInt(localStorage.getItem(keyTime));
|
||||||
|
const ttl = parseInt(localStorage.getItem(keyTTL));
|
||||||
|
|
||||||
|
// Check if valid cached data exists
|
||||||
|
if (description && timeCreated && ttl) {
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const age = currentTime - parseInt(timeCreated, 10);
|
||||||
|
if (age < parseInt(ttl, 10)) {
|
||||||
|
// Return cached data immediately
|
||||||
|
return Promise.resolve(description);
|
||||||
|
} else {
|
||||||
|
console.warn('Cached description expired; fetching new data');
|
||||||
|
// Fetch new data, update cache, and return it
|
||||||
|
return fetchAndUpdateCache(tableName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('No cached description; fetching from server');
|
||||||
|
// Fetch data, update cache, and return it
|
||||||
|
return fetchAndUpdateCache(tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchAndUpdateCache(tableName) {
|
||||||
|
return _api
|
||||||
|
.get(`${tableName}/describe`)
|
||||||
|
.then((data) => {
|
||||||
|
if (data) {
|
||||||
|
// Update local storage with new data
|
||||||
|
localStorage.setItem(keyDesc, JSON.stringify(data));
|
||||||
|
localStorage.setItem(keyTime, Date.now().toString());
|
||||||
|
localStorage.setItem(keyTTL, '60000'); // 60 seconds TTL
|
||||||
|
}
|
||||||
|
return data; // Return the fetched data
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to fetch description:', error);
|
||||||
|
// Fallback to cached data if available (even if expired)
|
||||||
|
return description || null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function returnTableDataByTableName(tableName) {
|
function returnTableDataByTableName(tableName) {
|
||||||
return _api.get(tableName)
|
return _api.get(tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function returnTableDataByTableNameWithSearch(tableName, search) {
|
function returnTableDataByTableNameWithSearch(tableName, search) {
|
||||||
return _api.get(tableName + "?search=" + search)
|
return _api.get(tableName + '?search=' + search);
|
||||||
}
|
}
|
||||||
|
|
||||||
function returnTableDataByTableNameAsync(tableName, callback) {
|
function returnTableDataByTableNameAsync(tableName, callback) {
|
||||||
_api.getAsync(tableName, callback)
|
_api.getAsync(tableName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCountByTable(tableName) {
|
async function getCountByTable(tableName) {
|
||||||
let result = await(_api.get(tableName + "?count"))
|
// Stored in `data:count:${tableName}`
|
||||||
if(typeof result !== 'number') {
|
let result = await _api.get(tableName + '?count=true');
|
||||||
_testPageWarn("Count was not a number, was: " + result)
|
if (typeof result !== 'number') {
|
||||||
console.warn("Count was not a number, was: " + result)
|
_testPageWarn('Count was not a number, was: ' + result);
|
||||||
return -1
|
console.warn('Count was not a number, was: ' + result);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRowsByTableAndColumnList(tableName, columnList) {
|
function getRowsByTableAndColumnList(tableName, columnList) {
|
||||||
//return _api.get(tableName + '/rows/' + columnList.join(','))
|
//return _api.get(tableName + '/rows/' + columnList.join(','))
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _testPageFail(reason) {
|
function _testPageFail(reason) {
|
||||||
document.getElementById("heroStatus").classList.remove("is-success")
|
document.getElementById('heroStatus').classList.remove('is-success');
|
||||||
document.getElementById("heroStatus").classList.add("is-danger")
|
document.getElementById('heroStatus').classList.add('is-danger');
|
||||||
|
|
||||||
document.getElementById("heroExplainer").innerHTML = "API Wrapper Test Failed, reason: " + reason
|
document.getElementById('heroExplainer').innerHTML = 'API Wrapper Test Failed, reason: ' + reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _testPageWarn(reason) {
|
function _testPageWarn(reason) {
|
||||||
document.getElementById("heroStatus").classList.remove("is-success")
|
document.getElementById('heroStatus').classList.remove('is-success');
|
||||||
document.getElementById("heroStatus").classList.add("is-warning")
|
document.getElementById('heroStatus').classList.add('is-warning');
|
||||||
|
|
||||||
document.getElementById("heroExplainer").innerHTML = "API Wrapper Test Warning, reason: " + reason
|
document.getElementById('heroExplainer').innerHTML = 'API Wrapper Test Warning, reason: ' + reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServerVersion() {
|
function getServerVersion() {
|
||||||
return _api.get('version')
|
return _api.get('version');
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEntry(tableName, data) {
|
function createEntry(tableName, data) {
|
||||||
return _api.post(tableName, data)
|
invalidateCache(tableName);
|
||||||
|
return _api.post(tableName, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function invalidateCache(tableName) {
|
||||||
|
const keyDesc = `desc:${tableName}`;
|
||||||
|
const keyTime = `${keyDesc}:time`;
|
||||||
|
const keyTTL = `${keyDesc}:ttl`;
|
||||||
|
|
||||||
|
localStorage.removeItem(keyDesc);
|
||||||
|
localStorage.removeItem(keyTime);
|
||||||
|
localStorage.removeItem(keyTTL);
|
||||||
|
}
|
||||||
|
@ -1,55 +1,55 @@
|
|||||||
_pageDriverVersion = "1.0.1";
|
_pageDriverVersion = '1.0.1';
|
||||||
|
|
||||||
// Handle color for icon svg with id="logo" based on the current theme
|
// Handle color for icon svg with id="logo" based on the current theme
|
||||||
const logo = document.getElementById("logo");
|
const logo = document.getElementById('logo');
|
||||||
if(logo) {
|
if (logo) {
|
||||||
logo.style.fill = getComputedStyle(document.documentElement).getPropertyValue("--bulma-text");
|
logo.style.fill = getComputedStyle(document.documentElement).getPropertyValue('--bulma-text');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_wrapperVersion === undefined) {
|
if (_wrapperVersion === undefined) {
|
||||||
console.error("API Wrapper not found; Please include the API Wrapper before including the Page Driver");
|
console.error('API Wrapper not found; Please include the API Wrapper before including the Page Driver');
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
console.log("API Wrapper found; Page Driver is ready to use");
|
console.log('API Wrapper found; Page Driver is ready to use');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all tables on the page which have data-dataSource attribute
|
// Find all tables on the page which have data-dataSource attribute
|
||||||
var tables = document.querySelectorAll("table[data-dataSource]");
|
var tables = document.querySelectorAll('table[data-dataSource]');
|
||||||
//var tables = []
|
//var tables = []
|
||||||
|
|
||||||
// Get all single values with data-dataSource, data-dataCol and data-dataAction
|
// Get all single values with data-dataSource, data-dataCol and data-dataAction
|
||||||
var singleValues = document.querySelectorAll("span[data-dataSource]");
|
var singleValues = document.querySelectorAll('span[data-dataSource]');
|
||||||
|
|
||||||
// Find all search fields with data-searchTargetId
|
// Find all search fields with data-searchTargetId
|
||||||
var searchFields = document.querySelectorAll("input[data-searchTargetId]");
|
var searchFields = document.querySelectorAll('input[data-searchTargetId]');
|
||||||
|
|
||||||
// Find all modalForms
|
// Find all modalForms
|
||||||
var modalForms = document.querySelectorAll("form[data-targetTable]");
|
var modalForms = document.querySelectorAll('form[data-targetTable]');
|
||||||
|
|
||||||
// Iterate over all tables
|
// Iterate over all tables
|
||||||
tables.forEach(async table => {
|
tables.forEach(async (table) => {
|
||||||
console.log("Table found: ", table);
|
console.log('Table found: ', table);
|
||||||
// Get THEAD and TBODY elements
|
// Get THEAD and TBODY elements
|
||||||
const thead = table.querySelector("thead");
|
const thead = table.querySelector('thead');
|
||||||
const tbody = table.querySelector("tbody");
|
const tbody = table.querySelector('tbody');
|
||||||
|
|
||||||
// get index per column
|
// get index per column
|
||||||
const columns = thead.querySelectorAll("th");
|
const columns = thead.querySelectorAll('th');
|
||||||
const columnIndices = [];
|
const columnIndices = [];
|
||||||
columns.forEach((column, index) => {
|
columns.forEach((column, index) => {
|
||||||
columnIndices[column.getAttribute("data-dataCol")] = index;
|
columnIndices[column.getAttribute('data-dataCol')] = index;
|
||||||
});
|
});
|
||||||
|
|
||||||
// All required cols
|
// All required cols
|
||||||
let requiredCols = [];
|
let requiredCols = [];
|
||||||
columns.forEach(column => {
|
columns.forEach((column) => {
|
||||||
requiredCols.push(column.getAttribute("data-dataCol"));
|
requiredCols.push(column.getAttribute('data-dataCol'));
|
||||||
});
|
});
|
||||||
console.log("Required columns: ", requiredCols);
|
console.log('Required columns: ', requiredCols);
|
||||||
|
|
||||||
// Get data from API
|
// Get data from API
|
||||||
//let result = getRowsByTableAndColumnList(table.getAttribute("data-dataSource"), requiredCols);
|
//let result = getRowsByTableAndColumnList(table.getAttribute("data-dataSource"), requiredCols);
|
||||||
let result = await returnTableDataByTableName(table.getAttribute("data-dataSource"))
|
let result = await returnTableDataByTableName(table.getAttribute('data-dataSource'));
|
||||||
// for (resultIndex in result) {
|
// for (resultIndex in result) {
|
||||||
// const row = result[resultIndex];
|
// const row = result[resultIndex];
|
||||||
// const tr = document.createElement("tr");
|
// const tr = document.createElement("tr");
|
||||||
@ -62,114 +62,186 @@ tables.forEach(async table => {
|
|||||||
// }
|
// }
|
||||||
writeDataToTable(table, result);
|
writeDataToTable(table, result);
|
||||||
|
|
||||||
console.log("Column indices: ", columnIndices);
|
console.log('Column indices: ', columnIndices);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.info("Processing single values");
|
console.info('Processing single values');
|
||||||
console.info(singleValues);
|
console.info(singleValues);
|
||||||
|
|
||||||
// Iterate over all single values
|
// Iterate over all single values
|
||||||
singleValues.forEach(async singleValue => {
|
singleValues.forEach(async (singleValue) => {
|
||||||
writeSingelton(singleValue);
|
writeSingelton(singleValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function writeSingelton(element) {
|
async function writeSingelton(element) {
|
||||||
const table = element.getAttribute("data-dataSource");
|
const table = element.getAttribute('data-dataSource');
|
||||||
console.log("Table: ", table, " Action: ", element.getAttribute("data-dataAction"), " Element: ", element);
|
console.log('Table: ', table, ' Action: ', element.getAttribute('data-dataAction'), ' Element: ', element);
|
||||||
switch(element.getAttribute("data-dataAction")) {
|
switch (element.getAttribute('data-dataAction')) {
|
||||||
case "COUNT": {
|
case 'COUNT': {
|
||||||
console.log("Count action found");
|
console.log('Count action found');
|
||||||
element.innerHTML = (await getCountByTable(table))
|
element.innerHTML = await getCountByTable(table);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "SPECIAL": {
|
case 'SPECIAL': {
|
||||||
if(table == "version") {
|
if (table == 'version') {
|
||||||
element.innerHTML = (await getServerVersion())["version"];
|
element.innerHTML = (await getServerVersion())['version'];
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
console.error("Unknown action found: ", element.getAttribute("data-dataAction"));
|
console.error('Unknown action found: ', element.getAttribute('data-dataAction'));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
element.classList.remove("is-skeleton");
|
element.classList.remove('is-skeleton');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Attach listeners to search fields
|
// Attach listeners to search fields
|
||||||
searchFields.forEach(searchField => {
|
searchFields.forEach((searchField) => {
|
||||||
searchField.addEventListener("input", async function() {
|
// Apply restrictions to search field (min, max, chars, etc)
|
||||||
console.log("Search field changed: ", searchField);
|
|
||||||
const targetId = searchField.getAttribute("data-searchTargetId");
|
getApiDescriptionByTable(document.getElementById(searchField.getAttribute('data-searchTargetId')).getAttribute('data-dataSource')).then((desc) => {
|
||||||
const target = document.getElementById(targetId);
|
desc = desc['GET']['keys']['search'];
|
||||||
const table = target.getAttribute("data-dataSource");
|
var rules = desc['rules'];
|
||||||
const column = target.getAttribute("data-dataCol");
|
rules.forEach((rule) => {
|
||||||
const value = searchField.value;
|
switch (rule['name']) {
|
||||||
console.log("Searching for ", value, " in ", table, " column ", column);
|
case 'min': {
|
||||||
const result = await returnTableDataByTableNameWithSearch(table, value);
|
searchField.setAttribute('minlength', rule['args']['limit']);
|
||||||
console.log("Result: ", result);
|
break;
|
||||||
clearTable(target);
|
}
|
||||||
writeDataToTable(target, result);
|
case 'max': {
|
||||||
|
searchField.setAttribute('maxlength', rule['args']['limit']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
searchField.addEventListener('input', async function () {
|
||||||
|
console.log('Search field changed: ', searchField);
|
||||||
|
if (searchField.checkValidity() == false) {
|
||||||
|
console.log('Invalid input');
|
||||||
|
searchField.classList.add('is-danger');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
searchField.classList.remove('is-danger');
|
||||||
|
const targetId = searchField.getAttribute('data-searchTargetId');
|
||||||
|
const target = document.getElementById(targetId);
|
||||||
|
const table = target.getAttribute('data-dataSource');
|
||||||
|
const column = target.getAttribute('data-dataCol');
|
||||||
|
const value = searchField.value;
|
||||||
|
console.log('Searching for ', value, ' in ', table, ' column ', column);
|
||||||
|
//const result = await returnTableDataByTableNameWithSearch(table, value);
|
||||||
|
//clearTable(target);
|
||||||
|
//writeDataToTable(target, result);
|
||||||
|
refreshTableByName(table);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Attach listeners to modal forms
|
// Attach listeners to modal forms
|
||||||
modalForms.forEach(modalForm => {
|
modalForms.forEach((modalForm) => {
|
||||||
modalForm.addEventListener("submit", async function(event) {
|
// Add validation to form by using API description (everything is assumed POST for now)
|
||||||
|
modalForm.addEventListener('input', async function (event) {
|
||||||
|
if (event.target.checkValidity() == false) {
|
||||||
|
modalForm.querySelector("input[type='submit']").setAttribute('disabled', true);
|
||||||
|
event.target.classList.add('is-danger');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
modalForm.querySelector("input[type='submit']").removeAttribute('disabled');
|
||||||
|
event.target.classList.remove('is-danger');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
getApiDescriptionByTable(modalForm.getAttribute('data-targetTable')).then((desc) => {
|
||||||
|
console.log('Description: ', desc);
|
||||||
|
const keys = desc['POST']['keys'];
|
||||||
|
// Apply resitrictions and types to form fields
|
||||||
|
for (key in keys) {
|
||||||
|
const field = modalForm.querySelector("input[name='" + key + "']");
|
||||||
|
if (field) {
|
||||||
|
const rules = keys[key]['rules'];
|
||||||
|
const flags = keys[key]['flags'];
|
||||||
|
console.log('Field: ', field, ' Rules: ', rules, ' Flags: ', flags);
|
||||||
|
rules.forEach((rule) => {
|
||||||
|
switch (rule['name']) {
|
||||||
|
case 'min': {
|
||||||
|
field.setAttribute('minlength', rule['args']['limit']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'max': {
|
||||||
|
field.setAttribute('maxlength', rule['args']['limit']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'pattern': {
|
||||||
|
field.setAttribute('pattern', rule['args']['regex'].substring(1, rule['args']['regex'].length - 1));
|
||||||
|
//field.setAttribute("pattern", "^[\\+]?[\\(]?[0-9]{3}[\\)]?[\\-\\s\\.]?[0-9]{3}[\\-\\s\\.]?[0-9]{4,9}$");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'type': {
|
||||||
|
//field.setAttribute("type", rule["args"]["type"]);
|
||||||
|
console.log('Type: ', rule['args']['type']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (flags) {
|
||||||
|
flags['presence'] == 'required' ? field.setAttribute('required', true) : field.removeAttribute('required');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('Keys: ', keys);
|
||||||
|
});
|
||||||
|
|
||||||
|
modalForm.addEventListener('submit', async function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
// Check what button submitted the form and if it has data-actionBtn = save
|
// Check what button submitted the form and if it has data-actionBtn = save
|
||||||
// If not, close modal
|
// If not, close modal
|
||||||
const pressedBtn = event.submitter;
|
const pressedBtn = event.submitter;
|
||||||
if(pressedBtn.getAttribute("data-actionBtn") != "save") {
|
if (pressedBtn.getAttribute('data-actionBtn') != 'save') {
|
||||||
modalForm.closest(".modal").classList.remove('is-active');
|
modalForm.closest('.modal').classList.remove('is-active');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Find .entryPhase and hide it
|
// Find .entryPhase and hide it
|
||||||
const entryPhase = modalForm.querySelector(".entryPhase");
|
const entryPhase = modalForm.querySelector('.entryPhase');
|
||||||
const loadPhase = modalForm.querySelector(".loadPhase");
|
const loadPhase = modalForm.querySelector('.loadPhase');
|
||||||
if(entryPhase) {
|
if (entryPhase) {
|
||||||
entryPhase.classList.add("is-hidden");
|
entryPhase.classList.add('is-hidden');
|
||||||
}
|
}
|
||||||
if(loadPhase) {
|
if (loadPhase) {
|
||||||
loadPhase.classList.remove("is-hidden");
|
loadPhase.classList.remove('is-hidden');
|
||||||
}
|
}
|
||||||
console.log("Form submitted: ", modalForm);
|
console.log('Form submitted: ', modalForm);
|
||||||
const table = modalForm.getAttribute("data-targetTable");
|
const table = modalForm.getAttribute('data-targetTable');
|
||||||
const data = new FormData(modalForm);
|
const data = new FormData(modalForm);
|
||||||
// Convert to JSON object
|
// Convert to JSON object
|
||||||
let jsonData = {};
|
let jsonData = {};
|
||||||
data.forEach((value, key) => {
|
data.forEach((value, key) => {
|
||||||
jsonData[key] = value;
|
jsonData[key] = value;
|
||||||
});
|
});
|
||||||
console.log("JSON Data: ", jsonData);
|
console.log('JSON Data: ', jsonData);
|
||||||
let resp = await createEntry(table, jsonData);
|
let resp = await createEntry(table, jsonData);
|
||||||
console.log("Response: ", resp);
|
console.log('Response: ', resp);
|
||||||
if(resp["status"] == "CREATED") {
|
if (resp['status'] == 'CREATED') {
|
||||||
console.log("Entry created successfully");
|
console.log('Entry created successfully');
|
||||||
modalForm.closest(".modal").classList.remove('is-active');
|
modalForm.closest('.modal').classList.remove('is-active');
|
||||||
modalForm.reset();
|
modalForm.reset();
|
||||||
// Hide loadPhase
|
// Hide loadPhase
|
||||||
if(loadPhase) {
|
if (loadPhase) {
|
||||||
loadPhase.classList.add("is-hidden");
|
loadPhase.classList.add('is-hidden');
|
||||||
}
|
}
|
||||||
// Show entryPhase
|
// Show entryPhase
|
||||||
if(entryPhase) {
|
if (entryPhase) {
|
||||||
entryPhase.classList.remove("is-hidden");
|
entryPhase.classList.remove('is-hidden');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Hide loadPhase
|
// Hide loadPhase
|
||||||
if(loadPhase) {
|
if (loadPhase) {
|
||||||
loadPhase.classList.add("is-hidden");
|
loadPhase.classList.add('is-hidden');
|
||||||
}
|
}
|
||||||
// Show entryPhase
|
// Show entryPhase
|
||||||
if(entryPhase) {
|
if (entryPhase) {
|
||||||
entryPhase.classList.remove("is-hidden");
|
entryPhase.classList.remove('is-hidden');
|
||||||
}
|
}
|
||||||
// TODO: Show error message
|
// TODO: Show error message
|
||||||
}
|
}
|
||||||
@ -177,8 +249,6 @@ modalForms.forEach(modalForm => {
|
|||||||
// const target = document.getElementById(table);
|
// const target = document.getElementById(table);
|
||||||
// writeDataToTable(target, result);
|
// writeDataToTable(target, result);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Find all tables with data-searchTargetId set to table
|
// Find all tables with data-searchTargetId set to table
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
refreshTableByName(table);
|
refreshTableByName(table);
|
||||||
@ -191,14 +261,14 @@ modalForms.forEach(modalForm => {
|
|||||||
async function refreshTable(table) {
|
async function refreshTable(table) {
|
||||||
// Refresh a table while keeping (optionally set) search value
|
// Refresh a table while keeping (optionally set) search value
|
||||||
const searchField = document.querySelector("input[data-searchTargetId='" + table.id + "']");
|
const searchField = document.querySelector("input[data-searchTargetId='" + table.id + "']");
|
||||||
if(searchField) {
|
if (searchField && searchField.value != '') {
|
||||||
const value = searchField.value;
|
const value = searchField.value;
|
||||||
const dbTable = table.getAttribute("data-dataSource");
|
const dbTable = table.getAttribute('data-dataSource');
|
||||||
const result = await returnTableDataByTableNameWithSearch(dbTable, value);
|
const result = await returnTableDataByTableNameWithSearch(dbTable, value);
|
||||||
clearTable(table);
|
clearTable(table);
|
||||||
writeDataToTable(table, result);
|
writeDataToTable(table, result);
|
||||||
} else {
|
} else {
|
||||||
const result = await returnTableDataByTableName(table.getAttribute("data-dataSource"));
|
const result = await returnTableDataByTableName(table.getAttribute('data-dataSource'));
|
||||||
clearTable(table);
|
clearTable(table);
|
||||||
writeDataToTable(table, result);
|
writeDataToTable(table, result);
|
||||||
}
|
}
|
||||||
@ -206,48 +276,47 @@ async function refreshTable(table) {
|
|||||||
|
|
||||||
async function refreshTableByName(name) {
|
async function refreshTableByName(name) {
|
||||||
const dirtyTables = document.querySelectorAll("table[data-dataSource='" + name + "']");
|
const dirtyTables = document.querySelectorAll("table[data-dataSource='" + name + "']");
|
||||||
for(dirty of dirtyTables) {
|
for (dirty of dirtyTables) {
|
||||||
refreshTable(dirty);
|
refreshTable(dirty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateSingeltonsByTableName(name) {
|
async function updateSingeltonsByTableName(name) {
|
||||||
const dirtySingles = document.querySelectorAll("span[data-dataSource='" + name + "']");
|
const dirtySingles = document.querySelectorAll("span[data-dataSource='" + name + "']");
|
||||||
for(dirty of dirtySingles) {
|
for (dirty of dirtySingles) {
|
||||||
writeSingelton(dirty);
|
writeSingelton(dirty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function clearTable(table) {
|
function clearTable(table) {
|
||||||
const tbody = table.querySelector("tbody");
|
const tbody = table.querySelector('tbody');
|
||||||
tbody.innerHTML = "";
|
tbody.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeDataToTable(table, data) {
|
function writeDataToTable(table, data) {
|
||||||
console.log("Writing data to table: ", table, data);
|
console.log('Writing data to table: ', table, data);
|
||||||
// Get THEAD and TBODY elements
|
// Get THEAD and TBODY elements
|
||||||
const thead = table.querySelector("thead");
|
const thead = table.querySelector('thead');
|
||||||
const tbody = table.querySelector("tbody");
|
const tbody = table.querySelector('tbody');
|
||||||
|
|
||||||
// get index per column
|
// get index per column
|
||||||
const columns = thead.querySelectorAll("th");
|
const columns = thead.querySelectorAll('th');
|
||||||
const columnIndices = [];
|
const columnIndices = [];
|
||||||
columns.forEach((column, index) => {
|
columns.forEach((column, index) => {
|
||||||
columnIndices[column.getAttribute("data-dataCol")] = index;
|
columnIndices[column.getAttribute('data-dataCol')] = index;
|
||||||
});
|
});
|
||||||
|
|
||||||
// All required cols
|
// All required cols
|
||||||
let requiredCols = [];
|
let requiredCols = [];
|
||||||
columns.forEach(column => {
|
columns.forEach((column) => {
|
||||||
requiredCols.push(column.getAttribute("data-dataCol"));
|
requiredCols.push(column.getAttribute('data-dataCol'));
|
||||||
});
|
});
|
||||||
|
|
||||||
for (resultIndex in data) {
|
for (resultIndex in data) {
|
||||||
const row = data[resultIndex];
|
const row = data[resultIndex];
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement('tr');
|
||||||
requiredCols.forEach(column => {
|
requiredCols.forEach((column) => {
|
||||||
const td = document.createElement("td");
|
const td = document.createElement('td');
|
||||||
td.innerHTML = row[column];
|
td.innerHTML = row[column];
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
@ -255,47 +324,46 @@ function writeDataToTable(table, data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Handle modal
|
// Handle modal
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
// Functions to open and close a modal
|
// Functions to open and close a modal
|
||||||
function openModal($el) {
|
function openModal($el) {
|
||||||
$el.classList.add('is-active');
|
$el.classList.add('is-active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeModal($el) {
|
function closeModal($el) {
|
||||||
$el.classList.remove('is-active');
|
$el.classList.remove('is-active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeAllModals() {
|
function closeAllModals() {
|
||||||
(document.querySelectorAll('.modal') || []).forEach(($modal) => {
|
(document.querySelectorAll('.modal') || []).forEach(($modal) => {
|
||||||
closeModal($modal);
|
closeModal($modal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a click event on buttons to open a specific modal
|
// Add a click event on buttons to open a specific modal
|
||||||
(document.querySelectorAll('.js-modal-trigger') || []).forEach(($trigger) => {
|
(document.querySelectorAll('.js-modal-trigger') || []).forEach(($trigger) => {
|
||||||
const modal = $trigger.dataset.target;
|
const modal = $trigger.dataset.target;
|
||||||
const $target = document.getElementById(modal);
|
const $target = document.getElementById(modal);
|
||||||
|
|
||||||
$trigger.addEventListener('click', () => {
|
$trigger.addEventListener('click', () => {
|
||||||
openModal($target);
|
openModal($target);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a click event on various child elements to close the parent modal
|
// Add a click event on various child elements to close the parent modal
|
||||||
(document.querySelectorAll('.modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button') || []).forEach(($close) => {
|
(document.querySelectorAll('.modal-close, .modal-card-head .delete, .modal-card-foot .button') || []).forEach(($close) => {
|
||||||
const $target = $close.closest('.modal');
|
const $target = $close.closest('.modal');
|
||||||
|
|
||||||
$close.addEventListener('click', () => {
|
$close.addEventListener('click', () => {
|
||||||
closeModal($target);
|
closeModal($target);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a keyboard event to close all modals
|
// Add a keyboard event to close all modals
|
||||||
document.addEventListener('keydown', (event) => {
|
document.addEventListener('keydown', (event) => {
|
||||||
if(event.key === "Escape") {
|
if (event.key === 'Escape') {
|
||||||
closeAllModals();
|
closeAllModals();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -42,60 +42,61 @@
|
|||||||
|
|
||||||
<i class="bi bi-arrow-clockwise title"></i>
|
<i class="bi bi-arrow-clockwise title"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="box entryPhase">
|
<div class="box entryPhase">
|
||||||
<h2 class="title">New Contact</h1>
|
<h2 class="title">New Contact</h1>
|
||||||
<form data-targetTable="AlertContacts">
|
<form data-targetTable="AlertContacts">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Name</label>
|
<label class="label">Name</label>
|
||||||
<div class="control has-icons-left">
|
<div class="control has-icons-left">
|
||||||
<input class="input" type="text" placeholder="John Doe" value="" name="name">
|
<input class="input" type="text" placeholder="John Doe" value="" name="name">
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
<i class="bi bi-file-earmark-person-fill"></i>
|
<i class="bi bi-file-earmark-person-fill"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Telephone</label>
|
<label class="label">Telephone</label>
|
||||||
<div class="control has-icons-left">
|
<div class="control has-icons-left">
|
||||||
<input class="input" type="text" placeholder="+49 1234 5678912" value="" name="phone">
|
<input class="input" type="text" placeholder="+49 1234 5678912" value="" name="phone">
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
<i class="bi bi-telephone-fill"></i>
|
<i class="bi bi-telephone-fill"></i>
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Comment</label>
|
<label class="label">Comment</label>
|
||||||
<div class="control has-icons-left">
|
<div class="control has-icons-left">
|
||||||
<input class="input" type="text" placeholder="" value="" name="comment">
|
<input class="input" type="text" placeholder="" value="" name="comment">
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
<i class="bi bi-chat-fill"></i>
|
<i class="bi bi-chat-fill"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input type="submit" class="button is-link" value="Save" data-actionBtn="save">
|
<input type="submit" class="button is-link" value="Save" data-actionBtn="save">
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<!--<div class="control">
|
||||||
<button class="button is-link is-light" data-actionBtn="cancel">Cancel</button>
|
<button type="button" class="button is-link is-light" data-actionBtn="cancel">Cancel</button>
|
||||||
|
</div>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="modal-close is-large" aria-label="close"></button>
|
<button class="modal-close is-large" aria-label="close"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<button class="js-modal-trigger button" data-target="modal-js-example">
|
<button class="js-modal-trigger button" data-target="modal-js-example">
|
||||||
Create new Contact
|
Create new Contact
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<h1 class="title" data-tK="start-recent-header">Alarm Kontakte</h1>
|
<h1 class="title" data-tK="start-recent-header">Alarm Kontakte</h1>
|
||||||
|
Loading…
Reference in New Issue
Block a user