PageSourceSearch

https://tokyogendai.com/wp-content/plugins/eventON/assets/js/eventon_functions.js?ver=5.0.8

js tokyogendai.com collected 2026-09-26 02:15:15 UTC 80,286 bytes, 2,383 lines download raw bytes

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

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.