"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} - 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("
"); elem = elem.parent().append( "
" + "
" + y + "
" + n + "
" + "
"); 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 = $("
").hide(); $("body").append(_this.jqObj); } _this.sRoundAjaxLoader = '
'; $(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 * * @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 = $( "" + "
" + "

Session will expire in:

" + "

Session has expired! Time left:

" + "
" + "
00:00
" + "
").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 = $("").hide(); _this.jqObject = $("
").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( '' ); } _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 * @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 * @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( '
' ); 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( "
" + (_this.gM.ajaxGenErr || "Failed to load content.") + "
" ); }, "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("
" + msg + "
"); }; 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 * @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 * @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 * @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; })(); })();