mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
⚙ Settings rework
This commit is contained in:
@@ -124,8 +124,10 @@ function cacheSettings()
|
||||
settingsData.forEach((set) => {
|
||||
|
||||
resolvedOptions = createArray(set.Options)
|
||||
resolvedOptionsOld = resolvedOptions
|
||||
setPlugObj = {};
|
||||
options_params = [];
|
||||
resolved = ""
|
||||
|
||||
// proceed only if first option item contains something to resolve
|
||||
if( !set.Code_Name.includes("__metadata") &&
|
||||
@@ -158,7 +160,12 @@ function cacheSettings()
|
||||
}
|
||||
}
|
||||
|
||||
console.log(resolved);
|
||||
console.log(resolvedOptionsOld);
|
||||
console.log(resolvedOptions);
|
||||
|
||||
setCache(`pia_set_${set.Code_Name}`, set.Value)
|
||||
|
||||
setCache(`pia_set_opt_${set.Code_Name}`, resolvedOptions)
|
||||
});
|
||||
}).then(() => handleSuccess('cacheSettings', resolve())).catch(() => handleFailure('cacheSettings', reject("cacheSettings already completed"))); // handle AJAX synchronization
|
||||
@@ -179,6 +186,7 @@ function getSettingOptions (key) {
|
||||
if (result == "")
|
||||
{
|
||||
console.log(`Setting options with key "${key}" not found`)
|
||||
result = []
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -743,10 +751,14 @@ function isRandomMAC(mac)
|
||||
// ---------------------------------------------------------
|
||||
// Generate an array object from a string representation of an array
|
||||
function createArray(input) {
|
||||
// Is already array, return
|
||||
if (Array.isArray(input)) {
|
||||
return input;
|
||||
}
|
||||
// Empty array
|
||||
if (input === '[]') {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Regex pattern for brackets
|
||||
const patternBrackets = /(^\s*\[)|(\]\s*$)/g;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// --------------------------------------------------
|
||||
// Read data and place intotarget location, callback processies the results
|
||||
function readData(sqlQuery, processDataCallback, valuesArray, targetLocation, targetField, nameTransformer) {
|
||||
|
||||
var apiUrl = `php/server/dbHelper.php?action=read&rawSql=${encodeURIComponent(sqlQuery)}`;
|
||||
$.get(apiUrl, function(data) {
|
||||
// Process the JSON data using the provided callback function
|
||||
|
||||
@@ -201,6 +201,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Utility function to check if the value is already Base64
|
||||
function isBase64(value) {
|
||||
const base64Regex = /^(?:[A-Za-z0-9+\/]{4})*?(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/;
|
||||
return base64Regex.test(value);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Validation
|
||||
// -------------------------------------------------------------------
|
||||
@@ -245,35 +252,37 @@ function settingsCollectedCorrectly(settingsArray, settingsJSON_DB) {
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Add item to list
|
||||
function addList(element, clearInput = true)
|
||||
{
|
||||
|
||||
const fromId = $(element).attr('my-input-from');
|
||||
const toId = $(element).attr('my-input-to');
|
||||
const toId = $(element).attr('my-input-to');
|
||||
|
||||
const input = $(`#${fromId}`).val();
|
||||
|
||||
console.log(`fromId | toId | input : ${fromId} | ${toId} | ${input}`);
|
||||
|
||||
const newOption = $("<option class='interactable-option'></option>").attr("value", input).text(input);
|
||||
|
||||
|
||||
input = $(`#${fromId}`).val();
|
||||
|
||||
console.log(input);
|
||||
console.log(toId);
|
||||
console.log($(`#${toId}`));
|
||||
|
||||
$(`#${toId}`).append($("<option ></option>").attr("value", input).text(input));
|
||||
const el = $(`#${toId}`).append(newOption);
|
||||
|
||||
// clear input
|
||||
if (clearInput)
|
||||
{
|
||||
$(`#${fromId}`).val("");
|
||||
}
|
||||
|
||||
// Initialize interaction options only for the newly added option
|
||||
initListInteractionOptions(newOption);
|
||||
|
||||
settingsChanged();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
function removeFromList(element)
|
||||
{
|
||||
settingsChanged();
|
||||
$(`#${$(element).attr('my-input')}`).find("option:last").remove();
|
||||
$(`#${$(element).attr('my-input-to')}`).find("option:last").remove();
|
||||
|
||||
}
|
||||
// ---------------------------------------------------------
|
||||
@@ -320,7 +329,7 @@ function removeOptionItem(option) {
|
||||
function removeAllOptions(element)
|
||||
{
|
||||
settingsChanged();
|
||||
$(`#${$(element).attr('my-input')}`).empty();
|
||||
$(`#${$(element).attr('my-input-to')}`).empty();
|
||||
|
||||
}
|
||||
|
||||
@@ -331,12 +340,14 @@ function removeAllOptions(element)
|
||||
let clickCounter = 0;
|
||||
|
||||
// Function to initialize list interaction options
|
||||
function initListInteractionOptions(selectorId) {
|
||||
// Select all options within the specified selector
|
||||
const $options = $(`#${selectorId} option`);
|
||||
|
||||
// Add class to make options interactable
|
||||
$options.addClass('interactable-option');
|
||||
function initListInteractionOptions(element) {
|
||||
if(element)
|
||||
{
|
||||
$options = $(element);
|
||||
} else
|
||||
{
|
||||
$options = $(`.interactable-option`);
|
||||
}
|
||||
|
||||
// Attach click event listener to options
|
||||
$options.on('click', function() {
|
||||
@@ -350,8 +361,6 @@ function initListInteractionOptions(selectorId) {
|
||||
// Perform action based on click count
|
||||
if (clickCounter === 1) {
|
||||
// Single-click action
|
||||
// btoa(iconHtml.replace(/"/g, "'") <-- encode
|
||||
// atob() <--- decode
|
||||
showModalFieldInput(
|
||||
`<i class="fa-regular fa-pen-to-square"></i> ${getString('Gen_Update_Value')}`,
|
||||
getString('settings_update_item_warning'),
|
||||
@@ -371,6 +380,7 @@ function initListInteractionOptions(selectorId) {
|
||||
clickCounter = 0;
|
||||
}, 300); // Adjust delay as needed
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -490,39 +500,165 @@ function getParam(targetId, key, skipCache = false) {
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// generate a list of options for a input select
|
||||
function generateOptions(pluginsData, set, input, isMultiSelect = false, isValueSource = true)
|
||||
{
|
||||
multi = isMultiSelect ? "multiple" : "";
|
||||
// ---------------------------------------------------------
|
||||
// generate a list of options for a input select
|
||||
function generateOptions(pluginsData, set, input, dataType, isMultiSelect = false, editable = false, transformers = []) {
|
||||
let multi = isMultiSelect ? "multiple" : "";
|
||||
let valuesArray = createArray(set['Value']);
|
||||
let settingKey = set['Code_Name'];
|
||||
// editable ? classNames += " interactable-option" : classNames = ""
|
||||
|
||||
// generate different ID depending on if it's the source for the value to be saved or only used as an input
|
||||
// isValueSource ? id = settingKey : id = settingKey + '_input';
|
||||
|
||||
// optionsArray = getSettingOptions(set['Code_Name'] )
|
||||
valuesArray = createArray(set['Value']);
|
||||
|
||||
|
||||
// create unique ID
|
||||
var targetLocation = set['Code_Name'] + "_initSettingDropdown";
|
||||
|
||||
// execute AJAX callabck + SQL query resolution
|
||||
initSettingDropdown(set['Code_Name'] , valuesArray, targetLocation, generateDropdownOptions);
|
||||
|
||||
// generate different ID depending on if it's the source for the value to be saved or only used as an input
|
||||
isValueSource ? id = set['Code_Name'] : id = set['Code_Name'] + '_input';
|
||||
// main selection dropdown wrapper
|
||||
input += `
|
||||
<select onChange="settingsChanged()" my-data-type="${dataType}" my-editable="${editable}" class="form-control" name="${settingKey}" id="${settingKey}" ${multi}>
|
||||
`;
|
||||
|
||||
// main selection dropdown wrapper
|
||||
input += `
|
||||
<select onChange="settingsChanged()"
|
||||
my-data-type="${set['Type']}"
|
||||
class="form-control"
|
||||
name="${set['Code_Name']}"
|
||||
id="${id}"
|
||||
${multi}>
|
||||
// if available transformers are applied
|
||||
valuesArray = valuesArray.map(value => applyTransformers(value, transformers));
|
||||
|
||||
<option id="${targetLocation}" temporary="temporary"></option>
|
||||
// get all options
|
||||
optionsArray = createArray(getSettingOptions(settingKey))
|
||||
|
||||
// loop over all options and select the ones selected in the valuesArray (saved by the user)
|
||||
if(optionsArray.length > 0 )
|
||||
{
|
||||
// check if needs to be processed ASYNC
|
||||
if(isSQLQuery(optionsArray[0]))
|
||||
{
|
||||
// create temporary placeholder
|
||||
targetLocation = settingKey + "_temp_"
|
||||
input += `<option value="" id="${targetLocation}" ></option>`;
|
||||
|
||||
// callback to the DB
|
||||
readData(optionsArray[0], generateDropdownOptions, valuesArray, targetLocation, settingKey);
|
||||
} else // sync processing
|
||||
{
|
||||
optionsArray.forEach(option => {
|
||||
let selected = valuesArray.includes(option) ? 'selected' : '';
|
||||
input += `<option value="${option}" ${selected}>${option}</option>`;
|
||||
});
|
||||
}
|
||||
} else // this is an interactable list with default and user-defined values
|
||||
{
|
||||
// generates [1x 📝 | 2x 🚮]
|
||||
valuesArray.forEach(option => {
|
||||
input += `<option class="interactable-option" value="${option}">${option}</option>`;
|
||||
});
|
||||
}
|
||||
|
||||
</select>`;
|
||||
|
||||
return input;
|
||||
input += `</select>`;
|
||||
|
||||
// add values from the setting options - execute AJAX callback + SQL query resolution
|
||||
// initSettingDropdown(settingKey, valuesArray, targetLocation, generateDropdownOptions);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Function to apply transformers to a value
|
||||
function applyTransformers(val, transformers) {
|
||||
transformers.forEach(transformer => {
|
||||
switch (transformer) {
|
||||
case 'sha256':
|
||||
// Implement sha256 hashing logic
|
||||
if (!isSHA256(val)) {
|
||||
val = CryptoJS.SHA256(val).toString(CryptoJS.enc.Hex);
|
||||
}
|
||||
break;
|
||||
case 'base64':
|
||||
// Implement base64 logic
|
||||
if (!isBase64(val)) {
|
||||
val = btoa(val);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown transformer: ${transformer}`);
|
||||
}
|
||||
});
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Function to initialize relevant variables based on HTML element
|
||||
const handleElementOptions = (codeName, elementOptions, transformers, val) => {
|
||||
let inputType = 'text';
|
||||
let readOnly = "";
|
||||
let isMultiSelect = false;
|
||||
let cssClasses = '';
|
||||
let placeholder = '';
|
||||
let suffix = '';
|
||||
let separator = '';
|
||||
let editable = false;
|
||||
let valRes = val;
|
||||
let sourceIds = [];
|
||||
let getStringKey = "";
|
||||
let onClick = "alert('Not implemented');";
|
||||
|
||||
elementOptions.forEach(option => {
|
||||
if (option.prefillValue) {
|
||||
valRes = option.prefillValue === 'null' ? "" : option.prefillValue;
|
||||
}
|
||||
if (option.type) {
|
||||
inputType = option.type;
|
||||
}
|
||||
if (option.readonly === "true") {
|
||||
readOnly = `readonly`;
|
||||
}
|
||||
if (option.multiple === "true") {
|
||||
isMultiSelect = true;
|
||||
}
|
||||
if (option.editable === "true") {
|
||||
editable = true;
|
||||
}
|
||||
if (option.cssClasses) {
|
||||
cssClasses = option.cssClasses;
|
||||
}
|
||||
if (option.placeholder) {
|
||||
placeholder = option.placeholder;
|
||||
}
|
||||
if (option.suffix) {
|
||||
suffix = option.suffix;
|
||||
}
|
||||
if (option.sourceSuffixes) {
|
||||
$.each(option.sourceSuffixes, function(index, suf) {
|
||||
sourceIds.push(codeName + suf)
|
||||
})
|
||||
}
|
||||
if (option.separator) {
|
||||
separator = option.separator;
|
||||
}
|
||||
if (option.getStringKey) {
|
||||
getStringKey = option.getStringKey;
|
||||
}
|
||||
if (option.onClick) {
|
||||
onClick = option.onClick;
|
||||
}
|
||||
});
|
||||
|
||||
if (transformers.includes('sha256')) {
|
||||
inputType = 'password';
|
||||
}
|
||||
|
||||
return {
|
||||
inputType,
|
||||
readOnly,
|
||||
isMultiSelect,
|
||||
cssClasses,
|
||||
placeholder,
|
||||
suffix,
|
||||
sourceIds,
|
||||
separator,
|
||||
editable,
|
||||
valRes,
|
||||
getStringKey,
|
||||
onClick
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ function initDeviceSelectors() {
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Initiate dropdown
|
||||
// (ASYNC) Initiate dropdown
|
||||
function initSettingDropdown(settingKey, // Identifier for the setting
|
||||
valuesArray, // Array of values to be pre-selected in the dropdown
|
||||
targetLocation, // ID of the HTML element where dropdown should be rendered (will be replaced)
|
||||
@@ -93,9 +93,15 @@ function initSettingDropdown(settingKey, // Identifier for the setting
|
||||
// NOTE {value} options to replace with a setting or SQL value are handled in the cacheSettings() function
|
||||
optionsArray = createArray(getSettingOptions(settingKey))
|
||||
|
||||
|
||||
// check if the result is a SQL query
|
||||
if(isSQLQuery(optionsArray[0]))
|
||||
if(optionsArray.length > 0 && isSQLQuery(optionsArray[0]))
|
||||
{
|
||||
|
||||
if (settingKey == "NEWDEV_dev_Network_Node_MAC_ADDR") {
|
||||
console.log("isSQLQuery in initSettingDropdown");
|
||||
|
||||
}
|
||||
readData(optionsArray[0], callbackToGenerateEntries, valuesArray, targetLocation, targetField, nameTransformer);
|
||||
|
||||
} else // this should be already an array, e.g. from a setting or pre-defined
|
||||
@@ -103,16 +109,18 @@ function initSettingDropdown(settingKey, // Identifier for the setting
|
||||
optionsArray.forEach(option => {
|
||||
let selected = valuesArray.includes(option) ? 'selected' : '';
|
||||
optionsHtml += `<option value="${option}" ${selected}>${option}</option>`;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Replace the specified placeholder div with the resulting HTML
|
||||
setTimeout(() => {
|
||||
|
||||
$("#" + targetLocation).replaceWith(optionsHtml);
|
||||
|
||||
}, 50);
|
||||
|
||||
}, 50);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user