1724 lines
57 KiB
JavaScript
1724 lines
57 KiB
JavaScript
|
|
|
|
function hrefonclickButtonGO(pagename, pagedatastring = '') {
|
|
if (!pagename) { return false; }
|
|
return `href="javascript:void(0);" onclick="ButtonGo('${pagename}',${pagedatastring});return false;"`;
|
|
}
|
|
|
|
function generateHTMLfromarray(prepend, append, array, func) {
|
|
if (!func || !array) { return false; }
|
|
let htmlres = prepend;
|
|
array.forEach((value) => {
|
|
if (value.length > 0) {
|
|
htmlres += func(...value);
|
|
}
|
|
});
|
|
htmlres += append;
|
|
return htmlres;
|
|
}
|
|
|
|
function imgiconuserdefault(imgsrc, imgwidth = '', imgheight = '', id = '', onclick = '') {
|
|
if (!imgsrc) { return false; }
|
|
if (!imgwidth) { imgwidth = 30; }
|
|
if (!imgheight) { imgheight = 30; }
|
|
if (id) { id = 'id="' + id + '"'; } else { id = '' }
|
|
return `<img src="${imgsrc}" style="width: ${imgwidth}; height: ${imgheight};" ${id} onclick="${onclick}" class="icon-user"/>`;
|
|
}
|
|
|
|
function UICardStatsDetails(Title = '', number = 0, Unit = '', leftORright = 'left', numberid = '') {
|
|
if (!leftORright) { leftORright = 'left'; }
|
|
return `<div class="col br-right">
|
|
<div class="inner-${leftORright}">
|
|
<p>${Title}</p>
|
|
<h3 id="${numberid}">${number}</h3>
|
|
<span>${Unit}</span>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
/**
|
|
* Generates an HTML string for displaying stats details.
|
|
*
|
|
* @param {array} statsarray - A 2D array containing stats data, where each inner array has the format [title, number, unit, leftorright,numberid]
|
|
* @returns {string} HTML string representing the stats details
|
|
*/
|
|
function UIStatsDetailsArray(statsarray) {
|
|
|
|
return generateHTMLfromarray('<div class="row">', '</div>', statsarray, UICardStatsDetails);
|
|
|
|
}
|
|
/**
|
|
* Generates an HTML string for displaying stats details.
|
|
*
|
|
* @param {array} statsarray - A 2D array containing stats data, where each inner array has the format [title, number, unit, leftorright,numberid]
|
|
* @returns {string} HTML string representing the stats details including the balance wrapper
|
|
*/
|
|
function UIBalance_WrapperfromArray(statsarray) {
|
|
if (!statsarray) { return false; }
|
|
let htmlres = `<div id="balance_wrapper">
|
|
<div class="balance">`;
|
|
htmlres += UIStatsDetailsArray(statsarray);
|
|
htmlres += '</div></div>'
|
|
return htmlres;
|
|
}
|
|
|
|
function UIBalance_Wrapper_WalletFooter_Item(maintitle = '', onclickstring = '', imgsrc = '', href = '', subtitleline1 = '', subtitleline2 = '', subtitleline3 = '', subtitleline4 = '', imgwidth = '', imgheight = '') {
|
|
|
|
if (!href) { href = "javascript:void(0);"; }
|
|
if (!imgwidth) { imgwidth = "30"; }
|
|
if (!imgheight) { imgheight = "30"; }
|
|
return `<li class="wallet-card-item">
|
|
<a class="fw_6 text-center" id="btn-popup-down" href="${href}"
|
|
onclick="${onclickstring}">
|
|
<ul>
|
|
<li class="path1">${subtitleline1}</li>
|
|
<li class="path2">${subtitleline2}</li>
|
|
<li class="path3">${subtitleline3}</li>
|
|
<li class="path4">${subtitleline4}</li>
|
|
</ul>
|
|
${imgiconuserdefault(imgsrc, imgwidth, imgheight)}
|
|
${maintitle}
|
|
</a>
|
|
</li>`;
|
|
}
|
|
|
|
function UIBalance_Wrapper_WalletFooter_Item_ButtonGO(maintitle, pagename, pagestring = '', iconclass = '', subtitleline1 = '', subtitleline2 = '', subtitleline3 = '', subtitleline4 = '') {
|
|
if (!pagename) { return false; }
|
|
const onclickstring = `ButtonGo('${pagename}','${pagestring}');return false;`;
|
|
//const iconclass =`icon far fa-hdd`;
|
|
const htmlres = UIBalance_Wrapper_WalletFooter_Item(maintitle, onclickstring, iconclass, false, subtitleline1, subtitleline2, subtitleline3, subtitleline4);
|
|
|
|
return htmlres;
|
|
}
|
|
|
|
/**
|
|
* Generates an HTML string for a balance wrapper item button array.
|
|
*
|
|
* @param {array} balancewrapper_item_array - A 2D array containing balance wrapper item data, where each inner array has the format [maintitle, pagename, pagestring, imagesrc, subtitleline1, subtitleline2, subtitleline3, subtitleline4,imgwidth,imgheight]
|
|
* @returns {string} HTML string representing the balance wrapper item button array
|
|
*/
|
|
function UIBalance_Wrapper_WalletFooter_ARRAY(balancewrapper_item_array) {
|
|
return generateHTMLfromarray(`<div class="wallet-footer">
|
|
<ul class="d-flex justify-content-between align-items-center">`, '</ul></div>', balancewrapper_item_array, UIBalance_Wrapper_WalletFooter_Item_ButtonGO);
|
|
}
|
|
/**
|
|
* Generates an HTML string for a balance wrapper item button array.
|
|
*
|
|
* @param {array} statsarray - A 2D array containing stats data, where each inner array has the format [title, number, unit, leftorright]
|
|
* @param {array} balancewrapper_item_array - A 2D array containing balance wrapper item data, where each inner array has the format [maintitle, pagename, pagestring, iconclass, subtitleline1, subtitleline2, subtitleline3, subtitleline4]
|
|
* @param {string} style - a string containing custom style for the balance box
|
|
* @returns {string} HTML string for the whole balance box
|
|
*/
|
|
function UIcreateBalanceBoxfromArray(statsarray, balancewrapper_item_array, style = 'border: solid 3px #000d88;') {
|
|
|
|
let htmlres = `<div class="tf-container">
|
|
<div class="tf-balance-box" style="${style}">`;
|
|
htmlres += UIBalance_WrapperfromArray(statsarray);
|
|
htmlres += UIBalance_Wrapper_WalletFooter_ARRAY(balancewrapper_item_array);
|
|
return htmlres;
|
|
}
|
|
|
|
function UIServices_Button(imgiconsrc, title = '', onclick = '', href = '', bgcolor8 = false) {
|
|
if (!bgcolor8) { bgcolor8 = '' } else { bgcolor8 = 'bg_color_8'; }
|
|
return `<li><a href="${href}" onclick="${onclick}"><div class="icon-box ${bgcolor8}" ><img src="${imgiconsrc}"/></div>${title}</a></li>`;
|
|
}
|
|
function UIServices_Button_GOTOPAGE(imgiconsrc, title, pagename, pagedatastring = '') {
|
|
return UIServices_Button(imgiconsrc, title, `ButtonGo('${pagename}','${pagedatastring}');return false;`, '');
|
|
}
|
|
|
|
function UIServices_FullDIV_GOTOPAGE_Array(title, viewallhref = '', viewallonclick = '', viewalltext = '', services_button_array) {
|
|
return generateHTMLfromarray(`<div class="mt-5">
|
|
<div class="tf-container">
|
|
<div class="tf-title d-flex justify-content-between">
|
|
<h3 class="fw_6">${title}</h3>
|
|
<a href="${viewallhref}" onclick="${viewallonclick}" class="primary_color fw_6">${viewalltext}</a>
|
|
</div>
|
|
<ul class="box-service mt-3">`, '</ul></div></div>', services_button_array, UIServices_Button_GOTOPAGE);
|
|
}
|
|
|
|
|
|
|
|
function UIServices_FullDIV_ONCLICK_Array(title, viewallhref = '', viewallonclick = '', viewalltext = '', services_button_array) {
|
|
|
|
return generateHTMLfromarray(`<div class="mt-5">
|
|
<div class="tf-container">
|
|
<div class="tf-title d-flex justify-content-between">
|
|
<h3 class="fw_6">${title}</h3>
|
|
<a href="${viewallhref}" onclick="${viewallonclick}" class="primary_color fw_6">${viewalltext}</a>
|
|
</div>
|
|
<ul class="box-service mt-3">`, '</ul></div></div>', services_button_array, UIServices_Button);
|
|
}
|
|
|
|
function UISideText_DualColumnButton(text, pagename, pagedatastring = '', imgsrc = '', imgwidth = '', imgheight = '') {
|
|
if (!pagename || !text) { return false; }
|
|
if (!imgwidth) { imgwidth = 30; } if (!imgheight) { imgheight = 30; }
|
|
return `<li onclick="ButtonGo('${pagename}','${pagedatastring}');return false;">
|
|
<div class="">
|
|
${imgiconuserdefault(imgsrc, imgwidth, imgheight)}
|
|
</div>${text}
|
|
</li>`;
|
|
}
|
|
|
|
function UISideText_DualColumnButton_Array(sidetext_button_dualcolumn_array) {
|
|
return generateHTMLfromarray('<ul class="mt-3 box-outstanding-service">', '</ul>', sidetext_button_dualcolumn_array, UISideText_DualColumnButton);
|
|
}
|
|
function UICardSimple(title, text = '', id = '') {
|
|
return CreateCardSimple(title, text, id);
|
|
}
|
|
|
|
function UIRecentSearchBar(searchplaceholdertext, classtosearch, id, imgsrclefticon = '', imgsrcrighticon = '', imgwidth = '', imgheight = '') {
|
|
if (!imgwidth) { imgwidth = 30; }
|
|
if (!imgheight) { imgheight = 30; }
|
|
if (!classtosearch) { classtosearch = ''; }
|
|
if (!imgsrclefticon) { imgsrclefticon = '<span class="icon-search"></span>'; } else {
|
|
imgsrclefticon = imgiconuserdefault(imgsrclefticon, imgwidth, imgheight);
|
|
}
|
|
if (!searchplaceholdertext) { searchplaceholdertext = 'Search'; }
|
|
let righticonhtml = '';
|
|
if (imgsrcrighticon) {
|
|
righticonhtml = imgiconuserdefault(imgsrcrighticon, imgwidth, imgheight, id + '-leftsearchicon');
|
|
} else {
|
|
righticonhtml = '';
|
|
}
|
|
|
|
return `<div class="box-search mt-3" >
|
|
<div class="input-field">
|
|
${imgsrclefticon}
|
|
<input id=${id} class="search-field value_input" placeholder="${searchplaceholdertext}" type="text">
|
|
<span class="icon-clear" id="clear-${id}"></span>
|
|
</div>
|
|
${righticonhtml}
|
|
</div>
|
|
<script>
|
|
$(document).ready(function() {
|
|
$('#${id}').on('keyup', function() {
|
|
let searchTerm_${id} = $(this).val().toLowerCase();
|
|
$('.list-card-invoice.${classtosearch}').filter(function() {
|
|
let contentText_${id} = $(this).find('.content-right h4 a').text().toLowerCase() +
|
|
$(this).find('.content-right p').text().toLowerCase();
|
|
});
|
|
});
|
|
|
|
$('#clear-${id}').on('click', function() {
|
|
$('#${id}').val('');
|
|
$('#${id}').trigger('keyup');
|
|
});
|
|
});
|
|
</script>
|
|
`;
|
|
}
|
|
|
|
|
|
|
|
|
|
function UIRecentSearchable_Button_GO(title, subtitle, rightsidetext, classforsearch, pagename, pagedatastring = '', imgsrc, imgwidth = '', imgheight = '') {
|
|
if (!pagename) { return false; }
|
|
if (!imgwidth) { imgwidth = 30; }
|
|
if (!imgheight) { imgheight = 30; }
|
|
if (!classforsearch) { classforsearch = ''; }
|
|
return `<li class="list-card-invoice ${classforsearch}">
|
|
<div class="logo">
|
|
<img src="${imgsrc}" style="width: ${imgwidth}; height: ${imgheight};" class="icon-user">
|
|
</div>
|
|
<div class="content-right">
|
|
<h4><a href="" onclick="ButtonGo('${pagename}',${pagedatastring});return false;">${title}
|
|
<span class="critical_color">${rightsidetext}</span></a></h4>
|
|
<p>
|
|
${subtitle}
|
|
</p>
|
|
</div>
|
|
</li>`;
|
|
}
|
|
|
|
function UIRecentSearchable_Button_GO_ARRAY(title, recentssearchablebuttonarray, viewallpagetarget, viewallpagedata = '', viewalltext = '') {
|
|
return generateHTMLfromarray(`<h3 class="fw_6 d-flex justify-content-between mt-3">${title}<a ${hrefonclickButtonGO(viewallpagetarget, viewallpagedata)}>${viewalltext}</a></h3>
|
|
<ul class="mt-3 mb-5">`, '</ul>', recentssearchablebuttonarray, UIRecentSearchable_Button_GO);
|
|
}
|
|
|
|
|
|
|
|
|
|
function UIListArrowButton_GO(title, subtitle, pagename, pagedatastring = '', imgsrc, imgwidth = '', imgheight = '') {
|
|
if (!pagename) { return false; }
|
|
if (!imgwidth) { imgwidth = 30; }
|
|
if (!imgheight) { imgheight = 30; }
|
|
return `<div class="list-bill-view mb-4">
|
|
${imgiconuserdefault(imgsrc, imgwidth, imgheight)}
|
|
<div class="content">
|
|
<h4><a ${hrefonclickButtonGO(PAGENAME, pagedatastring)} class="fw_6">${title}</a></h4>
|
|
<p>${subtitle}</p>
|
|
</div>
|
|
<i class="icon-right"></i>
|
|
</div>`;
|
|
}
|
|
function UIListArrowButton_GO_ARRAY(UIListArrowButtonGOARRAY) {
|
|
return generateHTMLfromarray('', '', UIListArrowButtonGOARRAY, UIListArrowButton_GO);
|
|
}
|
|
|
|
|
|
|
|
function UISearchBox_with_BUTTONS_FULL(title, recentssearchablebuttonarray, UIListArrowButtonGOARRAY = '', viewallpagetarget, viewallpagedata = '', viewalltext = '', classtosearch = '', searchid = '', searchplaceholdertext = '', searchlefticon = '', searchrighticon = '', imgwidth = '', imgheight = '') {
|
|
let htmlres = '';
|
|
if (classtosearch && searchid) {
|
|
htmlres += UIRecentSearchBar(searchplaceholdertext, classtosearch, searchid, searchlefticon, searchrighticon, imgwidth, imgheight);
|
|
}
|
|
htmlres += UIRecentSearchable_Button_GO_ARRAY(title, recentssearchablebuttonarray, viewallpagetarget, viewallpagedata, viewalltext);
|
|
if (UIListArrowButtonGOARRAY) {
|
|
htmlres += UIListArrowButton_GO_ARRAY(UIListArrowButtonGOARRAY);
|
|
}
|
|
return htmlres;
|
|
}
|
|
|
|
function UIinputgroupcore(innerhtml = '', label = '', inputgroupid = '') {
|
|
let htmllabel;
|
|
if (!label && !inputgroupid) { htmllabel = ''; }
|
|
else { htmllabel = `<label for="${inputgroupid}">${label}</label>`; }
|
|
return `${htmllabel}<div class="input-group mb-3" id="${inputgroupid}" style="">
|
|
${innerhtml}
|
|
</div>`;
|
|
}
|
|
|
|
|
|
//Input group
|
|
function UIInputGroup(placeholder, type, id, label = '', classinput = '', spanclass = '', imginsteadofspan = '', required = false, textvalue = '', datalist = '', imgwidth = '', imgheight = '', disabled = false) {
|
|
if (!required) { required = ''; } else { required = 'required'; }
|
|
if (!type) { return false; }
|
|
let span; let html; let inner; let labelid;
|
|
if (!type) { type = 'text'; }
|
|
if (!classinput) { classinput = 'form-control'; }
|
|
if (datalist) { datalist = ' list="' + datalist + '" '; } else { datalist = ''; }
|
|
span = `<span class="${spanclass}" id="${id}-span"></span>`;
|
|
if (!imgwidth) { imgwidth = '40px'; } if (!imgheight) { imgheight = '40px'; }
|
|
if (imginsteadofspan) { span = imgiconuserdefault(imginsteadofspan, imgwidth, imgheight, 'imgspan' + id); }
|
|
if (!imginsteadofspan && !spanclass) { span = ''; } else {
|
|
/*
|
|
span =`<div class="input-group-append">
|
|
<div class="input-group-text" id="${id}-input-group-text">
|
|
${span}
|
|
</div>
|
|
</div>`;
|
|
*/
|
|
}
|
|
|
|
if (disabled) {
|
|
disabled = ' disabled ';
|
|
}
|
|
|
|
if (label) { }
|
|
inner = `<input type="${type}" id="${id}" class="${classinput}" ${disabled} ${datalist} placeholder="${placeholder}" value="${textvalue}" name="${id}" ${required}>${span}`;
|
|
labelid = id + '-div-mb3';
|
|
html = UIinputgroupcore(inner, label, labelid);
|
|
return html;
|
|
}
|
|
|
|
function UIInputGroupFileUploadDropzone(id, label = '', url = '', inputgroupid = '', width = '100%', disabled = '') {
|
|
if (!url) { url = '/File/Upload/Unknown'; }
|
|
clearbuttonid = 'ClearUploadButton-' + id;
|
|
if (width) {
|
|
width = ' style="width: ' + width + ';" ';
|
|
} else {
|
|
width = '';
|
|
}
|
|
if (disabled) {
|
|
disabled = 'style=" pointer-events: none;"';
|
|
}
|
|
const clearuploadsbutton = ' ' + imgiconuserdefault('https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/b6dc254166b4.bin', '', '', clearbuttonid, `LoadDataPageFunc.ClearUpload['${id}']();`);
|
|
return UIinputgroupcore('<form ' + disabled + ' action="' + url + '" ' + width + ' class="dropzone" id="' + id + '"></form>', label + clearuploadsbutton, inputgroupid);
|
|
}
|
|
|
|
|
|
function DropZoneLOADDATAPAGEFUNC(url, dropzoneid, acceptedfiles = '', maxsizeMB = 100) {
|
|
if (!url) { url = '/File/Upload/Unknown'; }
|
|
|
|
const clearbuttonid = 'ClearUploadButton-' + dropzoneid;
|
|
$('#' + clearbuttonid).hide();
|
|
|
|
window.Target_Uploaded_Files = [];
|
|
|
|
if (!acceptedfiles) { acceptedfiles = DropZoneFunc.AcceptedFilesString.images; }
|
|
if (typeof window.currentDropzone === 'undefined') { window.currentDropzone = {}; }
|
|
|
|
// Initialize Dropzone
|
|
const dzInstance = DropZoneFunc.InitializeDropZone(
|
|
url,
|
|
(response) => {
|
|
if (response.success && response.hashkey) {
|
|
if (!Target_Uploaded_Files.includes(response.hashkey)) {
|
|
Target_Uploaded_Files.push(response.hashkey);
|
|
}
|
|
} else {
|
|
dzInstance.removeFile(dzInstance.files[dzInstance.files.length - 1]);
|
|
}
|
|
|
|
if (Target_Uploaded_Files.length > 0) {
|
|
$('#' + clearbuttonid).show();
|
|
} else {
|
|
$('#' + clearbuttonid).hide();
|
|
}
|
|
},
|
|
dropzoneid,
|
|
acceptedfiles,
|
|
'file',
|
|
maxsizeMB,
|
|
false,
|
|
(errorresponse) => {
|
|
// handle error if needed
|
|
}
|
|
);
|
|
|
|
// Store globally
|
|
window.currentDropzone[dropzoneid] = dzInstance;
|
|
|
|
//dzInstance.dropzoneobject = dzInstance;
|
|
dzInstance.functions = {};
|
|
|
|
|
|
|
|
dzInstance.functions.AddPreviouslyUploadedFiles = function (filesarray) {
|
|
return DropZoneFunc.AddPreviouslyUploadedFiles(dzInstance, filesarray);
|
|
};
|
|
|
|
dzInstance.functions.ReplaceDropzoneFiles = function (newFilesArray) {
|
|
return DropZoneFunc.ReplaceDropzoneFiles(dropzoneid, newFilesArray);
|
|
};
|
|
dzInstance.functions.ResetDropzoneUpload = function (url, obj = null, reqtype = 'POST', successfunc = false) {
|
|
return DropZoneFunc.ResetDropzoneUpload(url, obj, reqtype, successfunc);
|
|
};
|
|
|
|
dzInstance.functions.ClearDropzoneUpload = function () {
|
|
return DropZoneFunc.ClearDropzoneUpload(dropzoneid, dzInstance);
|
|
};
|
|
|
|
dzInstance.functions.hasOngoingUploads = function () {
|
|
return DropZoneFunc.hasOngoingUploads(dzInstance);
|
|
};
|
|
|
|
dzInstance.functions.RemoveLastUploadedDropzone = function () {
|
|
return DropZoneFunc.RemoveLastUploadedDropzone(dzInstance);
|
|
};
|
|
|
|
dzInstance.functions.AddFiles = function (dropzonemodal = 'Dropzone-Modal', errorcallback) {
|
|
return DropZoneFunc.AddFiles(url = '/File/Upload', errorcallback, filename = 'file', maxfilesize = 100, acceptedFiles, dropzoneid, dropzonemodal);
|
|
};
|
|
|
|
|
|
|
|
if (typeof LoadDataPageFunc.ClearUpload === 'undefined') {
|
|
LoadDataPageFunc.ClearUpload = {};
|
|
}
|
|
|
|
LoadDataPageFunc.ClearUpload[dropzoneid] = function () {
|
|
$('#' + clearbuttonid).hide();
|
|
DropZoneFunc.ClearDropzoneUpload(dropzoneid, dzInstance);
|
|
};
|
|
}
|
|
|
|
function InitializeLoadDataPageFuncDropZonePhotoUpload(url, dropzoneid, acceptedfiles = '', maxsizeMB = 100) {
|
|
if (typeof LoadDataPageFunc === 'undefined') { return false; }
|
|
// console.log('initializing photodropzone');
|
|
LoadDataPageFunc.InitializePhotoDropZone = function () { return DropZoneLOADDATAPAGEFUNC(url, dropzoneid, acceptedfiles, maxsizeMB); };
|
|
}
|
|
|
|
|
|
|
|
function SendPostDataURLData(url, data, sucessfunc, errorfunc = false, fromvarcache = false) {
|
|
if (!url || !data) { return false; }
|
|
let SendPostDataReqq = new RequestData(false);
|
|
SendPostDataReqq.url(url).type('POST').data(data)
|
|
.fromVarCache(fromvarcache)
|
|
.success((response) => {
|
|
if (typeof sucessfunc === 'function') { sucessfunc(response); }
|
|
}).error((response) => {
|
|
if (typeof errorfunc === 'function') { errorfunc(response); }
|
|
}).go();
|
|
|
|
}
|
|
|
|
function getInputAndTextareaValuesbyCSSClassName(className) {
|
|
const elements = document.getElementsByClassName(className);
|
|
const results = [];
|
|
elements.forEach(element => {
|
|
const id = element.id;
|
|
const value = element.value;
|
|
results.push({ id, value });
|
|
});
|
|
return results;
|
|
}
|
|
|
|
function getInputElementsValuesObjectbyCSSClassname(classname) {
|
|
const elements = document.getElementsByClassName(classname);
|
|
const results = {};
|
|
|
|
elements.forEach(element => {
|
|
const id = element.id;
|
|
const value = element.value;
|
|
results[id] = value;
|
|
});
|
|
return results;
|
|
}
|
|
|
|
|
|
// Helper function to extract hashkey from response (handles both string and JSON object responses)
|
|
function getHashkeyFromResponse(response) {
|
|
if (!response) return null;
|
|
|
|
// If response is already a string/hash key
|
|
if (typeof response === 'string') {
|
|
return response;
|
|
}
|
|
|
|
// If response is an object with hashkey property (JSON response from backend)
|
|
if (response && typeof response.hashkey === 'string') {
|
|
return response.hashkey;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// Helper function to extract hashkey and call callback with it
|
|
function getResponseHashkeyOrErrorMessage(response, successCallback, errorCallback) {
|
|
const hashkey = getHashkeyFromResponse(response);
|
|
if (hashkey) {
|
|
successCallback(hashkey);
|
|
} else {
|
|
// Check if response is an error object
|
|
if (response && typeof response === 'object' && !Array.isArray(response)) {
|
|
const errorMessage = response.message || response.error || 'Unknown error';
|
|
errorCallback(errorMessage);
|
|
} else {
|
|
errorCallback('Invalid response format');
|
|
}
|
|
}
|
|
}
|
|
|
|
function SendPostDataFormwithTARGETUPLOADEDFILES(url, forminputclass, successfunc, WithTarget_Uploaded_Files = true, errorfunc = false) {
|
|
if (!url || !forminputclass || !successfunc) { return false; }
|
|
let datatosend = getInputElementsValuesObjectbyCSSClassname(forminputclass);
|
|
if (isObjectEmpty(datatosend)) { return false; }
|
|
if (WithTarget_Uploaded_Files && typeof window.Target_Uploaded_Files !== 'undefined' && window.Target_Uploaded_Files.length > 0) {
|
|
datatosend['files'] = Target_Uploaded_Files;
|
|
}
|
|
|
|
let target;
|
|
let data = null;
|
|
|
|
|
|
if (typeof currenttarget === 'object') {
|
|
try {
|
|
target = currenttarget['target'];
|
|
} catch (error) {
|
|
target = currenttarget;
|
|
}
|
|
|
|
try {
|
|
data = currenttarget['data'];
|
|
} catch (error) {
|
|
data = null;
|
|
}
|
|
|
|
} else {
|
|
target = currenttarget;
|
|
data = null;
|
|
}
|
|
|
|
|
|
|
|
if (typeof datatosend.target === 'undefined') {
|
|
datatosend['target'] = target;
|
|
datatosend['data'] = data;
|
|
}
|
|
|
|
|
|
// Wrap successfunc to extract hashkey from JSON responses
|
|
const wrappedSuccessFunc = function(response) {
|
|
const hashkey = getHashkeyFromResponse(response);
|
|
if (hashkey) {
|
|
successfunc(hashkey);
|
|
} else {
|
|
// Pass original response for error handling
|
|
successfunc(response);
|
|
}
|
|
};
|
|
|
|
SendPostDataURLData(url, datatosend, wrappedSuccessFunc, errorfunc, fromvarcache = false);
|
|
}
|
|
|
|
|
|
|
|
function UIInputGroupTEXTAREA(label = '', textareaID = '', required = false, textareaCONTENT = '', textareaCLASS = '', inputgroupid = '', disabled = '') {
|
|
if (required) { required = ' required '; } else { required = ''; }
|
|
if (disabled) {
|
|
disabled = 'disabled'
|
|
}
|
|
const innerhtml = `<textarea ${disabled} id="${textareaID}" name="${textareaID}" ${required} class="${textareaCLASS}">${textareaCONTENT}</textarea>`;
|
|
return UIinputgroupcore(innerhtml, label, inputgroupid);
|
|
}
|
|
|
|
|
|
function UIInputGroupSelect(id = '', label = '', optionsarray = '', spanclass = '', imginsteadofspan = '', selectedvalue = '', imgwidth = '', imgheight = '', select_class = '', disabled = '') {
|
|
//optionsarray =[['value1','text1'],['value2','text2',selectedtrue] ]
|
|
let inner; let labelid; let htmlspan; let optionshtml = '';
|
|
if (!spanclass && !imginsteadofspan) { htmlspan = ''; }
|
|
if (!imgwidth) { imgwidth = '40px'; } if (!imgheight) { imgheight = '40px'; }
|
|
optionshtml = UIArraytoOptionforSelect(optionsarray, selectedvalue);
|
|
|
|
if (spanclass) {
|
|
htmlspan = `<span class="spanclass"></span>`;
|
|
}
|
|
if (imginsteadofspan) {
|
|
htmlspan = imgiconuserdefault(imginsteadofspan, '10px', '10px');
|
|
}
|
|
if (!spanclass && !imginsteadofspan) {
|
|
htmlspan = '';
|
|
} else {
|
|
htmlspan = `<div class="input-group-append">
|
|
<div class="input-group-text" id="${id}-input-group-text">
|
|
${htmlspan}
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
|
|
if (disabled) {
|
|
disabled = 'disabled';
|
|
} else {
|
|
disabled = '';
|
|
}
|
|
|
|
inner = `<select ${disabled} class="form-control ${select_class}" id="${id}">
|
|
${optionshtml}
|
|
</select>${htmlspan}`;
|
|
|
|
labelid = id + '-select-div-mb3';
|
|
html = UIinputgroupcore(inner, label, labelid);
|
|
return html;
|
|
}
|
|
|
|
function UIInputGroupDatePicker() {
|
|
|
|
}
|
|
|
|
|
|
function UIArraytoOptionforSelect(array, selectedvalue = '') {
|
|
if (!array) { return ''; } let optionshtml = '';
|
|
let val; let selected;
|
|
for (let i = 0; i < array.length; i++) {
|
|
val = array[i];
|
|
// selected = (val[2] !== undefined) ? val[2] : '';
|
|
selected = '';
|
|
|
|
if (selectedvalue !== '' && selectedvalue == val[0]) { selected = 'selected'; }
|
|
optionshtml += `<option value="${val[0]}" ${selected}>${val[1]}</option>`;
|
|
}
|
|
return optionshtml;
|
|
}
|
|
|
|
function UIReplaceCurrentOptionsSelect(selectid, optionsarray, selectedvalue = '') {
|
|
if (!selectid || !optionsarray) { return false; }
|
|
let optionshtml = UIArraytoOptionforSelect(optionsarray, selectedvalue);
|
|
$('#' + selectid).html(optionshtml);
|
|
}
|
|
|
|
function UIInputGroupNumber(placeholder, id, label = '', classinput = '', min = '', max = '', spanclass = '', imginsteadofspan = '', required = false, val = 0, datalist = '', imgwidth = '', imgheight = '', disabled = false) {
|
|
let UI = UIInputGroup(placeholder, 'number', id, label, classinput, spanclass, imginsteadofspan, required, val, datalist, imgwidth, imgheight, disabled);
|
|
// console.log('placeholder ',placeholder,' label ', label);
|
|
UI = '<div>' + UI + '</div>';
|
|
UI = $(UI);
|
|
let input = UI.find('input');
|
|
input.attr('min', min);
|
|
input.attr('max', max);
|
|
input.val(val);
|
|
return UI.html();
|
|
}
|
|
|
|
|
|
function UIInputGroupButton(buttontext, buttonclass = '', buttonid = '', onclick = '', buttonstyle = '') {
|
|
if (!buttontext) { return false; }
|
|
if (!buttonclass) { buttonclass = 'btn-primary'; }
|
|
|
|
return `<div class="input-group mb-3">
|
|
<button class="form-control ${buttonclass}" id="${buttonid}" onclick="${onclick}" style="${buttonstyle}">${buttontext}</button>
|
|
</div>`;
|
|
}
|
|
|
|
function UIInputGroupCheckBox(input_id, label, checked = false, additional_input_class = '', additional_label_class = '') {
|
|
if (checked === true) { checked = 'checked'; } else {
|
|
checked = '';
|
|
}
|
|
return `<div class="form-check">
|
|
<input class="form-check-input ${additional_input_class}" type="checkbox" value="" ${checked} id="${input_id}">
|
|
<label class="form-check-label ${additional_label_class}" for="${input_id}">
|
|
${label}
|
|
</label>
|
|
</div>`
|
|
}
|
|
|
|
function UISetDarkMode() {
|
|
$('body').addClass('dark-mode'); $('.tf-balance-box').removeAttr('style');
|
|
$('.card').addClass('dark-mode');
|
|
$('.card-header').addClass('dark-mode');
|
|
$('.card-body').addClass('dark-mode');
|
|
$('.modal-content').addClass('dark-mode');
|
|
$('.btn').addClass('dark-mode');
|
|
$('input').addClass('dark-mode');
|
|
$('textarea').addClass('dark-mode');
|
|
$('select').addClass('dark-mode');
|
|
$('form').addClass('dark-mode');
|
|
|
|
}
|
|
|
|
function UIUpdateBodyHTML(html = '') {
|
|
$('#main-body').html(html);
|
|
}
|
|
|
|
|
|
function changeTopbarTitle(title) {
|
|
$('#topbar-title').html(title);
|
|
}
|
|
|
|
function setDefaultBackOnclickifNoHistory(functtoCall) {
|
|
|
|
if (!functtoCall) {
|
|
defaultBackOnclick = null;
|
|
}
|
|
|
|
if (historylist.length < 2) {
|
|
if (typeof functtoCall === 'function') {
|
|
defaultBackOnclick = functtoCall;
|
|
}
|
|
}
|
|
}
|
|
|
|
function setDefaultbackGotoPageifNoHistory(pageName, targetdata) {
|
|
const functiongoto = function () {
|
|
gotoPage(pageName, targetdata);
|
|
};
|
|
setDefaultBackOnclickifNoHistory(functiongoto);
|
|
}
|
|
|
|
function getcurrenttargetHash() {
|
|
const url = new URL(window.location.href);
|
|
const parts = url.pathname.split('/').filter(Boolean);
|
|
return parts.at(-1) || null;
|
|
}
|
|
|
|
function requestGetData(targetURL, functionsuccess, cachefirst = false) {
|
|
request.url(targetURL)
|
|
.success((response) => {
|
|
if (typeof functionsuccess === 'function') {
|
|
functionsuccess(response);
|
|
}
|
|
})
|
|
.data()
|
|
.fromVarCache(cachefirst)
|
|
.type("GET")
|
|
.go();
|
|
}
|
|
|
|
|
|
let ElementDOM = {};
|
|
function getUIElementsAndAttributes() {
|
|
const uiElements = document.querySelectorAll('UI');
|
|
const uiData = {};
|
|
uiElements.forEach(uiElement => {
|
|
const attributes = {};
|
|
attributes.innerHTML = uiElement.innerHTML;
|
|
let Elementname = uiElement.id;
|
|
if (!Elementname) {
|
|
Elementname = uiElement.attributes.name.value;
|
|
}
|
|
console.log(Elementname);
|
|
Array.from(uiElement.attributes).forEach(attr => {
|
|
attributes[attr.name] = attr.value;
|
|
});
|
|
uiData[Elementname] = attributes;
|
|
uiData[Elementname].id = uiElement.id;
|
|
uiData[Elementname].name = uiElement.attributes.name.value;
|
|
});
|
|
return uiData;
|
|
}
|
|
|
|
function CheckChangesVariableVSDOM(domID) {
|
|
if (!domID) { return null; }
|
|
const DOMElementData = getUIElementsAndAttributes()[domID] || false;
|
|
if (!DOMElementData) { return null; }
|
|
const VarElementData = ElementDOM[domID] || false;
|
|
|
|
|
|
}
|
|
|
|
function UIElementsUpdateCard(elementData) {
|
|
if (!elementData) { return false; }
|
|
|
|
}
|
|
|
|
const ReplaceMainViewORTargetDiv = function (html, targetDiv, append = '', removeDivID = '') {
|
|
|
|
|
|
if (!targetDiv) {
|
|
targetDiv = 'main-body';
|
|
}
|
|
|
|
if (typeof append === 'undefined' || !append) {
|
|
append = '';
|
|
}
|
|
|
|
let elem = document.getElementById(targetDiv);
|
|
|
|
if (targetDiv === 'main-body') {
|
|
const mainview = document.getElementById('MainView');
|
|
if (mainview) {
|
|
elem = mainview;
|
|
} else {
|
|
elem.innerHTML = '<div id="MainView" class="MainView"></div>' + elem.innerHTML;
|
|
}
|
|
}
|
|
|
|
if (removeDivID) {
|
|
let removeElem = document.getElementById(removeDivID);
|
|
if (removeElem) {
|
|
removeElem.remove();
|
|
|
|
logDev('Removed element with ID: ' + removeDivID);
|
|
} else {
|
|
logDev(`Element with ID: ${removeDivID} not found.`);
|
|
}
|
|
}
|
|
|
|
html += '</div>';
|
|
html += append || '';
|
|
document.getElementById(targetDiv).innerHTML = html;
|
|
// logDev(`Element with ID: ${targetDiv} replaced html with. ${html}`);
|
|
|
|
}
|
|
|
|
const processTopBarTitleAndDefaultBack = function (topbartitle, defaultback) {
|
|
if (typeof topbartitle !== 'undefined') {
|
|
changeTopbarTitle(topbartitle);
|
|
}
|
|
|
|
if (typeof defaultback !== 'undefined' && typeof defaultback.page !== 'undefined' && typeof defaultback.data !== 'undefined') {
|
|
setDefaultbackGotoPageifNoHistory(defaultback.page, defaultback.data || 0);
|
|
}
|
|
}
|
|
|
|
|
|
function setDynamicCSS(cssText) {
|
|
let styleTag = document.getElementById("dynamic-css");
|
|
|
|
if (!styleTag) {
|
|
styleTag = document.createElement("style");
|
|
styleTag.id = "dynamic-css";
|
|
document.head.appendChild(styleTag);
|
|
}
|
|
|
|
styleTag.innerHTML = cssText;
|
|
}
|
|
|
|
function resetDynamicCSS() {
|
|
setDynamicCSS('');
|
|
}
|
|
|
|
const FormBuilder = {
|
|
config: {},
|
|
dropzones: {},
|
|
|
|
build: function (options) {
|
|
this.config = options;
|
|
const { targetDiv, fields, formClass, append, topbartitle, defaultback, onFormGenerated } = options;
|
|
|
|
processTopBarTitleAndDefaultBack(topbartitle, defaultback);
|
|
|
|
// document.getElementById(targetDiv).innerHTML = '<center>Please Wait..<center>';
|
|
ReplaceMainViewORTargetDiv('<div id="loadingText"><center>Please Wait..<center></div>', targetDiv);
|
|
let requestData;
|
|
let targetHash, targetData;
|
|
|
|
if (typeof currenttarget === 'object') {
|
|
try {
|
|
targetHash = currenttarget['target'];
|
|
} catch (error) {
|
|
targetHash = currenttarget;
|
|
}
|
|
} else {
|
|
targetHash = currenttarget;
|
|
}
|
|
|
|
|
|
try {
|
|
targetData = currenttarget['data'];
|
|
} catch (error) {
|
|
targetData = [];
|
|
}
|
|
|
|
|
|
if (typeof this.config.requestData === 'undefined') {
|
|
|
|
requestData = { 'target': targetHash, 'data': targetData };
|
|
} else {
|
|
requestData = this.config.requestData;
|
|
}
|
|
|
|
|
|
|
|
|
|
loadDataWithCache({
|
|
url: this.config.currentDataUrl,
|
|
current_page: this.config.pageName,
|
|
executeFunction: function (response) {
|
|
const html = this.createForm(fields, targetDiv, formClass, append);
|
|
|
|
if (typeof onFormGenerated === 'function') {
|
|
onFormGenerated(response, html);
|
|
}
|
|
}.bind(this),
|
|
'requestData': requestData,
|
|
'errorFunction': this.config.unabletoLoadFunc,
|
|
});
|
|
|
|
},
|
|
|
|
createForm: function (fields, targetDiv, formClass, append) {
|
|
let html = '';
|
|
|
|
fields.forEach(field => {
|
|
|
|
const currentDataVal = currentData[field.currentdatavar] || '';
|
|
const valuetoDisplay = field.value || currentDataVal || '';
|
|
let newValue;
|
|
|
|
const datalistMaker = function (id) {
|
|
return ' <datalist id="' + id + 'DataList"></datalist> ';
|
|
}
|
|
|
|
switch (field.type) {
|
|
case 'text':
|
|
html += UIInputGroup(field.placeholder || '', 'text', field.id, field.label, formClass,
|
|
'', '', field.required, valuetoDisplay, field.datalist || '', field.image_width || '', field.image_height || '', field.disabled || false) + datalistMaker(field.id);
|
|
break;
|
|
case 'number':
|
|
html += UIInputGroupNumber(field.placeholder || '', field.id, field.label, formClass,
|
|
1, '', '', '', field.required, valuetoDisplay, field.datalist || '', field.image_width || '', field.image_height || '', field.disabled || false) + datalistMaker(field.id);
|
|
break;
|
|
case 'textarea':
|
|
html += UIInputGroupTEXTAREA(field.label, field.id, field.required || false, valuetoDisplay, formClass, '', field.disabled || '');
|
|
break;
|
|
case 'dropzone':
|
|
html += UIInputGroupFileUploadDropzone(field.id, field.label, field.uploadUrl, '', 'width:100%', field.disabled || '');
|
|
break;
|
|
|
|
case 'select':
|
|
html += UIInputGroupSelect(field.id, field.label, valuetoDisplay || '', field.spanclass || '', field.imginsteadofspan || '', field.selectedvalue || '', field.imgwidth || '', field.imgheight || '', formClass || '', field.disabled || false)
|
|
break;
|
|
|
|
case 'button':
|
|
html += UIInputGroupButton(field.label, formClass, '', field.onClick || 'FormBuilder.submit()');
|
|
break;
|
|
}
|
|
});
|
|
|
|
html = CreateCardSimple(false, html);
|
|
|
|
|
|
ReplaceMainViewORTargetDiv(html, targetDiv, append, 'loadingText');
|
|
|
|
|
|
this.initializeDropzones(fields);
|
|
this.enforceBarcodeNumeric(fields);
|
|
|
|
return html;
|
|
|
|
},
|
|
|
|
|
|
initializeDropzones: function (fields) {
|
|
fields.filter(f => f.type === 'dropzone').forEach(f => {
|
|
// InitializeLoadDataPageFuncDropZonePhotoUpload(
|
|
// f.uploadUrl,
|
|
// f.id,
|
|
// '',
|
|
// 'clearuploadbutton',
|
|
// '',
|
|
// 100
|
|
// );
|
|
|
|
DropZoneLOADDATAPAGEFUNC(f.uploadUrl, f.id, '', f.maxsize);
|
|
|
|
const currentDataVal = currentData[f.currentdatavar] || '';
|
|
|
|
this.dropzones[f.id] = currentDropzone[f.id];
|
|
|
|
if (f.existingFiles && Array.isArray(f.existingFiles) && f.existingFiles.length > 0) {
|
|
|
|
this.dropzones[f.id].functions.ReplaceDropzoneFiles(f.existingFiles);
|
|
console.log(`[FormBuilder] Restored ${f.existingFiles.length} files into dropzone ${f.id}`);
|
|
} else if (currentDataVal) {
|
|
this.dropzones[f.id].functions.ReplaceDropzoneFiles(currentDataVal);
|
|
console.log(`[FormBuilder] Restored ${currentDataVal.length} files into dropzone ${f.id}`);
|
|
}
|
|
|
|
});
|
|
},
|
|
|
|
enforceBarcodeNumeric: function (fields) {
|
|
fields.filter(f => f.id && f.id.toLowerCase().includes('barcode')).forEach(f => {
|
|
const input = document.getElementById(f.id);
|
|
if (input) {
|
|
input.addEventListener('input', function () {
|
|
this.value = this.value.replace(/[^0-9]/g, '');
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
validate: function () {
|
|
const inputs = getInputElementsValuesObjectbyCSSClassname(this.config.formClass);
|
|
if (isObjectEmpty(inputs)) return false;
|
|
|
|
const invalid = Object.keys(inputs).some(k => {
|
|
const val = inputs[k];
|
|
return (!val && document.getElementById(k)?.required);
|
|
});
|
|
|
|
if (invalid) {
|
|
ModalQuickDismiss('Error', 'Please fill out all required fields.');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
submit: function () {
|
|
if (!this.validate()) return;
|
|
|
|
const { submitUrl, formClass, onSuccess, onError } = this.config;
|
|
SendPostDataFormwithTARGETUPLOADEDFILES(submitUrl, formClass, (response) => {
|
|
|
|
getResponseHashkeyOrErrorMessage(response, (hashkey) => {
|
|
if (onSuccess) onSuccess(response);
|
|
}, (err) => {
|
|
// if (onError) onError(err);
|
|
});
|
|
}, true, function (err) { if (onError) onError(err); });
|
|
}
|
|
};
|
|
|
|
|
|
|
|
const ViewBuilder = {
|
|
config: {},
|
|
loadPhotos: [],
|
|
targetData: null,
|
|
targetHash: null,
|
|
|
|
build: function (options) {
|
|
this.config = options;
|
|
|
|
let { targetDiv, sections, dataurl, pageName, append, topbartitle, defaultback, initialize } = options;
|
|
|
|
logDev('viewbuilder starting build with options:', options);
|
|
processTopBarTitleAndDefaultBack(topbartitle, defaultback);
|
|
|
|
this.targetData = currenttarget;
|
|
|
|
if (typeof this.targetData === 'object') {
|
|
this.targetHash = this.targetData.target;
|
|
} else {
|
|
this.targetHash = this.targetData;
|
|
}
|
|
|
|
let requestData;
|
|
|
|
if (typeof this.config.requestData === 'undefined') {
|
|
requestData = { 'target': this.targetHash, 'data': this.targetData };
|
|
} else {
|
|
requestData = this.config.requestData;
|
|
}
|
|
|
|
logDev('viewbuilder requestData set to:', requestData);
|
|
|
|
const renderErrorPage = (response) => {
|
|
sections = null;
|
|
|
|
sections = [{
|
|
type: 'card',
|
|
id: 'errorCard',
|
|
hidden: false,
|
|
value: this.config.defaultErrorHTML || 'Error Loading Data',
|
|
}];
|
|
logDev('viewbuilder Error:');
|
|
|
|
this.buildhtml(sections, targetDiv, append);
|
|
}
|
|
|
|
logDev('viewbuilder loading data from URL:', dataurl);
|
|
|
|
|
|
loadDataWithCache({
|
|
url: dataurl,
|
|
current_page: pageName,
|
|
executeFunction: function (response) {
|
|
|
|
logDev('viewbuilder Response Data:', response);
|
|
|
|
if (typeof initialize === 'function') {
|
|
initialize(response);
|
|
logDev('Initialize function ran after response:');
|
|
}
|
|
|
|
if (!response) {
|
|
logDev('viewbuilder No response received, rendering error page:');
|
|
renderErrorPage(response);
|
|
}
|
|
|
|
try {
|
|
logDev('viewbuilder building html with sections:', sections);
|
|
this.buildhtml(sections, targetDiv, append);
|
|
} catch (error) {
|
|
logDev('viewbuilder Error building html:', error);
|
|
console.error(error);
|
|
renderErrorPage(response);
|
|
}
|
|
|
|
}.bind(this),
|
|
'requestData': requestData,
|
|
'errorFunction': function (err) {
|
|
|
|
logDev('viewbuilder Error loading data:', err);
|
|
|
|
if (typeof this.config.unabletoLoadFunc === 'function') {
|
|
this.config.unabletoLoadFunc();
|
|
}
|
|
}.bind(this),
|
|
});
|
|
|
|
|
|
},
|
|
|
|
getValorCurrentData: function (section) {
|
|
|
|
if (!section) {
|
|
logDev('viewbuilder getValorCurrentData called with no section, returning null.');
|
|
return null;
|
|
}
|
|
|
|
let currentDataVal = null;
|
|
|
|
if (
|
|
typeof currentData !== 'undefined' &&
|
|
section.currentdatavar &&
|
|
currentData[section.currentdatavar] !== undefined
|
|
) {
|
|
currentDataVal = currentData[section.currentdatavar];
|
|
}
|
|
|
|
return section.value ?? currentDataVal ?? null;
|
|
},
|
|
|
|
buildhtml: function (sections, targetDiv, append) {
|
|
|
|
logDev('viewbuilder building html with sections:', sections);
|
|
let html = '<div class="row">';
|
|
|
|
|
|
|
|
sections.forEach((section, i) => {
|
|
|
|
html += this.renderSection(section, i);
|
|
});
|
|
|
|
if (!targetDiv) {
|
|
targetDiv = 'main-body';
|
|
}
|
|
|
|
// let elem = document.getElementById(targetDiv);
|
|
|
|
html += '</div>';
|
|
html += append || '';
|
|
|
|
// document.getElementById(targetDiv).innerHTML = html;
|
|
|
|
|
|
ReplaceMainViewORTargetDiv(html, targetDiv, append);
|
|
if (html && targetDiv) {
|
|
logDev('viewbuilder replaced main view or target div with html:' + html);
|
|
} else {
|
|
logDev('viewbuilder html or targetDiv is empty, skipping ReplaceMainViewORTargetDiv.');
|
|
}
|
|
|
|
|
|
this.postRender();
|
|
},
|
|
|
|
renderSection: function (section, index) {
|
|
switch (section.type) {
|
|
case 'photos':
|
|
return this.renderPhotosCard(section, index);
|
|
case 'details':
|
|
return this.renderDetailsCard(section, index);
|
|
case 'buttons':
|
|
return this.renderButtonsCard(section, index);
|
|
case 'card':
|
|
return this.renderCustomCard(section, index);
|
|
default:
|
|
return '';
|
|
}
|
|
},
|
|
|
|
renderPhotosCard: function (section, index) {
|
|
|
|
logDev('viewbuiler Rendering Photos Card for section:', section);
|
|
if (typeof section.target === 'undefined' || !section.target) { section.target = this.targetHash; }
|
|
Preloaders.ImageList(section.target, section.phototype);
|
|
|
|
|
|
const photosData = this.getValorCurrentData(section);
|
|
|
|
|
|
|
|
let loadingText = 'Loading photos...';
|
|
|
|
|
|
if (photosData) {
|
|
this.loadPhotos.push(photosData);
|
|
} else {
|
|
loadingText = 'No Photos';
|
|
}
|
|
|
|
logDev('viewbuilder Rendering Photos Card Success', section);
|
|
|
|
return `
|
|
<div class="col-md-12" style="overflow:hidden; margin:5px;">
|
|
<div class="card ListRowCard" id="PhotosCard-${index}">
|
|
<div class="card-body ListCardRow">
|
|
<div style="text-align:center;" id="${section.id || 'PhotosCard'}">
|
|
<center>
|
|
<div id="PhotosPlaceholder-${index}"
|
|
style="width: 100%; max-width: 600px; height: 350px; display: flex; justify-content: center; align-items: center; background: #f0f0f0; color: #555; font-size: 18px;">
|
|
${loadingText}
|
|
</div>
|
|
</center>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
},
|
|
|
|
renderDetailsCard: function (section, index) {
|
|
let htmlcols = '';
|
|
|
|
logDev('viewbuiler Rendering Details Card for section:', section);
|
|
const detailscol = section.data;
|
|
|
|
detailscol.forEach((arrVar) => {
|
|
if (arrVar.type !== 'text') return;
|
|
|
|
|
|
let textToDisplay = this.getValorCurrentData(arrVar);
|
|
|
|
|
|
if (typeof arrVar.func === 'function') {
|
|
|
|
try {
|
|
textToDisplay = arrVar.func();
|
|
} catch (error) {
|
|
textToDisplay = '';
|
|
}
|
|
|
|
|
|
}
|
|
|
|
textToDisplay = this.detailsCard.text(textToDisplay);
|
|
|
|
|
|
|
|
if (typeof arrVar.bold === 'boolean' && arrVar) {
|
|
textToDisplay = '<b>' + textToDisplay + '</b>';
|
|
}
|
|
|
|
if (typeof arrVar.h === 'number' && arrVar) {
|
|
textToDisplay = '<h' + arrVar.h + '>' + textToDisplay + '</h' + arrVar.h + '>';
|
|
}
|
|
|
|
if (textToDisplay) {
|
|
htmlcols += this.detailsCard.text(textToDisplay);
|
|
} else {
|
|
console.warn('No text or current data available for:', arrVar);
|
|
}
|
|
|
|
});
|
|
|
|
logDev('viewbuilder Rendering Details Card Success', section);
|
|
|
|
return `
|
|
<div class="col-md-12" style="overflow:hidden; margin:5px;">
|
|
<div class="card ListRowCard" id="DetailsCard-${index}">
|
|
<div class="card-body ListCardRow">
|
|
<div class="row">
|
|
${htmlcols}
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
},
|
|
|
|
detailsCard: {
|
|
|
|
text: function (text) {
|
|
return `<div class="col">${text}</div>`;
|
|
},
|
|
|
|
|
|
},
|
|
|
|
renderButtonsCard: function (section, index) {
|
|
logDev('viewbuiler Rendering Buttons Card for section:', section);
|
|
const buttonsHTML = section.buttons.map(btn => `
|
|
<li onclick="${btn.onclick}">
|
|
<div><img src="${btn.icon}" style="width:30px;height:30px;"></div>
|
|
${btn.label}
|
|
</li>`).join('');
|
|
|
|
logDev('viewbuilder Rendering Buttons Card Success', section);
|
|
return `
|
|
<div class="col-md-12" style="overflow:hidden; margin:5px;">
|
|
<div class="card ListRowCard" id="ButtonsCard-${index}">
|
|
<div class="card-body ListCardRow">
|
|
<ul class="mt-3 box-outstanding-service">${buttonsHTML}</ul>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
},
|
|
|
|
renderCustomCard: function (section, index) {
|
|
|
|
let data = this.getValorCurrentData(section);
|
|
|
|
logDev('viewbuiler Rendering Custom Card for section:', section, 'with data:', data);
|
|
|
|
if (typeof section.render === 'function') {
|
|
data = section.render(data);
|
|
}
|
|
|
|
logDev('viewbuilder Rendering Custom Card Success', section);
|
|
return `
|
|
<div class="col-md-12" style="overflow:hidden;margin:5px; min-height: 100px;${section.hidden ? 'display:none;' : ''}">
|
|
<div class="card ListRowCard" id="${section.id || 'CustomCard-' + index}" style="height:100%;">
|
|
<div class="card-body ListCardRow">${data || ''}</div>
|
|
</div>
|
|
</div>`;
|
|
},
|
|
|
|
postRender: function () {
|
|
|
|
logDev('viewbuilder postRender starting photo loads for:', this.loadPhotos);
|
|
|
|
this.loadPhotos.forEach((arrVar) => {
|
|
if (Array.isArray(arrVar) || typeof arrVar === 'object') {
|
|
LoadPhotosCard('PhotosCard', `ButtonGo('ViewAllPhotos','${this.targetHash}');`, arrVar);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
const ListBuilder = (() => {
|
|
|
|
const defaultConfig = {
|
|
targetDiv: "",
|
|
title: "List",
|
|
dataUrl: "",
|
|
method: "POST",
|
|
search: true,
|
|
pageName: "",
|
|
cols: 6,
|
|
type: "tiled",
|
|
defaultback: "",
|
|
renderCard: null,
|
|
customCss: null,
|
|
width: null,
|
|
height: null,
|
|
|
|
|
|
card: {
|
|
imageField: null,
|
|
nameField: null,
|
|
descriptionField: null,
|
|
priceField: null,
|
|
unitField: null,
|
|
onClick: null,
|
|
fallbackImage: "https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/146710fe9ece.bin",
|
|
}
|
|
};
|
|
|
|
function build(config) {
|
|
if (config.defaultback) {
|
|
setDefaultbackGotoPageifNoHistory(config.defaultback, currenttarget);
|
|
}
|
|
|
|
config = deepMerge(structuredClone(defaultConfig), config);
|
|
|
|
|
|
if (!config.targetDiv) {
|
|
console.error("ListBuilder: targetDiv is required");
|
|
return;
|
|
}
|
|
|
|
setupUI(config);
|
|
loadList(config);
|
|
}
|
|
|
|
function setupUI(config) {
|
|
resetDynamicCSS();
|
|
let searchHTML = "";
|
|
if (config.search) {
|
|
searchHTML = UIInputGroup(
|
|
"Search",
|
|
"text",
|
|
"LB_Search",
|
|
"",
|
|
"",
|
|
"",
|
|
"https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/839d72e8ef8a.bin"
|
|
);
|
|
}
|
|
|
|
|
|
|
|
const body = `
|
|
${searchHTML}
|
|
<div id="LB_ListContainer" style="padding:5px;">
|
|
<center>Loading Please Wait...</center>
|
|
</div>
|
|
`;
|
|
|
|
const mainCard = UICardSimple(config.title, body, "LB_MainCardBody");
|
|
|
|
$("#" + config.targetDiv).html(mainCard);
|
|
|
|
$("#imgspanLB_Search").attr("onclick", "ListBuilder.clearSearch()");
|
|
$("#LB_Search").on("keyup", ListBuilder.filterList);
|
|
|
|
|
|
}
|
|
|
|
function loadList(config) {
|
|
|
|
|
|
// loadDataWithCache({
|
|
// url: config.dataUrl,
|
|
// currentPage: this.config.pageName,
|
|
// executeFunction: function () {
|
|
// this.createForm(fields, targetDiv, formClass, append);
|
|
// }.bind(this),
|
|
// 'requestData': requestData,
|
|
// 'errorFunction': this.config.unabletoLoadFunc,
|
|
// });
|
|
|
|
|
|
loadDataWithCache({
|
|
url: config.dataUrl,
|
|
type: config.method,
|
|
current_page: config.pageName,
|
|
executeFunction: function (response) {
|
|
|
|
if (config.customCss !== null) {
|
|
setDynamicCSS(config.customCss);
|
|
} else if (config.type === 'tiled') {
|
|
setCSStoTiled();
|
|
}
|
|
renderList(response, config)
|
|
|
|
changeTopbarTitle(config.title);
|
|
},
|
|
'errorFunction': config.unabletoLoadFunc,
|
|
});
|
|
|
|
|
|
}
|
|
|
|
function setCSStoTiled() {
|
|
const tiledcss = `.ListRowCard {
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.ListCardRow {
|
|
flex: 1;
|
|
}
|
|
|
|
.equal-height {
|
|
display: flex;
|
|
}`;
|
|
setDynamicCSS(tiledcss);
|
|
|
|
}
|
|
|
|
function renderList(data, config) {
|
|
|
|
|
|
if (!Array.isArray(data)) data = [];
|
|
|
|
if (data.length === 0) {
|
|
$("#LB_ListContainer").html("<center>No Data</center>");
|
|
return;
|
|
}
|
|
|
|
let html = [`<div class="row">`];
|
|
|
|
data.forEach((item, index) => {
|
|
html.push(renderCard(item, index, config));
|
|
});
|
|
|
|
html.push(`</div>`);
|
|
|
|
|
|
|
|
$("#LB_ListContainer").html(html.join(""));
|
|
|
|
|
|
postLoadImages();
|
|
|
|
|
|
setupIntersectionObserver();
|
|
}
|
|
|
|
function renderCard(item, index, config) {
|
|
if (typeof config.renderCard === 'function') {
|
|
return config.renderCard(item, index, config);
|
|
}
|
|
|
|
|
|
const c = config.card;
|
|
|
|
let img = item[c.imageField];
|
|
if (Array.isArray(img)) img = img[0];
|
|
|
|
const imageId = `LB_photo_${index}`;
|
|
queueImageLoad(imageId, img);
|
|
|
|
let imageHtml = `
|
|
<img id="${imageId}" src="${c.fallbackImage}" loading="lazy"
|
|
style="width: 60%; height: 60%; object-fit: contain;">
|
|
`;
|
|
|
|
let description = item[c.descriptionField] || "";
|
|
if (description.length > 80) {
|
|
description = description.substring(0, 80) + "...";
|
|
}
|
|
|
|
const clickAction = c.onClick ? c.onClick(item) : "javascript:void(0)";
|
|
|
|
let width = '';
|
|
let height = '';
|
|
|
|
if (config.width) {
|
|
width = ' width: ' + config.width + '; ';
|
|
}
|
|
if (config.height) {
|
|
height = ' height: ' + config.height + '; ';
|
|
}
|
|
|
|
return `
|
|
<div class="col-${config.cols}" class="equal-height" style="overflow:hidden; padding-bottom:10px; ${width} ${height}">
|
|
<a href="javascript:void(0);" onclick="${clickAction}">
|
|
<div class="card ListRowCard" id="LB_Card_${index}">
|
|
<div class="card-body ListCardRow">
|
|
<div style="text-align:center;">${imageHtml}</div>
|
|
<br>
|
|
<div class="row">
|
|
<div class="col"><h3>${item[c.nameField]}</h3></div>
|
|
<div class="col">P${item[c.priceField]} / ${item[c.unitField]}</div>
|
|
</div>
|
|
<br>
|
|
<h5>${description}</h5>
|
|
<br>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>`;
|
|
}
|
|
|
|
/* ------------------------------ IMAGE HANDLING ------------------------------ */
|
|
|
|
const preloadQueue = [];
|
|
|
|
function queueImageLoad(imageId, fileHash) {
|
|
preloadQueue.push([imageId, fileHash]);
|
|
}
|
|
|
|
function postLoadImages() {
|
|
preloadQueue.forEach(([imageId, hash]) => {
|
|
LoadAndCreateURLfromFileHash(hash).then(url => {
|
|
const ElementIMG = document.getElementById(imageId);
|
|
if (ElementIMG) {
|
|
ElementIMG.src = url;
|
|
}
|
|
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ------------------------------ OBSERVER ------------------------------ */
|
|
|
|
function setupIntersectionObserver() {
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (!entry.isIntersecting) return;
|
|
|
|
const rowIndex = entry.target.id.split("_")[2];
|
|
const hashDiv = $("#LB_Hash_" + rowIndex).text();
|
|
|
|
if (hashDiv) {
|
|
request.url('/View/Product/Details/data')
|
|
.success(() => { })
|
|
.data({ target: hashDiv })
|
|
.fromVarCache(true)
|
|
.type("POST")
|
|
.go();
|
|
}
|
|
});
|
|
}, { threshold: 0.1 });
|
|
|
|
$(".ListRowCard").each(function () {
|
|
observer.observe(this);
|
|
});
|
|
}
|
|
|
|
/* ------------------------------ SEARCH ------------------------------ */
|
|
|
|
function filterList() {
|
|
const searchTerm = $("#LB_Search").val().toLowerCase();
|
|
|
|
$("#LB_ListContainer .card").each(function () {
|
|
const text = $(this).text().toLowerCase();
|
|
|
|
if (text.includes(searchTerm)) {
|
|
this.style.display = "block";
|
|
if (this.parentElement.parentElement.id !== 'LB_ListContainer') { this.parentElement.parentElement.style.display = "block"; }
|
|
} else {
|
|
this.style.display = "none";
|
|
if (this.parentElement.parentElement.id !== 'LB_ListContainer') { this.parentElement.parentElement.style.display = "none"; }
|
|
}
|
|
});
|
|
}
|
|
|
|
function clearSearch() {
|
|
$("#LB_Search").val("");
|
|
filterList();
|
|
}
|
|
|
|
/* ------------------------------ UTILS ------------------------------ */
|
|
|
|
function deepMerge(target, source) {
|
|
for (const key in source) {
|
|
if (source[key] && typeof source[key] === "object") {
|
|
if (!target[key]) target[key] = {};
|
|
deepMerge(target[key], source[key]);
|
|
} else {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
|
|
return {
|
|
build,
|
|
filterList,
|
|
clearSearch,
|
|
queueImageLoad,
|
|
};
|
|
|
|
})();
|
|
|
|
|
|
|
|
/**
|
|
* Create a searchable, paginated table using jQuery DataTables
|
|
*
|
|
* @param {Object} options
|
|
* @param {Array} options.data - Array of objects OR array of arrays
|
|
* @param {Array} [options.headers] - Optional table headers
|
|
* @param {String} [options.tableId] - Table ID
|
|
* @param {Number} [options.defaultSortColumn] - Column index
|
|
* @param {String} [options.defaultSortDirection] - 'asc' | 'desc'
|
|
* @param {String} [options.defaultSearch] - Default search text
|
|
* @param {Number} [options.pageLength] - Rows per page
|
|
* @param {Boolean} [options.initializeTable]
|
|
* @param {Boolean} [options.placeTable]
|
|
*/
|
|
function createSearchableTable({
|
|
data,
|
|
headers = [],
|
|
tableId = "dynamicTable",
|
|
defaultSortColumn = 0,
|
|
defaultSortDirection = "asc",
|
|
defaultSearch = "",
|
|
pageLength = 10,
|
|
initializeTable = true,
|
|
placeTable = true,
|
|
}) {
|
|
if (!Array.isArray(data) || data.length === 0) {
|
|
console.error("Data must be a non-empty array");
|
|
return null;
|
|
}
|
|
|
|
const isObjectData =
|
|
data[0] !== null &&
|
|
typeof data[0] === "object" &&
|
|
!Array.isArray(data[0]);
|
|
|
|
if (isObjectData && headers.length === 0) {
|
|
headers = Object.keys(data[0]);
|
|
}
|
|
|
|
let tableHTML = `<table id="${tableId}" class="display"><thead><tr>`;
|
|
|
|
headers.forEach(header => {
|
|
tableHTML += `<th>${header}</th>`;
|
|
});
|
|
|
|
tableHTML += `</tr></thead><tbody>`;
|
|
|
|
data.forEach(row => {
|
|
tableHTML += `<tr>`;
|
|
if (isObjectData) {
|
|
headers.forEach(key => {
|
|
tableHTML += `<td>${row[key] ?? ""}</td>`;
|
|
});
|
|
} else {
|
|
row.forEach(cell => {
|
|
tableHTML += `<td>${cell}</td>`;
|
|
});
|
|
}
|
|
tableHTML += `</tr>`;
|
|
});
|
|
|
|
tableHTML += `</tbody></table>`;
|
|
|
|
let dataTable = null;
|
|
|
|
if (placeTable) {
|
|
$("#tableContainer").html(tableHTML);
|
|
|
|
if (initializeTable) {
|
|
dataTable = $(`#${tableId}`).DataTable({
|
|
pageLength,
|
|
order: [[defaultSortColumn, defaultSortDirection]],
|
|
search: { search: defaultSearch }
|
|
});
|
|
}
|
|
}
|
|
|
|
return {
|
|
html: tableHTML,
|
|
dataTable
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|