PageSourceSearch

https://www.hafenstadt.at/wp-content/plugins/eventON/assets/js/eventon_functions.js?ver=5.0.2

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

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.