ElixirVault/www/js/base.js

1941 lines
72 KiB
JavaScript

"use strict";
/**
* @property {string} no
* @property {string} yes
*
* @property {string} baseUrl
* @property {string} sessionTime
* @property {string} sessionLoginLink
*
* @property {string} show_login_frm
* @property {string} reqLogin
* @property {string} pRedirect
* @property {string} subCfg
* @property {string} fData
*
* @property {string} JsModuleTitle
* @property {boolean} JsInitPostpone
*
* @property {string} msg_subscription_title
* @property {string} msg_request
* @property {string} msg_request_download
* @property {string} msg_continue
* @property {string} msg_download
* @property {string} msg_cancel
*/
var JsVars, Calc, PBaseUrl, PCheckBoxes;
var AjaxLoader, AppBase;
if(!String.prototype.trim){
String.prototype.trim = function (){
return this.replace(/^\s+|\s+$/g, "");
};
}
if(!Date.prototype.addDays){
Date.prototype.addDays = function(days){
var d = new Date(this.valueOf());
d.setDate(d.getDate() + days);
return d;
}
}
if(!Array.prototype.sum){
Array.prototype.sum = function(){
return this.reduce(function(a,b){return a+b;});
};
}
(function(){
/**
* Dynamically loads a JavaScript class from a file path.
* @param {string} filePath - Path to the .js file (e.g., './models/User.js')
* @param {string} [className] - Optional: specific export name. Defaults to the default export.
* @returns {Promise<Function>} - The loaded class constructor
*/
async function loadClass(filePath, className = null) {
try {
const module = await import(filePath);
if (className) {
if (!module[className]) {
throw new Error(`Class "${className}" not found in module "${filePath}"`);
}
return module[className];
}
// Fall back to default export
if (module.default) {
return module.default;
}
throw new Error(`No default export or named class found in "${filePath}"`);
} catch (err) {
throw new Error(`Failed to load class from "${filePath}": ${err.message}`);
}
}
/********************************************************************
* GLOBAL FUNCTIONS
********************************************************************/
window.pr = function(obj){
if("console" in window){
var vArgs = Array.from(arguments);
for(var i = 0; i < vArgs.length; i++){
console.log(vArgs[i]);
}
}
};
window.mprint = function(obj){
if("console" in window){
var vArgs = Array.from(arguments);
for(var i = 0; i < vArgs.length; i++){
console.log(vArgs[i]);
}
}
};
window.toBinaryStr = function(str) {
const encoder = new TextEncoder();
// 1: split the UTF-16 string into an array of bytes
const charCodes = encoder.encode(str);
// 2: concatenate byte data to create a binary string
return String.fromCharCode(...charCodes);
}
window.toBase64encode = function(str) {
return btoa(toBinaryStr(str));
}
// Sets default variable
window.defaultVal = function(arg, val){
return typeof arg !== 'undefined' && arg !== null ? arg : val;
};
// Sets default variable even if var exists and is false
window.defaultValNotFalse = function(arg, val){
var rVal = defaultVal(arg, val);
if(rVal === false)
return val;
return rVal;
};
window.roundNumber = function (num, dec) {
return Number(Math.round(parseFloat(num+'e'+dec))+'e-'+dec).toFixed(dec);
};
// Format date
window.formatDateToString = function(date){
// 01, 02, 03, ... 29, 30, 31
var dd = (date.getDate() < 10 ? '0' : '') + date.getDate();
// 01, 02, 03, ... 10, 11, 12
var MM = ((date.getMonth() + 1) < 10 ? '0' : '') + (date.getMonth() + 1);
// 1970, 1971, ... 2015, 2016, ...
var yyyy = date.getFullYear();
// create the format you want
return (dd + "." + MM + "." + yyyy);
};
// Add jQuery object check function
$.isObject = function(e){ return !(typeof e !== "object"); };
$.isDefined = function(e){ return (typeof e !== "undefined"); };
/********************************************************************
* BASE jQuery plugin extensions
********************************************************************/
// Create Jquery Pseudo for case insensitive text lookup
jQuery.expr[":"].icontains = jQuery.expr.createPseudo(function (arg) {
return function (elem) {
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
jQuery.fn.hasAttr = function(name) {
return this.attr(name) !== undefined;
};
/********************************************************************
* GLOBAL FUNCTIONS
********************************************************************/
Calc = (function() {
function Calc(num) {
if (typeof (Big) !== "undefined") {
this.oBig = new Big(defaultVal(num, 0));
} else pr("Calculation plugin 'Big.js' must be preloaded!");
}
Calc.prototype = {
oBig : {},
plus : function(num){
this.oBig = this.oBig.plus(num);
return this;
},
minus : function(num){
this.oBig = this.oBig.minus(num);
return this;
},
times : function(num){
this.oBig = this.oBig.times(num);
return this;
},
div : function(num){
this.oBig = this.oBig.div(num);
return this;
},
round : function(num, mode){
this.oBig = this.oBig.round(num, mode);
return this;
},
toNumber : function(){
return this.oBig.toNumber();
},
toFixedStr : function(dec, mode){
return this.oBig.toFixed(dec, mode);
},
formatNumber : function(num, dec, decP, sep){
dec = defaultVal(dec, 2);
sep = defaultVal(sep, " ");
decP = defaultVal(decP, ".");
return this.formatNumTh((new Big(num)).toFixed(dec), decP, sep);
},
formatNumTh : function(v, decP, sep){
sep = defaultVal(sep, " ");
decP = defaultVal(decP, ".");
if(!isNaN(v)){
if (v >= 1000) {
v += '';
var _ = v.split(/\D/);
var i = _[0].length % 3 || 3;
_[0] = v.slice(0,i + (v < 0)) +
_[0].slice(i).replace(/(\d{3})/g, sep+'$1');
v = _.join(decP);
}
}
return v;
}
};
return Calc;
})();
/********************************************************************
* BASE URL CLASS
********************************************************************/
PBaseUrl = (function() {
function PBaseUrl(PBaseUrl){
// Add url
var url, len, _this = this;
if(PBaseUrl && PBaseUrl.url) {
_this.lang = PBaseUrl.lang;
url = PBaseUrl.url;
}else{
_this.lang = "none";
url = window.location.pathname;
}
_this.path = url;
len = url.length;
_this.endSlash = url.substring(len - 1) === "/";
if(url.substring(len - (_this.lang.length + (_this.endSlash ? 1 : 0))) === _this.lang + (_this.endSlash ? "/" : "")){
url = url.substring(0, len - (_this.lang.length + (_this.endSlash ? 1 : 0)));
_this.pathAndParam = url + "p:var/" + _this.lang + (_this.endSlash ? "/" : "");
}else{
_this.pathAndParam = url + (_this.endSlash ? "" : "/") + "p:var" + (_this.endSlash ? "/" : "");
}
}
PBaseUrl.prototype.path = "";
PBaseUrl.prototype.pathAndParam = "";
PBaseUrl.prototype.lang = "";
PBaseUrl.prototype.endSlash = false;
PBaseUrl.prototype.insertSmartsChunk = function(url, chunk, lang){
if(url.length && chunk.length){
// Replace starting and ending slashes
var chunks = url.replace("/^\/|\/+$/", '').split('/');
// Handle language
if($.isDefined(lang) && lang.length){
/*$lang = array_pop($chunks);
$chunks[] = $chunk;
$chunks[] = $lang;*/
}else{
chunks.push(chunk);
}
if(chunks[0] === 'index')
delete(chunks[0]);
return chunks.join('/');
}
};
return PBaseUrl;
})();
/*******************************************************************
* CHECKBOXES
*******************************************************************/
PCheckBoxes = (function() {
function PCheckBoxes(){ }
PCheckBoxes.prototype.NO = "No";
PCheckBoxes.prototype.YES = "Yes";
PCheckBoxes.prototype.bindSliderCheckboxes = function(obj){
if($.isDefined(obj)){
obj = $(".content > .cnt");
}
var no = defaultVal(JsBase.gM.no, this.NO);
var yes = defaultVal(JsBase.gM.yes, this.YES);
obj.find(".chk-value").each(function(){
var parent = $(this).parent();
var y = (parent.find(".on").length ? parent.find(".on").text() : yes);
var n = (parent.find(".off").length ? parent.find(".off").text() : no);
var elem = $(this).wrap("<div class='chk'></div>");
elem = elem.parent().append(
"<div class='slider'>" +
"<div class='on'>" + y + "</div><div class='off'>" + n + "</div><div class='switch'></div><div class='clear' style='display: none;'></div>" +
"</div>");
if(elem.find("input").val()){
elem.find(".slider").css({"margin-left" : 0}).find(".off");
}else{
elem.find(".slider").css({"margin-left" : "-41px"}).find(".on").css({opacity : 0});
}
elem.click(function(){
var val = $(this).find("input");
if(val.val()){
val.val("");
$(this).find(".slider").animate({"margin-left" : "-41px"}, 100, function(){
$(this).find(".on").css({opacity : 0});
val.change();
});
}else{
val.val(1);
$(this).find(".on").css({opacity : 1});
$(this).find(".slider").animate({"margin-left" : 0}, 100, function(){
val.change();
});
}
});
});
};
PCheckBoxes.prototype.bindBaseCheckboxes = function(obj){
if(!$.isDefined(obj)){
obj = $(".content > .cnt");
}
// New style checkboxes
obj.find(".hasChk:not(.disabled) .chk:not(.disabled)").each(function(){
let i = $(this);
let p = $(this).parent();
$(i).add(p).click(function(e){
e.stopPropagation();
if(!i.hasClass("dis")){
if(i.hasClass("chked")){
i.removeClass("chked");
}else{
i.addClass("chked");
}
i.change();
}
});
});
};
return PCheckBoxes;
})();
/********************************************************************
* AJAX LOADER CLASS
********************************************************************/
AjaxLoader = (function() {
function AjaxLoader(){
var _this = this;
// Use existing ajax loader
_this.jqObj = $("#ju-loading-screen");
_this.jqLineObj = $("#loader-l");
// Create ajax container & loader
if(!_this.jqObj.length){
_this.jqObj = $("<div id='ju-loading-screen'></div>").hide();
$("body").append(_this.jqObj);
}
_this.sRoundAjaxLoader = '<div id="ju-loading-screen" class="style-fix custom-embed-loader"><div class="sk-double-bounce"><div class="sk-child sk-double-bounce1"></div><div class="sk-child sk-double-bounce2"></div></div></div>';
$(document).ajaxStart(function(){
_this.showLoader();
}).ajaxStop(function(){
_this.hideLoader();
});
}
/**
* @property {jQuery} jqObj
* @property {jQuery} jqLineObj
* @property {string} sRoundAjaxLoader
*
* @property {int} iTimer
*
* @property {boolean} disabled
* @property {boolean} disabledFadeOut
* @property {boolean} bAjaxLine
*
* @property {jQuery|boolean} jqAjaxCaller
* @property {jQuery|boolean} jqAjaxSaveCaller
**/
AjaxLoader.prototype = {
jqObj : {},
jqLineObj : {},
sRoundAjaxLoader : {},
iTimer : 0,
disabled : false,
disabledFadeOut : false,
bAjaxLine : false,
jqAjaxCaller : false,
jqAjaxSaveCaller : false
};
AjaxLoader.prototype.showLoader = function(fnCallback){
var _this = this;
if(!_this.disabled){
if(_this.bAjaxLine)
_this.jqLineObj.addClass("ajax");
_this.showLoaderPro();
_this.jqObj.addClass("style-fix ajax-act").show().removeClass("ju-hide--loading-screen--");
if($.isFunction(fnCallback))
fnCallback();
}
};
AjaxLoader.prototype.hideLoader = function(force){
var _this = this;
if(!_this.disabled){
if(!_this.disabledFadeOut || $.isDefined(force) && force){
_this.disabledFadeOut = false;
if(_this.bAjaxLine){
_this.jqLineObj.addClass("fin");
setTimeout(function(){ _this.jqLineObj.removeClass("run ajax fin"); }, 600);
}
_this.hideLoaderPro();
_this.jqObj.addClass("ju-hide--loading-screen--").removeClass("ajax-act").hide();
}
}
};
AjaxLoader.prototype.resetAjaxObjects = function(){
var _this = this;
_this.jqObj.hide();
if(_this.jqAjaxCaller.length)
_this.jqAjaxCaller.removeClass("act");
_this.jqAjaxCaller = $();
_this.disabled = false;
_this.jqObj = $("#ju-loading-screen").hide().addClass("ju-hide--loading-screen--").removeClass("ajax-act");
};
AjaxLoader.prototype.showLoaderPro = function(){
var _this = this;
_this.jqAjaxCaller = defaultValNotFalse(_this.jqAjaxCaller, _this.jqAjaxSaveCaller);
if(_this.jqAjaxCaller.length)
_this.jqAjaxCaller.addClass("act");
};
AjaxLoader.prototype.hideLoaderPro = function(){
var _this = this;
_this.jqAjaxCaller = defaultValNotFalse(_this.jqAjaxCaller, _this.jqAjaxSaveCaller);
if(_this.jqAjaxCaller.length)
_this.jqAjaxCaller.removeClass("act");
_this.jqAjaxCaller = false;
};
return AjaxLoader;
})();
/*******************************************************************
* SESSION CLASS
*******************************************************************/
class BaseSession {
iTime = 0;
iTimeout = 0;
sBody = $();
sUrlSrc = "";
jqIframe = $();
jqObject = $();
bExternalForm = false;
bSessionEnabled = false;
/** @type {SessionTicker} */
timer;
/**
* BaseSession class for starting session timer
*
* @category PUB
* @dependencies PHP ajax.php
* @author Mareks Keiss <mareks.keiss@brsystems.lv>
*
* @constructor
* @this {BaseSession}
* @param {int} sessionTime - session time
* @param {string} sLoginLink - user redirect login link
**/
constructor(sessionTime, sLoginLink) {
let _this = this;
_this.bSessionEnabled = !!$(".wrapper.session").length;
_this.bExternalForm = $("html").hasClass("ext-load");
if (
sessionTime
&& sLoginLink.length
&& _this.bSessionEnabled
&& !_this.bExternalForm
) {
_this.sUrlSrc = sLoginLink;
_this.sBody = $("#sessionTime");
_this.iTime = _this.iTimeout = (parseInt(sessionTime) - 1);
if (!_this.sBody.length) {
$("footer").append(_this.sBody = $(
"<a id='sessionTime'>" +
"<div class='left'>" +
"<p>Session will expire in:</p>" +
"<p class='ed'>Session has expired! Time left:</p>" +
"</div>" +
"<div class='right'><span>00:00</span></div>" +
"</a>").css({opacity: 0.5}));
}
_this.appendSessionTime();
_this.sBody.find(".ed").hide();
_this.init();
} else {
_this.bSessionEnabled = false;
}
}
async init() {
let _this = this;
// Load required classes
const SessionTicker = await loadClass('./class/SessionTicker.js');
_this.timer = new SessionTicker({
duration: _this.iTime,
tickInterval: 1,
onTick: (remaining) => {
_this.iTime = remaining;
_this.appendSessionTime();
},
onExpire: () => {
_this.callLoginForm();
},
});
_this.timer.start();
}
updateTimer(login, timeOut){
let _this = this;
if (_this.bSessionEnabled) {
login = $.isDefined(login) ? login : false;
timeOut = $.isDefined(timeOut) ? timeOut : false;
if (_this.iTime > 0 || login || timeOut) {
_this.iTime = (timeOut ? timeOut : _this.iTimeout);
_this.timer.reset(_this.iTime);
}
// Restart counter timer
if (login || timeOut) {
setTimeout(function () {
_this.sBody.find("span").removeClass("ajax");
}, 1000);
}
}
}
appendSessionTime(){
let _this = this;
_this.sBody.find("span").html(_this.secondsToTime(_this.iTime));
}
callLoginForm(){
let _this = this;
if (_this.bSessionEnabled) {
// Format status timer
_this.sBody.find("span").addClass("ajax");
JsBase.ajaxLoader.disabled = true;
JsBase.ajax({ac: "tcheck", app: 1}, "/ajax/g", function (d) {
if (d && d.jsonok && d.t) {
// Check if session still active - then update timer
let t = parseInt(d.t);
if (t > 5) {
_this.updateTimer(false, t);
return true;
}
}
_this.sBody.addClass("hover");
_this.sBody.find("span").html("00:00").removeClass("ajax");
JsBase.ajaxLoader.disabled = false;
_this.showLoginForm();
});
}
}
showLoginForm(bApiReq, sUrlSrc){
let _this = this;
bApiReq = defaultVal(bApiReq, false);
sUrlSrc = defaultVal(sUrlSrc, _this.sUrlSrc);
if (_this.bSessionEnabled || bApiReq && sUrlSrc) {
// Create form only if already not exists
if (!_this.jqIframe.length) {
_this.jqIframe = $("<iframe class='loginf' id='loginf' src='" + sUrlSrc + "'></iframe>").hide();
_this.jqObject = $("<div class='iframe-overlay act'></div>").hide().add(_this.jqIframe);
$("body").append(_this.jqObject);
_this.jqObject.first().append(JsBase.ajaxLoader.sRoundAjaxLoader).fadeIn("fast");
}
if (!$("#fancybox-style-noscroll-fix").length) {
$("head").append(
'<style id="fancybox-style-noscroll-fix" type="text/css">' +
' .compensate-for-scrollbar{' +
' margin:0!important; padding-right:' + JsBase.getScrollBarWidth() + 'px;' +
' }' +
' .fancybox-active.compensate-for-scrollbar #fh5co-header{ ' +
' width: calc(100% - ' + JsBase.getScrollBarWidth() + 'px);' +
' }' +
'</style>'
);
}
_this.jqIframe.on("load", function () {
_this.jqObject.first().removeClass("act");
_this.jqIframe.contents().find("html").addClass("session_exp_login");
$("body")
.addClass("compensate-for-scrollbar oh")
.find("> .wrapper, #confirmDialog, footer > div, #dialogSlider")
.addClass("fmoreblur");
setTimeout(function () {
_this.jqIframe.fadeIn("fast");
}, 100);
});
}
}
hideIframe(){
this.jqObject.first().addClass("act");
this.jqIframe.hide();
}
removeIframeForm(bApiReq){
let _this = this;
bApiReq = defaultVal(bApiReq, false);
if (_this.bSessionEnabled || bApiReq) {
_this.updateTimer(true);
_this.jqObject.fadeOut("fast", function () {
$(this).remove();
_this.jqObject = $();
_this.jqIframe = $();
});
$("body")
.removeClass("compensate-for-scrollbar oh")
.find("> .wrapper, #confirmDialog, footer > div, #dialogSlider")
.removeClass("fmoreblur");
}
}
secondsToTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
}
}
AppBase = (function() {
/**
* AppBase base class object
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @this {AppBase}
*/
function AppBase(){
var _this = this;
// Load base js params
if(JsVars && JsVars.data){
_this.dt = {};
for(var i in JsVars.data){
if(JsVars.data.hasOwnProperty(i)){
if(i === 'gM'){
_this.gM = $.parseJSON(JsVars.data[i]);
}else{
_this.dt[i] = $.parseJSON(JsVars.data[i]);
}
}
}
}
// Set starting win width
_this.winWidth = $(window).width();
// Init subclasses
_this.url = new PBaseUrl($.isDefined(_this.dt.baseUrl) ? _this.dt.baseUrl : false);
// Load required classes
_this.oSession = new BaseSession(
("sessionTime" in _this.dt ? _this.dt.sessionTime : 3600),
("sessionLoginLink" in _this.dt ? _this.dt.sessionLoginLink : "")
);
_this.ajaxLoader = new AjaxLoader();
_this.checkboxes = new PCheckBoxes();
if(!_this.isMobile && typeof BrsConsole === 'function'){
_this.bDebug = true;
_this.oConsole = new BrsConsole(_this);
}
// Add function to resize event
// _this.onResize['top_menu'] = _this.recalculateMenu;
// Additional actions
_this.getDevice();
_this.resizeForm();
_this.bindBaseActions();
}
/**
* @property {object} dt
* @property {object} gM
* @property {object} os
* @property {boolean} isMobile
*
* @property {PBaseUrl} url
* @property {object} browser
* @property {PCheckBoxes} checkboxes
*
* @property {int} winWidth
* @property {PTables|boolean} oTables
*
* @property {boolean} bDebug
* @property {BrsConsole|boolean} oConsole
*
* @property {object} jsModule
* @enum {int} iKeys
*
* @property {Validator} validatorSubscribe
* @property {object} onResize
**/
AppBase.prototype = {
dt : {},
gM : {},
os : {},
isMobile : false,
url : {},
browser : {},
settings : {},
checkboxes : {},
winWidth : 0,
oTables : false,
oAllSliders : {},
oNewObjectSlider : false,
bDebug : false,
oConsole : false,
jsModule : {},
iKeys : {
BACKSPACE : 8,
TAB : 9,
ENTER : 13,
SHIFT : 16,
ESC : 27,
SPACE : 32,
ARROW_UP : 38,
ARROW_DOWN : 40,
DEL : 46,
KEY_F : 70,
KEY_N : 78,
KEY_S : 83,
KEY_V : 86
},
validatorSubscribe : {},
onResize : {}
};
// Call additional resize functions from array
AppBase.prototype.resizeForm = function(){
var _this = this;
//_this.recalculateMenu();
if($.isDefined(_this.onResize)){
for(var i in _this.onResize){
if(_this.onResize.hasOwnProperty(i))
if($.isFunction(_this.onResize[i]))
_this.onResize[i]();
}
}
};
// Get Class name
AppBase.prototype.getObjectClass = function(obj){
var sName = "";
var _this = this;
if(_this.dt && _this.dt.JsModuleTitle && _this.dt.JsModuleTitle.length){
sName = _this.dt.JsModuleTitle;
}else{
if(!$.isDefined(obj)){
sName = this.getObjectClass(this.jsModule);
}else{
if($.isFunction(obj)){
sName = obj.name;
}else if($.isObject(obj)){
sName = /(\w+)\(/.exec(obj.constructor.toString())[1];
}
}
}
if(!!sName)
sName = sName.charAt(0).toLocaleLowerCase() + sName.slice(1);
return sName;
};
// Analyse browser agent to get properties
AppBase.prototype.getDevice = function(){
var _this = this;
var ua = navigator.userAgent.toLowerCase();
_this.browser = {
idevice: /(iphone|ipod|ipad)/.test(ua),
blackberry: /blackberry/.test(ua),
android: /android/.test(ua),
firefox: /firefox/.test(ua)
};
_this.os = {
mac: /(mac)/.test(ua),
win: /(win)/.test(ua),
linux: /(linux)/.test(ua)
};
try{ document.createEvent("TouchEvent"); _this.isMobile = true; }
catch(e){ _this.isMobile = false; }
if(_this.isMobile) $("body").addClass("mob");
};
// Gather base fields
AppBase.prototype.getFields = function(obj, exclude, sKeyAttr){
var key;
obj = defaultVal(obj, $(".cnt"));
sKeyAttr = defaultValNotFalse(sKeyAttr, "id");
exclude = defaultValNotFalse(exclude, ".skip");
var oData = {};
$(obj).find("input:text, input:hidden, textarea, input:password").not(exclude).each(function(){
if(key = $(this).attr(sKeyAttr))
oData[key] = ($(this).val()?$(this).val():"");
});
$(obj).find("input:checkbox,.chk").not(exclude).each(function(){
if(key = $(this).attr(sKeyAttr))
oData[key] = ($(this).hasClass("chked") || $(this).is(":checked")? 1: 0);
});
$(obj).find("select").not(exclude).each(function(){
if(key = $(this).attr(sKeyAttr)){
if($(this).hasClass("getall")){
var sel = $(this).find("option:selected");
$(this).find("option").not(exclude).prop("selected", true);
oData[key] = $(this).val();
$(this).find("option").not(sel).prop("selected", false);
}else{
oData[key] = ($(this).val()?$(this).val():"");
}
}
});
$(obj).find("input:radio:checked").not(exclude).each(function(){
if(key = $(this).attr(sKeyAttr))
oData[key] = ($(this).val()?$(this).val():"");
});
return oData;
};
// Send ajax data
AppBase.prototype.ajax = function(data, url, onSuccess, type, onError, dataType){
var _this = this;
var ajax = $("#ajaxCode");
if(ajax.length){
$.extend((data?data:{}), {ajaxCode : ajax.val()})
}
if(!url || url && !url){
url = window.location;
}
if(!$.isDefined(type))
type = "POST";
if(!$.isDefined(dataType))
dataType = "json";
return $.ajax({
url: url,
type: type,
data: data,
dataType: dataType,
success: function(d) {
if(d){
// Update session timer
_this.oSession.updateTimer();
// Update gM messages
if(d.gM) $.extend(_this.gM, d.gM);
// Check if redirect request sent
if(d.error){
if(d.show_login_frm) _this.oSession.callLoginForm();
if((d.reqLogin || d.pRedirect) && d.url){
window.location = d.url;
return false;
}
}
}
// Success function
if($.isFunction(onSuccess)){
onSuccess(d);
}
},
error: function() {
// Error function
if ($.isFunction(onError)) {
onError();
}
}
});
};
/**
* Load basic bar chart
*
* @namespace
* @author Aivars Žukovskis <info@brsystems.lv>
* @property {int} number
* @property {int} [decimals = 2]
* @property {string} [dec_point = '.']
* @property {string} [thousands_sep = '']
*/
AppBase.prototype.formatNumber = function(number, decimals, dec_point, thousands_sep){
var n = number, prec = decimals;
var toFixedFix = function (n,prec) {
var k = Math.pow(10,prec);
return (Math.round(n*k)/k).toString();
};
n = !isFinite(+n) ? 0 : +n;
prec = !isFinite(+prec) ? 0 : Math.abs(prec);
var sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep;
var dec = (typeof dec_point === 'undefined') ? '.' : dec_point;
var s = (prec > 0) ? toFixedFix(n, prec) : toFixedFix(Math.round(n), prec); //fix for IE parseFloat(0.55).toFixed(0) = 0;
var abs = toFixedFix(Math.abs(n), prec);
var _, i;
if (abs >= 1000) {
_ = abs.split(/\D/);
i = _[0].length % 3 || 3;
_[0] = s.slice(0,i + (n < 0)) +
_[0].slice(i).replace(/(\d{3})/g, sep+'$1');
s = _.join(dec);
} else {
s = s.replace('.', dec);
}
var decPos = s.indexOf(dec);
if (prec >= 1 && decPos !== -1 && (s.length-decPos-1) < prec){
s += new Array(prec-(s.length-decPos-1)).join('0')+'0';
}
else if (prec >= 1 && decPos === -1) {
s += dec+new Array(prec).join('0')+'0';
}
return s;
};
// Binds base actions for html
AppBase.prototype.bindBaseActions = function(){
let _this = this;
// Bind cookies
let jqCookieCnt = $(".accept_cookies");
if (jqCookieCnt.length) {
$(document).ready(function () {
jqCookieCnt.find("a#accept-cookies,a#accept-all-cookies").click(function(){
let vData = ($(this).attr("id")==="accept-all-cookies" ? {all:1} : {
statistics:jqCookieCnt.find("#checkbox_stat").hasClass("chked")?1:0,
preferences:jqCookieCnt.find("#checkbox_pref").hasClass("chked")?1:0
});
_this.ajax(vData, $(this).attr("data-href"), function(d){
jqCookieCnt.fadeOut(400, function(){
$(this).remove();
});
if(d && d.html){
$("body").append(d.html);
}
});
});
_this.checkboxes.bindBaseCheckboxes(jqCookieCnt);
});
}
_this.bindFormValidations();
_this.bindFormSubmits();
_this.bindMobileMenuActions();
_this.bindCartActions();
_this.bindSearchAjax();
_this.bindCartErrorModal();
_this.bindTermsModalLinks();
_this.bindWishlistActions();
// Theme scripts (e.g. Swiper) may clone/render product cards after base init.
// Apply wishlist state once UI components are fully initialized.
setTimeout(function() {
_this.initWishlistState();
}, 1200);
$(window).off("load.wishlistInit").on("load.wishlistInit", function() {
_this.initWishlistState();
});
};
AppBase.prototype.encodeSearchToBase64Url = function(text) {
var base64 = btoa(encodeURIComponent(text));
return base64
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
};
AppBase.prototype.bindSearchAjax = function() {
var _this = this;
var searchTimer = null;
$(document).on("keyup", ".search-form .search-input", function() {
var $searchInput = $(this);
var $searchQuery = $searchInput.val().trim();
if ($searchQuery.length < 3) return;
var $searchForm = $searchInput.closest(".search-form");
var $searchResult = $searchForm.find(".search-results");
var $searchUl = $searchResult.find("ul.search-ul");
var $searchMore = $searchResult.find(".search-more");
var $searchFail = $searchResult.find(".search-fail");
var $searchText = $searchResult.find(".search-text");
$searchResult.removeClass("d-none");
$searchText.text($searchQuery);
clearTimeout(searchTimer);
searchTimer = setTimeout(function() {
var encodedSearch = _this.encodeSearchToBase64Url($searchQuery);
_this.ajax(
{ajax : 1, f : encodedSearch, global_search : 1},
"/meklet/",
function(data) {
var html = data && data.html ? data.html : '';
$searchUl.empty();
if (html && html.length) {
$searchUl.html(html);
// Update "See all results" link with search phrase
$searchMore.find("a").attr("href", "/meklet/?f=" + encodedSearch);
$searchMore.show();
$searchFail.hide();
} else {
$searchMore.hide();
$searchFail.show();
}
},
'POST',
function() {
$searchUl.empty();
$searchMore.hide();
$searchFail.show();
}
)
}, 300);
});
};
AppBase.prototype.bindCartErrorModal = function() {
// When the cart error modal is shown, close the cart drawer
// (theme2.js may open it after 1s regardless of error)
$(document).on("shown.bs.modal", "#cart-error-modal", function() {
$("#cart-drawer").addClass("invisible").removeClass("active visible");
$(".bg-shop").addClass("opacity-0 invisible").removeClass("opacity-50 visible");
});
};
AppBase.prototype.showErrorModal = function(msg) {
// Show guest login modal
let $errModal = $("#cart-error-modal");
if ($errModal.length) {
$errModal.find(".cart-error-body").text(msg);
let bsErrModal = new bootstrap.Modal($errModal[0]);
bsErrModal.show();
}
};
AppBase.prototype.bindTermsModalLinks = function() {
let _this = this;
$(document)
.off("click.termsModal")
.on("click.termsModal", ".js-popup-link, .js-terms-modal", function(e) {
let $link = $(this);
let href = $link.attr("href");
let $modal = $("#terms-modal");
if (!href) {
return true;
}
e.preventDefault();
e.stopPropagation();
if (!$modal.length || typeof bootstrap === "undefined") {
window.location.href = href;
return false;
}
$modal.find(".terms-modal-title").text($link.data("modal-title") || $.trim($link.text()) || "Terms & Conditions");
$modal.find(".terms-modal-content").html(
'<div class="terms-modal-loading text-center py-4"><i class="ri-loader-4-line icon-24 d-block lh-1 mx-auto"></i></div>'
);
bootstrap.Modal.getOrCreateInstance($modal[0]).show();
_this.ajax(false, href, function(html) {
$modal.find(".terms-modal-content").html(html);
}, "GET", function() {
$modal.find(".terms-modal-content").html(
"<div class='alert alert-danger meb-0'>" +
(_this.gM.ajaxGenErr || "Failed to load content.") +
"</div>"
);
}, "html");
return false;
});
};
AppBase.prototype.getProductId = function (jqObj) {
return jqObj.closest(".product-image").find("[data-product-id]").data("product-id");
}
AppBase.prototype.getWishlistProductId = function (jqObj) {
return String(
jqObj.attr("data-product-id") ||
jqObj.data("product-id") ||
this.getProductId(jqObj) ||
""
).trim();
}
AppBase.prototype.setWishlistButtonState = function(jqButton, productId, isActive) {
let _this = this;
let jqTargets = jqButton.closest(".single-product, .product-detail, .quickview-modal, .wish-table-info").find(".add-to-wishlist");
if (productId.length) {
jqTargets = jqTargets.add($(".add-to-wishlist[data-product-id='" + productId + "']"));
}
jqTargets.each(function() {
let $target = $(this);
let $icon = $target.find("i.ri-heart-line, i.ri-heart-fill").first();
let $tooltip = $target.find(".tooltip-text").first();
$target.toggleClass("active", isActive).attr("data-wl-action", (isActive ? "remove" : "add"));
if ($icon.length) {
$icon.removeClass("ri-heart-line ri-heart-fill").addClass(isActive ? "ri-heart-fill" : "ri-heart-line");
}
if ($tooltip.length) {
$tooltip.text(isActive
? defaultVal(_this.gM["remove from wishlist"], "remove from wishlist")
: defaultVal(_this.gM["wishlist"], "wishlist"));
}
});
}
AppBase.prototype.bindWishlistActions = function() {
var _this = this;
// Heart icon click - add to wishlist (global, on all pages)
$(document).on("click", ".add-to-wishlist", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
var $btn = $(this);
var productId = _this.getWishlistProductId($btn);
if (!productId) {
console.warn("No product ID for wishlist");
return;
}
var action = ($btn.hasClass("active") || $btn.attr("data-wl-action") === "remove" ? "remove" : "add");
_this.ajax(
{action: "runWishlist", wl_action: action, product_id: productId},
defaultVal(_this.dt.profileLink, false),
function(data) {
if (data && data.jsonok) {
_this.setWishlistButtonState($btn, productId, action === "add");
_this.updateWishlistCount(defaultVal(data.count, 0));
} else if (data && data.error) {
_this.showErrorModal(data.msg ? data.msg : 'You must be logged in to use wishlist');
}
},
'POST',
function() {
console.log("Wishlist add failed");
}
);
});
};
AppBase.prototype.initWishlistState = function() {
var _this = this;
var wishlistUrl = defaultVal(_this.dt.profileLink, false);
if (!wishlistUrl || !$(".add-to-wishlist, .wishlist-counter").length) {
return;
}
_this.ajax(
{action: "runWishlist", wl_action: "getIds"},
wishlistUrl,
function(data) {
if (!data || data.error || !data.jsonok) {
return;
}
var wishlistIds = Array.isArray(data.ids) ? data.ids.map(String) : [];
_this.updateWishlistCount(defaultVal(data.count, wishlistIds.length));
$(".add-to-wishlist").each(function() {
var $btn = $(this);
var productId = _this.getWishlistProductId($btn);
if (!productId.length) {
return;
}
_this.setWishlistButtonState($btn, productId, wishlistIds.indexOf(productId) !== -1);
});
},
"POST"
);
};
AppBase.prototype.updateWishlistCount = function(count) {
$(".wishlist-count, .wish-counter, .wishlist-counter").text(count);
};
AppBase.prototype.getCartOptionValue = function(jqScope, suffix){
let jqValue = jqScope.find("input[type='radio'][name$='" + suffix + "']:checked").first();
if (!jqValue.length) {
jqValue = jqScope.find("input[type='radio'][name*='" + suffix.replace('-', '') + "']:checked").first();
}
return String(jqValue.val() || "").trim();
};
AppBase.prototype.getCartAddPayload = function(jqButton){
let productId = String(jqButton.attr("data-product-id") || jqButton.data("product-id") || "").trim();
if (!productId.length) {
return false;
}
let selectors = ".product-detail, .single-product, .product-info, .product-action-wrap, .product-image-col, .product-review, .drawer-recommended-product, .cart-area";
let jqScope = jqButton.closest(selectors);
// If scoped to a sub-section (not a top-level wrapper), expand to the full product detail container
// so variant radio inputs in sibling sections are also reachable via find()
if (jqScope.length && !jqScope.is(".product-detail, .single-product, .cart-area")) {
let jqWider = jqScope.closest(".product-detail-info, .product-detail, .single-product");
if (jqWider.length) jqScope = jqWider;
}
let d1 = String(jqButton.attr("data-d1") || jqButton.data("d1") || "").trim();
let d2 = String(jqButton.attr("data-d2") || jqButton.data("d2") || "").trim();
if (!d1.length) {
d1 = this.getCartOptionValue(jqScope, "-size") || String(jqScope.find("[data-d1]").first().data("d1") || "").trim();
}
if (!d2.length) {
d2 = this.getCartOptionValue(jqScope, "-color") || String(jqScope.find("[data-d2]").first().data("d2") || "").trim();
}
let jqQty = jqScope.find(".js-qty-num").first();
let count = parseInt(jqQty.val(), 10);
if (isNaN(count) || count < 1) {
count = 1;
}
return {
action: "addToCart",
p: productId,
d1: d1 || 0,
d2: d2 || 0,
count: count
};
};
AppBase.prototype.getCartItemId = function(jqButton){
// First try to get from parent .cart-drawer-info
let jqCartItem = jqButton.closest("[data-item]");
console.log(jqCartItem);
if (jqCartItem.length) {
return String(jqCartItem.attr("data-item") || "").trim();
}
return '';
// Fallback: try to get from nearby elements (for backward compatibility)
//let jqWrap = jqButton.closest(".js-qty-wrap, .cart-drawer-qty-remove, .cart-qty-remove");
//let jqInput = jqWrap.find(".js-qty-num").first();
//return String(jqButton.attr("data-item") || jqInput.attr("name") || jqInput.attr("data-item") || "").trim();
};
AppBase.prototype.requestCartAction = function(data, onSuccess){
if (!this.dt || !this.dt.cartLink) {
return false;
}
return this.ajax(data, this.dt.cartLink, function(resp) {
if ($.isFunction(onSuccess)) {
onSuccess(resp);
}
return resp;
});
};
AppBase.prototype.openCartDrawer = function($force){
// Remove invisible, then trigger CSS transition
var $drawer = $("#cart-drawer");
var $bgShop = $(".bg-screen .bg-shop");
$drawer.removeClass("invisible");
$bgShop.removeClass("opacity-0 invisible");
if (defaultVal($force, true)) {
// Force reflow, and trigger animation
void $drawer[0].offsetWidth;
}
$drawer.addClass("active visible");
$bgShop.addClass("opacity-50 visible");
$("body").addClass("oh");
};
AppBase.prototype.openMobileMenu = function(){
var $menu = $("#mobile-menu");
var $bgBack = $(".bg-screen .bg-back");
if (!$menu.length) {
return false;
}
$menu.removeClass("invisible").addClass("active visible").attr("aria-hidden", "false");
$bgBack.removeClass("opacity-0 invisible").addClass("opacity-50 visible").attr("aria-hidden", "false");
$("body").addClass("mobile-menu-open");
$("a.toggler-btn").attr("aria-expanded", "true");
return true;
};
AppBase.prototype.closeMobileMenu = function(resetAccordions){
var $menu = $("#mobile-menu");
var $bgBack = $(".bg-screen .bg-back");
$menu.addClass("invisible").removeClass("active visible").attr("aria-hidden", "true");
$bgBack.addClass("opacity-0 invisible").removeClass("opacity-50 visible").attr("aria-hidden", "true");
$("body").removeClass("mobile-menu-open");
$("a.toggler-btn").attr("aria-expanded", "false");
if (resetAccordions && $.fn.collapse) {
$menu.find(".collapse.show").collapse("hide");
}
};
AppBase.prototype.bindMobileMenuActions = function(){
var _this = this;
$(document).off("click", "a.toggler-btn");
$(document).off("click", ".menu-close button.menu-close-btn, .bg-screen .bg-back");
$(document).on("click.baseMobileMenu", "a.toggler-btn", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
if ($("#mobile-menu").hasClass("active")) {
_this.closeMobileMenu(true);
return false;
}
_this.openMobileMenu();
return false;
});
$(document).on("click.baseMobileMenu", ".menu-close button.menu-close-btn, .bg-screen .bg-back", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
_this.closeMobileMenu(true);
return false;
});
$(document).on("click.baseMobileMenu", "#mobile-menu a.js-mobile-menu-link", function() {
var href = String($(this).attr("href") || "").trim().toLowerCase();
if (href && href !== "#" && href !== "javascript:void(0)") {
_this.closeMobileMenu(true);
}
});
$(document).off("keyup.baseMobileMenu").on("keyup.baseMobileMenu", function(e) {
if (e.key === "Escape" && $("#mobile-menu").hasClass("active")) {
_this.closeMobileMenu(true);
}
});
$(window).off("resize.baseMobileMenu").on("resize.baseMobileMenu", function() {
if ($(window).width() >= 1200 && $("#mobile-menu").hasClass("active")) {
_this.closeMobileMenu(true);
}
});
};
AppBase.prototype.closeCartDrawer = function(){
$("#cart-drawer").addClass("invisible").removeClass("active visible");
$(".bg-screen .bg-shop").addClass("opacity-0 invisible").removeClass("opacity-50 visible");
$("body").removeClass("oh");
};
AppBase.prototype.applyCartResponse = function(resp, options){
let _this = this;
options = defaultVal(options, {});
if (!resp) {
return false;
}
if (resp.counter !== undefined) {
$(".cart-counter").text(resp.counter);
} else if (resp.total !== undefined) {
$(".cart-counter").text(resp.total);
}
if (resp.subtotal !== undefined) {
$(".js-cart-subtotal").text("€ " + resp.subtotal);
}
// Full drawer refresh (add-to-cart, open drawer)
if (resp.html) {
let wasOpen = $("#cart-drawer").hasClass("visible");
$("#cart-drawer").replaceWith(resp.html);
if (wasOpen) {
_this.openCartDrawer(false);
}
_this.updateCheckoutButtonState();
}
// Optimized items-only refresh (qty adjust, remove from drawer)
if (resp.cart_view_items_html) {
$(".cart-table-detail").replaceWith(resp.cart_view_items_html);
}
// Optimized items-only refresh (qty adjust, remove from drawer)
if (resp.cart_items_html) {
let $cart = $(".cart-table");
let cartTable = $cart.length ? $cart : $(".cart-drawer-table");
cartTable.replaceWith(resp.cart_items_html);
}
if (resp.reload && options.reloadOnEmpty) {
window.location.reload();
}
$(document).trigger("cart:updated", [resp, options]);
return true;
};
AppBase.prototype.bindCartActions = function(){
let _this = this;
if (!this.dt || !this.dt.cartLink) {
return;
}
// Global Open cart drawer
$(document).on("click", ".js-cart-drawer", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
_this.openCartDrawer();
});
// Global Close cart drawer
$(document).on("click", ".drawer-close-btn, .bg-screen .bg-shop", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
_this.closeCartDrawer();
});
// Global add to cart
$(document).on("click", ".add-to-cart", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
let $btn = $(this);
if ($btn.hasClass("disabled") || $btn.is("[disabled]")) {
return false;
}
let payload = _this.getCartAddPayload($btn);
if (!payload) {
return true;
}
_this.ajaxLoader.jqAjaxSaveCaller = $btn;
_this.requestCartAction(payload, function(resp) {
_this.applyCartResponse(resp, {action: payload.action});
if (resp && resp.error) {
_this.showErrorModal(resp.data || resp.message || '');
} else if (resp && !resp.error) {
_this.openCartDrawer();
}
});
return false;
});
// Global buy now
$(document).on("click", ".js-buy-now", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
let $btn = $(this);
if ($btn.hasClass("disabled") || $btn.is("[disabled]")) {
return false;
}
let payload = _this.getCartAddPayload($btn);
if (!payload) {
return true;
}
payload.buyNow = 1;
_this.ajaxLoader.jqAjaxSaveCaller = $btn;
_this.requestCartAction(payload, function(resp) {
_this.applyCartResponse(resp, {action: payload.action});
if (resp) {
if (resp.error) {
_this.showErrorModal(resp.data || resp.message || '');
} else if (resp.checkoutUrl) {
window.location.href = resp.checkoutUrl;
} else {
window.location.href = $btn.attr("href");
}
}
});
return false;
});
// Cart drawer qty adjust
$(document).on("click", ".cart-drawer .js-qty-adjust, .cart-area .js-qty-adjust", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
let $btn = $(this);
let itemId = _this.getCartItemId($btn);
if (!itemId.length) {
return false;
}
let $input = $btn.closest(".js-qty-wrap").find(".js-qty-num").first();
let count = parseInt($input.val(), 10);
if (isNaN(count) || count < 1) {
count = 1;
}
if ($btn.hasClass("js-qty-adjust-minus")) {
count -= 1;
} else {
count += 1;
}
_this.ajaxLoader.jqAjaxSaveCaller = $btn;
if (count < 1) {
_this.requestCartAction({action: "remItem", item: itemId}, function(resp) {
_this.applyCartResponse(resp, {action: "remItem"});
});
return false;
}
$input.val(count);
_this.requestCartAction({action: "incDec", item: itemId, count: count}, function(resp) {
_this.applyCartResponse(resp, {action: "incDec"});
});
return false;
});
// Cart drawer remove
$(document).on("click", ".cart-drawer .cart-drawer-remove, .cart-area .cart-remove", function(e) {
e.stopImmediatePropagation();
e.preventDefault();
let $btn = $(this);
let itemId = _this.getCartItemId($btn);
if (!itemId.length) {
return false;
}
_this.ajaxLoader.jqAjaxSaveCaller = $btn;
_this.requestCartAction({action: "remItem", item: itemId}, function(resp) {
_this.applyCartResponse(resp, {action: "remItem"});
});
return false;
});
// Cart drawer agree to terms
$(document).on("click", ".cart-drawer #agree_to_terms", function() {
$(this).toggleClass("chked");
_this.updateCheckoutButtonState();
});
// Cart drawer agree to terms checkbox label
$(document).on("click", ".cart-drawer .agree_to label", function () {
$(this).parent().find("#agree_to_terms").toggleClass("chked");
_this.updateCheckoutButtonState();
});
};
AppBase.prototype.updateCheckoutButtonState = function(){
let $termsCheckbox = $("#agree_to_terms");
let $checkoutBtn = $("#cart-drawer a.secondary-btn[href*='STEP_2_CHECKOUT'], #cart-drawer .drawer-cart-checkout a.secondary-btn");
if (!$checkoutBtn.length) {
return;
}
if ($termsCheckbox.length && $termsCheckbox.hasClass("chked")) {
$checkoutBtn.removeClass("disabled opacity-50 pe-none").addClass("enabled");
} else {
$checkoutBtn.addClass("disabled opacity-50 pe-none").removeClass("enabled");
}
};
AppBase.prototype.bindFormSubmits = function(){
let _this = this;
let jqForms = $("#popup_subscribe, #footer_subscribe");
jqForms.each(function() {
let $form = $(this);
// Form input handling
$form.find("input").on({
focus: function() {
$(this).parent().addClass("active");
},
blur: function() {
$(this).parent().removeClass("active");
},
keydown: function(e) {
if (e.which === _this.iKeys.ENTER) {
_this.ajaxLoader.jqAjaxSaveCaller = $(this);
_this.submitSubscribeForm($form);
}
}
});
// Submit button
$form.find("button[type='submit']").click(function(e) {
e.preventDefault();
_this.ajaxLoader.jqAjaxSaveCaller = $(this);
_this.submitSubscribeForm($form);
return true;
});
});
// Search form submit handler
$(document).on("submit", ".search-form", function(e) {
var $form = $(this);
var $searchInput = $form.find(".search-input");
var searchVal = $searchInput.val().trim();
if (!searchVal.length) {
e.preventDefault();
return false;
}
// PHP side handles base64 encoding, just let form submit naturally
});
};
AppBase.prototype.submitSubscribeForm = function(jqParent){
let _this = this;
let jqField = jqParent.find('input[type="email"]');
if (!_this.validatorSubscribe.isFormValid(jqField)) return false;
let oData = {action: 'subscribe', data: {sub_email: jqField.val()}};
_this.ajax(oData, _this.dt['subLink'], (data) => {
_this.handleFormResponse(jqParent, data);
_this.closePopup(jqParent);
});
return true;
};
AppBase.prototype.closePopup = function(jqParent){
jqParent.closest("div.modal-body").find("button > i.ri-close-large-line").click();
};
AppBase.prototype.bindFormValidations = function(){
let _this = this;
if (typeof Validator === "undefined") {
console.log("Validator is not defined, form validation will not work.");
return;
}
Validator.prototype.showError = function(caller, msg) {
if (caller) _this.showFieldError(caller, msg);
};
Validator.prototype.hideError = function(caller) {
if (caller) _this.hideFieldError(caller);
};
if ($.isDefined(_this.dt.subCfg)) {
_this.validatorSubscribe = new Validator(_this.dt.subCfg, "body", _this.gM);
if ($.isDefined(_this.dt.fData)) {
_this.validatorSubscribe.showErrorsByObject(_this.dt.fData.err);
}
}
};
AppBase.prototype.getValidationWrapper = function(caller) {
let $caller = $(caller);
let $validate = $caller.closest(".validate");
return ($validate.length ? $validate : $caller.parent());
};
AppBase.prototype.showFieldError = function(caller, msg) {
let $wrapper = this.getValidationWrapper(caller);
let $errMsg = $wrapper.addClass("v-error").removeClass("v-ok").find(".errMsg");
$errMsg.length ? $errMsg.show().html(msg) : $wrapper.append("<div class='errMsg'>" + msg + "</div>");
};
AppBase.prototype.hideFieldError = function(caller) {
this.getValidationWrapper(caller).addClass("v-ok").removeClass("v-error").find(".errMsg").hide().html("");
};
AppBase.prototype.shakeInvalidCheckboxes = function(jqScope) {
let $scope = $(jqScope || document.body);
let $invalidGroups = $scope.find(".validate.v-error").has("input[type='checkbox']");
if (!$invalidGroups.length || !$.isFunction($.fn.effect)) {
return;
}
$invalidGroups.each(function() {
$(this).stop(true, true).effect("shake", {}, 500);
});
};
AppBase.prototype.handleFormResponse = function(jqParent, data) {
let _this = this;
let isSuccess = data && data.jsonok;
if (!isSuccess && data.error && data.err) {
for(let i in data.err) {
if (data.err.hasOwnProperty(i)) {
let $field = jqParent.find("#" + i);
if ($field.length) {
_this.validatorContactUs.showError($field, data.err[i]);
}
}
}
}
setTimeout(() => {
jqParent.find("h3.tt, .v-ok").removeClass("ok err v-ok");
if (isSuccess) {
jqParent.find("input:not(.btn), textarea").val('');
}
}, 1400);
};
AppBase.prototype.genRandomUniqueDocID = function(){
var sID = "ID" + Math.floor((Math.random() * 100000) + 1);
while($("#"+sID).length) sID = "ID" + Math.floor((Math.random() * 100000) + 1);
return sID;
};
AppBase.prototype.genRandomID = function(length){
var result = [];
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result.push(characters.charAt(Math.floor(Math.random() *
charactersLength)));
}
return result.join('');
};
AppBase.prototype.scrollToSeeElement = function(jqElement, fnCallback){
var iScrollTo = false;
var winH = window.innerHeight;
var jqHtml = $("html"), winS2Top = jqHtml.scrollTop();
var iElemTop = jqElement.offset().top;
if(iElemTop < winS2Top){
iScrollTo = iElemTop - 30;
}else if((iElemTop + jqElement.outerHeight()) > (winH + winS2Top)){
iScrollTo = winS2Top + (iElemTop + jqElement.outerHeight()) - (winH + winS2Top) + 20;
}
if(iScrollTo){
jqHtml.stop(true, true).animate({scrollTop: iScrollTo}, 400, function(){
if ($.isFunction(fnCallback))
fnCallback();
});
}
};
// Copies a string to the clipboard. Must be called from within an event handler such as click.
// May return false if it failed, but this is not always
// possible. Browser support for Chrome 43+, Firefox 42+, Edge and IE 10+.
// No Safari support, as of (Nov. 2015). Returns false.
// IE: The clipboard feature may be disabled by an adminstrator. By default a prompt is
// shown the first time the clipboard is used (per session).
AppBase.prototype.copyToClipboard = function(text) {
if (window.clipboardData && window.clipboardData.setData) {
// IE specific code path to prevent textarea being shown while dialog is visible.
return clipboardData.setData("Text", text);
} else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
var textarea = document.createElement("textarea");
textarea.textContent = text;
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in MS Edge.
document.body.appendChild(textarea);
textarea.select();
try {
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
} catch (ex) {
console.warn("Copy to clipboard failed.", ex);
return false;
} finally {
document.body.removeChild(textarea);
}
}
};
AppBase.prototype.xPos = 0;
AppBase.prototype.yPos = 0;
// Function that logs user mouse position at all time
AppBase.prototype.findDocumentXY = function(e){
var _this = this;
// FireFox Chrome Safari
if(e){
_this.xPos = e.pageX;
_this.yPos = e.pageY;
//IE
}else{
_this.xPos = window.event.x + document.body.scrollLeft - 2;
_this.yPos = window.event.y + document.body.scrollTop - 2;
}
//console.log(_this.xPos, _this.yPos);
};
/**
* Function to get scrollbar width
*
* @this {AppBase}
* @author Mareks Keiss <mareks.keiss@brsystems.lv>
* @return int
*/
AppBase.prototype.getScrollBarWidth = function(){
// Creating invisible container
const outer = document.createElement('div');
outer.style.visibility = 'hidden';
outer.style.overflow = 'scroll'; // forcing scrollbar to appear
outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
document.body.appendChild(outer);
document.body.appendChild(outer);
// Creating inner element and placing it in the container
const inner = document.createElement('div');
outer.appendChild(inner);
// Calculating difference between container's full width and the child width
const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);
// Removing temporary elements from the DOM
outer.parentNode.removeChild(outer);
return scrollbarWidth;
};
/**
* Function to check if scrollbar is activated
*
* @this {AppBase}
* @author Mareks Keiss <mareks.keiss@brsystems.lv>
* @param {jQuery} [jqContainer = $(#cms-table-drop-marker > .table-rows:first-child)] - container object
* @param {int} [eType = 1] - Scroll to check 1 - Horizontal, 2 - vertical
* @return boolean
*/
AppBase.prototype.chkScrollActive = function(jqContainer, eType){
eType = defaultVal(eType, 1);
jqContainer = defaultVal(jqContainer, $("#cms-table-drop-marker > .table-rows:first-child"));
if(jqContainer.length && jqContainer.is(":visible")){
if(eType === 1)
return jqContainer[0].scrollWidth > jqContainer[0].clientWidth;
else
return jqContainer[0].scrollHeight > jqContainer[0].clientHeight;
}
return false;
};
/**
* Function to initialize & load JS module
*
* @this {AppBase}
* @author Mareks Keiss <mareks.keiss@brsystems.lv>
* @return void
*/
AppBase.prototype.initJsModule = function() {
var _this = this;
// Init module if set
if(_this.dt && _this.dt.JsModuleTitle && !defaultVal(_this.dt.JsInitPostpone, false))
_this.jsModule = new window[_this.dt.JsModuleTitle]();
_this.dt.JsInitPostpone = false;
};
return AppBase;
})();
})();