PageSourceSearch

https://bitcoinnews.ch/wp-content/plugins/eventON/assets/js/eventon_functions.js?ver=5.0.6

js bitcoinnews.ch collected 2026-10-01 10:20:27 UTC 80,131 bytes, 2,379 lines download raw bytes

1/**
2 * Javascript: EventON functions for all calendars
3 * @version: 5.0
4 * @license EventON JavaScript Assets 
5 * Copyright (C) 2014-2025 Ashan Jay, AshanJay Designs LLC.
6 * 
7 * PROPRIETARY LICENSE - All Rights Reserved
8 * 
9 * Permission granted solely for personal use with valid EventON license.
10 * YOU MAY NOT: redistribute, resell, sublicense, or publish these Assets.
11 * 
12 * Trademark: "EventON" is a trademark of AshanJay Designs LLC.
13 * Contact: [email protected]
14 * 
15 * PROVIDED "AS IS" WITHOUT WARRANTY. VIOLATION MAY RESULT IN LEGAL ACTION.
16 */
17
18jQuery(document).ready(function($) {
19
20	const BB = $('body');
21
22	// Basics
23		// Calendar function s
24			$.fn.evo_cal_functions = function(O){
25				const el = this;
26				switch(O.action){
27					// load shortcodes inside calendar data
28					case 'load_shortcodes':
29						return el.find('.evo_cal_data').data('sc');		
30					break;
31					case 'update_json':
32						//console.log(O.json);
33						el.find('.evo_cal_events').data('events', O.json);		
34					break;
35					case 'update_shortcodes':
36						//console.log(O.SC);
37						el.find('.evo_cal_data').data( 'sc', O.SC );
38					break;
39				}
40			};
41
42		// access page GLOBALS
43			$.fn.evo_get_global = function(opt){
44				var defaults = { S1:'', S2:''};
45				var OPT = $.extend({}, defaults, opt);
46
47				var BUS = $('#evo_global_data').data('d');
48
49				if(!(OPT.S1 in BUS)) return false;
50				if(!(OPT.S2 in BUS[OPT.S1])) return false;
51				return BUS[OPT.S1][OPT.S2];
52			}
53			$.fn.evo_get_txt = function(opt){
54				var defaults = { V:''}
55				var OPT = $.extend({}, defaults, opt);
56
57				var BUS = $('#evo_global_data').data('d');
58				//console.log(BUS);
59				if(!('txt' in BUS)) return false;
60				if(!(OPT.V in BUS.txt)) return false;
61				return BUS.txt[OPT.V];
62			}
63
64			// get translated text strings from ajax loaded data @4.6.4
65			$.fn.evo_lang = function(text){
66				var t = text.toLowerCase()
67				    .replace(/ /g, "_")
68				    .replace(/[^\w-]+/g, "");
69
70				var BUS = $('#evo_global_data').data('d');
71
72				if(!('txt' in BUS)) return text;
73				if(!(t in BUS.txt)) return text;
74				return BUS.txt[ t ];
75
76			}
77			$.fn.evo_get_cal_def = function(opt){
78				var defaults = { V:''}
79				var OPT = $.extend({}, defaults, opt);
80
81				var BUS = $('#evo_global_data').data('d');
82				if(!('cal_def' in BUS)) return false;
83				if(!(OPT.V in BUS.cal_def)) return false;
84				return BUS.cal_def[OPT.V];
85			}
86
87			// return dms translates values from global data
88			// added 4.0
89			$.fn.evo_get_dms_vals = function(opt){
90				// type = d, d1,d3, m, m3
91				// V = 0-x
92				var defaults = { type:'d', V:''}
93				var OPT = $.extend({}, defaults, opt);
94
95				var BUS = $('#evo_global_data').data('d');			
96				if(!('dms' in BUS)) return false;
97				if(!(OPT.type in BUS.dms)) return false;
98
99				return BUS.dms[ OPT.type ][ OPT.V ];
100				
101			}
102
103	// GENERAL AJAX ACCESS @4.7.2 updated @4.9.2
104		$.fn.evo_admin_get_ajax = function(opt){
105
106			var el = $(this);
107
108  			var OO = this.evo_process_ajax_params( opt );
109
110
111  			var _lbdata = OO.lbdata;
112			var _adata = OO.adata;	
113			var _populate_id = OO._populate_id;	
114
115			// Allow custom success callback to be passed in opt -- 4.9.2    		
116    		var customBefore = typeof opt.onBefore === 'function' ? opt.onBefore : null;   // New onBefore callback
117		    var customSuccess = typeof opt.onSuccess === 'function' ? opt.onSuccess : (typeof opt.success === 'function' ? opt.success : null); 
118		    	// Rename to onSuccess, keep backward compatibility with 'success'
119		    var customSuccess_Extra = typeof opt.successExtra === 'function' ? opt.successExtra : null; // this will run with default ajax
120		    var customComplete = typeof opt.onComplete === 'function' ? opt.onComplete : null; // New onComplete callback
121
122			var ajax_url = el.evo_get_ajax_url({a: _adata.a, e: _adata.end, type: _adata.ajax_type});
123
124			// for lightbox
125				var LB = false;
126	  			if( _lbdata.class != '') LB = $('body').find('.evo_lightbox.'+ _lbdata.class );
127
128
129	  		// Run AJAX
130  			$.ajax({
131				beforeSend: function(){
132					if (customBefore) {   customBefore.call(el, OO, LB); } // Call with onBefore:function(OO, LB){}
133					el.evo_perform_ajax_run_loader( OO, LB, 'start'  );
134				},
135				type: 'POST', url: ajax_url, data: _adata.data,	dataType:'json',
136				success:function(data){	
137
138					//console.log(data);
139					// If a custom success callback is provided, use it
140		            if (customSuccess) {
141		                customSuccess.call(el, OO, data, LB); // Call with onSuccess:function( OO, data, LB){} 
142		                // call data with data.data
143		                // Trigger a custom event for onSuccess - 4.9.11
144		                $('body').trigger('evo_ajax_success_' + OO.uid,[ OO, data , el]);	
145		            } else {
146		                // Otherwise, use the default success behavior
147		                el.evo_perform_ajax_success(OO, data, LB);
148		                if( customSuccess_Extra ) customSuccess_Extra.call( el, OO, data, LB );
149		            }
150
151				},complete:function(){
152					if (customComplete) {     customComplete.call(el, OO, data, LB);  } // Call with onSuccess:function( OO, data, LB){} 
153					el.evo_perform_ajax_run_loader( OO, LB, 'end'  );
154					
155				}
156			});				
157		}
158
159		// submit forms via ligtbox
160		// @since 4.2.2		@updated 4.8
161		$.fn.evo_ajax_form_submit = function( opt , boxtype , formObj){
162			const el = this;	
163
164
165  			var OO = this.evo_process_ajax_params( opt );
166
167  			//console.log(OO);
168
169  			var _lbdata = OO.lbdata;
170  			var _spdata = OO.spdata;
171			var _adata = OO.adata;	
172			var _populate_id = OO._populate_id;	
173  			  			
174  			// get parent element
175  			var parent = '';
176  			if( boxtype == 'sp') parent = el.closest('.evosp_in');
177  			if( boxtype == 'lb'){
178  				parent = el.closest('.evo_lightbox');
179  				if( _lbdata.class != '') parent = $('body').find('.evo_lightbox.'+ _lbdata.class );
180  			} 
181
182  			var form = parent.find('form');
183  			if( formObj !== undefined ) form = formObj;
184
185  			if( form.length == 0){ console.log('No Fom object found'); return;}
186
187  			// form required fields validation - @4.9
188			if( el.hasClass('validate')){
189
190				var hasError = false;
191				$('body').trigger('evo_elm_form_presubmit_validation', [form, function(isValid) {
192				    hasError =  isValid ? false: true;
193				}]);
194			    if( hasError){
195			    	el.evo_snackbar( 'Required fields missing' );
196			    	//LB.evo_lightbox_show_msg({message:'Required fields missing'});
197			    	return;
198			    }	
199			}
200
201
202  			// reset LB message
203  			if( boxtype == 'lb') parent.evo_lightbox_hide_msg();
204
205  			var ajax_url = el.evo_get_ajax_url({a: _adata.a, e: _adata.end, type: _adata.ajax_type});
206
207
208  			// Add passed on data from ajax object @4.8.2
209			var extra_ajax_data = ('data' in _adata ) ? _adata.data : null;
210	  			
211  			// Submit form
212				form.ajaxSubmit({
213					beforeSubmit: function(opt, xhr){
214						el.evo_perform_ajax_run_loader( OO, parent, 'start', boxtype  );
215					},
216					dataType: 	'json',	
217					url: ajax_url,	type: 	'POST',
218					data: extra_ajax_data,
219					success:function(data){
220						console.log(data);
221						el.evo_perform_ajax_success( OO, data, parent , boxtype);
222					},
223					complete:function(){	
224						el.evo_perform_ajax_run_loader( OO, parent, 'end' , boxtype );
225					}
226				});
227		}
228		$.fn.evo_ajax_lightbox_form_submit = function(opt , formObj ){			
229  			this.evo_ajax_form_submit( opt, 'lb', formObj );
230		}
231
232	// perform ajax functions / type = start/end
233		$.fn.evo_perform_ajax_run_loader = function( OO , LB, type , boxtype){
234			var el = this;
235			var _lbdata = OO.lbdata;
236			var _adata = OO.adata;	
237			var _spdata = OO.spdata;	
238
239			//console.log(OO);
240
241			var customer_loader_elm = false;
242			var loader_btn_el = false;
243			var loader_in_icon = false;
244
245  			if( _adata.loader_el !='')	customer_loader_elm = _adata.loader_el;
246  			if( 'loader_class' in _adata && _adata.loader_class != '') 
247  				customer_loader_elm = $('.' + _adata.loader_class);
248  			if( _adata.loader_btn_el != '' && _adata.loader_btn_el !== undefined ) loader_btn_el = el;
249  			if( _adata.loader_in_icon != '' && _adata.loader_in_icon !== undefined ) loader_in_icon = el;
250  			
251  			var LB_loader = false;
252  			if( LB && 'loader' in _lbdata && _lbdata.loader ) LB_loader = true;
253
254  			if( type == 'start'){
255
256  				var trigger_id = ( 'uid' in OO && OO.uid != '' ) ? OO.uid : OO.ajax_action; // @4.8
257  				$('body').trigger('evo_ajax_beforesend_' + trigger_id ,[ OO, el ]);
258
259				if( LB_loader ){
260					LB.find('.ajde_popup_text').addClass( 'evoloading'); // legacy
261					LB.evo_lightbox_start_inloading();
262				}
263				if( customer_loader_elm ) $( customer_loader_elm ).addClass('evoloading ');
264				if( loader_btn_el ) el.addClass('evobtn_loader'); // loader on button
265				if( loader_in_icon ) el.addClass('evoloader_icon'); // Loader in Icon (replace i.fa child with loader elm) @5.0.3
266  			}else{
267
268  				var trigger_id = ( 'uid' in OO && OO.uid != '' ) ? OO.uid : OO.ajax_action; // @4.8
269  				if( trigger_id === undefined ) trigger_id = OO.adata.a;
270  				//console.log(OO);
271
272  				$('body').trigger('evo_ajax_complete_' + trigger_id ,[ OO , el ]);
273			
274				if( LB_loader ){
275					LB.find('.ajde_popup_text').removeClass( 'evoloading');
276					LB.evo_lightbox_stop_inloading();	
277				}
278				if( customer_loader_elm ) $( customer_loader_elm ).removeClass('evoloading');
279				if( loader_btn_el ) el.removeClass('evobtn_loader'); // loader on button
280				if( 'loader_btn_el_done' in _adata && _adata.loader_btn_el_done ) el.addClass('evobtn_loader success' );
281				if( loader_in_icon ) el.removeClass('evoloader_icon'); // Loader in Icon (replace i.fa child with loader elm) @5.0.3
282
283				
284  			}
285
286			return {
287				'l1': customer_loader_elm,
288				'l2':LB_loader
289			};
290		}
291
292		$.fn.evo_perform_ajax_success = function ( OO, data, LB , boxtype){
293			var el = this;
294			var _lbdata = OO.lbdata;
295			var _adata = OO.adata;	
296			var _spdata = OO.spdata;	
297			var _populate_id = OO._populate_id;		
298
299			if( !data || data === undefined ) return;
300
301
302			//console.log(OO);
303
304			// if json is passing data object @4.9
305			var _success = ('success' in data) ? data.success : (data.status === 'good');
306
307			var extractedContent = 'content' in data ? data.content: '';
308			if( 'data' in data && 'content' in data.data) extractedContent = data.data.content;
309			var extractedData = ('data' in data) ? data.data : data;
310			extractedData['content'] = extractedContent;
311
312			// Ensure extractedData is an object for property checks; if it’s a string, wrap it
313		    if (typeof extractedData !== 'object' || extractedData === null) {
314		        extractedData = { msg: extractedData }; // Convert string to object
315		    }
316
317		    // Assign success and status to the extracted data
318		    extractedData.success = _success;
319		    extractedData.status = ('status' in extractedData) ? extractedData.status : (_success ? 'good' : 'bad');
320
321		    // Replace original data with processed data
322		    data = extractedData;
323
324		    //console.log(data);
325			//console.log( OO);
326
327			// if inside lightbox
328			if( LB.length > 0 ){
329				// show message
330					if (data && typeof data === 'object' && !Array.isArray(data) && 'msg' in data && data.msg !== '') {
331						LB.evo_lightbox_show_msg({
332							'type': ( _success ? 'good':'bad'), 
333							'message':data.msg, 
334							hide_lightbox: (  _success ? _lbdata.hide : false ),	
335							hide_message: _lbdata.hide_msg
336						});
337					}	
338
339				// populate lightbox
340				if( data && _lbdata.new_content && 'content' in data && data.content != '' ){
341
342					// populate a specific dom element with content
343					if( _populate_id ){
344						$('body').find('#'+_populate_id ).replaceWith( data.content );					
345					}else{
346						LB.evo_lightbox_populate_content({content: data.content});
347					}
348				}	
349								
350			}else{
351				// populate content
352				if( data && _populate_id && 'content' in data && data.content != ''){
353					$('body').find('#'+_populate_id ).html( data.content );
354				}						
355			}
356
357			// Show snackbar message
358				if( 'show_snackbar' in  _adata && ('msg' in data)  && data.msg != '' ) 
359					el.evo_snackbar({message: data.msg});
360
361			// populate content with matching DOM class names, will set new html @4.7.2
362				if( data && 'populate_dom_classes' in data){
363					$.each( data.populate_dom_classes, function( domclass, content){
364						$('body').find('.'+ domclass).html( content );
365					} );
366				}
367
368			// if ajax data pass dom content to be replaced with run through each and replace - @4.2.3
369				if(data &&  'refresh_dom_content' in data ){
370					$.each(data.refresh_dom_content, function(domid, content){
371						$('body').find('#'+ domid).replaceWith( content);
372					});
373				}
374
375			// Trigger success actions @5.0.3
376			// call like 'trig_success'=> [ ['evosp_trig_close', ['delay'=> 2000] ] ]
377				if( _success &&  'trig_success' in _adata ){
378					$.each( _adata.trig_success, function(i, item) {
379				        var event_name = item[0];
380				        var extra_data = item[1] || {};   // parameters object (or {} if none)
381				        $('body').trigger( event_name, extra_data );
382				    });
383				}
384
385			// for SP content @since 4.5.2
386				if(data &&  'sp_content' in data){
387					$("body").find('#evops_content').html( data.sp_content);
388				}
389			// SP footer content @since 4.5.2
390				if( data && 'sp_content_foot' in data){
391					$("body").find('.evosp_foot_in').html( data.sp_content_foot);
392				}
393
394			// SP Show message 
395				if( data && 'sp_show_msg' in data){
396					BB.evo_showmsg_sidepanel( data.sp_show_msg );
397				}
398			// process trumbowyg editors
399				$('body').trigger('evo_elm_load_interactivity');
400
401
402			// assign dynamic vals to DOM element
403				setTimeout(function(){
404					if( 'evoelms' in data ){
405						$.each( data.evoelms , function( uniqueid, elm_data ){
406
407							$('body').find('.has_dynamic_vals').each(function(){
408
409								if( $(this).attr('id') != uniqueid ) return;
410								var dynamic_elm = $(this);
411
412								$.each( elm_data , function( elm_key, elmv){
413									dynamic_elm.data( elm_key, elmv );
414								});
415							});
416						});
417					}
418				},200);
419
420
421			// call like $('body').on('evo_ajax_success_X', function(event, OO, data, el){
422			$('body').trigger('evo_ajax_success_' + OO.uid,[ OO, data , el]);	
423		}
424
425	// Process ajax and lightbox values @4.7.2
426		$.fn.evo_process_ajax_params = function ( opt ){
427			// defaults
428			var defz = { 
429				'uid':'',
430
431				// @since 4.7.2
432				'adata':{}, // @4.7.2 include all ajax data in here, type (ajax,rest,endpoint),action/a, other data
433				'lbdata':{},// @4.7.2 lightbox data all in one place, class, title, size, padding
434				'spdata':{},// @5.0.3 side panel data all in one place, class, title, size, padding, ajax_data
435				'_populate_id':'', // loading new content into matching elements outside of lightbox
436				
437				// legacy values
438				'content':'',// passed on dynamic content
439				'content_id' :'',// id to get dynamic content from page		
440								
441				't':'', //title
442				'lbc':'',// * lightbox class - REQUIRED
443				'lbac':'',// ligthbox additional class 4.6
444				'lbsz':'',// lightbox size = mid small, s400, s500, s700, s800
445				'lightbox_loader': true,
446				'preload_temp_key': 'init', // 4.6
447				'load_new_content': true, // @since 4.3.5
448				'lb_padding': '', // @4.3.5
449				'load_new_content_id':'',
450
451				'ajax':'no',// use ajax to load content yes no
452				'ajax_url':'',// load content from ajax file
453				'end':'admin',// admin or client end
454				'ajax_action':'', // @4.4 pass on ajax endpoint action key
455				'a':'',
456				'ajax_type':'ajax', // @4.4 ajax type, ajax, rest or endpoint
457				'd':'', // data object for ajax
458				'other_data':'',
459				'ajaxdata':'',				
460			};
461
462
463			// extend passed with defaults
464			var OO = $.extend({}, defz, opt);
465
466			// Build processed object
467				var processed = {};
468				processed['uid'] = OO.uid;
469
470
471			// Ajax	
472				var _adata = ( OO.adata == '') ? {}: OO.adata;
473
474				// type passed value fix
475				var passed_type_val = false;
476				if( 'type' in _adata && _adata.type != '' &&
477					!['ajax', 'rest', 'endpoint'].includes(_adata.type)
478				){
479					passed_type_val = _adata.type;
480					_adata.type = '';
481				}
482
483				// set default needed values
484				var def_avals = { 
485					'a':'',
486					'type':'ajax',
487					'end':'admin',
488					'data': '',
489					'loader_el':'',
490					'loader_btn_el':'',//4.8
491					'loader_class':'',
492					'url':'',
493					'trig_success':[], // @5.0.3 trigger actions to run on success
494				}
495				
496				// set default values
497				$.each( def_avals, function(key, value) {					
498					if( key == 'data' && !( 'a' in _adata ) && ('data' in _adata ) && 'a' in _adata.data ) return;
499					if( !(key in _adata ) && value != '' ) _adata[ key ] = value;
500				});	
501
502				//console.log( _adata );
503
504				// map old to new
505				var def_adata_mapping = { 
506					'a' : 'a',
507					'ajax_action' : 'a',
508					'ajax_type':'type',
509					'end': 'end',
510					'ajax_url': 'url',
511					'ajaxdata':'data',
512					'ajax_data':'data',
513					'd':'data',
514				}
515				$.each( def_adata_mapping, function(oldV, newV) {					
516					if( newV in _adata && _adata[ newV ] != '' ) return;
517
518					if(  oldV in OO && OO[oldV] !== '' ) {
519						_adata[newV] = OO[oldV];
520					}  
521				});	
522
523				if( _adata.data === undefined ) _adata.data = {};
524
525				//console.log( _adata );			
526
527				// Move additional values in _adata to _adata.data
528					$.each(_adata, function(key, value) {
529						if ( !(key in def_avals)) {
530							//_adata.data[key] = value; // Move any extra values to _adata.data
531							//delete _adata[key]; // Remove them from the main _adata object
532						}
533					});
534
535				if( 'data' in _adata ){
536					//_adata['data']['nn'] = ( _adata.end == 'client' ) ? evo_general_params.n : evo_admin_ajax_handle.postnonce; 
537										
538					_adata['data']['nn'] = (typeof evo_admin_ajax_handle !== 'undefined' && evo_admin_ajax_handle !== null) 
539					    ? evo_admin_ajax_handle.postnonce 
540					    : evo_general_params.n;
541
542
543					_adata['data']['uid'] = processed['uid'];
544					if( passed_type_val ) _adata['data']['type'] = passed_type_val;
545					if( 'action' in _adata.data ) _adata['a'] =  _adata.data.action;
546					if( 'a' in _adata.data ) _adata['a'] =  _adata.data.a;
547					if( 'ajaxdata' in OO ) processed['ajaxdata'] = _adata.data;
548				}		
549
550				processed['adata'] = _adata;
551				
552
553			// lightbox
554				var _lbdata = ( OO.lbdata == '') ? {}: OO.lbdata;
555
556				// if legacy values exists > convert them to new
557				var def_lbdata_mapping = {
558					'lbc':'class',
559				    'lbsz':'size',
560				    'lbac' :'additional_class',
561				    't':'title',
562				    'lb_padding': 'padding',
563				    'load_new_content':'new_content',
564				    'lightbox_loader': 'loader',
565				    'content_id':'content_id',
566				    'content':'content',
567				    'hide_lightbox':'hide',
568				    'hide_message':'hide_msg',
569				    'lightbox_key': 'class',
570				}
571				$.each( def_lbdata_mapping, function(oldV, newV) {
572					// if _lbdata has new value > skip
573					if (newV in _lbdata && _lbdata[newV] !== '' && _lbdata[newV] !== null && _lbdata[newV] !== undefined) {
574				        return; 
575				    }
576					if(  oldV in OO && OO[oldV] !== '' ) {
577						_lbdata[newV] = OO[oldV];
578					} 
579				});	
580
581				// set default needed values
582				var def_lbvals = {
583					'padding':'evopad30',
584					'loader': false,
585					'preload_temp_key':'init',
586					'new_content': true,
587					'additional_class':'',
588					'title':'',
589					'hide':false,
590					'hide_msg':2000,
591					'content':'', // content for lightbox
592					'content_id':'', // content id in DOM to grab content for lightbox
593				}
594				// set default values
595				$.each( def_lbvals, function(key, value) {
596					if(  key in _lbdata )  return;
597					if( value == '') return;
598					_lbdata[ key ] = value;
599				});
600
601
602				//console.log( _lbdata.new_content ) ;
603
604				// load lightbox content legacy
605				if( OO.ajaxdata.load_lbcontent ) _lbdata['new_content'] = true;
606				if( OO.ajaxdata.load_new_content ) _lbdata['new_content'] = true;
607
608				// populate new content @4.7.3
609					processed['_populate_id'] =  false;
610					if( OO.load_new_content_id != '')  processed['_populate_id'] = OO.load_new_content_id;
611					if( 'new_content_id' in _lbdata && _lbdata.new_content_id != '')  processed['_populate_id'] = _lbdata.new_content_id;
612					if( 'content_id' in _lbdata && _lbdata.content_id != '') processed['_populate_id'] = _lbdata.content_id;
613
614				processed['lbdata'] = _lbdata;
615
616			// make sure uid is moved to main level
617				if( processed.uid == '' && 'uid' in processed['lbdata'] ) processed['uid'] = processed['lbdata']['uid'];
618
619			// add legacy variables for backward compatibility
620				$.each(opt, function(oldkey, oldval){
621					if( oldkey in processed ) return;
622					processed[ oldkey ] = oldval;
623				});
624
625			// Side Panel
626				var _spdata = ( OO.spdata == '' ) ? {} : OO.spdata;
627				// set default needed values
628				var def_spvals = {
629					'class':'',
630					'loader': false,
631					'new_content': true,
632					'additional_class':'',
633					'title':'',
634					'hide':false,
635					'hide_msg':2000,
636					'content':'', // content for sp
637					'content_id':'', // content id in DOM to grab content for sp
638					'size':'',
639				}
640				// set default values
641				$.each( def_spvals, function(key, value) {
642					if(  key in _lbdata )  return;
643					if( value == '') return;
644					_lbdata[ key ] = value;
645				});
646
647			//console.log( processed );
648
649			return processed;
650		}
651
652	// LIGHTBOX triggers
653		// @version 4.2
654		$('body').on('click','.evolb_trigger', function(event){
655			if( event !== undefined ){
656				event.preventDefault();
657				event.stopPropagation();
658			}
659				
660			$(this).evo_lightbox_open(
661				$(this).data('lbvals') ?? $(this).data('d')
662			);
663		});
664		$('body').on('click','.evolb_close_btn', function (){
665			const LB = $(this).closest('.evo_lightbox');
666			LB.evo_lightbox_close();
667		});
668
669		// save form content - @since 4.2.2
670		$('body').on('click','.evolb_trigger_save, .evo_submit_form', function(event){
671			if( event !== undefined ){	event.preventDefault();	event.stopPropagation();	}
672
673			$(this).evo_ajax_form_submit( $(this).data('d') , ( $(this).closest('.evo_lightbox').length ? 'lb':'') );
674		});
675
676		$('body').on('click','.evo_trigger_ajax_run', function(event){
677			if( event !== undefined ){
678				event.preventDefault();
679				event.stopPropagation();
680			}
681
682			//console.log($(this).data('d') );
683			$(this).evo_admin_get_ajax( $(this).data('d') );
684		});
685		// @since 4.3.3
686		$('body').on('evo_lightbox_trigger', function(event, data){
687			event.preventDefault();
688			//console.log( data );
689			$('body').evo_lightbox_open(data);
690		});
691
692	// Lightbox opening	
693	// @updated 4.9.11	
694		$.fn.evo_alert = function(opt){ // @since 4.9.2
695			var defz = { 
696		        'title': 'Confirmation Action',
697		        'message': '',
698		        'yes_text': 'Proceed',
699		        'no_text': 'No',
700		        'on_yes': function() {}, // Callback for Yes
701		        'on_no': function() {}   // Callback for No
702		    };	
703
704		    // Extend passed options with defaults
705		    var options = $.extend({}, defz, opt);
706
707		    // Create alert HTML content
708		    var alertHtml = '<div class="evo_alert_box">' +
709		        '<p class="evotal evopad10i">' + options.message + '</p>' +
710		        '<div class="evo_alert_buttons evotar">' +		            
711		            '<button class="evo_alert_no evoboxsn evobrn evooln evocurp evohoop7 evopad10-20 evobr20 evobgclt">
711' + options.no_text + '</button>' +
712		            '<button class="evo_alert_yes evoboxsn evobrn evooln evocurp evoHbgc1 evopad10-20 evobr20 evomarr10 evobgclp evoclw">' + options.yes_text + '</button>' +
713		        '</div></div>';
714
715		    // Define lightbox options with the alert content
716		    var lightboxOptions = {
717		        lbdata: {
718		            class: 'evo_alert_lightbox',
719		            title: options.title || 'Alert',
720		            content: alertHtml, // Set the alert HTML as the lightbox content
721		            padding: 'pad20', // Optional: Add padding class if needed
722		            size:'small',
723		        },
724		    };
725
726		    // Open the lightbox with the alert content
727		    $(this).evo_lightbox_open(lightboxOptions);
728
729		    // After the lightbox is opened, attach event handlers
730		    setTimeout(function() {
731		        var LIGHTBOX = $('.evo_lightbox.evo_alert_lightbox');
732		        
733		        LIGHTBOX.find('.evo_alert_yes').on('click', function() {
734		        	var shouldClose = options.on_yes(LIGHTBOX);// Execute Yes callback
735		        	console.log(shouldClose);
736		        	if (shouldClose !== false) {
737		        		LIGHTBOX.evo_lightbox_close(); // Close the lightbox
738		        	}
739		            removeKeyListeners(); // Remove key listeners
740		        });
741
742		        LIGHTBOX.find('.evo_alert_no').on('click', function() {
743		            options.on_no(LIGHTBOX); // Execute No callback
744		            LIGHTBOX.evo_lightbox_close(); // Close the lightbox
745		            removeKeyListeners(); // Remove key listeners
746		        });
747
748		        // Keypress handler function
749		        function handleKeyPress(event) {
750		            if (event.key === 'Escape') { // Esc key
751		                options.on_no(LIGHTBOX); // Execute No callback
752		                LIGHTBOX.remove(); // Close the lightbox
753		                removeKeyListeners(); // Remove key listeners
754		            } else if (event.key === 'Enter') { // Enter key
755		                options.on_yes(LIGHTBOX); // Execute Yes callback
756		                LIGHTBOX.remove(); // Close the lightbox
757		                removeKeyListeners(); // Remove key listeners
758		            }
759		        }
760
761		        // Add keypress listener
762		        $(document).on('keydown', handleKeyPress);
763
764		        // Function to remove key listeners
765		        function removeKeyListeners() {
766		            $(document).off('keydown', handleKeyPress);
767		        }
768
769		        // Ensure key listeners are removed when lightbox is closed manually (e.g., via close button)
770		        LIGHTBOX.find('.evolb_close_btn').on('click', function() {
771		            removeKeyListeners();
772		        });
773		    }, 350); // Delay to ensure lightbox is fully rendered
774		}
775		$.fn.evo_lightbox_open = function (opt ){
776
777			var OO = this.evo_process_ajax_params( opt );
778			
779			var _lbdata = OO.lbdata;
780			var _adata = OO.adata;
781			var _populate_id = OO._populate_id;
782
783			//console.log(opt);
784			//console.log(OO);
785			
786
787			// check if required values missing for lightbox
788			if( !('class' in _lbdata) || _lbdata.class == '' ) return;
789
790
791			const fl_footer = _adata.end == 'client' ? '<div class="evolb_footer"></div>' :'';
792
793			// create lightbox HTML
794				var __lb_size = _lbdata.size === undefined ? '' : _lbdata.size;
795
796				var html = '<div class="evo_lightbox '+_lbdata.class+' '+_adata.end+' '+ ( _lbdata.additional_class !== undefined ? _lbdata.additional_class :'') +'" data-lbc="'+_lbdata.class+'"><div class="evolb_content_in"><div class="evolb_content_inin"><div class="evolb_box '+_lbdata.class+' '+ __lb_size +'"><div class="evolb_header"><a class="evolb_backbtn" style="display:none"><i class="fa fa-angle-left"></i></a>';
797				if( _lbdata.title !== undefined ) html += '<p class="evolb_title">' + _lbdata.title + '</p>';
798				html += '<span class="evolb_close_btn evolbclose "><i class="fa fa-xmark"><i></span></div><div class="evolb_content '+ _lbdata.padding +'"></div><p class="message"></p>'+fl_footer+'</div></div></div></div>';
799
800			$('#evo_lightboxes').append( html );	
801			var LIGHTBOX = $('.evo_lightbox.'+ _lbdata.class );		
802
803			
804			// Open lightbox on page
805				setTimeout( function(){ 
806					$('#evo_lightboxes').show();
807					LIGHTBOX.addClass('show');	
808					$('body').addClass('evo_overflow');
809					$('html').addClass('evo_overflow');
810				},300);
811
812				// show loading animation
813				LIGHTBOX.evo_lightbox_show_open_animation(OO);
814
815
816			// Load content locally from DOM
817			    if (_lbdata.content_id != '') {
818			        var content = $('#' + _lbdata.content_id).html();
819			        LIGHTBOX.find('.evolb_content').html(content);
820			    }
821			    if (_lbdata.content != '') {
822			        LIGHTBOX.find('.evolb_content').html(_lbdata.content);
823			    }
824
825			// run ajax to load content for the lightbox inside
826				if( 'a' in _adata  && _adata.a != ''){ // @4.7.2
827					LB.evo_admin_get_ajax( OO );
828				}
829				
830			// load content from a AJAX file			
831				if( 'url' in _adata && _adata.url != '' ){
832					$.ajax({
833						beforeSend: function(){},
834						url:	OO.ajax_url,
835						success:function(data){
836							LIGHTBOX.find('.evolb_content').html( data);							
837						},complete:function(){}
838					});
839				}
840			
841			$('body').trigger('evo_lightbox_processed', [ OO, LIGHTBOX]);
842		}
843
844		$.fn.evo_lightbox_close = function(opt) {
845		    if (!this.hasClass('show')) return;
846
847		    const defaults = { delay: 500, remove_from_dom: true };
848		    const OO = $.extend({}, defaults, opt);
849		    const hideDelay = parseInt(OO.delay);
850		    const completeClose = this.parent().find('.evo_lightbox.show').length === 1;
851
852		    // Remove 'show' class with delay if needed
853		    hideDelay > 500 ? setTimeout(() => this.removeClass('show'), hideDelay - 500) : this.removeClass('show');
854
855		    // Final cleanup after delay
856		    setTimeout(() => {
857		        if (completeClose) {
858		            $('body, html').removeClass('evo_overflow');
859		        }
860		        if (OO.remove_from_dom) this.remove();
861		    }, hideDelay);
862		};
863
864
865		// Other LB functions
866			$.fn.evo_lightbox_populate_content = function(opt){
867				LB = this;
868				var defaults = { 
869					'content':'',
870				}; var OO = $.extend({}, defaults, opt);
871
872				LB.find('.evolb_content').html( OO.content );
873			}
874			
875			$.fn.evo_lightbox_show_msg = function(opt){
876				LB = this;
877				var defaults = { 
878					'type':'good',
879					'message':'',
880					'hide_message': false,// hide message after some time pass time or false
881					'hide_lightbox': false, // hide lightbox after some time of false
882				}; var OO = $.extend({}, defaults, opt);
883				LB.find('.message').removeClass('bad good').addClass( OO.type ).html( OO.message ).fadeIn();
884
885				if( OO.hide_message ) setTimeout(function(){  LB.evo_lightbox_hide_msg() }, OO.hide_message );
886
887				if( OO.hide_lightbox ) LB.evo_lightbox_close({ delay: OO.hide_lightbox });
888			}
889			$.fn.evo_lightbox_hide_msg = function(opt){
890				LB = this;
891				LB.find('p.message').hide();
892			}
893
894
895			// add preload animations to lightbox u4.6
896			$.fn.evo_lightbox_show_open_animation = function(opt){
897				LB = this;
898				var defaults = { 
899					'animation_type':'initial', // animation type initial or saving
900					'preload_temp_key': 'init', // 4.6 passed on preload template key
901					'end':'admin',
902				};
903				var OO = $.extend({}, defaults, opt);
904
905				if( OO.animation_type == 'initial'){
906
907					passed_data = (  typeof evo_admin_ajax_handle !== 'undefined') ? evo_admin_ajax_handle: evo_general_params;
908
909					//console.log( passed_data);
910
911					html = passed_data.html.preload_general;
912					if( OO.preload_temp_key != 'init') html = passed_data.html[ OO.preload_temp_key ];
913					LB.find('.evolb_content').html( html );
914				}
915
916				if( OO.animation_type == 'saving')
917					LB.find('.evolb_content').addClass('evoloading');
918			}
919
920		// eventcard Lightbox function v4.6
921			$.fn.evo_cal_lightbox_trigger = function( SC_data , obj, CAL , LB = null){
922				
923				const event = obj.closest('.eventon_list_event');
924			    const classes = ['cancel_event', SC_data.additional_class, SC_data.calendar_type]
925			        .filter(cls => cls && (cls !== 'cancel_event' || obj.hasClass('cancel_event')))
926			        .join(' ');
927
928			    //console.log( SC_data);
929
930				const other_data = {
931			        extra_classes: `evo_lightbox_body eventon_list_event evo_pop_body evcal_eventcard event_${SC_data.event_id}_${SC_data.repeat_interval} ${classes}`,
932			        CAL,
933			        obj,
934			        et_data: obj.find('.evoet_data').data(),
935			        SC: SC_data
936			    };
937				
938				const randomId = `evo_eventcard_${Math.floor(Math.random() * 90) + 10}`;
939				const lbac = { 'sc1': 'within', 'sc2': 'within ecSCR' }[evo_general_params.cal.lbs] || '';
940
941				const openLightbox = (content,  ajaxData = null) => {
942			        const config = {
943			            //uid: ajaxData?.uid || 'evo_open_eventcard_lightbox',
944			            uid: 'evo_open_eventcard_lightbox',
945			            lbc: randomId,
946			            lbc: LB ? LB.data('lbc') || randomId : randomId,
947			            lbac,
948			            end: 'client',
949			            content,
950			            other_data
951			        };
952			        if (ajaxData) {
953			            Object.assign(config, {
954			                ajax: 'yes',
955			                ajax_type: 'endpoint',
956			                ajax_action: 'eventon_load_single_eventcard_content',
957			                d: ajaxData
958			            });
959			        }
960
961			        // if LB is passed populate that LB @4.9
962			        if( LB  ){
963			        	if( ajaxData){			        		
964
965			        		var OO = this.evo_process_ajax_params( config );
966			        		LB.evo_admin_get_ajax( OO );
967			        		$('body').trigger('evo_lightbox_processed', [ config, LB]);
968			        		return;
969			        	}
970			        	LB.evo_lightbox_populate_content({content: content}); 
971			        	$('body').trigger('evo_lightbox_processed', [ config, LB]);
972			        	return;
973			        }
974
975			        //console.log( config);
976			        $('body').evo_lightbox_open(config);
977			    };
978
979				if (SC_data.ux_val === '3a') {
980			        const placeholder = `
981			            <div class="evo_cardlb" style="padding:10px 10px 0 10px">
982			                <div style="margin-bottom:20px; width:100%; height:200px" class="evo_preloading"></div>
983			                ${Array(3).fill('<div style="display:flex;justify-content:space-between;margin-bottom:10px"><div style="width:40px;height:40px;margin-right:20px" class="evo_preloading"></div><div style="flex:1 0 auto"><div class="evo_preloading" style="width:70%;height:20px;margin-bottom:10px"></div><div class="evo_preloading" style="width:100%;height:80px;margin-bottom:10px"></div></div></div>').join('')}
984			            </div>
985			        `;
986
987			        
988			        const ajaxData = {
989			            event_id: SC_data.event_id,
990			            ri: SC_data.repeat_interval,
991			            SC: { ...SC_data, tile_style: '0', tile_bg: '0', tiles: 'no', eventtop_style: SC_data.tile_style == '2' ? '0' : SC_data.eventtop_style },
992			            load_lbcontent: true,
993			            action: 'eventon_load_single_eventcard_content',
994			            uid: 'load_single_eventcard_content_3a',
995			            calid: ( CAL ? CAL.attr('id') : '' ), 
996			        };
997
998			        openLightbox(placeholder, ajaxData);
999			    } else {
1000			        const content = event.find('.event_description').html();
1001			        const clrW = event.hasClass('clrW') ? 'clrW' : 'clrD';
1002			        openLightbox(`<div class="evopop_top ${clrW}">${obj.html()}</div><div class="evopop_body">${content}</div>`);
1003			    }
1004			}
1005
1006			// listerners for lightbox on eventcard
1007			$.fn.evo_cal_lb_listeners = function(){
1008				// Listerners
1009				// process various lightbox types
1010				$('body')
1011				.on('evo_lightbox_processed', function(event, OO, LIGHTBOX){
1012					if( OO.uid != 'evo_open_eventcard_lightbox') return false;
1013
1014					var CAL = OO.other_data.CAL;
1015
1016					LIGHTBOX.addClass('eventcard eventon_events_list');
1017					LIGHTBOX_content = LIGHTBOX.find('.evolb_content');
1018					LIGHTBOX_content.attr('class', 'evolb_content '+ OO.other_data.extra_classes );
1019					
1020					var SC = OO.other_data.SC;
1021					var obj = OO.other_data.obj;
1022
1023					//console.log(SC);
1024
1025					// update border color and eventtop color
1026						const evoet_data = OO.other_data.et_data;
1027						
1028						bgcolor = bggrad ='';
1029						if( evoet_data ){
1030							bgcolor = evoet_data.bgc;
1031							bggrad = evoet_data.bggrad;
1032						}
1033						
1034
1035						// if tiles and eventtop style set to clean
1036						var show_lightbox_color = ( SC.eventtop_style == '0' || SC.eventtop_style == '4') ? false: true;
1037						
1038						if( (CAL && CAL.hasClass('color') && show_lightbox_color) ||
1039							(!CAL && show_lightbox_color)
1040
1041						){
1042							LIGHTBOX_content.addClass('color');
1043							LIGHTBOX_content.find('.evopop_top').css({
1044								'background-color':bgcolor,
1045								'background-image': bggrad,
1046							});
1047						}else{
1048							LIGHTBOX_content.addClass('clean');
1049							LIGHTBOX_content.find('.evopop_top').css({'border-left':'3px solid '+bgcolor});
1050						}
1051
1052					// trigger 
1053					if( obj.data('runjs')){
1054						$('body').trigger('evo_load_single_event_content',[ SC.event_id, OO.other_data.obj]);
1055					}
1056									
1057					
1058					// RTL
1059					if( SC.evortl =='yes')	LIGHTBOX.addClass('evortl');
1060
1061					$('body').trigger('evolightbox_end', [ LIGHTBOX , CAL, OO]);	// @s4.6
1062
1063				})
1064
1065				// after eventcard content is loaded to lightbox via 3a - @since 4.2.3
1066					.on('evo_ajax_success_evo_open_eventcard_lightbox', function (event, OO, data){
1067						
1068						if( OO.ajaxdata.uid != "load_single_eventcard_content_3a") return false;
1069						
1070						LIGHTBOX = $('.evo_lightbox.'+ OO.lightbox_key);
1071
1072						CAL = $('body').find('#'+ OO.ajaxdata.calid);
1073						
1074						$('body').trigger('evolightbox_end', [ LIGHTBOX , CAL, OO]);	// @s4.6	
1075					})
1076				;			
1077			}
1078
1079	// Side Panel for admin
1080	// @since 4.5.2 @updated 5.0
1081		BB
1082		.on('click', '.evosp_trigger', function(e){ 
1083			e.preventDefault(); e.stopPropagation();
1084			const $el = $(this);
1085			$el.addClass('evo_sp_trig_on');
1086			$el.evo_open_sidepanel($el.data('d'), $el.data('spv'));
1087		 })
1088		.on('click', '.evosp_close', function(e){ e.preventDefault(); e.stopPropagation(); $(this).evo_close_sidepanel() })
1089		.on('click', '.evosp_trigger_save', function(e){ e.preventDefault(); e.stopPropagation(); $(this).evo_ajax_form_submit( $(this).data('d'), 'sp');  })
1090		.on('evosp_trig_close', function(e, opt){ $(this).evo_close_sidepanel( opt ); });
1091		
1092
1093		/**
1094		 * Side panel for eventON 
1095		 * @version 4.9
1096		 */ 		
1097		$.fn.evo_open_sidepanel = function(opt, spv){
1098			var defs = {
1099				'uid':'',
1100				'end':'admin', // admin or client
1101				'hide_sp':false,
1102				'hide_message':false,
1103				'title':'',
1104				'sp_title':'',
1105				'sp_class':'',
1106				'sp_id':'',// identifier for side panel @5.0.3
1107				'content_id':'',  // only to load dynamic content
1108				'content':'',// @5.0.3 populate passed on content with delay
1109				'content_load_delay':0,// 1000
1110				'ajax':'no',
1111				'ajax_data':'',		
1112				'adata':{},
1113				'other_data':{},	
1114				'spdata':{}, // in progress pass all sidepanel data in one			
1115				'size': 'sm', // sm | 
1116				'movepage': false,// in complete -- idea to move the entire page
1117				end:'admin'
1118			}
1119			var OO = $.extend({}, defs, opt);
1120			//console.log(OO);
1121
1122			const SP = $('body').find('.evo_sp');
1123
1124			// structure
1125				const load_html = "<div class='evo_loading_bar_holder h100'><div class='evo_loading_bar wid_50 hi_50'></div><div class='evo_loading_bar hi_100'></div><div class='evo_loading_bar'></div><div class='evo_loading_bar'></div><div class='evo_loading_bar hi_50'></div></div>";
1126
1127				const footer_html = `<div class='evosp_foot evo_bordert evodfx evofxdrr evofxaic evofxww evogap10'><div class='evosp_foot_in evofx_1 evogap10'>
1128				<div class='evo_loading_bar_holder h100 evopad0i'><div class='evo_loading_bar wid_50 hi_50'></div></div>
1129				</div><p class='evosp_message message evomar0i'></p></div>`;
1130
1131				SP.html(`<div id='${OO.sp_id}' class='evosp_in ${OO.sp_class}'><span class='evosp_close'><i class='fa fa-multiply'></i></span><div class='evosp_head evoff_1'>${OO.sp_title}</div><div id='evops_content' class='evosp_body'>${load_html}</div>${footer_html}</div>`);
1132
1133				SP.addClass('show');
1134				SP.removeClass('med lar sm').addClass( OO.size );
1135
1136				// if move page as well
1137				//if( OO.movepage ) $('body').find('.editor-editor-interface').addClass('evotrans pagemoved').css('right', '400px');
1138
1139				const SP_body = SP.find('.evosp_body');
1140				const SP_head = SP.find('.evosp_head');
1141				const SP_foot = SP.find('.evosp_foot');
1142
1143			// load using content
1144				if( OO.content_id != ''){
1145					if( OO.content_load_delay > 0){
1146						setTimeout(function(){
1147							SP.evo_populate_sidepanel( BB.find('#'+ OO.content_id ).html() );
1148						}, OO.content_load_delay );
1149					}else{
1150						SP.evo_populate_sidepanel( BB.find('#'+ OO.content_id ).html() );
1151					}				
1152				}
1153
1154			// run ajax to load content for the lightbox inside
1155				if( ( OO.ajax == 'yes' && OO.ajax_data != '') || ( OO.adata != '' && 'a' in OO.adata) ){
1156					var passing_data = {
1157						adata: OO.adata,
1158						ajaxdata: OO.ajax_data, 
1159						uid: OO.uid ,
1160						end: OO.end,
1161						load_new_content: true,
1162						load_new_content_id: 'evops_content',
1163						lightbox_loader:false,
1164						end: OO.end,
1165					};
1166
1167					SP.evo_admin_get_ajax( passing_data );
1168				}else{
1169					setTimeout(()=> BB.trigger('evo_sp_stop_loading'),OO.content_load_delay);
1170				}
1171
1172			// populate with passed on content with delay @5.0.3
1173				if( OO.content != ''){
1174					setTimeout(()=> SP.evo_populate_sidepanel( OO.content ),OO.content_load_delay);
1175				}
1176			// populate new content with spv values
1177				if( spv != ''){
1178					BB.on('evo_ajax_success_'+ OO.uid , function(){
1179						$('#evops_content').find('input, select').each(function(){
1180							var fel = $(this);
1181							$.each(spv,function(index, val){
1182								if( fel.attr('name') == index){
1183
1184									if( val == 'no' || val == 'yes') fel.evo_elm_change_yn_btn( val );
1185									fel.val( val );
1186								}
1187							});					
1188						});
1189					});
1190				}
1191	  		
1192	  		BB.trigger('evo_sp_opened_'+OO.uid, OO);
1193	  		BB.trigger('evo_sp_opened', OO);
1194	  		
1195	  	}
1196
1197	  	BB.on('evo_sp_stop_loading',function(){
1198	  		$('body').find('.evo_sp').find('.evo_loading_bar_holder').remove();
1199	  	});
1200	  	$.fn.evo_savevals_sidepanel = function(spv){
1201	  		const el = BB.find('.evo_sp_trig_on');
1202
1203	  		el.data('spv', spv);
1204	  		el.removeClass('evo_sp_trig_on');
1205	  	}
1206
1207	  	$.fn.evo_populate_sidepanel = function(content){
1208	  		const SP = $('body').find('.evo_sp');
1209	  		SP.find('.evosp_body').html( content );
1210	  		console.log('Populate SP');
1211	  	}
1212
1213	  	// populate sidepanel footer @5.0.3
1214	  	$.fn.evo_populate_sidepanel_footer = function(content ){
1215	  		const SP = $('body').find('.evo_sp');
1216	  		SP.find('.evosp_foot_in').html( content );
1217	  	}
1218	  	// CLOSE sidepanel
1219	  	$.fn.evo_close_sidepanel = function(opt){
1220	  		SP = BB.find('.evo_sp');
1221
1222	  		var defaults = { 'delay':200};
1223			if( !(SP.hasClass('show')) ) return;
1224			var OO = $.extend({}, defaults, opt);
1225			
1226	  		setTimeout(function(){	
1227	  			BB.trigger('evo_sp_closed',[ SP ]);
1228	  			SP.removeClass('show');
1229	  			$('body').find('.editor-editor-interface.pagemoved').removeClass('pagemoved').css('right', 'auto');
1230	  			BB.find('.evo_sp_trig_on').removeClass('evo_sp_trig_on');
1231	  		}, OO.delay );
1232	  		setTimeout(function(){	SP.html('');	}, ( OO.delay + 100 ) );
1233	  	}
1234
1235	  	$.fn.evo_showmsg_sidepanel = function(opt){
1236	  		var defaults = { 
1237				'type':'good',
1238				'message':'',
1239				'hide_message': false,// hide message after some time pass time or false
1240				'hide_sp': false, // hide lightbox after some time of false
1241			}; var OO = $.extend({}, defaults, opt);
1242
1243			const SP = $('body').find('#evo_sp');
1244
1245			SP.find('.message').removeClass('bad good').addClass( OO.type ).html( OO.message ).fadeIn();
1246			if( OO.hide_message ) setTimeout(function(){  SP.evo_hidemsg_sidepanel() }, OO.hide_message );
1247			if( OO.hide_sp ) SP.evo_close_sidepanel({ delay: OO.hide_sp });
1248	  	}
1249	  	$.fn.evo_hidemsg_sidepanel = function(opt){
1250			SP = this;
1251			SP.find('p.message').hide();
1252		}
1253
1254
1255
1256	// Get Ajax url @since 4.4 @u 4.5.5
1257		$.fn.evo_get_ajax_url = function(opt){
1258			var defaults = { 
1259				a:'', // action key
1260				e:'client', // end
1261				type: 'ajax'};
1262			var OO = $.extend({}, defaults, opt);
1263
1264			
1265
1266			// end point url
1267			if( OO.type == 'endpoint'){
1268				var evo_ajax_url = ( OO.e == 'client' || typeof evo_general_params !== 'undefined' )? 
1269					evo_general_params.evo_ajax_url : evo_admin_ajax_handle.evo_ajax_url;
1270				return  evo_ajax_url.toString().replace( '%%endpoint%%', OO.a );
1271			// rest api url
1272			}else if( OO.type == 'rest' ){
1273				var evo_ajax_url = ( OO.e == 'client' || typeof evo_general_params !== 'undefined')? 
1274					evo_general_params.rest_url : evo_admin_ajax_handle.rest_url;
1275					//console.log(evo_ajax_url);
1276					//console.log(OO);
1277				return  evo_ajax_url.toString().replace( '%%endpoint%%', OO.a );
1278			}else{
1279				action_add = OO.a != '' ? '?action='+ OO.a: '';
1280				return ( OO.e == 'client' || typeof evo_general_params !== 'undefined') ? 
1281					evo_general_params.ajaxurl + action_add : evo_admin_ajax_handle.ajaxurl + action_add;
1282			}	
1283		}
1284
1285	// loading animations @4.7.2
1286		$.fn.evo_start_loading = function( opt ){
1287			var defaults = { type:'1'};
1288			var OPT = $.extend({}, defaults, opt);
1289			var el = this;
1290
1291			if( OPT.type == '1') el.addClass('evoloading loading');
1292			if( OPT.type == '2') el.addClass('evoloading_2');
1293		}
1294		$.fn.evo_stop_loading = function( opt ){
1295			var el = this;
1296			var defaults = { type:'1'};
1297			var OPT = $.extend({}, defaults, opt);
1298
1299			if( OPT.type == '1') el.removeClass('evoloading loading');
1300			if( OPT.type == '2') el.removeClass('evoloading_2');
1301		}
1302		$.fn.evo_lightbox_start_inloading = function(opt){
1303			LB = this;
1304			LB.find('.evolb_content').addClass('loading evoloading');
1305		}
1306		$.fn.evo_lightbox_stop_inloading = function(opt){
1307			LB = this;
1308			LB.find('.evolb_content').removeClass('loading evoloading');
1309		}
1310	
1311	// Count down	// @+ 4.5
1312		$.fn.evo_countdown_get = function(opt){
1313			var defaults = { gap:'', endutc: ''};
1314			var OPT = $.extend({}, defaults, opt);
1315			var gap = OPT.gap;
1316
1317			// if gap not provided use endutc
1318			if( gap == '' ){				
1319				var Mnow = moment().utc();
1320				var M = moment();
1321				M.set('millisecond', OPT.endutc );
1322
1323				gap = OPT.endutc - Mnow.unix();
1324			}
1325			
1326			// if negative gap
1327			if( gap < 0){
1328				return {
1329					'd': 0,
1330					'h':0,
1331					'm':0,
1332					's':0
1333				}; 
1334			}
1335		
1336			distance = ( gap * 1000);
1337
1338			var days = Math.floor(distance / (1000 * 60 * 60 * 24));
1339			var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
1340			var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
1341			var seconds = Math.floor((distance % (1000 * 60)) / 1000);
1342
1343			minutes = minutes<10? '0'+minutes : minutes;
1344			seconds = seconds<10? '0'+seconds : seconds;
1345
1346			return {
1347				'd': days,
1348				'h':hours,
1349				'm':minutes,
1350				's':seconds
1351			}; 
1352		};
1353		// @u 4.5.2
1354		$.fn.evo_countdown = function(opt){
1355			var defaults = { S1:''};
1356			var OPT = $.extend({}, defaults, opt);
1357			var el = $(this);
1358
1359			const day_text = ( el.data('d') !== undefined && el.data('d') != '' )? el.data('d'):'Day';
1360			const days_text = ( el.data('ds') !== undefined && el.data('ds') != '' )? el.data('ds'):'Days';
1361
1362			// intial run
1363			//var gap = parseInt(el.data('gap'));
1364			var duration = el.data('dur');
1365			var endutc = parseInt(el.data('endutc'));
1366			var text = el.data('t');
1367			
1368			if(text === undefined) text = '';
1369
1370			if( el.hasClass('evo_cd_on')) return;
1371
1372			// get gap using end time utc
1373				var Mnow = moment().utc();
1374				var M = moment();
1375				M.set('millisecond', OPT.endutc );
1376
1377				//console.log(Mnow.unix());
1378				//console.log(endutc);
1379
1380				gap = endutc - Mnow.unix();
1381
1382
1383			// on initial run - event hasnt happened yet
1384			if( gap > 0 ){
1385
1386				// initial
1387				dd = el.evo_countdown_get({ 'gap': gap });
1388				
1389				el.html( ( dd.d>0 ? dd.d + ' ' + ( dd.d >1 ? days_text: day_text ) + " "  :'') + dd.h + ":" + dd.m +':'+ dd.s +'  '+text );
1390				
1391				el.data('gap', ( gap - 1)  );	// save new gap value
1392				el.addClass('evo_cd_on');
1393
1394				//return;
1395				
1396				// set intervals
1397				var CD = setInterval(function(){
1398					
1399					gap = el.data('gap'); // get gap for this cycle
1400					duration = el.data('dur');	
1401
1402					const bar_elm = el.closest('.evo_event_progress').find('.evo_ep_bar');	
1403
1404					// when timer is ticking
1405					if( gap > 0 ){
1406
1407						// increase bar width if exists
1408						if( duration !== undefined && bar_elm.length){
1409							perc = ( (duration - gap)/ duration ) * 100;
1410							bar_elm.find('b').css('width',perc+'%');							
1411						}
1412						
1413						dd = el.evo_countdown_get({ 'gap': gap });	
1414
1415						el.html( ( dd.d>0 ? dd.d + ' '  + ( dd.d >1 ? days_text: day_text ) + " ":'') + dd.h + ":" + dd.m +':'+ dd.s +' '+text );
1416						el.data('gap', ( gap - 1)  );
1417
1418					// when timer expired
1419					}else{
1420
1421						const expire_timer_action = el.data('exp_act');
1422
1423						// perform ajax task after expiration
1424						if(expire_timer_action !== undefined){
1425							$('body').trigger('runajax_refresh_now_cal',[ 
1426								el , 
1427								el.data('n'),
1428							]);
1429						}
1430
1431						const _complete_text = el.evo_get_txt({V:'event_completed'});
1432
1433						// live now text
1434						if(bar_elm.length){
1435							bar_elm.addClass('evo_completed');
1436							//el.siblings('.evo_ep_pre').html( _complete_text );
1437						}
1438
1439
1440						// event tag & live elements
1441						if( el.closest('.evcal_desc').length){
1442							el.closest('.evcal_desc').find('.eventover').html( _complete_text);
1443							el.closest('.evcal_desc').find('.evo_live_now').remove();
1444						}
1445
1446						// event card
1447						if( el.closest('.eventon_list_event').length){
1448							el.closest('.eventon_list_event').find('span.evo_live_now').hide();
1449						}
1450
1451						el.html('');
1452						clearInterval(CD);
1453					}
1454
1455				},1000);
1456			// event has already passed
1457			}else{
1458				// if gap is less
1459				el.closest('.evo_event_progress').find('.evo_ep_bar').hide();
1460				clearInterval(CD);
1461			}
1462		};	
1463
1464	// Handlebar process template data into html
1465		$.fn.evo_HB_process_template = function(opt){
1466			var defaults = { TD:'', part:''}
1467			var OPT = $.extend({}, defaults, opt);
1468
1469			BUS = $('#evo_global_data').data('d');
1470						
1471			template = Handlebars.compile( BUS.temp[ OPT.part ] );
1472			return template( OPT.TD );
1473		}
1474
1475	// Date range and events @4.6.7
1476		// Date range and events - from webpage
1477		$.fn.evo_cal_events_in_range = function(opt){
1478			var defaults = { S:'', E:'', 
1479				hide: true, 
1480				closeEC:true,
1481				showEV: false, // show events
1482				showEVL: false, // show events list
1483				showAllEvs: false // show all events regardless of the range
1484			};
1485			var OPT = $.extend({}, defaults, opt);
1486			var CAL = $(this);
1487
1488			var eJSON = CAL.find('.evo_cal_events').data('events');
1489			var SC = CAL.evo_shortcode_data();
1490
1491			R = {};
1492			html = '';
1493			json = {};
1494
1495			show = 0;
1496
1497			// using events JSON data
1498			if( eJSON && eJSON.length > 0){
1499				$.each(eJSON, function(ind, ED){
1500					eO = CAL.find('#event_'+ ED._ID);
1501					if(eO === undefined || eO.length==0) return;
1502
1503					if(OPT.hide)	eO.hide(); // pre hide
1504					this_show = false;
1505
1506					// month long or year long events
1507					if( ED.month_long || ED.year_long ){
1508						this_show = true;
1509
1510					}else{
1511						if(CAL.evo_is_in_range({
1512							'S': OPT.S,	'E': OPT.E,	'start': ED.unix_start ,	'end':ED.unix_end 
1513						})){						
1514							this_show = true;
1515						} 
1516					}
1517
1518					if( OPT.showAllEvs) this_show = true;
1519					
1520					if( this_show){	
1521						// show event
1522						if( OPT.showEV) eO.show();
1523
1524						// close open event cards
1525						if(OPT.closeEC && SC.evc_open == 'no') eO.find('.event_description').hide().removeClass('open');
1526
1527						html += eO[0].outerHTML;
1528						json[ ED._ID] = ED;
1529						show++;	
1530					} 
1531				});
1532			}else{	
1533				// get all the events in the events list
1534				var cal_events = CAL.find('.eventon_list_event');
1535
1536				cal_events.each(function(index, elm){
1537					var ED = $(elm).evo_cal_get_basic_eventdata();
1538					if( !ED) return;
1539
1540					if(OPT.hide)	$(elm).hide(); // pre hide
1541					this_show = false;
1542
1543					// month long or year long events
1544					if( $(elm).hasClass('month_long') || $(elm).hasClass('year_long') ){
1545						this_show = true;
1546
1547					}else{
1548						if(CAL.evo_is_in_range({
1549							'S': OPT.S,	'E': OPT.E,	'start': ED.unix_start ,	'end':ED.unix_end 
1550						})){						
1551							this_show = true;
1552						} 
1553					}
1554
1555					if( OPT.showAllEvs) this_show = true;
1556					
1557					if( this_show){	
1558						// show event
1559						if( OPT.showEV) $(elm).show();
1560
1561						// close open event cards
1562						if(OPT.closeEC && SC.evc_open == 'no') 
1563							$(elm).find('.event_description').hide().removeClass('open');
1564
1565						html += $(elm)[0].outerHTML;
1566						json[ ED.uID ] = ED;
1567						show++;	
1568					} 
1569				});
1570			}
1571
1572
1573			// No events
1574			if( OPT.showEV){
1575
1576				no_event_content = CAL.evo_get_global({S1: 'html', S2:'no_events'});
1577
1578				tx_noevents = CAL.evo_get_txt({V:'no_events'});
1579				EL = CAL.find('.eventon_events_list');
1580				EL.find('.eventon_list_event.no_events').remove();
1581				if( show == 0 )
1582					EL.append('<div class="eventon_list_event no_events">'+ no_event_content +'</div>');
1583			}
1584
1585			// if show events list
1586			if( OPT.showEVL){
1587				CAL.find('.eventon_events_list').show().removeClass('evo_hide');
1588			}
1589
1590			R['count'] = show;
1591			R['html'] = html;
1592			R['json'] = json;
1593
1594			return R;
1595		}
1596
1597		// check if an event is in the given date range
1598			$.fn.evo_is_in_range = function(opt){
1599				var defaults = { S:'', E:'', start:'',end:''}
1600				var OPT = $.extend({}, defaults, opt);
1601
1602				S = parseInt(OPT.S);
1603				E = parseInt(OPT.E);
1604				start = parseInt(OPT.start);
1605				end = parseInt(OPT.end);
1606
1607				return (
1608					( start <= S && end >= E ) ||
1609					( start <= S && end >= S && end <= E) ||
1610					( start <= E && end >= E ) ||
1611					( start >= S && end <= E )
1612				) ? true: false;
1613			}
1614			$.fn.evo_cal_hide_events = function(){
1615				CAL = $(this);
1616				CAL.find('.eventon_list_event').hide();
1617			}
1618
1619	// get event data basics from html event on page 
1620	// ~@version 4.0.3 @updated 4.9.8
1621		$.fn.evo_cal_get_basic_eventdata = function(){
1622			var ELM = $(this);
1623
1624			var _time = ELM.data('time');
1625			if( _time === undefined ) return false;
1626
1627			const time = _time.split('-');
1628			const ri = ELM.data('ri').replace('r','');
1629			const eID = ELM.data('event_id');
1630
1631			var _event_title = ELM.find('.evcal_event_title').text();
1632			_event_title = _event_title.replace(/'/g, '&apos;');
1633
1634			// extract text time
1635			let timeRange = '';
1636			const timeElement = ELM.find('.evo_tz_time');
1637			if( timeElement.length > 0){
1638				const timeClone = timeElement.clone();
1639		        // Remove the span.evo_tz and its contents
1640		        timeClone.find('.evo_tz').remove();
1641		        // Get the text, trim it, and remove any remaining icon-related characters
1642		        let timeText = timeClone.text().trim();
1643		        // Remove any lingering non-time characters (e.g., leftover from <i> tags)
1644		        timeText = timeText.replace(/[^\d:\s-]/g, '');
1645		        // Trim again to remove any extra spaces
1646		        timeRange = timeText.trim() || 'N/A';
1647			}
1648			
1649			var RR = {
1650				'uID': eID + '_' + ri,
1651				'ID': eID ,
1652				'event_id': eID ,
1653				'ri': ri,
1654				'event_start_unix': parseInt(time[0]),
1655				'event_end_unix': parseInt(time[1]),
1656				'time_text': timeRange, // @since 4.9.8
1657				'ux_val': ELM.find('.evcal_list_a').data('ux_val'),
1658				'event_title': _event_title,
1659				'hex_color': ELM.data('colr'),
1660				'hide_et': ELM.hasClass('no_et') ? 'y':'n', // hide endtime
1661				'evcal_event_color': ELM.data('colr'),
1662				'unix_start': parseInt(time[0]),// @4.5.7
1663				'unix_end': parseInt(time[1]),// @4.5.7
1664			};
1665
1666			// event type
1667			RR['ett1'] = {};
1668			ELM.find('.evoet_eventtypes.ett1 .evoetet_val').each(function(){
1669				RR['ett1'][ $(this).data('id')] = $(this).data('v');
1670			});
1671
1672			// since 4.3.5
1673			const eventtop_data = ELM.find('.evoet_data').data('d');
1674
1675			// location
1676			if(eventtop_data && 'loc.n' in eventtop_data && eventtop_data['loc.n'] != ''){
1677				RR['location'] = eventtop_data['loc.n'];
1678			}
1679
1680			// organizer
1681			if(eventtop_data && 'orgs' in eventtop_data && eventtop_data.orgs !== undefined ){
1682				var org_names = '';
1683				$.each(eventtop_data.orgs, function(index, value){
1684					org_names += value +' ';
1685				});
1686				RR['organizer'] = org_names;
1687			}
1688
1689			// event image
1690			if( ELM.find('.evo_event_schema').length > 0){
1691				imgObj = ELM.find('.evo_event_schema').find('meta[itemprop=image]').attr('content');
1692				RR['image_url'] = imgObj;
1693			}
1694
1695			// event tags @s 4.5.2
1696			if( eventtop_data && 'tags' in eventtop_data && eventtop_data.tags !== undefined ){
1697				//console.log(eventtop_data.tags);
1698				RR['event_tags'] = eventtop_data.tags;
1699			}
1700
1701
1702			return RR;
1703
1704		}
1705
1706
1707	// Calendar Helper functions @+2.8 @updated 4.9	
1708		$.fn.evo_cal_oneevent_onload = function(type){// @since 4.9
1709			if( type != 'complete') return;
1710
1711			const bodyClasses = $('body').attr('class') || '';
1712			const match = bodyClasses.match(/one_event_\d+_\d+/);
1713			if (match) {
1714        		const className = match[0];
1715        		const [, x, y] = className.match(/one_event_(\d+)_(\d+)/);
1716
1717				const event_obj = $('body').find('#event_'+ x +'_'+ y);
1718				const $cal = event_obj.closest('.ajde_evcal_calendar');
1719				const SC = $cal.evo_shortcode_data();
1720
1721
1722				if( event_obj.length > 1 ) return;
1723
1724				const new_SC_data = {
1725		            ...SC,
1726		            repeat_interval: y,
1727		            event_id: x,
1728		            ux_val: '3a',
1729		            evortl: event_obj.find('.eventon_events_list').hasClass('evortl') ? 'yes' : 'no',			            
1730		            ajax_eventtop_show_content: true,
1731		            additional_class: CAL.attr('class').match(/etttc_\w+/)?.[0] || '',
1732		        };
1733
1734		        console.log( new_SC_data);
1735		        $cal.evo_cal_lightbox_trigger(new_SC_data, event_obj, $cal);
1736				
1737			}
1738		}
1739		$.fn.evo_cal_event_get_uxval = function(SC, obj){
1740			const CAL = this;
1741			var ux_val = obj.data('ux_val');
1742
1743			if(SC && 'ux_val' in SC && SC.ux_val!='' && SC.ux_val!== undefined && SC.ux_val!='0'){
1744				ux_val = SC.ux_val;
1745			}
1746
1747			// special mobile only user interaction 
1748			if( SC && SC.ux_val_mob !== undefined && SC.ux_val_mob != '' && 
1749				SC.ux_val_mob != '-' && SC.ux_val_mob != ux_val){
1750				if( CAL.evo_is_mobile() ) ux_val = SC.ux_val_mob;
1751			}
1752			return ux_val;
1753		}
1754
1755		// to run before cal ajax is performed @4.6
1756		$.fn.evo_pre_cal = function(options){
1757			var el = this;
1758			var cal = {};
1759			var OO = $.extend({}, options);
1760
1761			var run = function(){
1762				cal_width_assoc();
1763				cal_load_nav_html();
1764			}
1765			var cal_width_assoc = function(){
1766				cal_w = el.width();
1767				if( cal_w <300) el.addClass('szS');
1768				if( cal_w >300 && cal_w <600) el.addClass('szM');
1769				if( cal_w >600 && cal_w <900) el.addClass('szL');
1770				if( cal_w >900) el.addClass('szX');
1771			}
1772
1773			// load nav html into cal
1774			var cal_load_nav_html = function(){
1775				nav_data = el.evo_cal_get_footer_data('nav_data');				
1776				if( nav_data && 'month_title' in nav_data){
1777					__html = nav_data.month_title;
1778					if( 'arrows' in nav_data ) __html += nav_data.arrows;
1779					el.find('.evo_header_mo').html( __html );
1780					el.find('.evo_footer_nav').html( __html );
1781				}
1782			}
1783			run();
1784		}
1785
1786		// localize time @4.6.7 @u 4.9
1787		$.fn.evo_cal_localize_time = function(){			
1788			this.find('.evo_loct_inprocess').each(function(e){	$(this).evo_localize_time();	});
1789		}
1790		$.fn.evo_localize_time = function( ){
1791			
1792			const eventcard = this.closest('.eventon_list_event');
1793		    const hideEnd = eventcard.hasClass('no_et');
1794		    const textLocal = evo_general_params.text.local_time;
1795
1796		    eventcard.find('.evo_mytime').each(function() {
1797		    	const $el = $(this);
1798		        const isEventCard = $el.hasClass('evocard');
1799		        const { times, __f: fullFormat, __tf: timeOnlyFormat, tzo: utcOffset = 0 } = $el.data();
1800		        const [start, end] = times.split('-').map(Number);
1801
1802		        const startMoment = moment.unix(start).utc().local();
1803		        const endMoment = moment.unix(end).utc().local();
1804		        const sameMonth = startMoment.format('YYYY/M') === endMoment.format('YYYY/M');
1805		        const sameDay = sameMonth && startMoment.format('DD') === endMoment.format('DD');
1806
1807		        const startText = startMoment.format(fullFormat);
1808		        const endText = endMoment.format(sameDay ? timeOnlyFormat : fullFormat);
1809		        const html = `${startText}${hideEnd ? '' : ' - ' + endText}` + 
1810		                     (isEventCard ? `<span class='evomarl5'>(${textLocal})</span>` : '');
1811
1812		        $el.replaceWith(`<span class='evo_newmytime'>${html}</span>`);
1813		    });
1814		}	
1815		$.fn.evo_day_in_month = function(opt){
1816			var defaults = { M:'', Y:''}
1817			var OPT = $.extend({}, defaults, opt);
1818
1819			return new Date(OPT.Y, OPT.M, 0).getDate();
1820		}
1821		$.fn.evo_get_day_name_index = function(opt){
1822			var defaults = { M:'', Y:'', D:''}
1823			var OPT = $.extend({}, defaults, opt);
1824
1825			//return moment(OPT.Y+'-'+OPT.M+'-'+OPT.D).utc().day();
1826
1827			return new Date(  Date.UTC(OPT.Y, OPT.M-1, OPT.D) ).getUTCDay();
1828		}
1829
1830		// scrollbar
1831		// Function to initialize custom scrollbar
1832		$.fn.evo_init_scrollbars = function(options){
1833
1834			const defaults = { scrollSpeed: 50 };
1835		    const settings = $.extend({}, defaults, options);
1836
1837
1838		    return this.each(function() {
1839		        const $scope = $(this);
1840		        $scope.find('.evo-scrollbar').each(function() {
1841		            const $container = $(this);
1842		            if ($container.hasClass('evo-scroll-container')) return;
1843
1844		            $container.addClass('evo-scroll-container');
1845		            const $parent = $container.parent();
1846		            if (!$parent.css('height') || $parent.css('height') === 'auto') {
1847		                $parent.css('height', '300px');
1848		            }
1849
1850		            const $content = $container.children().wrapAll('<div class="evo-scroll-content"></div>').parent();
1851		            $container.append('<div class="evo-scroll-tab-container"><div class="evo-scroll-tab"></div></div>');
1852
1853		            const $tabContainer = $container.find('.evo-scroll-tab-container');
1854		            const $tab = $tabContainer.find('.evo-scroll-tab');
1855		            const $scrollContent = $container.find('.evo-scroll-content');
1856
1857		            // Dynamic tab height and visibility
1858		            const updateTabHeight = () => {
1859		                const height = $container.height();
1860		                const contentHeight = $scrollContent[0].scrollHeight;
1861		                const maxScroll = contentHeight - height;
1862		                const tabHeight = Math.max(height * (height / contentHeight), 20);
1863		                $tab.css('height', `${tabHeight}px`);
1864		                $tab.toggleClass('scroll-needed', maxScroll > 0); // Show tab only if scrollable
1865		                console.log(height+' '+contentHeight+' '+maxScroll+' '+tabHeight);
1866            		};
1867		            $container.on('mouseenter', updateTabHeight);
1868
1869		            // Click to scroll
1870		            $tab.on('click', (e) => {
1871		                const height = $container.height();
1872		                const maxScroll = $scrollContent[0].scrollHeight - height;
1873		                const current = $container.scrollTop();
1874		                $container.scrollTop(current < maxScroll ? current + settings.scrollSpeed : current - settings.scrollSpeed);
1875		            });
1876
1877		            // Drag events
1878		            let isDragging = false;
1879		            let startY, startScrollTop;
1880
1881		            // Drag events
1882		            $tab.on('mousedown', (e) => {
1883		                isDragging = true;
1884		                $tab.addClass('dragging');
1885		                startY = e.pageY;
1886		                startScrollTop = $container.scrollTop();
1887		                e.preventDefault();
1888		            });
1889
1890		            $(document).on('mouseup', () => {
1891		                isDragging = false;
1892		                $tab.removeClass('dragging');
1893		            });
1894
1895		            $(document).on('mousemove', (e) => {
1896		                if (!isDragging) return;
1897
1898		                const height = $container.height();
1899		                const maxScroll = $scrollContent[0].scrollHeight - height;
1900		                const tabHeight = $tab.height();
1901		                const tabMaxTravel = height - tabHeight;
1902		                const deltaY = e.pageY - startY;
1903		                const scrollPercent = deltaY / tabMaxTravel;
1904		                $container.scrollTop(Math.max(0, Math.min(startScrollTop + (scrollPercent * maxScroll), maxScroll)));
1905		            });
1906
1907		            // Scroll event with requestAnimationFrame
1908		            $container.on('scroll', () => {
1909		                const height = $container.height();
1910		                const contentHeight = $scrollContent[0].scrollHeight;
1911		                const maxScroll = contentHeight - height;
1912		                const tabHeight = $tab.height();
1913		                const tabMaxTravel = height - tabHeight;
1914		                const scrollPosition = $container.scrollTop();
1915		                const scrollPercent = maxScroll > 0 ? scrollPosition / maxScroll : 0;
1916
1917		                requestAnimationFrame(() => {
1918		                    $tabContainer.css('top', `${scrollPosition}px`);
1919		                    $tab.css('top', `${scrollPercent * tabMaxTravel}px`);
1920		                });
1921		            });
1922		        });
1923		    });
1924		}
1925
1926
1927		/*
1928	    // Run on page load for all elements with .evo-scrollbar
1929	    initCustomScrollbar($('body').find('.evo-scrollbar'));
1930
1931	    // Expose function globally for on-demand use
1932	    window.initCustomScrollbar = function(selector) {
1933	        const $elements = selector ? $(selector) : $('body').find('.evo-scrollbar');
1934	        initCustomScrollbar($elements);
1935	    };
1936	    */
1937
1938
1939
1940	// LIGHTBOX
1941	// page Lightbox functions @+2.8
1942	// append to the lightbox main class name .evo_lightbox		
1943		// Legacy
1944			$.fn.evo_prepare_lb = function(){
1945				$(this).find('.evo_lightbox_body').html('');
1946			}
1947			$.fn.evo_show_lb = function(opt){
1948				var defaults = { RTL:'', calid:''}
1949				var OPT = $.extend({}, defaults, opt);
1950
1951				$(this).addClass('show '+ OPT.RTL).attr('data-cal_id', OPT.calid);
1952				$('body').trigger('evolightbox_show');
1953			}
1954			$.fn.evo_append_lb = function(opt){
1955				var defaults = { C:'', CAL:''}
1956				var OPT = $.extend({}, defaults, opt);
1957				$(this).find('.evo_lightbox_body').html( OPT.C);
1958
1959				if(  OPT.CAL!= '' && OPT.CAL !== undefined && OPT.CAL.hasClass('color')){
1960					const LIST = $(this).find('.eventon_events_list');
1961					if( LIST.length>0){
1962						LIST.find('.eventon_list_event').addClass('color');
1963					}				
1964				}
1965			}
1966
1967	// event image gallery @4.6
1968		$.fn.eventon_process_main_ft_img = function(OO){
1969			const IMG = this;
1970			var img_sty = 'def';
1971			if( IMG.hasClass('fit') ) img_sty = 'fit';
1972			if( IMG.hasClass('full') ) img_sty = 'full';
1973			
1974			// Initialize box dimensions
1975		    let box_width =  IMG.width();
1976		    let box_height =  IMG.height();
1977			
1978			// Ensure valid box dimensions
1979		    box_width = box_width > 0 ? box_width : 100; // Fallback to prevent errors
1980		    box_height = box_height > 0 ? box_height : 100;
1981			
1982
1983			 // Get image dimensions from data attributes
1984		    const img_width = parseInt(IMG.data('w')) || 100; // Fallback to prevent division by zero
1985		    const img_height = parseInt(IMG.data('h')) || 100;
1986		    const img_ratio = img_height / img_width; // Image aspect ratio
1987					
1988			let new_width, new_height;
1989			
1990			// Handle 'fit' style 
1991			if( IMG.hasClass('fit')){
1992				// Scale to fit within box while maintaining aspect ratio
1993		        new_width = box_height / img_ratio;
1994				new_height = box_height;
1995				if( new_width > box_width ){// width is wider than box
1996
1997					if( img_ratio <1 ){
1998						new_width = box_width; new_height = img_ratio * new_width;
1999					}else{
2000						new_height = box_height; new_width = new_height / img_ratio;
2001					}
2002				} 	
2003					
2004				IMG.find('span').css({'width':new_width, 'height': new_height} );
2005			}
2006
2007			// full style
2008			if( IMG.hasClass('full')){
2009				new_height = img_ratio * box_width;
2010				new_width = box_width;
2011				IMG.find('span').css({'width':new_width, 'height': new_height} );
2012				IMG.css({'height': new_height} );
2013			}
2014
2015			//console.log(box_width +' '+img_width+' '+new_width);
2016		}
2017
2018
2019	/**
2020	 * Form functions
2021	 * @version 4.8.2
2022	 * @updated 4.9.6
2023	 */
2024		$.fn.evo_RealTime_form_validation = function() {
2025	        return this.each(function() {
2026	            var form = $(this);
2027	            var req_fields = form.find('.input.req');
2028	            var email_fields = form.find('.input.email');
2029	            var humanvalid_fields = form.find('.input.evoelm_hval_val');
2030
2031            		        
2032	            req_fields.on('input blur', function() { $(this).evo_form_validate_field( 'text'); });
2033            	email_fields.on('input blur', function() { $(this).evo_form_validate_field( 'email'); });
2034            	humanvalid_fields.on('input blur', function() { $(this).evo_form_validate_field( 'humanvalid'); });
2035            	
2036	        });
2037	    }
2038
2039	    $.fn.evo_form_validation_check = function(){
2040
2041	    	var form = this;
2042	    	var req_fields = form.find('.input.req'); // Define here for use in validateForm
2043		    var email_fields = form.find('.input.email');
2044		    var humanvalid_fields = form.find('.input.evoelm_hval_val');
2045
2046	    	
2047            function validateForm() {
2048	            var hasErrors = false;
2049	            req_fields.each(function() {
2050	                if ( $(this).evo_form_validate_field( 'text')) hasErrors = true;
2051	            });
2052	            email_fields.each(function() {
2053	                if ($(this).evo_form_validate_field( 'email')) hasErrors = true;
2054	            });
2055	            humanvalid_fields.each(function() {
2056	                if ($(this).evo_form_validate_field( 'humanvalid')) hasErrors = true;
2057	            });
2058
2059	            return !hasErrors;
2060	        }
2061
2062	        return validateForm();
2063	    }
2064	    $.fn.evo_form_validate_field = function(type){
2065	    	var field = this;
2066	    	var errorElement = field.siblings('em');
2067            var hasError = false;
2068            var fieldValue = field.val().trim();
2069
2070            if (type === 'email') {		   
2071            	if (field.hasClass('req')) {
2072                    // Required email: Check if filled AND valid
2073                    hasError = fieldValue === '' || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(fieldValue);
2074                } else {
2075                    // Optional email: Only check if it’s not empty
2076                    hasError = fieldValue !== '' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(fieldValue);
2077                }
2078                 	
2079            } else if (type === 'humanvalid') {
2080                var correctAnswer =  field.data('val'); // Expected answer from data attribute
2081                hasError = ( '89r329' +field.val().trim()+ '8932ufe' ) !== correctAnswer;
2082            } else {
2083                hasError = field.val().trim() === '';
2084            }                
2085
2086            if (hasError) {
2087                if (errorElement.length === 0) {
2088                    errorElement = $('<em class="evoelm_field_errmsg evopadt5"></em>');
2089                    field.after(errorElement);
2090                }
2091                errorElement.html(getErrorMessage(type === 'email' ? 'err2' : type === 'humanvalid' ? 'err3' : 'err1'))
2092                    .removeClass('evodn')
2093                    .addClass('evodib');
2094                field.addClass('err');
2095            } else {
2096                errorElement.remove();
2097                field.removeClass('err');
2098            }	   
2099
2100            function getErrorMessage(type) {
2101	            const messages = {
2102	                err1: evo_general_params.text.err1, // Required field error
2103	                err2: evo_general_params.text.err2, // Email format error
2104	                err3: evo_general_params.text.err3  // Human validation error (e.g., "Incorrect answer")
2105	            };
2106	            return messages[type] || "";
2107	        }             
2108
2109            return hasError;
2110	    }	
2111
2112	    $('body').on('evo_elm_form_presubmit_validation', function(event, form, callback){
2113    		event.preventDefault();
2114    		var $form = $(form);
2115
2116    		var isValid = $form.evo_form_validation_check();
2117
2118            if (typeof callback === "function") {
2119                callback(isValid); // Return true/false to the callback
2120            }
2121    	});
2122
2123	// Calendar Data & Shortcodes
2124		// get shortcodes from evo bottom
2125		$.fn.evo_shortcode_data = function(){		
2126			var ev_cal = $(this);
2127			return ev_cal.find('.evo_cal_data').data('sc');			
2128		}
2129
2130		// get filter data @4.6
2131			$.fn.evo_get_filter_data = function(){			
2132				return $(this).find('.evo_cal_data').data('filter_data');			
2133			}
2134			$.fn.evo_cal_get_filter_sub_data = function( tax , key){
2135				newdata = $(this).evo_get_filter_data();
2136
2137				return newdata[ tax ][ key ];
2138			}
2139			$.fn.evo_cal_update_filter_data = function(tax, new_val, key){
2140
2141				newdata = $(this).evo_get_filter_data();
2142				if( key === undefined) key = 'nterms';
2143				newdata[ tax ][ key ] = new_val;
2144				$(this).find('.evo_cal_data').data('filter_data', newdata );
2145			}
2146			$.fn.evo_cal_get_footer_data = function( key ){
2147				data = $(this).find('.evo_cal_data').data();
2148
2149				//console.log(data);
2150
2151				if( data === undefined ) return false; // 4.6.2
2152				if( key in data ) return data[ key ];
2153				return false;		
2154			}
2155
2156		// hide cal data from view
2157		$.fn.evo_cal_hide_data = function(){			
2158			$(this).find('.evo_cal_data').attr({
2159				'data-sc':'',
2160				'data-filter_data':'',
2161				'data-nav_data':'',
2162			});			
2163		}
2164
2165		// update shortcode values from filter changes @u4.6
2166		$.fn.evo_update_sc_from_filters = function(){
2167			var el = $(this); 	
2168			SC = el.evo_shortcode_data();
2169
2170
2171			$.each( el.evo_get_filter_data() , function(index, value){
2172				var default_val 	= value.terms;
2173				var filter_val 		= value.nterms;
2174				const NOT_values 	= value.__notvals;
2175
2176				filter_val = filter_val == ''? 'NOT-all': filter_val;	
2177				
2178				var not_string = '';
2179
2180				// if NOT filter in place > include that in tax value for query
2181				if( NOT_values!== undefined && NOT_values.length >0 && filter_val != default_val ){	
2182					
2183					$.each(NOT_values, function(index, value){
2184						not_string += 'NOT-'+ value +',';
2185					});
2186				}		
2187
2188				SC[ index ] = not_string + filter_val;
2189			});
2190			
2191
2192			el.find('.evo_cal_data').data( 'sc', SC );
2193		}
2194		
2195		
2196
2197		// get shortcode single value
2198		$.fn.evo_get_sc_val = function(opt){
2199			var defaults = {	F:''}
2200			var OPT = $.extend({}, defaults, opt);
2201			var ev_cal = $(this); 
2202
2203			if(OPT.F=='') return false;
2204			SC = ev_cal.find('.evo_cal_data').data('sc');
2205
2206			if(!(SC[ OPT.F])) return false;
2207			return SC[ OPT.F];
2208		}
2209		// UPDATE Single value
2210		$.fn.evo_update_cal_sc = function(opt){
2211			var defaults = {
2212				F:'', V:''
2213			}
2214			var OPT = $.extend({}, defaults, opt);
2215			var ev_cal = $(this); 
2216			SC = ev_cal.find('.evo_cal_data').data('sc');
2217
2218			SC[ OPT.F ] = OPT.V;
2219
2220			ev_cal.find('.evo_cal_data').data( 'sc', SC );
2221		}
2222		// UPDATE all shortcode values
2223		$.fn.evo_update_all_cal_sc = function(opt){
2224			var defaults = {SC:''}
2225			var OPT = $.extend({}, defaults, opt);
2226			var CAL = $(this);
2227			CAL.find('.evo_cal_data').data( 'sc', OPT.SC );
2228		}
2229
2230		
2231
2232	// OTHERS
2233		// hex colors // @+2.8 @updated 4.7.2
2234			$.fn.evo_is_hex_dark = function(opt){
2235				var defaults = { hex:'808080'}
2236				var OPT = $.extend({}, defaults, opt);
2237
2238				hex = OPT.hex;
2239
2240				var c = hex.replace('#','');
2241				var is_hex = typeof c === 'string' && c.length === 6 && !isNaN(Number('0x' + c));
2242
2243				if(is_hex){	
2244					var values = c.split('');
2245					r = parseInt(values[0].toString() + values[1].toString(), 16);
2246				    g = parseInt(values[2].toString() + values[3].toString(), 16);
2247				    b = parseInt(values[4].toString() + values[5].toString(), 16);
2248				}else{
2249					var vals = c.substring(c.indexOf('(') +1, c.length -1).split(', ');
2250					var r = vals[0]  // extract red
2251					var g = vals[1];  // extract green
2252					var b = vals[2];
2253				}
2254
2255				var luma = ((r * 299) + (g * 587) + (b * 114)) / 1000; // per ITU-R BT.709
2256
2257				return luma> 128? true:false;
2258			}
2259
2260		// get rgb from hex code @4.5
2261			$.fn.evo_rgb_process = function(opt){
2262				var defaults = { data:'808080',type:'rgb', method:'rgb_to_val'}
2263				var opt = $.extend({}, defaults, opt);
2264
2265				const color = opt.data;
2266
2267				// RGB => hex
2268				if( opt.method == 'rgb_to_hex'){
2269					if(color == '1'){
2270						return;
2271					}else{
2272						if(color !=='' && color){
2273							rgb = color.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
2274							
2275							return "#" +
2276							("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
2277							("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
2278							("0" + parseInt(rgb[3],10).toString(16)).slice(-2);
2279						}
2280					}
2281				}
2282
2283				// RGB => rgb val
2284				if( opt.method == 'rgb_to_val'){
2285					if( opt.type == 'hex'){
2286						var rgba = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);	
2287						var rgb = new Array();
2288						rgb['r']= parseInt(rgba[1], 16);			
2289						rgb['g']= parseInt(rgba[2], 16);			
2290						rgb['b']= parseInt(rgba[3], 16);
2291						
2292					}else{
2293						rgb = color;
2294					}
2295					
2296					return parseInt((rgb['r'] + rgb['g'] + rgb['b'])/3);
2297				}				
2298			}
2299
2300		// Other data
2301			$.fn.evo_get_OD = function(){			
2302				var ev_cal = $(this);
2303				return ev_cal.find('.evo_cal_data').data('od');			
2304			}
2305
2306	
2307
2308		// get evo data for a given calendar
2309		$.fn.evo_getevodata = function(){
2310
2311			var ev_cal = $(this);
2312			var evoData = {};
2313			
2314			ev_cal.find('.evo-data').each(function(){
2315				$.each(this.attributes, function(i, attrib){
2316					var name = attrib.name;
2317					if(attrib.name!='class' && attrib.name!='style' ){
2318						name__ = attrib.name.split('-');
2319						evoData[name__[1]] = attrib.value;	
2320					}
2321				});
2322			});	
2323
2324			return evoData;
2325		}
2326
2327		// check if mobile device v4.6
2328		$.fn.evo_is_mobile = function(){
2329			return ( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) )? true: false;		
2330		}
2331
2332	// eventon loading functions
2333	// v 2.4.5 -- deprecating
2334		$.fn.evo_loader_animation = function(opt){
2335			var defaults = {
2336				direction:'start'
2337			}
2338			var OPT = $.extend({}, defaults, opt);
2339
2340			if(OPT.direction == 'start'){
2341				$(this).find('#eventon_loadbar').slideDown();
2342			}else{
2343				$(this).find('#eventon_loadbar').slideUp();
2344			}
2345		}
2346
2347	// DEPRECATED functions
2348		$.fn.evo_item_shortcodes = function(){			
2349			var OBJ = $(this);
2350			var shortcode_array ={};			
2351			OBJ.each(function(){	
2352				$.each(this.attributes, function(i, attrib){
2353					var name = attrib.name;
2354					if(attrib.name!='class' && attrib.name!='style' && attrib.value !=''){
2355						name__ = attrib.name.split('-');
2356						shortcode_array[name__[1]] = attrib.value;	
2357					}
2358				});
2359			});
2360			return shortcode_array;
2361		}
2362		$.fn.evo_shortcodes = function(){			
2363			var ev_cal = $(this);
2364			var shortcode_array ={};
2365					
2366			ev_cal.find('.cal_arguments').each(function(){
2367				$.each(this.attributes, function(i, attrib){
2368					var name = attrib.name;
2369					if(attrib.name!='class' && attrib.name!='style' && attrib.value !=''){
2370						name__ = attrib.name.split('-');
2371						shortcode_array[name__[1]] = attrib.value;	
2372					}
2373				});
2374			});	
2375			return shortcode_array;
2376		}
2377		
2378
2379});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.