PageSourceSearch

https://www.lichen.pl/wp-content/plugins/eventON/assets/js/eventon_functions.js?ver=4.9.12

js lichen.pl collected 2026-10-02 12:30:35 UTC 70,653 bytes, 2,140 lines download raw bytes

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

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.