var debugHelp= {
// comes in handy at some points
showScreenSize : function()
{
var screenWidth = window.screen.width;
var screenHeight = window.screen.height;
alert("Screen Width: " + screenWidth + " pixels\nScreen Height: " + screenHeight + " pixels");
}
}
class AudioPlayer {
constructor() {
this.dbName = 'audioCacheDB';
this.audioElements = {}; // To keep track of audio elements by name
this.initDB();
}
async initDB() {
if (!('indexedDB' in window)) {
console.log('This browser doesn\'t support IndexedDB');
return;
}
const request = indexedDB.open(this.dbName, 1);
request.onupgradeneeded = event => {
const db = event.target.result;
if (!db.objectStoreNames.contains('audios')) {
db.createObjectStore('audios', { keyPath: 'name' });
}
};
request.onerror = event => {
console.error('Database error: ', event.target.errorCode);
};
request.onsuccess = event => {
this.db = event.target.result;
};
}
load(name, url) {
if (this.audioElements[name]) {
console.log(`Audio ${name} is already loaded or loading.`);
return;
}
const transaction = this.db.transaction(['audios'], 'readonly');
const store = transaction.objectStore('audios');
const request = store.get(name);
request.onerror = event => {
console.error('Error fetching audio from DB:', event.target.errorCode);
};
request.onsuccess = event => {
if (request.result) {
const audioBlob = request.result.audioBlob;
this.audioElements[name] = new Audio(URL.createObjectURL(audioBlob));
} else {
console.log(`Fetching ${name} from network`);
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.blob();
})
.then(blob => {
const audio = new Audio(URL.createObjectURL(blob));
this.audioElements[name] = audio;
const transaction = this.db.transaction(['audios'], 'readwrite');
const store = transaction.objectStore('audios');
store.add({ name: name, audioBlob: blob });
console.log(`Audio ${name} has been loaded and cached.`);
})
.catch(error => {
console.error(`Failed to fetch audio ${name}:`, error);
// Optionally remove from memory if partially added
delete this.audioElements[name];
});
}
};
}
play(name) {
const audio = this.audioElements[name];
if (audio) {
console.log(`Playing ${name}`);
audio.play();
} else {
console.log(`Audio ${name} is not loaded yet. Please load it first.`);
}
}
flush() {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['audios'], 'readwrite');
const store = transaction.objectStore('audios');
const request = store.clear();
request.onsuccess = () => {
console.log('All audio files have been removed from the database.');
this.audioElements = {}; // Clear the audio elements stored in memory
console.log('In-memory audio cache has been cleared.');
resolve();
};
request.onerror = (event) => {
console.error('Failed to clear database:', event.target.errorCode);
reject(event.target.errorCode);
};
});
}
}
// search object
var swSearch = {
// timer for searching
SearchTimer: false,
// characters needed for invoking search
SearchInvoke: 3,
goSearch: function (forced) {
// when forced cancel the timer
if (forced === true)
clearTimeout(this.SearchTimer);
var searchstring = $("#sw_header_searchbar").val();
if (searchstring.length < swSearch.SearchInvoke)
return;
SW_UI.hideNavbar();
var url = swSearchEngine.executeSearch(searchstring);
swSearchEngine.uiHide();
return;
},
// timer
handleSearch: function (element) {
if (this.SearchTimer != undefined)
clearTimeout(this.SearchTimer);
this.SearchTimer = setTimeout(function () {
var val = $(element).val();
if (val.length >= swSearch.SearchInvoke) {
swSearch.goSearch();
}
}, 1000);
},
// bind some stuff and boot up the searchengine
init: function () {
// loadup the searchengine if it is not there already
if ($("#sw_search_engine_script").length == 0) {
$.get(SW_Router.go("MySWRetail", "searchEngine"), function (data) {
$("#sw_userinterface_start").after(data);
swSearchEngine.initSearch();
});
}
$(document).off("input", "input#sw_header_searchbar");
$(document).on("input", "input#sw_header_searchbar", function (e) {
swSearch.handleSearch(this);
});
},
};
var SW_LangTable = undefined;
var SW_Lang = {
// translation function
translate: function (input) {
var retval = SW_LangTable[input];
return retval ?? input;
},
getCurrent: function () {
return $("#sw_app_lang_select").val();
},
langFormat: function (state) {
if (!state.id)
return state.text; // optgroup
return " " + state.text;
},
setupSelection: function (id) {
id = id ?? "langselect";
$("#" + id).select2({
minimumResultsForSearch: Infinity,
formatResult: SW_Lang.langFormat,
formatSelection: SW_Lang.langFormat,
escapeMarkup: function (m) {
return m;
}
});
}
}
// generic translation helper function
function __(input) {
return SW_Lang.translate(input);
}
String.prototype.beginsWith = function (string) {
return (this.indexOf(string) === 0);
};
// serialize a grid, using sw_serialize_form, will need a data-sw-serializer-linenumber attribute in order for the serialization to work
// will go by each line and return an array that can be used to do other neat things (like posting to the server)
function sw_grid_serialize(line_selector) {
var rows = $(line_selector).length - 1;
var retval = {};
$.each($(line_selector), function (number) {
var curline = $(this).attr("data-sw-serializer-linenumber");
if (curline != undefined) {
var data = sw_serialize_form($(line_selector + '[data-sw-serializer-linenumber="' + curline + '"] input'));
retval[curline] = data;
}
});
return retval;
}
// serialise all fields, based upon the name attribute, will create an array [name:value,name:value] that can be used. the fdields serialized do not have to be in a form, just everything the query catches will be serialized
function sw_serialize_form(selector) {
var inputs = $(selector);
var retval = {};
var obj = $.map(inputs, function (n, i) {
var o = {};
if (n.name == undefined)
return;
if (n.type == "checkbox") {
if ($(n).is(':checked') == true)
o[n.name] = 1;
else
o[n.name] = -1;
} else
o[n.name.replace('[]', '')] = $(n).val();
doit = 1;
if (n.type == 'radio') {
doit = 0;
o = {};
var lbl = $(n).closest("label");
;
if (lbl.hasClass("active")) {
o[n.name.replace('[]', '')] = n.id;
jQuery.extend(retval, o);
}
}
if (doit == 1)
jQuery.extend(retval, o);
return [[n.name, o]];
});
return retval;
}
function sw_deserialize_form(selector, data, load_undefined) {
var inputs = $(selector);
var retval = {};
load_undefined = load_undefined ?? true;
$(selector).each(function (item) {
input = $(this);
name = input.attr("name");
if (input.attr("type") == "checkbox") {
if (data[name] != undefined) {
if (data[name] == 1)
input.prop('checked', true);
else
input.prop('checked', false);
}
} else {
if (load_undefined == true) {
if (data[name] != undefined)
input.val(data[name]);
} else
input.val(data[name]);
}
});
return;
}
// default alert box, use SW_UI.alert instead of this
function sw_alert(input, callback) {
bootbox.alert({
"message": input,
"callback": callback,
"animate": false
});
}
function toggleSidebar() {
if ($('#sidebar-toggle').hasClass('collapsed')) {
showSidebar();
} else {
hideSidebar();
}
// Reset fixedHeader
if ($('.fixedHeader').length != 0) {
handleFixedHeader();
}
}
function showSidebar() {
$('#primary-sidebar').show(); //, .sidebar-background
$('#sidebar-toggle').removeClass('collapsed');
$('body').addClass('with-sidebar');
$('#sidebar-toggle-left').hide()
}
function hideSidebar() {
$('#primary-sidebar').hide(); //, .sidebar-background
$('#sidebar-toggle').addClass('collapsed');
$('#sidebar-toggle-left').show()
$('body').removeClass('with-sidebar');
}
(function ($) {
$.fn.customCheckbox = function () {
var selector = this.selector;
return this.each(function () {
// Get the original element
var el = this;
// Hide the checkbox
$(this).hide();
// Create replacement element
var rep = $('').addClass('sw-slider').insertAfter(this);
// Check help attr
if ($(this).attr('data-help') != "undefined") {
$(rep).attr('data-help', $(this).attr('data-help'));
}
// Set default state
if ($(this).is(':checked')) {
$(rep).addClass('on');
} else {
$(rep).addClass('off');
}
});
};
})(jQuery);
// include element Library/sw_progress.ctp for this to work
var SWProgressObject = {
gSWProgress: "0",
gSWProgressPump: "",
last_modal_id: "",
Show: function (title, subheader) {
this.last_modal_id = SW_UI.hideModals();
if (title == undefined)
$("#sw_progress_dialog_header").html(__("SW-Retail is bezig!"));
else
$("#sw_progress_dialog_header").html(title);
if (subheader == undefined)
$("#sw_progress_dialog_subheader").html(__("Sluit uw browser niet af en ga niet naar een andere pagina!"));
else
$("#sw_progress_dialog_subheader").html(subheader);
$("#sw_progress_dialog").modal();
this.gSWProgress = 10;
this.gSWProgressPump = setInterval(function () {
$("#sw_progress_bar").css('width', SWProgressObject.gSWProgress + '%')
SWProgressObject.gSWProgress += 10;
if (SWProgressObject.gSWProgress > 99) {
SWProgressObject.gSWProgress = 10;
}
}, 500);
},
descriptionSet: function (description) {
$("#sw_progress_dialog_customtext").html(description);
},
Hide: function () {
if (!SW_UI.modalsVisible("sw_progress_dialog"))
return;
$("#sw_progress_dialog").modal("hide");
//checks if the button exists and removes the button if it does.
if ($("#cancelPaymentBtn").length) {
$("#sw_progress_dialog_footer").empty();
}
if (this.last_modal_id != "") {
$("#" + this.last_modal_id).modal('show');
this.last_modal_id = "";
}
clearInterval(this.gSWProgressPump);
},
CancelButton: function () {
$("#sw_progress_dialog_footer").append('');
}
}
// play a help wizard
var SW_Wizard = {
tileToggle: function (divider_element) {
var divider = $(divider_element);
divider.parent().children(".sw_tile").addClass("hidden");
var select = false;
divider.parent().children().each(function () {
var item = $(this);
if (item.hasClass("sw_tile_divider")) {
if (item.get(0) == divider.get(0)) {
select = true;
} else
select = false;
}
if (item.hasClass("sw_tile")) {
if (select)
item.removeClass("hidden");
else
item.addClass("hidden");
}
});
},
hideAll: function () {
$(".sw_help_wizard_page").addClass("hidden");
},
stopWizard: function () {
$(".sw_help_item_start").removeClass("hidden");
SW_Wizard.hideAll();
SW_UI.setHistory("Wizard", SW_Router.currentURL());
$("#helpnavi").removeClass("hidden");
},
playStep: function (id, step) {
if ($("#" + id + "_" + step).length == 0) {
SW_UI.alert(__("Wizard bestaat niet"));
return;
}
$(".sw_help_item_start").addClass("hidden");
$("#helpnavi").addClass("hidden");
SW_UI.setHistory("Wizard", SW_Router.currentURL() + "?wizard=" + id + "&step=" + step);
SW_Wizard.hideAll();
SW_Wizard.playSlide($("#" + id + "_" + step));
},
playNext: function (button) {
if ($(button).hasClass("disabled"))
return;
var next = $(button).closest(".sw_help_wizard_page").next();
SW_Wizard.hideAll();
SW_Wizard.playSlide(next);
},
playPrevious: function (button) {
if ($(button).hasClass("disabled"))
return;
var previous = $(button).closest(".sw_help_wizard_page").prev();
if (previous.length < 1)
return;
SW_Wizard.hideAll();
SW_Wizard.playSlide(previous);
},
playSlide: function (item) {
item.removeClass("hidden");
item.find(".sw_help_item_start").removeClass("hidden");
$(".sw-wizard-prev").removeClass("disabled");
if (item.attr("data-sw-wizard-number") == "0") {
$(".sw-wizard-prev").addClass("disabled");
}
var next = item.next();
$(".sw-wizard-next").removeClass("disabled");
if (next.attr("data-sw-wizard") != item.attr("data-sw-wizard")) {
$(".sw-wizard-next").addClass("disabled");
}
}
};
class SW_InputValidator {
constructor(inputId, rule, withblurring) {
this.inputId = inputId;
this.inputField = document.getElementById(inputId);
if (this.inputField == undefined)
return;
this.validationEndpoint = SW_Router.go("SWGenericServices", "validator");
this.isValid = false; // Initialize isValid property
this.validation_rule = rule;
this.errorMessage = "";
this.inputClass = "form-group";
if (withblurring == true)
this.inputField.addEventListener('blur', () => this.validateInput());
}
validateInput() {
const valueToValidate = this.inputField.value;
this.clearError();
this.errorMessage = "";
return fetch(this.validationEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({value: valueToValidate, rule: this.validation_rule}),
})
.then(response => response.json())
.then(data => this.handleValidationResponse(data))
.catch(error => {
console.error('Error during validation:', error);
});
}
handleValidationResponse(data) {
this.isValid = false;
if (data.status == "error") {
this.errorMessage = data.extended;
this.showError();
}
// Set isValid based on the validation result
if (data.status == "ok")
this.isValid = true;
}
showError() {
// for some reason, there are also input-groups used, i donw know the difference. for now we only use class form-group but i suspect this is wrong
$("#" + this.inputId).closest("." + this.inputClass).addClass('has-error');
$("#" + this.inputId).closest("." + this.inputClass).append('
' + this.errorMessage + '
');
}
clearError() {
$("#" + this.inputId).closest("." + this.inputClass).removeClass('has-error');
$("#" + this.inputId).closest("." + this.inputClass).find(".invalid-feedback").remove();
}
}
var SW_Services = {
currentModuleName: "",
// get val from generic services
getVal: function ($item, param, callback) {
$.get(SW_Router.go("SWGenericServices", "val_only_" + $item, [param]), function (data) {
callback(data);
}, 'json');
},
modulenameSetCurrent: function (name) {
this.currentModuleName = name;
},
// get current running module name (for display purposes etc..)
modulenameGetCurrent: function () {
return this.currentModuleName;
},
jsonToCommaSep: function (json_input) {
return json_input;
},
removeLastPart: function (url_to_remove_last_part) {
var lastSlashIndex = url_to_remove_last_part.lastIndexOf("/");
if (lastSlashIndex > url_to_remove_last_part.indexOf("/") + 1) { // if not in http://
return url_to_remove_last_part.substr(0, lastSlashIndex); // cut it off
} else {
return url_to_remove_last_part;
}
},
loggedOnCheck: function (suffix) {
var data = {};
data.current = window.location.href;
data.device_token = this.getDeviceToken();
var suf="";
if (suffix==undefined)
suf="";
else
suf="?"+suffix;
$.post(SW_Router.go("sw_lightning", "ajaxloggedoncheck.php")+suf, data, function (data) {
if (data.loggedon == 0) {
if (SW_UI.isPWA()) {
SW_Services.relogin();
return;
}
SW_UI.blockUI();
window.location = SW_Router.go("Medewerker", "logout");
return;
}
;
// and reload the page since the version has changed (very important for PWA)
if (SW_Router.getVersion() != data.version) {
location.reload();
}
}, 'json');
},
sendTelemetry: function () {
var data = {};
data.current = window.location.href;
var width = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var height = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
data.vp_width = width;
data.vp_height = height;
data.platform = navigator.platform;
data.is_pwa = SW_UI.isPWA();
data.current_url = SW_Router.getController();
$.post(SW_Router.go("Medewerker", "telemetry"), data, function (data) {
}, 'json');
},
// perform relogin in background when necessary
relogin: function () {
if (SW_UI.isPWA()) {
var logindata = Lockr.get("logindata");
if (logindata != undefined) {
SW_UI.blockUI();
$(".content").hide();
$.post(SW_Router.go('Medewerker', "appHashedLogon", [logindata.id, logindata.hash, logindata.env]), function (data) {
try {
var obj = JSON.parse(data);
SW_UI.unblockUI();
} catch (err) {
console.log(err);
console.log("logon failed");
SW_UI.blockUI();
window.location = SW_Router.go("Medewerker", "logout") + "?fromrelogin";
}
});
}
}
},
// use only in conjunction with the callback
getNewDeviceToken: function (type, callback) {
if (SW_Cache.read("device_token") != undefined) {
if (callback && typeof (callback) === "function")
callback();
}
$.post(SW_Router.go("Medewerker", "getDeviceToken", [type]), function (data) {
SW_Cache.write("device_token", data.additional.device_token);
if (callback && typeof (callback) === "function")
callback();
}, 'json');
},
// a device must be there
startDeviceAdd : function()
{
SW_UI.yesorno(__("Deze scanner is nog niet toegevoegd als scanner. Wilt u hier een apparaat voor toevoegen? "),function() {
SW_UI.blockUI();
SW_Services.getNewDeviceToken(9,function()
{
SW_UI.unblockUI();
SW_UI.alert(__("Er is een handscanner toegevoegd, u kunt nu scannen. U kun de apparaatnaam wijziging in de configuratie!"));
});
});
},
// get the device token
getDeviceToken: function () {
return SW_Cache.read("device_token");
},
//check wether the device token is still valid, and otherwise invalidates the cache
checkDeviceToken: function () {
if (this.getDeviceToken() == undefined)
return;
$.get(SW_Router.go("Medewerker", "checkDeviceToken", [this.getDeviceToken()]), function (data) {
if (data.status == "error")
SW_Cache.clear("device_token");
}, 'json');
return true;
},
}
// for rendereing a correct UI. Remember -> ALWAYS validate on server!!!!
var SW_UI_Auth = {
tagCheck: function (tag, callback) {
$.get(SW_Router.go("Medewerker", "verifyTag", [tag]), function (data) {
if (callback && typeof (callback) === "function") {
if (data.result == 0)
callback(false);
else
callback(true);
}
}, 'json');
},
// make sure elements with a certain tag are visible
updateElements: function (tag) {
}
}
// the one and only sw_ui
var SW_UI = {
isLoading: false,
timerID: 0,
overlays: 0,
resizerOffsetBottom: 0,
resizerID: "",
resizerInit: 0,
inDialogLoading: 0,
isBlocked: 0,
configUpdateController: "Dashboard",
sounds: true,
vibrate: true,
assistantShow: function () {
if ($("#assistant_master_block").length == 0) {
$.get(SW_Router.go("MySWRetail", "assistant"), function (data) {
$("#sw_userinterface_start").after(data);
swAssistant.showMe();
})
} else {
swAssistant.showMe();
}
},
articlePopup: function (id, warehouse_id) {
SW_UI.blockUI();
var data = {};
if (warehouse_id != undefined)
data.warehouse_id = warehouse_id;
data.article_id = id;
SW_UI.runDialog(SW_Router.go('ArticleInfo', 'lightInfo'), data, "sw_dynamic_data", null, function () {
SW_UI.unblockUI();
});
},
// if this is the mobile scanner return true
isScanner : function()
{
// for now pwa is scanner
if (this.isPWA())
return true;
return false;
},
articlePopupBarcode: function (barcode, warehouse_id) {
SW_UI.blockUI();
var data = {};
if (warehouse_id != undefined)
data.warehouse_id = warehouse_id;
data.barcode = barcode;
SW_UI.runDialog(SW_Router.go('ArticleInfo', 'lightInfo'), data, "sw_dynamic_data", null, function (data) {
if (data.article_found == 0)
SW_UI.Beep_Error();
else
SW_UI.Beep_OK();
SW_UI.unblockUI();
});
},
// plave a sound when a barcode has been scanned (after that we play beep_ok or beep_warning /beep_error
Code_OK: function (pattern) {
if (!this.sounds)
return;
if (!this.isPWA())
return;
audioManager.play("code_ok");
if (!this.vibrate)
return;
if (pattern == undefined)
pattern = [70];
if (typeof navigator.vibrate === 'function')
navigator.vibrate([70]);
},
// we beep only in pwa mode
Beep_OK: function () {
if (!this.sounds)
return;
if (!this.isPWA())
return;
audioManager.play("beep_ok");
},
// we beep only in pwa mode
Beep_Warning: function () {
if (!this.sounds)
return;
if (!this.isPWA())
return;
audioManager.play("beep_warning");
},
// we beep only in pwa mode
Beep_Error: function () {
if (!this.sounds)
return;
if (!this.isPWA())
return;
audioManager.play("beep_error");
},
// character counter for better seo
maxMetaDesc: 160,
maxMetaTitle: 70,
attachCharacterCount: function (inputIdOrTextAreaId, maxCount) {
// Get a reference to the input or textarea
var inputOrTextArea = document.getElementById(inputIdOrTextAreaId);
if (inputOrTextArea == undefined)
return;
// Create a new character count element (a span)
var charCount = document.createElement('span');
// Initialize the character count in the span
charCount.textContent = inputOrTextArea.value.length + " / " + maxCount;
// Append the character count element after the input or textarea
inputOrTextArea.parentNode.insertBefore(charCount, inputOrTextArea.nextSibling);
// Add an event listener to the input or textarea for input events
inputOrTextArea.addEventListener('input', function () {
// Get the length of the text in the input or textarea
var text = inputOrTextArea.value;
var length = text.length;
// Update the character count element with the current count and maximum count
charCount.textContent = length + " / " + maxCount;
// Check if the maximum count is reached and add a class if necessary
if (maxCount && length > maxCount) {
charCount.classList.add('char-count-limit-exceeded');
} else {
charCount.classList.remove('char-count-limit-exceeded');
}
});
// Initialize the character count and apply the class if needed
if (maxCount && inputOrTextArea.value.length > maxCount) {
charCount.classList.add('char-count-limit-exceeded');
}
},
// pwa menu
pwaMenu: function () {
if (!this.isPWA())
return true;
if ($("#pwa-menu").length < 1) {
$("body").append('');
SW_UI.blockUI();
$.get(SW_Router.go("Medewerker", "menuPWA", [], true), function (data) {
$("#pwa-menu").html(data.html);
SW_UI.unblockUI();
swPWAPopup.display();
}, 'json');
return false;
}
swPWAPopup.display();
return false;
},
OverlayInc: function () {
SW_UI.overlays++;
},
OverlayDec: function () {
SW_UI.overlays--;
if (SW_UI.overlays < 0)
SW_UI.overlays = 0;
},
// Overlay, status can be show / hide
Overlay: function (status) {
return false;
},
// to hide the normal ui and display a custom overlayed thing
UIHide: function () {
$("#sw_userinterface_start div div.row-fluid").addClass("hide");
$("#sw_userinterface_start div.sidebar").addClass("hide");
$("#sw_userinterface_start div.main-content").addClass("hide");
},
// to hide the normal ui and display a custom overlayed thing
UIShow: function () {
$("#sw_userinterface_start div div.row-fluid").removeClass("hide");
$("#sw_userinterface_start div.main-content").removeClass("hide");
$("#sw_userinterface_start div.sidebar").removeClass("hide");
},
OverlayHook: function (status) {
//console.log("HOOK "+status);
//console.trace();
if (status == "show") {
SW_UI.OverlayInc();
if (SW_UI.overlays > 0)
SW_UI.Overlay("show");
}
if (status == "hide") {
//console.log("HOOK HIDING");
SW_UI.OverlayDec();
if (SW_UI.overlays == 0)
SW_UI.Overlay("hide");
}
},
// scroll to div, if div in a sw_scrolltainer div we scroll there
scrollTo: function (divid, offset) {
target = $("#" + divid);
if (target.length) {
offset = offset ?? 200;
var top = target.offset().top - offset;
//console.log(top);
var done = false;
if (target.closest("div .sw_scrolltainer").length) {
target.closest("div .sw_scrolltainer").animate({scrollTop: top}, 100);
done = true;
}
// proper scrolling in a modal
if (target.closest("div.modal-body").length) {
target.closest("div.modal-body").animate({scrollTop: top}, 100);
done = true;
}
if (!done) {
$('html,body').animate({scrollTop: top}, 100);
}
return false;
}
},
setLanguage: function (elem) {
var lang = $(elem).val();
$.post(SW_Router.go("Medewerker", "setLanguage", [lang]), function (data) {
location.reload();
});
},
// set history
setHistory: function (title, url) {
console.log(url);
var stateObj = {url: url, title: title};
document.title = title;
history.pushState(stateObj, title, url);
},
sizeIT: function (element) {
var bottommargin = 0;
$(element + ".modal").height(($(window).height() - bottommargin) + "px");
var parent = $(element + ".modal").height();
var mh = $(element + " .modal-header").height();
var mf = $(element + " .modal-footer").height();
$(element + " .modal-body").height((parent - 200) + "px");
},
// Loading top bar
setLoading: function () {
this.isLoading = true;
$("#top-loading").removeClass("hide").fadeIn(50);
},
// set a dialog to full screen, except when sw_do_not_fullsize class has been set
dialogSizeToScreen: function (element, bottommargin) {
if ($(element).hasClass("sw_do_not_fullsize"))
return;
bottommargin = bottommargin ?? 20;
$(element + ".modal").height(($(window).height() - bottommargin) + "px");
var parent = $(element + ".modal").height();
bottom_offset = 220;
if ($(window).width() < 1031)
bottom_offset = 110;
$(element + " .modal-body").height((parent - bottom_offset) + "px");
},
redactorize_simple: function (selector) {
var redactor_object = RedactorX(selector, {
context: true,
embed: {
checkbox: true
},
addbar: false,
image: false,
quote: false,
block: false,
table: false,
control: false,
editor: {
lang: SW_Lang.getCurrent(),
minHeight: "200px",
},
shortcutsRemove: true,
subscribe: {
// we gotta trigger the on change of the originazl element. set the value and go with the flow
'editor.blur': function () {
$(this.$element.nodes[0]).val(this.app.editor.getContent());
var event = new Event('change');
this.$element.nodes[0].dispatchEvent(event);
}
},
paste: {
images: false,
blockTags: ['p']
},
})
;
return redactor_object;
},
// remove top bar
removeLoading: function () {
this.isLoading = false;
$("#top-loading").fadeOut(50);
},
// block just a div
blockDIV: function (selector, message) {
message = message ?? __("");
message = "";
$(selector).block({
message,
css: {
border: 'none',
padding: '15px',
top: '10%',
'-webkit-border-radius': '10px',
'-moz-border-radius': '10px',
'z-index': 95000,
},
// styles for the overlay
overlayCSS: {
backgroundColor: '#000',
opacity: 0.6,
cursor: 'wait',
'border-radius': '4px',
'z-index': 94999
},
});
},
unblockDIV: function (selector) {
$(selector).unblock();
},
// block the user interface
blockUI: function (message) {
//console.trace()
if (this.isBlocked == 1) {
return;
}
this.isBlocked = 1;
message = message ?? __("Een moment alstublieft");
message = "
" + message + "
";
SW_UI.OverlayHook("show");
// removing this
//this.setLoading();
$.blockUI({
message: message,
css: {
border: 'none',
padding: '15px',
'-webkit-border-radius': '10px',
'-moz-border-radius': '10px',
'z-index': 95000,
},
// styles for the overlay
overlayCSS: {
backgroundColor: '#000',
opacity: 0.6,
cursor: 'wait',
'z-index': 94999
},
onUnblock: function () {
SW_UI.removeLoading();
SW_UI.OverlayHook("hide");
}
});
},
// returns a link with title. url needs to be relative
linkApp: function (title, url) {
var link = '' + title + '';
return link;
},
blockUIMessage: function (message) {
$(".blockMsg").html(message);
},
unblockUI: function () {
this.isBlocked = 0;
$.unblockUI();
},
goHome: function () {
window.location = SW_Router.go("Dashboard", "");
},
// setup the modal fullscreen. Sets the dialog to fullscreen and also sets the table to fullscreen scrolling
fullScreenGridModal: function (table_id) {
return;
var modal = $("#" + table_id + "_wrapper").closest("div.modal");
// nothing to see here
if (modal.length < 1)
return;
var modal_id = modal.attr("id");
$("#" + modal_id).addClass("modal-fullheight");
var header_height = $("#" + modal_id + " .modal-header").outerHeight();
var footer_height = $("#" + modal_id + " .modal-footer").outerHeight();
var ht = window.innerHeight - 238;
var pp = ht - header_height - footer_height;
$('#' + modal_id + ' .dataTables_scrollBody').css({
"overflow": "visible",
"height": pp + "px",
"overflow-y": "scroll",
});
// and even more luxuries, autoscale when window resized
// do not add a listeren when we already have done this
if ($("#" + modal_id).hasClass("has_scale_listener"))
return;
$('#' + modal_id).addClass("has_scale_listener");
$(window).on('resize', function () {
SW_UI.fullScreenGridModal(table_id);
});
},
// wil open a ticket at the helpdesk
sendMessage: function (to, subject, body) {
data = {
'to': to,
'subject': subject,
'body': body,
};
SW_UI.runDialog(SW_Router.go("MySWRetail", "ticketUI"), data, "sw_dynamic_data");
},
// should provice a callback for handling a select click
webContentUI: function (clickfunc) {
SW_UI.blockUI();
SW_UI.runDialog(SW_Router.go("CMSForm", "webContentUI"));
if (clickfunc!=undefined)
{
$(document).off('click',"#webshopFileManager div.sw-img-manager-container");
$(document).on('click',"#webshopFileManager div.sw-img-manager-container",function(data) {
var source=$(this).find("img").attr("src");
var img_id=$(this).closest(".sw-grid-block").attr("data-id");
clickfunc(source,img_id);
});
}
},
hideTooltips: function () {
$('.tooltip').hide();
},
// run a dialog (fetch dialog from backend)
runDialog: function (dialog_url, requestdata, dialog_div, callback, run_before_dialog_start) {
if (SW_UI.inDialogLoading == 1) {
return;
} else {
SW_UI.inDialogLoading = 1;
}
// hide tooltips
$('.tooltip').hide();
dialog_div = dialog_div ?? "sw_dynamic_data";
if ($("#" + dialog_div).length == 0) {
var newdiv = "";
$("body").append(newdiv);
}
val = $.post(
dialog_url,
requestdata,
function (data) {
console.log(data);
if (data.error !== undefined) {
SW_UI.alert("Fout! "+data.errortext);
SW_UI.inDialogLoading = 0;
return;
}
if (run_before_dialog_start && typeof (run_before_dialog_start) === "function") {
run_before_dialog_start(data);
}
$("#" + dialog_div).html(data.html);
SW_RUN_DYNAMIC(window[callback]);
SW_UI.inDialogLoading = 0;
},
'json'
);
},
// hide all modals
hideModals: function () {
lastid = "";
$(".modal.in").each(function () {
$(this).modal("hide");
lastid = $(this).attr("id");
});
return lastid;
},
systemidSet: function (id) {
Lockr.set('CashRegister', id);
},
sideBarToggler: function (hide) {
if (hide == undefined) {
if ($(".sidebar:visible").length == 0) {
showSidebar();
} else {
hideSidebar();
}
// Reset fixedHeader
if ($('.fixedHeader').length != 0) {
handleFixedHeader();
}
return;
}
;
if (hide == true)
hideSidebar();
if (hide == false)
showSidebar();
},
systemidGet: function () {
var sysid = Lockr.get('CashRegister');
return sysid ?? "";
},
// hide an expanded navbar
hideNavbar: function () {
if (SW_UI.isMobileDevice()) {
$(".navbar-toggle").click();
}
},
startMyRegister: function () {
var location = SW_Router.go("TbltMain", "/");
if (SW_UI.systemidGet() != "") {
location += "/index/" + SW_UI.systemidGet();
}
window.location = location;
},
// test for visible modals, modal_id can be left empty or be the id of an mobile to test wether it is visible
modalsVisible: function (modal_id) {
if (modal_id != undefined) {
if ($("#" + modal_id + ".modal.in").length > 0) {
return true;
}
;
return false;
}
if ($(".modal.in").length > 0) {
return true;
}
;
return false;
},
// double callback function. if coice_b is a function then only one option button will be shown
aorb_dialog: function (question, dismissable, choice_a, choice_b, callback_a, callback_b, callback_close) {
SW_UI.hideModals();
SW_UI.OverlayHook("show");
var buttons = {};
var cb = true;
if ((choice_b && typeof (choice_b) === "function")) {
callback_a = choice_b;
}
;
buttons.choicea = {
label: choice_a,
className: "btn-default",
callback: function () {
SW_UI.OverlayHook("hide");
if (callback_a && typeof (callback_a) === "function") {
callback_a();
}
}
};
if (!(choice_b && typeof (choice_b) === "function")) {
buttons.choiceb = {
label: choice_b,
className: "btn-default",
callback: function () {
SW_UI.OverlayHook("hide");
if (callback_b && typeof (callback_b) === "function") {
callback_b();
}
}
};
}
;
bootbox.dialog({
message: question,
title: "",
buttons: buttons,
closeButton: cb,
onEscape: function () {
if (callback_close && typeof (callback_close) === "function") {
SW_UI.OverlayHook("hide");
callback_close();
}
}
});
},
// ask yes or nbo question with callback
yesorno: function (question, callback_yes, callback_no) {
last_modal_id = SW_UI.hideModals();
SW_UI.OverlayHook("show");
var confirm_settings = {
"message": question,
"callback": function (result) {
SW_UI.OverlayHook("hide");
if (last_modal_id != "") {
$("#" + last_modal_id).modal('show');
}
if (result == true) {
if (callback_yes && typeof (callback_yes) === "function") {
callback_yes();
}
} else {
if (callback_no && typeof (callback_no) === "function") {
callback_no();
}
}
},
"animate": false
};
bootbox.confirm(confirm_settings);
},
// default alert box
alert: function (input, callback) {
SW_UI.OverlayHook("show");
var message = input;
var title = "";
if ((Array.isArray(input))) {
title = input[0];
message = input[1];
}
bootbox.alert({
"message": message,
"title": title,
"animate": false,
"callback": function (result) {
SW_UI.OverlayHook("hide");
if (callback && typeof (callback) === "function") {
callback();
}
}
});
$(".bootbox-alert.in button").attr("data-sw-key", "F9");
},
// default alert box
alert_wide: function (input, callback) {
SW_UI.OverlayHook("show");
bootbox.alert({
"message": input,
"animate": false,
"size": "large",
"callback": function (result) {
SW_UI.OverlayHook("hide");
if (callback && typeof (callback) === "function") {
callback();
}
}
});
$(".bootbox-alert.in button").attr("data-sw-key", "F9");
},
valCompare: function (input) {
myval = input.value;
compval = $("#" + $(input).attr("valcheck")).val();
console.log(myval + " " + compval);
if (myval != compval) {
console.log("nop");
$(input).closest("div").addClass("has-warning")
} else {
$(input).closest("div").removeClass("has-warning")
}
},
valCompareSetup: function (input) {
val = 'SW_UI.valCompare(this);';
input.attr('onblur', val);
input.attr('onkeyup', val);
input.attr('onfocus', val);
},
setTooltips: function () {
// Tooltips
$('[rel="tooltip"]').tooltip();
},
showReceipt: function (id) {
this.setLoading();
this.runDialog(SW_Router.go("SWReceiptsView", "getReceiptUI", [id]), "", "receiptUI");
},
inViewport: function (elem) {
var el = document.getElementById($(elem).attr("id"));
var r, html;
if (!el || 1 !== el.nodeType) {
return false;
}
html = document.documentElement;
r = el.getBoundingClientRect();
return (!!r
&& r.bottom >= 0
&& r.right >= 0
&& r.top <= html.clientHeight
&& r.left <= html.clientWidth
);
},
// get the screen height
getScreenHeight: function (offset) {
if (offset == undefined)
offset = 0;
return (document.documentElement.clientHeight + offset);
},
barcodeFieldFocus: function () {
if ($("#barcodeinput").length > 0)
$("#barcodeinput").focus();
},
alertInDiv: function (text, div, type) {
$("#" + div).html('
' + text + '
');
$("#" + div).show();
clearTimeout(this.timerID);
this.timerID = setTimeout(function () {
$("#" + div).hide();
}, 15000);
},
reloadPage: function () {
location.reload();
},
logoff: function () {
Lockr.rm("logindata");
window.location = SW_Router.go("Medewerker", "logout");
},
// are we in PWA mode? i.e. on the homescreen of an android of iphone device?
isPWA: function () {
// ipad
if (window.navigator.standalone == true) {
return true;
//android
} else if (window.matchMedia('(display-mode: standalone)').matches === true) {
return true;
}
if (Lockr.get('isPWA') == "1")
return true;
return false;
},
forcePWA: function (off) {
off = off ?? 1;
Lockr.set('isPWA', off);
},
// start the helppoup
helpPopup: function (id, showall, callback, dismiss, fullscreen) {
SW_Help.helpPopup(id, showall, callback, dismiss, fullscreen);
},
marketingPopup: function (id) {
$("#sw_help_popup").remove();
SW_UI.blockUI();
$.post(SW_Router.go("SWHelp", "helppopup", [id, "marketing"]), function (data) {
SW_UI.unblockUI();
if (data.dialog != "") {
$("body").append(data.dialog);
$("#sw_help_popup").modal();
$('#sw_help_popup').on('hidden.bs.modal', function () {
$("#sw_help_popup").find(".sw_video").remove();
})
}
}, 'json').fail(function (response) {
SW_UI.unblockUI();
SW_UI.alert("Couldn't find item!");
});
},
loginHelpPopup: function (id) {
$("#sw_help_popup").remove();
SW_UI.blockUI();
$.post(SW_Router.go("SWHelp", "helppopup", [id, "small"]), function (data) {
SW_UI.unblockUI();
if (data.dialog != "") {
$("body").append(data.dialog);
$("#sw_help_popup").modal();
$('#sw_help_popup').on('hidden.bs.modal', function () {
$("#sw_help_popup").find(".sw_video").remove();
})
}
}, 'json');
},
loginHelpPopupHide: function () {
$("#sw_help_popup").modal('hide');
},
helpPage: function (id) {
window.location = SW_Router.go("SWHelp", "index", [id, "item_id"]);
},
// handle enter key processing in fields
enterHandler: function (event, callback) {
if (event.key == "Enter") {
if (callback && typeof (callback) === "function") {
callback();
}
return false;
}
return true;
},
// get the value of a update
configUpdaterGetValue: function (inputs) {
var data = [];
$(inputs).each(function (index) {
data[index] = {};
item = $(inputs)[index];
if ($(item).hasClass("sw_form_block_title_collapser")) {
if ($(item).hasClass("sw_form_block_title_open"))
data[index].value = 1;
else
data[index].value = 0;
} else {
data[index].value = $(item).val();
}
if ($(item).attr("type") == "checkbox") {
data[index].value = 0;
if ($(item).is(':checked'))
data[index].value = 1;
}
if ($(item).prop('nodeName') == "BUTTON")
data[index].value = "pressed";
data[index].id = $(item).attr("data-sw-id");
data[index].hash = $(item).attr("data-sw-hash");
data[index].element_id = $(item).attr("id");
data[index].element_name = $(item).attr("name");
data[index].element_parent_form = $(item).closest("form").attr("id");
});
return data;
},
//generic configuration update, gets called from forms / grid
configUpdate: function (inputs, callback) {
var data = {"items": SW_UI.configUpdaterGetValue(inputs)};
// remove all errors
$(inputs).each(function (i) {
$($(inputs)[i]).closest(".form-group").removeClass('has-error');
$($(inputs)[i]).closest(".form-group").find(".invalid-feedback").remove();
});
$.post(SW_Router.go(this.configUpdateController, "directUpdateMulti"), data, function (data) {
if (typeof (SW_UI_configUpdateCallback) === "function") {
SW_UI_configUpdateCallback(data);
}
// we're ok
if (data.status == "ok") {
$(data.additional).each(function (i) {
var cur = data.additional[i];
var t = cur["element_id"];
// and select the item
var item = $("#" + t);
if (cur.status == "error") {
$(item).closest(".form-group").addClass('has-error');
$(item).closest(".form-group").append('
' + cur.extended + '
');
}
if (item[0].hasAttribute("callback_after_update"))
eval($(item).attr("callback_after_update"));
});
}
if (callback && typeof (callback) === "function") {
callback(data);
}
}, 'json');
// update the shadow items and dismissboxes
$(inputs).each(function (i) {
var item = $(inputs)[i];
var item_id = $(item).attr("id");
$("input[data-sw-shadow='" + item_id + "']").each(function (index) {
$(this).val($(item).val());
SW_UI.configUpdate(this);
});
// and sync the input boxes
if ($(item).hasClass("sw_dismissbox")) {
$(item).closest("div").closest(".sw_dismissbox").hide();
}
;
});
},
// update configuration, hash comes from json_encoded $this->SWPanelCompiler->paramDirectEmployee, of when made paramDirect
configUpdateJSon: function (hash, value) {
var data = {};
data.id = hash.id;
data.value = value
data.hash = hash.hash;
$.post(SW_Router.go(this.configUpdateController, "directUpdate"), data, function (data) {
if (typeof (SW_UI_configUpdateCallback) === "function") {
SW_UI_configUpdateCallback(data);
}
}, 'json');
},
//generic configuration read
configRead: function (item) {
var data = {};
data.id = $(item).attr("data-sw-id");
data.hash = $(item).attr("data-sw-hash");
$.post(SW_Router.go(this.configUpdateController, "directRead"), data, function (data) {
$(item).val(data.additional.value);
}, 'json');
},
jumpTo: function (url, newwindow) {
newwindow = newwindow ?? true;
if (newwindow == true)
window.open(url);
else
window.location = url;
},
//set the barcode scanned module name
scannerSetModuleName: function (name) {
gScannerModuleName = name + " : ";
$('#barcodeinput').attr('placeholder', gScannerModuleName + 'Scan een barcode');
},
//returns true if IOS device, else it returns false
isIos: function () {
var ios = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if (ios == false) {
if (this.isIpad() == true)
return true;
}
return ios;
},
isAndroid: function () {
return /(android)/i.test(navigator.userAgent);
},
// uses a media query to determine mobile device (actually whether it is a device with a small screen but ok)
isMobileDevice: function () {
var result = window.matchMedia("(max-width: 768px)");
return result.matches;
},
isIpad: function () {
// ipados detection
if (navigator.maxTouchPoints != undefined) {
if (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) {
return true;
}
}
return /iPad/.test(navigator.userAgent) && !window.MSStream;
},
// align the help menu so that it appears properly
alignHelpMenu : function(ul) {
// Get the bounding rectangle of the ul element
const rect = ul.getBoundingClientRect();
// Get the width of the viewport excluding the scrollbar width
const viewportWidth = window.innerWidth - (window.innerWidth - document.documentElement.clientWidth);
// Calculate the amount of overflow on the right side
const overflow = (rect.left + rect.width) - viewportWidth;
// If there's no overflow or the ul is within the viewport, return 0
const overflowPixels = overflow > 0 ? overflow : 0;
// Set the margin-left to adjust the ul position
if (overflowPixels > 0) {
ul.style.marginLeft = `-${overflowPixels}px`;
}
},
tilesSave: function () {
var tiles_visible = {};
var itemIds = gTileGrid.getItems().map(function (item) {
if (item.isVisible())
tiles_visible[$(item.getElement()).attr("id")] = "1"
});
$.post(SW_Router.go("Dashboard", "Save"), tiles_visible, function (data) {
}, 'json');
},
// close tile
tileClose: function (id, save) {
save = save ?? true;
if ($("#" + id).hasClass("sw_tile_always"))
return;
$("li[name='" + id + "']").show();
gTileGrid.hide([$("#" + id)[0]], {instant: true});
// also stop video when there is video
var id = $("#" + id + " .video-js").attr("id");
if (id !== undefined) {
var player = videojs(id);
player = player.pause();
}
if (save)
this.tilesSave();
},
tileUp: function (id) {
if ($("#" + id).hasClass("sw_tile_always"))
return;
gTileGrid.synchronize();
var number = $(".muuri-item").index($("#" + id));
var next = $("#" + id).prevAll(".muuri-item-shown")[0];
var nextnumber = $(".muuri-item").index($("#" + $(next).attr("id")));
if (nextnumber == -1)
return;
// nothing to do here
if (number == 0)
return;
gTileGrid.move(number, nextnumber, {action: 'swap'});
gTileGrid.synchronize();
this.tilesSave();
},
tileDown: function (id) {
if ($("#" + id).hasClass("sw_tile_always"))
return;
gTileGrid.synchronize();
var number = $(".muuri-item").index($("#" + id));
var next = $("#" + id).nextAll(".muuri-item-shown")[0];
var nextnumber = $(".muuri-item").index($("#" + $(next).attr("id")));
if (nextnumber == -1)
return;
if (number > $(".muuri-item").length)
return;
gTileGrid.move(number, nextnumber, {action: 'swap'});
gTileGrid.synchronize();
this.tilesSave();
},
tileShow: function (id, save, movetofront) {
if (id == "_show_all_")
return this.tilesShowAll();
gTileGrid.show([$("#" + id)[0]]);
// move to 1st widget
if ((movetofront == undefined) || (movetofront == true)) {
gTileGrid.move($("#" + id)[0], 0);
}
$("li[name='" + id + "']").hide();
// resetup a possible graph
if ($("#" + id).find(".sw-chart").attr("data-sw-chartname") != undefined)
eval($("#" + id).find(".sw-chart").attr("data-sw-chartname") + '.render()');
if ((save == undefined) || (save == true)) {
this.tilesSave();
}
},
openSupplies: function () {
window.open("https://www.swretail.nl/supplies");
},
tilesShowAll: function () {
$(".muuri-item").each(function (number, item) {
SW_UI.tileShow($(item).attr("id"), false, false);
});
$(".sw_tile_always").each(function (ind, elem) {
gTileGrid.move(elem, 0);
});
SW_UI.tilesSave();
},
// puts an alert above the where element
// when no parameter given the alert is removed
inlineAlert: function (message, where) {
$(".sw_ui_inline_alert").remove();
if (message == undefined)
return;
var html = '
' + message + '
';
$(html).insertBefore(where);
},
tileSync: function () {
var activeItems = gTileGrid.getItems();
$.each(activeItems, function (index, item) {
if (item.isVisible()) {
$("li[name='" + $(item.getElement()).attr("id") + "']").hide();
} else
$("li[name='" + $(item.getElement()).attr("id") + "']").show();
});
},
select2: function (selector) {
$(selector).select2({"containerCssClass": "form-control", "width": "resolve"});
},
select2_selectall: function (item) {
var selector = $(item).attr("selector");
$(selector + " >option").prop("selected", "selected")
$(selector).trigger("change");
},
select2_deselectall: function (item) {
var selector = $(item).attr("selector");
$(selector + " > option").prop("selected", false);
$(selector).trigger("change");
},
select2setval: function (selector, val) {
$(selector).val(val).trigger('change.select2');
},
click: function (element) {
if ($(element).attr("target") == undefined || $(element).attr("target") == "" || $(element).attr("target") == "_self") {
//get the destination of the link clicked
var dest = $(element).attr("href");
//if the destination is an absolute url, ignore it
if (!dest.match(/^http(s?)/g)) {
//prevent default behavior (opening safari)
if (typeof (event) != "undefined")
event.preventDefault();
//update location of the web app
console.log(dest);
self.location = dest;
}
}
;
},
resizeToWindow: function (id, offsetbottom) {
SW_UI.resizerOffsetBottom = offsetbottom;
SW_UI.resizerID = id;
var height = $(window).height();
var rect = document.getElementById(id).getBoundingClientRect();
var remaining = height - rect.top;
remaining = remaining - offsetbottom;
$("#" + id).height(remaining + "px");
if (SW_UI.resizerInit == 0) {
SW_UI.resizerInit = 1;
$(window).resize(function () {
SW_UI.resizeToWindow(SW_UI.resizerID, SW_UI.resizerOffsetBottom);
});
}
},
helpRateItem: function (item, rating) {
SW_UI.blockUI();
$.post(SW_Router.go("SWHelp", "rateItem", [item, rating]), function (data) {
SW_UI.helpRatingsLoad();
SW_UI.unblockUI();
});
},
helpRatingsLoad: function () {
$.post(SW_Router.go("SWHelp", "rateItemGet"), function (data) {
var my = data.additional;
my.forEach(function (entry) {
$("[data-item='" + entry.item + "'] [data-state='up']").removeClass("btn-info");
$("[data-item='" + entry.item + "'] [data-state='down']").removeClass("btn-info");
if (entry.rating == "thumb_up")
$("[data-item='" + entry.item + "'] [data-state='up'] ").addClass("btn-info");
if (entry.rating == "thumb_down")
$("[data-item='" + entry.item + "'] [data-state='down'] ").addClass("btn-info");
});
}, 'json');
},
expt_waiting_start: function (selector) {
selector = selector ?? "div.modal-body:visible";
tmp_html = $(selector).html();
$(selector).empty();
$(selector).html('
');
},
expt_waiting_end: function (selector) {
selector = selector ?? "div.modal-body:visible";
$(selector).empty();
$(selector).html(tmp_html);
},
bottomToID: function (id, bottom, offsetbottom) {
var height = $("#" + bottom).height();
$("#" + bottom).height("1px");
;
var torect = document.getElementById(id).getBoundingClientRect();
var rect = document.getElementById(bottom).getBoundingClientRect();
var parentheight = torect.bottom - torect.top;
var posinparent = rect.top - torect.top;
console.log("pos in parent = " + posinparent);
console.log("parentheight = " + parentheight);
$("#" + bottom).height((parentheight - 20) + "px");
},
pwaSetupAutostart: function (module) {
Lockr.set("autoStart", module);
},
// setup specific styles for swretail in conjuntion with pwa etc
setupDynamicCSS: function (noscrolling, withbackground) {
var sheet = document.createElement('style')
if (this.isIpad()) {
$(sheet).append(".sw_notontablet {display:none}");
}
if (this.isPWA()) {
$(sheet).append(".sw_notonpwa {display:none !important}");
$(sheet).append("@media only screen and (max-width:768px) { " +
".sw_notonpwa_menu {display:none !important} " +
".sw_notonpwa_small {display:none !important} " +
".paneal-body {padding:0px} " +
"} ");
$(sheet).append("@media only screen and (max-width:768px) { .sw_notonpwa_small {display:none !important} } ");
$(sheet).append("@media only screen and (min-width:768px) { .sw_onpwa_small {display:none !important} } ");
// disable reload on drag down on android for the scanners
$(sheet).append("body { overscroll-behavior-y: contain; } ");
if (withbackground != undefined)
if (withbackground == true) {
$(sheet).append(' body {background:#ffffff}');
}
if (noscrolling == true)
$(sheet).append(' body {position:fixed;width:100%}');
} else {
$(sheet).append(".sw_onpwa {display:none !important}");
$(sheet).append("sw_onpwa_small {display:none !important} ");
}
// maximize screen real-estate on small screens
$(sheet).append("@media only screen and (max-width:768px) { .panael-body {padding:0px} }");
$(sheet).append(' #sw_totals {box-shadow:none}');
document.body.appendChild(sheet);
},
openWebshop: function () {
window.open(SW_Router.go("MySWRetail", "gotoWebshop"), '_blank');
},
addSerialnumber: function () {
$("#sw_modal_add_serialnumber").modal();
swSerialnumber.init();
},
filterNonPrintableCharacters: function (input) {
if (input == null || typeof input != 'string')
return false;
return input.replace(/[\x00-\x09\x14-\x1F\x7F\xA0]/g, '');
}
}
// catch these to handle modals
$(document).on("show.bs.modal", function (e) {
// lotta code for preventing the padding right on the navbar
if ($(document).height() > $(window).height()) {
$("body").addClass("modal_has_underlaying_scrollbar");
}
SW_UI.hideTooltips();
SW_UI.OverlayHook("show");
});
$(document).on("click","a.sw_video_link", function (e) {
SW_Help.helpPopup($(this).attr("data-sw-id"));
e.preventDefault();
});
// catch these to handle modals
$(document).on("hidden.bs.modal", function (e) {
$("body").removeClass("modal_has_underlaying_scrollbar");
SW_UI.OverlayHook("hide");
if (SW_UI.inViewport($("#barcodeinput")))
SW_UI.barcodeFieldFocus();
var tgt = $(e.target);
if (tgt.attr("data-sw-onclose") != undefined) {
eval(tgt.attr("data-sw-onclose"));
}
SW_UI.hideTooltips();
});
// Hide overlays when menus shown. However do not hide overlays on dropdows that have class keepoverlay. This is needed so that the dropdownmenus in a floating block do not cause the floating block to disappear
$(document).on("shown.bs.dropdown", function (e) {
if (!$(e.target).hasClass("keepoverlay"))
SW_UI.OverlayHook("show");
});
$(document).on("hide.bs.dropdown", function (e) {
if (!$(e.target).hasClass("keepoverlay")) {
SW_UI.OverlayHook("hide");
}
});
// startup function
$(function () {
bootbox.setDefaults({
locale: SW_Lang.getCurrent()
});
// Check for mobile device.
var isMobile = false;
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Opera Mobile|Kindle|Windows Phone|PSP|AvantGo|Atomic Web Browser|Blazer|Chrome Mobile|Dolphin|Dolfin|Doris|GO Browser|Jasmine|MicroB|Mobile Firefox|Mobile Safari|Mobile Silk|Motorola Internet Browser|NetFront|NineSky|Nokia Web Browser|Obigo|Openwave Mobile Browser|Palm Pre web browser|Polaris|PS Vita browser|Puffin|QQbrowser|SEMC Browser|Skyfire|Tear|TeaShark|UC Browser|uZard Web|wOSBrowser|Yandex.Browser mobile/i.test(navigator.userAgent))
isMobile = true;
// Tooltips
if (!isMobile) {
// Hide tooltip for mobile devices.
$('#sidebar-toggle').tooltip({placement: 'bottom'});
$('[rel="tooltip"]').tooltip();
}
// Toggle sidebar
if ($('#sidebar-toggle').length != 0) {
$('#sidebar-toggle').click(toggleSidebar);
$('.main-header:not(.no-click) ').click(toggleSidebar);
}
});
// some selection api changes for the grids
$.fn.dataTable.Api.register('SW_Selected()', function (row) {
tableId = $(row).closest("table").attr("id");
if (tableId === undefined)
return;
url = $("#" + tableId).attr("myurl");
id = $(row).attr("id");
var item = {'parent_ids': id, 'table': tableId};
$.post(url + "selectRow", item, function (data) {
if ($(row).hasClass('active')) {
$(row).removeClass('active');
} else {
$(row).addClass('active');
}
});
});
$.fn.dataTable.Api.register('SW_SelectedCount()', function (callback) {
var thetable = $(this.table().node());
url = thetable.attr("myurl");
$.post(url + "countSelection/" + thetable.attr("id"), function (data) {
if (callback && typeof (callback) === "function") {
callback(data);
}
}, 'json');
});
$.fn.dataTable.Api.register('SW_SelectedClear()', function (callback) {
var thetable = $(this.table().node());
url = thetable.attr("myurl");
$.post(url + "clearSelection/" + thetable.attr("id"), function (data) {
if (callback && typeof (callback) === "function") {
callback(data);
}
}, 'json');
});
$.fn.dataTable.Api.register('SW_getColumnIndex()', function (tosearchfor) {
var colidx = 0;
var colfound = -1;
this.columns().every(function () {
var data = this.data();
if ($(this.header()).attr("data-sw-binding") == tosearchfor) {
colfound = colidx;
}
colidx++;
});
return colfound;
});
// align hte help menu properly so it is always on screen, we need to hook into the popup and then align it
$(document).on('shown.bs.dropdown', (event) => {
const targetButton = event.relatedTarget;
if (targetButton && targetButton.classList.contains('sw_menu')) {
const ulElement = document.querySelector('ul.sw-help-menu');
SW_UI.alignHelpMenu(ulElement);
}
});
// pressing enter should not proceed to the next input box
var gEnterBlocking = true;
$(document).on('keypress', 'input', function (e) {
if ((gEnterBlocking == true)) {
var target = $(e.target);
if (e.keyCode == 13) {
e.preventDefault();
if (target.attr("sw-enter-next"))
eval(target.attr("sw-enter-next"));
$.tabNext();
}
}
;
});
// stay in brwoser always. needed for ios, links must be loaded via javascript otherwise app opens the webbrowser
;(function ($) {
//extend the jQuery object, adding $.stayInWebApp() as a function
$.extend({
stayInWebApp: function (selector) {
//detect iOS full screen mode
if (("standalone" in window.navigator) && window.navigator.standalone) {
//if the selector is empty, default to all links
if (!selector) {
selector = 'a';
}
//bind to the click event of all specified elements
$("body").delegate(selector, "click", function (event) {
//only stay in web app for links that are set to _self (or not set) and do not have an onclick
if ($(this).attr("onclick") == "")
if ($(this).attr("target") == undefined || $(this).attr("target") == "" || $(this).attr("target") == "_self") {
//get the destination of the link clicked
var dest = $(this).attr("href");
//if the destination is an absolute url, ignore it
if (!dest.match(/^http(s?)/g)) {
//prevent default behavior (opening safari)
event.preventDefault();
//update location of the web app
self.location = dest;
}
}
});
}
} //end stayInWebApp func
});
})(jQuery);
window.onpopstate = function (event) {
console.log("popstate");
if (event.state) {
console.log(event.state.url);
}
return false;
};
// OSD keyboard handling
// for normal processing loop trhough the $(document).keypress(function(e) { sw_keyb.processKeypress(e);}); just needed in cases where the is no barcodehandler like the swreceiptsview
var sw_keyb = {
gGotFocus: null,
gTimer: null,
gShift: false,
fKeys: {
"112": "F1",
"113": "F2",
"114": "F3",
"115": "F4",
"116": "F5",
"117": "F6",
"118": "F7",
"119": "F8",
"120": "F9",
"121": "F10"
},
keyLookup: function (keycode) {
if (this.fKeys[keycode] != undefined) {
return this.fKeys[keycode];
}
return undefined;
},
genericPadSetFocus: function (item) {
this.gGotFocus = "#" + $(item).attr("id");
item.onblur = function (event) {
sw_keyb.onBlur(this, event)
}
// clear out on doubleclick
item.ondblclick = function () {
$(item).val("");
}
},
// set data-sw-onchange to handle a notification when clicked
onBlur: function (input, event) {
var cur = $(event.relatedTarget);
if (cur.hasClass("sw_generic_pad"))
return true;
if (!cur.hasClass("sw_generic_pad")) {
if ($(input).attr("data-sw-onchange")) {
var func = $(input).attr("data-sw-onchange") + "($('#" + $(input).attr("id") + "'))";
eval(func);
} else {
$(input).trigger("onchange");
}
}
;
if (!cur.hasClass("sw_want_keyinput")) {
this.gGotFocus = null;
}
},
// called when input has changed, can run a generic funtoin from data-sw-oninput attribute
onChange: function (input) {
if ($(input).attr("data-sw-oninput")) {
var func = $(input).attr("data-sw-oninput") + "($('#" + $(input).attr("id") + "'))";
eval(func);
}
return;
},
keyDownHandler: function (e) {
// should event bubble
return true;
},
processBackspace: function (e) {
},
processKeypress: function (e) {
},
// load the buttons with their values
setItems: function () {
$(".sgp_shift").each(function (index) {
var val = $(this).attr("sw_data");
if (sw_keyb.gShift == false)
val = val.charAt(0);
else
val = val.charAt(1);
$(this).html(val);
});
},
// items si the first input that will be selected.
genericPadClick: function (e, items) {
var val = $(e).attr('sw_data');
if (items != undefined) {
var t = items.split(";");
var fc = t[0];
if (this.gGotFocus == null)
this.gGotFocus = fc;
}
var target = this.gGotFocus;
//apptmp console.log("genericPadClick Target = "+target);
if (val !== 'undefined') {
switch (val) {
case 'SHIFT':
if (this.gShift == true)
this.gShift = false;
else
this.gShift = true;
this.setItems();
break;
case 'BS':
var [astart, aend] = [$(target)[0].selectionStart, $(target)[0].selectionEnd];
// when no content do nothing
if (astart == 0)
return;
$(target)[0].setRangeText("", astart - 1, aend, 'end');
break;
// normal key
default:
if (this.gShift == false)
val = val.charAt(0);
else {
val = val.charAt(1);
}
const [start, end] = [$(target)[0].selectionStart, $(target)[0].selectionEnd];
$(target)[0].setRangeText(val, start, end, 'end');
break;
}
}
this.onChange(target);
}
}
// help wrapper for clean help handling
var SW_Help = {
// email a topic to indicated addresses
emailTopic: function (item_id) {
$.get(SW_Router.go("Configuration", "getAllAdministrators"), function (data) {
var url = SW_Router.go("SWHelp", "mailHelpText", [item_id]);
bootbox.prompt({
title: __("Geef email adressen (; gescheiden)"),
value: data.additional,
callback: function (emailadress) {
if (emailadress !== null) {
SW_UI.blockUI();
url = url + "?to_address=" + encodeURI(emailadress);
$.ajax({
url: url,
}).done(function (data) {
SW_UI.unblockUI();
SW_UI.alert(__("E-Mail verstuurd!"));
});
}
}
});
}, 'json');
},
// same as topic but we can also specify the file
emailHelpChapter: function (file, item_id) {
$.get(SW_Router.go("Configuration", "getAllAdministrators"), function (data) {
var url = SW_Router.go("SWHelp", "mailHelpChapter", [file, item_id]);
bootbox.prompt({
title: __("Geef e-mail adressen (; gescheiden)"),
value: data.additional,
callback: function (emailadress) {
if (emailadress !== null) {
SW_UI.blockUI();
url = url + "?to_address=" + encodeURI(emailadress);
$.ajax({
url: url,
}).done(function (data) {
SW_UI.unblockUI();
SW_UI.alert(__("E-Mail verstuurd!"));
});
}
}
});
}, 'json');
},
// start the helppoup
helpPopup: function (id, showall, callback, dismiss, fullscreen) {
fullscreen = fullscreen ?? true;
$("#sw_help_popup").remove();
SW_UI.blockUI();
SW_UI.hideModals();
var collapsed = 1;
if (showall != undefined)
if (showall == true)
collapsed = 0;
$.post(SW_Router.go("SWHelp", "helppopup", [id, "normal", collapsed, dismiss]), function (data) {
SW_UI.unblockUI();
if (data.dismissed == 1) {
if (callback != undefined)
eval(callback + "()");
return;
}
if (data.dialog != "") {
$("body").append(data.dialog);
$("#sw_help_popup").attr("callback", callback);
// some nice ballpark width
$("#sw_help_jumper").select2({'width': ' 100%'});
$("#sw_help_popup").modal();
$('#sw_help_popup').off('hidden.bs.modal');
if (fullscreen == false)
$("#sw_help_popup").addClass("sw_do_not_fullsize");
$('#sw_help_popup').on('hidden.bs.modal', function () {
$("#sw_help_popup").find(".sw_video").remove();
if ($("#sw_help_popup").attr("callback") != "")
if ($("#sw_help_popup").attr("callback") != undefined)
eval($("#sw_help_popup").attr("callback") + "()");
});
}
}, 'json').fail(function (response) {
SW_UI.unblockUI();
SW_UI.alert("Couldn't find helpitem!");
});
},
}
// caching engine for SW-Retail for in the browser. wrapper around lockr
var SW_Cache = {
prefix: 'sw_cache_',
read: function (tag) {
return Lockr.get(this.prefix + "_" + tag);
},
write: function (tag, value) {
Lockr.set(this.prefix + "_" + tag, value);
},
// read user specific cache
read_user: function (tag) {
return Lockr.get(this.prefix + "_uid" + SW_RoutingData.currentUserID + "_" + tag + "_" + tag);
},
// write user specific cache
write_user: function (tag, value) {
Lockr.set(this.prefix + "_uid" + SW_RoutingData.currentUserID + "_" + tag, value);
},
// set timestamp
setts: function (ts) {
Lockr.set(this.prefix + "_timestamp", ts);
},
getts: function () {
return Lockr.get(this.prefix + "_timestamp");
},
clear: function (prefix) {
var pfx = this.prefix;
if (prefix != undefined)
pfx = this.prefix + "_" + prefix;
for (var key in localStorage) {
if (key.beginsWith(pfx)) {
Lockr.rm(key);
}
}
}
}
/**
SW_Router.go(controller,action,[array with parameters] )
SW_Router.go(action) -> to current controller and action
SW_Router.go(action,[array with parameters]) -> to current controller and action
SW_Router.currentURL -> get a link to the current URL (except options
uses SWRoutingData for generating urls
*/
var SW_Router = {
getVersion: function () {
return SW_RoutingData.currentVersion;
},
// get the base url to the app
getBaseURL: function (options, version) {
var addversion = "";
if (version == undefined)
version = false;
if (version == true)
addversion = "?version=" + SW_RoutingData.currentVersion;
if (options != undefined) {
if (Array.isArray(options)) {
options.forEach(function (element, index) {
options[index] = encodeURI(element);
});
var tmp = options.join("/");
return SW_RoutingData.baseURL + options + addversion;
} else
return SW_RoutingData.baseURL + options + addversion;
}
return SW_RoutingData.baseURL + addversion;
},
getController: function () {
return SW_RoutingData.currentController;
},
getAction: function () {
return SW_RoutingData.currentAction;
},
currentURL: function () {
return SW_RoutingData.baseURL + SW_RoutingData.currentController + "/" + SW_RoutingData.currentAction;
},
// options should be an array of extra url parameters
go: function (controller, action, options, random) {
if (controller == undefined)
return SW_RoutingData.baseURL + SW_RoutingData.currentController;
// shift right all params
if ((Array.isArray(action)) || (action == undefined)) {
options = action;
action = controller;
controller = SW_RoutingData.currentController;
}
if (action == "/")
action = "";
else
action = "/" + action;
if (options == undefined)
return SW_RoutingData.baseURL + controller + action;
if (random != undefined)
random = "?" + Math.random();
else
random = "";
if (Array.isArray(options)) {
options.forEach(function (element, index) {
options[index] = encodeURI(element);
});
var tmp = options.join("/");
return SW_RoutingData.baseURL + controller + action + "/" + tmp + random;
}
return SW_RoutingData.baseURL + controller + action + "/" + tmp + random;
},
jumpModule: function (module) {
SW_UI.blockUI();
switch (module) {
case "cashregister":
window.location = SW_Router.go("TbltMain", "index", [SW_UI.systemidGet()]);
break;
case "orderpicker":
window.location = SW_Router.go("SWBackofficeOP", "/");
break;
case "retourpicker":
window.location = SW_Router.go("SWBackofficeRP", "/");
break;
case 'artomatic':
window.location = SW_Router.go("ArticleInfo", "artomatic");
break;
case 'backoffice':
window.location = SW_Router.go("SWBackoffice", "/");
break;
case "dashboard":
window.location = SW_Router.go("Dashboard", "/");
break;
case "swinventory":
window.location = SW_Router.go("SWInventory", "/");
break;
case "scanner":
window.location = SW_Router.go("scan", "/");
break;
default:
window.location = SW_Router.go("Dashboard", "Show");
break;
}
},
getURLParameters: function () {
return window.location.search;
},
//helper for creating a nice object
helper_paramsToObject: function (entries) {
const result = {}
for (const [key, value] of entries) { // each 'entry' is a [key, value] tupple
result[key] = value;
}
return result;
},
// get the url parameters as an object
getURLParamsObject: function () {
let params = new URLSearchParams(window.location.search);
return this.helper_paramsToObject(params);
}
};
var gRemoveAllScannerInputs = true;
const audioManager = new AudioPlayer();
function loadAudio()
{
audioManager.load('beep_ok', SW_Router.getBaseURL(["beep_ok.wav"], true));
audioManager.load('beep_error', SW_Router.getBaseURL(["boing_x.wav"], true));
audioManager.load('beep_warning', SW_Router.getBaseURL(["beep_warning.wav"], true));
audioManager.load('code_ok', SW_Router.getBaseURL(["scan_ok.wav"], true));
}
// startup function
$(function () {
// setup specific styles for swretail in conjuntion with pwa etc
SW_UI.setupDynamicCSS();
// add a custom header to all ajax requests
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader('x-swretail-webclient', 'true');
}
});
var version=SW_Cache.read("audio_version");
if (version!=SW_Router.getVersion())
{
console.log("audio version reset");
SW_Cache.write("audio_version",SW_Router.getVersion());
audioManager.flush().then(() => {
loadAudio();
}).catch(error => {
console.error('Error clearing the database:', error);
});
} else
loadAudio();
// scroll to a div click handler
$(document).on("click", ".sw_scroller", function (e) {
e.preventDefault();
// maybe there is an offset in the parent diff
var offset = 200;
var scroll_offset = $(this).closest("ul").attr("data-scroll-offset");
if (scroll_offset != undefined)
offset = offset + parseInt(scroll_offset);
SW_UI.scrollTo($(this).attr("name"), offset);
});
// readonly checkboxes should not do anything
$(document).on("click", ".form-switch input.readonly", function (data) {
return false;
})
// pull to refresh init
const ptr = PullToRefresh.init({
mainElement: 'body',
distThreshold: 180,
distMax: 200,
instructionsPullToRefresh: __("Omlaag trekken om te verversen."),
instructionsReleaseToRefresh: __("Loslaten om te verversen."),
instructionsRefreshing: __("Verversen."),
// only refresh when no modals in the screen
shouldPullToRefresh: function(){
if (SW_UI.modalsVisible())
{
return false;
}
// default functionality
return !window.scrollY;
},
onRefresh() {
SW_UI.hideModals();
SW_UI.blockUI();
window.location.reload();
}
});
});
// experimental, does nothing
var gridNav = {
getCurPage: function (grid) {
console.log($("#" + grid + "_paginate .pagination li.paginate_button.active a").attr("data-dt-idx"));
},
nextPage: function () {
},
}
///////////////////////////////////////////////////
// autocomplete control
class Autocomplete {
encapsulateInput(inputId) {
// Get the input element by its ID
const inputElement = document.getElementById(inputId);
// Check if the input element exists
if (!inputElement) {
console.error(`No input element found with ID: ${inputId}`);
return;
}
// Create a new div element
const divElement = document.createElement('div');
// Set the div's style to have position: relative
divElement.style.position = 'relative';
// Get the parent of the input element
const parentElement = inputElement.parentNode;
// Insert the div before the input element
parentElement.insertBefore(divElement, inputElement);
// Move the input element inside the div
divElement.appendChild(inputElement);
}
// data can either be a json string, or an url to a dataprovider
// the url gets called with ?query= or /clear for clearing data
constructor(inputId, dropdownId, data) {
this.input = document.getElementById(inputId);
this.dropdown = document.getElementById(dropdownId);
this.encapsulateInput(inputId);
if (this.dropdown == undefined) {
const dropdown = document.createElement('div');
dropdown.className = 'autocomplete-dropdown';
dropdown.id = 'autocomplete-dropdown-' + this.input.id;
var parent = this.input.parentNode;
var nextelem = this.input.nextSibling;
parent.insertBefore(dropdown, nextelem);
this.dropdown = dropdown;
}
if (Array.isArray(data)) {
this.data = data;
this.url = false;
} else {
this.data = false;
this.url = data;
}
this.selectedIndex = -1;
this.addClear = false;
this.setupEventListeners();
}
addClearButton() {
this.addClear = true;
}
setupEventListeners() {
// Event listener for changes in the input
this.input.addEventListener('input', () => this.handleInput());
// Event listener to open the dropdown on the first click
this.input.addEventListener('click', () => this.handleFirstClick());
// Event listener to close the dropdown when clicking outside the autocomplete box
document.addEventListener('click', (event) => this.handleClickOutside(event));
// Prevent the input click event from propagating to the document click event
this.input.addEventListener('click', (event) => event.stopPropagation());
// Event listener for keydown events
this.input.addEventListener('keydown', (event) => this.handleKeydown(event));
}
handleKeydown(event) {
const dropdownItems = this.dropdown.querySelectorAll('.autocomplete-dropdown-item');
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
this.navigateDropdown('down', dropdownItems);
break;
case 'ArrowUp':
event.preventDefault();
this.navigateDropdown('up', dropdownItems);
break;
case 'Enter':
event.preventDefault();
this.handleEnterKey();
break;
}
}
navigateDropdown(direction, items) {
if (items.length === 0) return;
if (direction === 'down' && this.selectedIndex < items.length - 1) {
this.selectedIndex++;
} else if (direction === 'up' && this.selectedIndex > 0) {
this.selectedIndex--;
}
this.updateSelectedClass(items);
}
handleEnterKey() {
const selectedElement = this.dropdown.querySelector('.autocomplete-selected');
if (selectedElement) {
this.input.value = selectedElement.childNodes[1].textContent;
console.log(this.input.value);
this.clearDropdown();
this.itemSelected();
} else {
this.itemSelected();
}
}
updateSelectedClass(items) {
// Remove the "selected" class from all items
items.forEach((item, index) => {
if (index === this.selectedIndex) {
item.classList.add('autocomplete-selected');
} else {
item.classList.remove('autocomplete-selected');
}
});
}
async handleInput() {
const inputValue = this.input.value.toLowerCase();
// Clear previous results
this.dropdown.innerHTML = '';
this.selectedIndex = -1;
try {
var data;
// Fetch data from the server
if (!this.data) {
const response = await fetch(`${this.url}?query=${inputValue}`);
data = await response.json();
} else {
data = this.data;
}
this.dropdown.innerHTML = '';
// Create and append dropdown items
data.forEach((item, index) => {
const dropdownItem = document.createElement('div');
dropdownItem.className = 'autocomplete-dropdown-item';
dropdownItem.textContent = item;
// Create delete button
const deleteButton = document.createElement('span');
deleteButton.className = 'autocomplete-delete-button';
deleteButton.textContent = 'X';
deleteButton.addEventListener('click', (event) => {
event.stopPropagation(); // Prevent dropdown from closing
this.deleteDropdownItem(item); // Call deleteDropdownItem function
dropdownItem.remove(); // Remove item from dropdown
});
dropdownItem.prepend(deleteButton); // Add delete button to dropdown item
dropdownItem.addEventListener('click', () => this.handleItemClick(item));
dropdownItem.addEventListener('mouseenter', () => this.handleItemMouseEnter(index));
this.dropdown.appendChild(dropdownItem);
});
if (this.addClear) {
const clearListButton = document.createElement('div');
clearListButton.className = 'clear-list-button';
clearListButton.textContent = __('Lijst wissen');
clearListButton.addEventListener('click', () => this.removeAutoCompleteData());
this.dropdown.appendChild(clearListButton);
}
// Show the dropdown
this.dropdown.style.display = data.length ? 'block' : 'none';
// If there are no results, hide the dropdown and call SW_UI.OverlayHook("hide");
if (data.length === 0)
this.clearDropdown();
if (this.isDropdownVisible())
SW_UI.OverlayHook("show");
} catch (error) {
console.error('Error fetching data:', error);
}
}
// and clear the data
async removeAutoCompleteData() {
this.clearDropdown();
const response = await fetch(`${this.url}/clear`);
await response.json();
}
handleItemMouseEnter(index) {
// Update the selected index on mouse enter
this.selectedIndex = index;
const dropdownItems = this.dropdown.querySelectorAll('.autocomplete-dropdown-item');
this.updateSelectedClass(dropdownItems);
}
handleFirstClick() {
if (this.isDropdownVisible())
return;
// Show the dropdown on the first click
this.handleInput();
// Show the dropdown
//this.dropdown.style.display = 'block';
}
isDropdownVisible() {
// Check if the dropdown is currently visible
return this.dropdown.style.display === 'block';
}
handleClickOutside(event) {
const isClickInside = this.input.contains(event.target) || this.dropdown.contains(event.target);
if (!isClickInside) {
// Clicked outside the autocomplete box, hide the dropdown
if (this.isDropdownVisible())
this.clearDropdown();
}
}
handleItemClick(item) {
// Set the selected item in the input field
this.input.value = item;
// Clear the dropdown
this.clearDropdown();
this.itemSelected();
}
async deleteDropdownItem(item) {
console.log('Deleted item:', item);
const response = await fetch(`${this.url}/remove?data=${item}`);
data = await response.json();
// Add logic to delete item from your data source
}
clearDropdown() {
// Hide the dropdown
this.dropdown.style.display = 'none';
// Call SW_UI.OverlayHook("hide");
//console.log("cleaR");
if (!SW_UI.modalsVisible())
SW_UI.OverlayHook("hide");
}
// Gets run when an item is selected. needs the data-onselect item to be filled
itemSelected() {
// Get the function name from the data-attribute
const script = this.input.dataset.onselect;
if (script != "")
eval(script);
}
}
// fancy textarea control
class FancyTextarea {
constructor(selector) {
this.container = document.querySelector(selector);
if (this.container) {
this.textarea = this.container.querySelector('textarea');
this.button = this.container.querySelector('button');
this.initEvents();
this.autoGrow();
}
}
initEvents() {
this.textarea.addEventListener('focus', () => this.container.classList.add('focused'));
this.textarea.addEventListener('blur', () => this.container.classList.remove('focused'));
this.textarea.addEventListener('input', () => this.autoGrow());
// verbetering zodat de clik op de caontiner ook leidt tot een focus
this.container.addEventListener('click', () => this.focusTextarea());
this.textarea.addEventListener('keydown', (e) => this.handleEnterPress(e));
}
focusTextarea() {
this.textarea.focus();
}
handleEnterPress(e) {
if (e.key === 'Enter' || e.keyCode === 13) {
e.preventDefault(); // Voorkom dat de Enter-toets een nieuwe regel invoegt
this.button.click(); // Simuleer een klik op de knop
}
}
autoGrow() {
this.textarea.style.height = '18px'; // Reset de hoogte zodat deze kan krimpen bij verwijderen van tekst
this.textarea.style.height = (this.textarea.scrollHeight) + 'px'; // Stel de hoogte in op de scrollHeight om alle tekst te passen
}
}
// handle overlays efficiently
// looks like the card manager but it is different
var swOverlayer = {
showOverlay: function (selector) {
$(".sw-ui-overlayed").addClass("hide");
$(selector).removeClass("hide");
$(selector).addClass("sw-ui-overlayed");
},
hideOverlay: function () {
$(".sw-ui-overlayed").addClass("hide");
}
}
///////////////////////////////////////////////////
// card manager for overlaying screens on top of each other
var SW_CardMGT = {
currentCard: "#sw_block_main",
getCurrent: function () {
return SW_CardMGT.currentCard;
},
historyClear: function () {
Lockr.set('cash_CardHistory', []);
},
toggleInputs: function () {
// init when not run
if ($(this.currentCard).attr("data-sw-disabled") == undefined)
$(this.currentCard).attr("data-sw-disabled", "false");
if ($(this.currentCard).attr("data-sw-disabled") == "false") {
$.each($(this.currentCard + " input," + this.currentCard + " button," + this.currentCard + " select"), function (index, item) {
if ($(item).prop("disabled"))
$(item).attr("data-sw-disabled-was", "1");
$(item).prop("disabled", true)
});
$(this.currentCard).attr("data-sw-disabled", "true");
} else {
$(this.currentCard).attr("data-sw-disabled", "false");
$.each($(this.currentCard + " input," + this.currentCard + " button," + this.currentCard + " select"), function (index, item) {
if ($(item).attr("data-sw-disabled-was") != "1")
$(item).prop("disabled", false)
});
}
},
historyPush: function (cardid) {
var history = Lockr.get('cash_CardHistory');
if (history == undefined)
var history = [];
history.push(cardid);
if (history.length > 20)
history = history.slice(-1);
Lockr.set('cash_CardHistory', history);
},
showCard: function (cardid) {
if (cardid == undefined)
cardid = this.currentCard;
else {
if (this.currentCard != cardid)
this.historyPush(this.currentCard);
this.currentCard = cardid;
}
$(cardid).addClass("sw_tablet_card");
$(cardid).removeClass("hidden");
if ($(cardid).attr("data-sw-card-additional-div") != "")
$("#" + $(cardid).attr("data-sw-card-additional-div")).removeClass("hidden");
if ($(cardid).attr("data-sw-card-has-scanning") == "1")
barcodescanningSwitch(true);
if ($(cardid).attr("data-sw-card-set-state") != undefined) {
$.post(SW_Router.go(SW_Router.getController(), "updateState"), getCommonRequestData({"state": $(cardid).attr("data-sw-card-set-state")}), function (data) {
}, 'json');
}
},
hideCard: function () {
if ($(this.currentCard).attr("data-sw-card-has-scanning") == "1")
barcodescanningSwitch(false);
if ($(this.currentCard).attr("data-sw-card-additional-div") != "")
$("#" + $(this.currentCard).attr("data-sw-card-additional-div")).addClass("hidden");
$(this.currentCard).addClass("hidden");
return this.currentCard;
}
}