PageSourceSearch

https://mcrvip.com/js/js-common.js?v=1.13.2

js mcrvip.com collected 2026-10-06 11:24:21 UTC 143,336 bytes, 5,525 lines download raw bytes

1
2var vOverlaySelect = false
3var myTips
4
5
6// SOME SHORTCUTS FOR A POST MOOTOOLS WORLD WHEN WE GET THERE
7
8var _ = {
9	id: function (el) {
10		return document.getElementById(el);
11	}
12}
13
14
15
16if (!window.console || typeof console === "undefined") {
17	var console = {
18		log: function (logMsg) { }
19	};
20}
21
22window.addEvent('load', function () {
23	//this stuff needs the CSS to have finished and been loaded
24
25	//adds flashes any errorText
26	Array.each($$('.errorText'), function (el) {
27		cBC = el.getStyle('background-color')
28		if (cBC == '' || cBC == 'transparent') {
29			cBC = '#fff'
30		}
31		el.flash('#FF9999', cBC, 1, null, 1000)
32		
33	});
34
35	//adds flashes any notification text
36	Array.each($$('.notifyText'), function (el) {
37		cBC = el.getStyle('background-color')
38		if (cBC == '' || cBC == 'transparent') {
39			cBC = '#fff'
40		}
41		el.flash('#ffdbdb', cBC, 1, null, 1000)
42
43	});
44
45	/* PREPARE TOGGLE TARGETS  */
46	Array.each($$('.toggleTgtCentreNB'), function (el) {
47		el.setStyles({
48			'opacity': 0,
49			'visibility': 'visible'
50		});
51	});
52
53	//centres all the toggle targets and sets them to opacity 0 but display block for later fades.
54	//sets z-index to 1 so they are above any screen wipes
55	Array.each($$('.toggleTgtCentre'), function (el) {
56
57		el.setStyles({
58			'opacity': 0,
59			'display': 'block',
60			'z-index': 10
61		});
62
63		elsize = el.getSize()
64
65		var postop = window.getSize()
66		postopmiddle = (postop.y / 2) - (elsize.y / 2)
67		posleftmiddle = (postop.x / 2) - (elsize.x / 2)
68
69		//need to check to see if the element height is larger then the portal
70		if (postopmiddle < 0) {
71			postopmiddle = 0
72		};
73		//el.setStyles({'top':top+'px', 'left':left+'px'});
74		el.setStyles({
75			'top': postopmiddle,
76			'left': posleftmiddle,
77			'display': 'none',
78			'visibility': 'visible',
79			'opacity': 100
80		});
81
82	});
83
84	/*====== THIS IS HERE IN CASE THERE IS ANY PAGE LOADING PROCESSING SUCH AS HIGHLIGHTING GOING ON ====== */
85
86
87	/*====== REPLACED WITH A MORE ACCESSIBLE VERSION ====*/
88	/*
89	myTips = new Tips('.Tips1');
90	myTipsFixed = new Tips('.Tips1Selects', {
91			fixed: true,
92			offset: {
93				x: -300,
94				y: -10
95			}
96		});
97	*/
98
99
100	myTipsUnder = new Tips('.Tips1Under', {
101		fixed: true,
102		offset: {
103			x: 0,
104			y: 140
105		}
106	});
107
108	/*======================== TRY AND GRAB LOCATION ======================= */
109	/*======================== DONT NEED THIS IF THEY ARE LOGGED ON ================*/
110	// IM NOT SURE WE NEED THIS EVERYWHERE ALL THE TIME
111	// WE ONLY USE IT ON THE SEARCH PAGE
112
113	/*
114	var options = {
115	enableHighAccuracy: true,
116	timeout: 4000,
117	maximumAge: 1000
118	}
119
120	if (navigator.geolocation) {
121	//check we dont already have it
122	if  (Cookie.read('GPS')==null) {
123	//console.log('trying to get GPS');
124	navigator.geolocation.getCurrentPosition(GPSsuccess, GPSfail, options);
125	}else{
126	//console.log('already have gps')
127	var position = {coords:{latitude: Cookie.read('lat'),longitude: Cookie.read('lng')}}
128	GPSsuccess(position)
129	}
130	} else {
131	console.log('Geolocation not supported');
132	}
133
134	function GPSsuccess(position) {
135	//console.log('We have the position - ' + position.coords.latitude);
136	//set some position cookies
137	Cookie.write('GPS', true)
138	Cookie.write('lat', position.coords.latitude)
139	Cookie.write('lng', position.coords.longitude)
140	}
141
142	function GPSfail(){};
143
144	 */
145
146});
147
148window.addEvent('domready', function () {
149
150	/*===========================================================
151	================= SORT OUT ICON LINKS ======================
152	===========================================================*/
153	//Array.each for arrays, Object.each for objects
154	Array.each($$('i'), function (el) {
155		elTarget = el.getParent();
156		if (elTarget.get('tag') == 'a') {
157			elTarget.addClass('iconNoLinkStyle');
158		}
159	});
160
161
162	/*===========================================================
163	================= GPS REQUEST LOCATION ======================
164	===========================================================*/
165
166	/*======================== TRY AND GRAB LOCATION ======================= */
167	/*======================== DONT NEED THIS IF THEY ARE LOGGED ON ================*/
168	// IM NOT SURE WE NEED THIS EVERYWHERE ALL THE TIME
169	// WE ONLY USE IT ON THE SEARCH PAGE
170
171	/*
172	if (navigator.geolocation) {
173	//check we dont already have it
174	if(!Cookie.read('GPS')) {
175	navigator.geolocation.getCurrentPosition(gpsSuccess, gpsFail,{ enableHighAccuracy: true,timeout: 4000,maximumAge: 1000});
176	}else{
177	var position = {coords:{latitude: Cookie.read('lat'),longitude: Cookie.read('lng')}}
178	gpsSuccess(position)
179	}
180	} else {
181	console.log('no geolocation');
182	Cookie.write('GPS', false)
183	}
184
185
186	function gpsSuccess(position) {
187	//set some position cookies
188	Cookie.write('lat', position.coords.latitude);
189	Cookie.write('lng', position.coords.longitude);
190	Cookie.write('GPS', true)
191	};
192
193	function gpsFail(position){Cookie.write('GPS', false)};
194
195	 */
196
197
198
199
200
201	/*===========================================================
202	================= SEARCH AUTO COMPLETE ======================
203	===========================================================*/
204	(function () {
205
206		if ($('searchString')) {
207
208			//create the target if it doesnt exist
209			if ($('autoSuggest')) {
210				var elTarget = $('autoSuggest')
211			} else {
212				var elTarget = new Element('div', {
213					id: 'autoSuggest'
214				}).inject(document.body);
215			};
216
217
218			$('searchString').addEvent('keyup', function (e) {
219
220				elSearchBox = $('searchString');
221
222				if (elSearchBox.value.length > 2 && e.keyCode != 13 && e.keyCode != 9 && e.keyCode != 16 && e.keyCode != 17 && e.keyCode != 18 && e.keyCode != 37 && e.keyCode != 38 && e.keyCode != 39 && e.keyCode != 40) {
223
224					var myRequest = new Request({
225						url: '/' + cVKHome + 'shared_functions/ajax/ajax_opp_search.htm',
226						method: 'post',
227						data: {
228							'search': elSearchBox.value
229						},
230
231						onComplete: function (returned) {
232
233							var myObject = JSON.decode(returned);
234
235							if (myObject != null) {
236
237
238								elTarget.set('html', '');
239								elTarget.setStyles({
240									'width': elSearchBox.getWidth(),
241									'left': elSearchBox.getLeft(),
242									'top': elSearchBox.getTop() + elSearchBox.getHeight(),
243									visibility: 'visible'
244								});
245
246								myObject.each(function (opp) {
247
248									new Element('a', {
249										'class': 'searchsuggestrollover',
250										'href': '/volunteers/opportunity/' + opp.PLACEMENTID,
251										'id': 'opp_' + opp.PLACEMENTID,
252										'html': opp.NAME + ' - for ' + opp.PROVIDERNAME
253									}).inject(elTarget, 'bottom');
254								});
255
256							}
257
258							elTarget.reveal();
259
260						}
261
262					});
263					myRequest.send();
264
265				} else {
266					//REMOVE THE RESULTS BOX
267					elTarget.hide();
268				}
269
270			});
271
272		};
273
274	}
275		());
276
277	/*===========================================================
278	================= GENERAL AUTO COMPLETE ======================
279	===========================================================*/
280	(function () {
281
282		var autoSuggestRequest = new Request({});
283
284		var elTarget
285		if ($('autoSuggestEntry')) {
286
287			//create the target if it doesnt exist
288			if ($('autoSuggest')) {
289				elTarget = $('autoSuggest')
290			} else {
291				elTarget = new Element('div', {
292					id: 'autoSuggest'
293				}).inject(document.body);
294			};
295
296			$('autoSuggestEntry').addEvent('keyup', function (e) {
297
298				elSearchBox = $('autoSuggestEntry');
299
300				if (elSearchBox.value.length > 1 && e.keyCode != 13 && e.keyCode != 9 && e.keyCode != 16 && e.keyCode != 17 && e.keyCode != 18 && e.keyCode != 37 && e.keyCode != 38 && e.keyCode != 39 && e.keyCode != 40) {
301
302					autoSuggestRequest = new Request({
303						url: '/' + cVKHome + 'shared_functions/ajax/' + this.getAttribute('data-target') + '.htm',
304						method: 'post',
305						data: {
306							'search': elSearchBox.value
307						},
308
309						onComplete: function (returned) {
310
311							var myObject = JSON.decode(returned);
312
313							if (myObject != null) {
314
315								elTarget.set('html', '');
316								elTarget.setStyles({
317									'width': elSearchBox.getWidth(),
318									'left': elSearchBox.getLeft(),
319									'top': elSearchBox.getTop() + elSearchBox.getHeight(),
320									visibility: 'visible'
321								});
322
323								myObject.each(function (item) {
324
325									//inject the text and add an event, also store anything else we have collected
326
327									new Element('a', {
328										'class': 'searchsuggestrollover',
329										'href': '/',
330										'id': item.ID,
331										'html': item.NAME,
332										events: {
333											click: function (e) {
334												e.stop();
335												//set the value in the text box and also set an id value
336												elSearchBox.value = this.get('html');
337												if ($('autoSuggestId')) {
338													$('autoSuggestId').value = this.id
339												}
340												elTarget.hide();
341											}
342										}
343
344									}).inject(elTarget, 'bottom');
345								});
346
347							}
348
349							elTarget.reveal();
350
351						}
352
353					});
354
355					autoSuggestRequest.cancel();
356					autoSuggestRequest.send();
357
358				} else {
359					//REMOVE THE RESULTS BOX
360					elTarget.hide();
361				}
362
363			});
364
365		};
366
367	}
368		());
369
370	/*===========================================================
371	====================== SET LOCALE ===========================
372	===========================================================*/
373	Locale.use('en-GB');
374
375	/*===========================================================
376	============= SET UP ALERTS FOR UPLOADS =====================
377	===========================================================*/
378
379	$$('.js-upload').addEvent('submit', function (e) {
380
381		var roarUpload = new Roar({
382			position: 'upperleft',
383			duration: 20000 // 3 seconds until message fades out,
384		});
385
386		roarUpload.alert('<p>Uploading files, please wait and do not refresh the page.</p>');
387
388	});
389
390	/*===========================================================
391	============= SET UP GENERAL ROAR ALERTS =====================
392	===========================================================*/
393
394	$$('.js-RoarOnClick').addEvent('click', function (e) {
395
396
397		let roarMessage = 'Loading, please wait...';
398
399		if (this.getAttribute('data-roar-message')) {
400			roarMessage = this.getAttribute('data-roar-message');
401        }
402
403		roar.alert(roarMessage);
404
405
406	});
407
408	/*===========================================================
409	================= SET UP DATE PICKERS =======================
410	===========================================================*/
411
412	if (typeof this.Picker != 'undefined') {
413
414		//set up normal calender
415		//only on non DATE inputs, where date is supported it will render its own picker
416
417		//new Picker.Date($$('input.date_toggled[type=text]'), {
418		new Picker.Date($$('.date_toggled'), {
419			pickerClass: 'datepicker_vk',
420			openLastView: true
421		});
422
423		//set up inline calender
424		new Picker.Date($$('.date_toggledInline'), {
425			pickerClass: 'datepicker_vk',
426			openLastView: true
427		});
428
429		//set up decades calender
430		new Picker.Date($$('.date_toggledDecades'), {
431			pickerClass: 'datepicker_vk',
432			startView: 'decades',
433			openLastView: true
434		});
435
436		//set up past calender
437		new Picker.Date($$('.date_toggledPast'), {
438			pickerClass: 'datepicker_vk',
439			openLastView: true,
440			maxDate: Date.now()
441		});
442
443		//set up future calender
444		new Picker.Date($$('.date_toggledFuture'), {
445			pickerClass: 'datepicker_vk',
446			openLastView: true,
447			minDate: Date.now()
448		});
449
450	};
451
452	/*===========================================================
453	================ SET UP CHECK ALL BOXES =====================
454	===========================================================*/
455
456	$$('#ucuc').addEvent('click', function () {
457		if ($('ucuc').hasClass('fa-check-square-o')) {
458			do_check = false;
459			$('ucuc').removeClass('fa-check-square-o')
460			$('ucuc').addClass('fa-square-o')
461		} else {
462			do_check = true;
463			$('ucuc').removeClass('fa-square-o')
464			$('ucuc').addClass('fa-check-square-o')
465		}
466		$$('.check-me').each(function (el) {
467			el.checked = do_check;
468		});
469	});
470
471	if ($('selectAllCheckBox')) {
472
473		$('selectAllCheckBox').addEvent('click', function (e) {
474
475			if (this.checked) {
476				$$('.check-me').each(function (el) {
477					el.checked = true;
478				});
479			} else {
480				$$('.check-me').each(function (el) {
481					el.checked = false;
482				});
483			}
484
485		});
486
487	}
488
489	/*===========================================================
490	================= FOLLOWING FUNCTIONS =======================
491	===========================================================*/
492
493	$$('.js-FollowProvider').addEvent('click', function (e) {
494		e.stop();
495		providerID = this.getAttribute('data-providerid');
496
497		var myRequest = new Request({
498			url: '/volunteers/opportunity',
499			method: 'post',
500			data: {
501				'ajaxAction': 'putFollowProvider',
502				'follow': true,
503				'providerId': providerID
504			},
505			onSuccess: function () {
506				//let the user know somehow....roar message..?
507				roar.alert('<p>You are now following this provider</p><p>You will receive an alert when this provider creates a new opportunity</p>');
508			}
509
510		});
511		myRequest.send();
512
513	});
514
515	$$('.js-FollowCategory').addEvent('click', function (e) {
516		e.stop();
517		catID = this.getAttribute('data-catid');
518
519		var myRequest = new Request({
520			url: '/volunteers/opportunity',
521			method: 'post',
522			data: {
523				'ajaxAction': 'putFollowCategory',
524				'follow': true,
525				'categoryId': catID
526			},
527			onSuccess: function () {
528				//let the user know somehow....roar message..?
529				roar.alert('<p>You are now following this opportunity type</p><p>You will receive an alert when a similar new opportunity is created</p>');
530			}
531
532		});
533		myRequest.send();
534
535	});
536
537	/*===========================================================
538	============== SET UP ELEMENT FUNCTIONS =====================
539	===========================================================*/
540
541	Element.implement({
542		//implement centre
543
544
545		toJSON: function () {
546			var j = {};
547			Array.each(this.toQueryStringFull().split('&'), function (a) {
548				var kv = a.split('=')
549				//double quotes get url encoded from above but not json encoded
550				//shall we remove them
551				j[kv[0]] = kv[1].replaceAll('%22', '') || '';
552			});
553			return JSON.encode(j);
554		},
555
556		toQueryStringFull: function () {
557			var queryString = [];
558			this.getElements('input, select, textarea').each(function (el) {
559				var type = el.type;
560
561				if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image')
562					return;
563
564				/*
565				var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){
566				// IE
567				return document.id(opt).get('value');
568				}) : ((type == 'radio' || type == 'checkbox')) ? null : el.get('value');
569				 */
570
571
572				var value = (el.get('tag') == 'select') ? el.getSelected().map(function (opt) {
573					// IE
574					return document.id(opt).get('value');
575				}) : (el.type == 'checkbox' && el.checked == false) ? 0 : (type == 'radio' && el.checked == false) ? null : el.get('value');
576
577				Array.convert(value).each(function (val) {
578					if (typeof val != 'undefined')
579						queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val));
580				});
581			});
582			return queryString.join('&');
583		},
584
585		showWhatever: function () {
586			this.setStyles({
587				'visibility': 'visible',
588				'display': 'block',
589				'opacity': 1
590			});
591		},
592
593		centreEl: function () {
594			//have to set display block otherwise has no height
595
596			this.setStyles({
597				opacity: 0,
598				'display': 'block'
599			});
600			elSc = window.getScroll();
601			elsize = this.getSize()
602			var postop = window.getSize()
603
604			postopmiddle = (elSc.y + (postop.y / 2)) - (elsize.y / 2)
605			posleftmiddle = (postop.x / 2) - (elsize.x / 2)
606
607			//need to check to see if the element height is larger then the portal
608			if (postopmiddle < 0) {
609				postopmiddle = 0
610			};
611			this.setStyles({
612				'top': postopmiddle + 'px',
613				'left': posleftmiddle + 'px'
614			});
615
616		},
617
618		centreElFade: function () {
619			//so we can measure it but cant see it and fade it in
620			this.setStyles({
621				opacity: 0,
622				'display': 'block'
623			});
624			elSc = window.getScroll();
625			elsize = this.getSize()
626			var postop = window.getSize()
627			postopmiddle = (elSc.y + (postop.y / 2)) - (elsize.y / 2)
628			posleftmiddle = (postop.x / 2) - (elsize.x / 2)
629
630			//need to check to see if the element height is larger then the portal
631			if (postopmiddle < 0) {
632				postopmiddle = 0
633			};
634			//el.setStyles({'top':top+'px', 'left':left+'px'});
635			this.setStyles({
636				'top': postopmiddle,
637				'left': posleftmiddle
638			});
639			this.fade('in');
640		},
641
642		recentre: function () {
643
644			if (this.getStyle('display') != 'none') {
645
646				elSc = window.getScroll();
647				elsize = this.getSize()
648				var postop = window.getSize()
649				postopmiddle = (elSc.y + (postop.y / 2)) - (elsize.y / 2)
650				posleftmiddle = (postop.x / 2) - (elsize.x / 2)
651
652				//need to check to see if the element height is larger then the portal
653				if (postopmiddle < 0) {
654					postopmiddle = 0
655				};
656				//el.setStyles({'top':top+'px', 'left':left+'px'});
657				this.setStyles({
658					'top': postopmiddle,
659					'left': posleftmiddle
660				});
661
662			}
663
664		},
665
666		//implement a block level fade
667		fadeToggleBlock: function () {
668
669			currentStyle = this.getStyle('display')
670			if (currentStyle == 'block') {
671				//we are fading out
672				//no point fading out unless chaining as it will switch ti display none immediately
673				//this.fade('out');
674				this.setStyles({
675					'display': 'none'
676				});
677			} else {
678				this.setStyles({
679					opacity: 0,
680					'display': 'block'
681				});
682				this.fade('in');
683			}
684
685		},
686
687		//implement show
688		fadeShow: function () {
689			//set display:none and opacity 0
690			this.setStyles({
691				opacity: 0,
692				'display': 'block'
693			});
694			this.fade('in');
695		},
696		//implement hide
697		fadeHide: function () {
698			this.fade('out');
699			this.setStyles({
700				'display': 'none'
701			});
702		},
703
704		//fade in inline block visibility
705		elFadeShowInline: function () {
706
707			this.setStyles({
708				opacity: 0,
709				'display': 'inline-block'
710			});
711			this.fade('in');
712
713		},
714
715		//fade out inline block visibility
716		elFadeHideInline: function () {
717
718			this.setStyles({
719				'display': 'none'
720			});
721
722		},
723
724		//implement fade destroy
725		ElFadeDestroy: function () {
726
727			//alert(this.id)
728			//this.fade('out').get('tween').chain(function() { this.dispose(); });
729
730
731			var fx = new Fx.Tween(this);
732			fx.start('opacity', '0').chain(function () {
733				this.start('display', 'none')
734			});
735
736			/*var myChain = new Chain();
737
738			myChain.chain(
739			function(el) {this.fade('out'); this.callChain();},
740			function(el) {this.dispose(); this.callChain();}
741			);
742
743			myChain.callChain(this);*/
744		},
745
746		//implement our toggle
747		ElToggleHide: function () {
748
749			//alert(this.id)
750			//this.fade('out').get('tween').chain(function() { this.dispose(); });
751			vState = this.get('opacity')
752			vHidden = this.getStyle('display')
753
754			if (vHidden == 'none' || vState == 0) {
755				//this is a block level which has display none
756				//give it back being a block
757				this.setStyles({
758					opacity: 0,
759					'display': 'inline-block'
760				});
761				this.fade('in')
762
763			} else {
764				this.fade('out').get('tween').chain(
765					(function () {
766						this.setStyle('display', 'none');
767					}).bind(this));
768
769			};
770
771		},
772
773		highlightText: function (search, insensitive, klass) {
774
775			var regex = new RegExp('(<[^>]*>)|(\\b' + search.escapeRegExp() + ')', insensitive ? 'ig' : 'g');
776
777			return this.set('html', this.get('html').replace(regex, function (a, b, c) {
778				return (a.charAt(0) == '<') ? a : '<strong class="' + klass + '">' + c + '</strong>';
779			}));
780
781		},
782
783		flash: function (to, from, reps, prop, dur) {
784
785			//defaults
786
787			if (typeof to == 'undefined') {
788				to = '#FF9999'
789			};
790			if (typeof from == 'undefined') {
791				from = '#ffffff'
792			};
793			if (!reps) {
794				reps = 1;
795			}
796			if (!prop) {
797				prop = 'background-color';
798			}
799			if (!dur) {
800				dur = 750;
801			}
802
803			//create effect
804			var effect = new Fx.Tween(this, {
805				duration: dur,
806				link: 'chain'
807			})
808
809			//do it!
810			for (x = 1; x <= reps; x++) {
811				effect.start(prop, from, to).start(prop, to, from);
812			}
813		}
814
815	});
816
817	//closes fadeins
818	Array.each($$('.closethis'), function (el) {
819		//have to fade out te window then fade out the overlay
820		el.addEvent('click', function (event) {
821			//close the parent
822			var parent = el.getParent('div');
823			parent.fade('out').get('tween').chain(function () {
824				$('overlay_').dispose();
825			});
826
827		});
828	});
829
830	//removes removeMe elements after 10 seconds
831	Array.each($$('.removeMe'), function (el) {
832		//alert(el.id)
833		//el.delay(1000).ElFadeDestroy();
834		(function () {
835			el.ElFadeDestroy();
836		}).delay(5000);
837
838		//el.chain(function(){}.delay(3500, el.ElFadeDestroy()));
839	});
840
841	/* update cursor on add/remove click event */
842	Element.Events.click = {
843		base: 'click',
844		onAdd: function () {
845			if (!this == document) {
846				this.setStyle('cursor', 'pointer');
847			}
848		},
849		onRemove: function () {
850			if (!this == document) {
851				this.setStyle('cursor', '');
852			}
853		}
854	};
855
856	//adds a visual clue to pseudoButton CLASSES
857	Array.each($$('.pseudoButton'), function (el) {
858		//get the current colour of the button
859
860		el.addEvent('mouseover', function (e) {
861			vEC = $(e.target).getStyle('background-color');
862			vENC = '#' + colorscale(vEC, 0.5)
863			el.setStyles({
864				'cursor': 'pointer'
865			});
866			el.tween('background-color', vENC)
867		});
868
869		el.addEvent('mouseout', function (e) {
870			vEC = $(e.target).getStyle('background-color');
871			vENC = '#' + colorscale(vEC, 0.5)
872			el.setStyles({
873				'curosr': 'default'
874			});
875			el.tween('background-color', this.vEC)
876		});
877
878	});
879
880	//button rollovers
881	$$('.btnRoll').addEvent('mouseover', function (event) {
882		this.setStyle('background-position', 'top');
883	});
884	$$('.btnRoll').addEvent('mouseout', function (event) {
885		this.setStyle('background-position', 'bottom');
886	});
887
888	// zebra stripe tables with shade-table class
889	var count = 0;
890
891	//GRAB LOCATION
892	$$('.getLocation').addEvent('click', function (e) {
893
894		navigator.geolocation.getCurrentPosition(
895			function (position) {
896				//set a cookie with the lat and lng in
897				var myCookie = Cookie.write('volLat', position.coords.latitude);
898				var myCookie = Cookie.write('volLng', position.coords.longitude);
899
900				if (confirm('Thanks, we have now got your approximate location and can show you how far away opportunities are from you.\nClick ok to refresh the page.')) {
901					window.location.reload();
902				}
903			},
904			function errorCallback(error) {
905				alert('nothing')
906			}, {
907			maximumAge: 30000,
908			timeout: 5000,
909			enableHighAccuracy: true
910		});
911
912	});
913
914	//======== CHECK POSTCODE FOR LAT LNG ============== //
915
916	$$('.postcodeCheck').addEvent('blur', function (e) {
917
918		checkMyPostcode(e.target)
919
920	});
921
922	//=========== SEND A TEXT VIA AJAX =================
923
924	$$('.textnumber').addEvent('click', function (e) {
925
926		e.stop();
927
928		var tgt = e.target || e.srcElement; // IE doesn't use .target
929		//stick in the values of theclicked number to the form
930
931		if (this.getAttribute('data-id')) {
932
933			$('tVolID').value = this.getAttribute('data-id');
934
935		} else {
936
937			var tgtArr = tgt.id.split('|')
938			//if the target is empty then they have clicked osmething inside the table division
939			$('tNumber').value = tgtArr[1];
940			$('tVolID').value = tgtArr[0];
941
942		}
943		//make the form appear in the middle
944		$$('.toggleTgt').tween('opacity', 0);
945		$('open_textmessageform').centreElFade();
946
947	});
948
949	$$('.interview').addEvent('click', function (event) {
950
951		var tgt = $(event.target)
952
953		if (this.getAttribute('data-id')) {
954
955			$('iVolID').value = this.getAttribute('data-id')
956
957		} else {
958
959			if (!tgt.id) {
960				//get its parent instead
961				var tgt = tgt.getParent();
962			};
963
964			$('iVolID').value = tgt.id
965
966		}
967
968		var myTogglingChain = new Chain();
969
970		myTogglingChain.chain(
971			function (el) {
972				$$('.toggleTgt').fade('out');
973				this.callChain();
974			},
975			function (el) {
976				$('open_interviewform').centreElFade();
977				this.callChain();
978			});
979
980		myTogglingChain.callChain('something');
981
982	});
983
984	$$('.buttonToggle').addEvent('click', function (e) {
985
986		e.stop();
987		el = $(this.target);
988		el.toggle()
989
990	});
991
992	$$('select.togglingSelect').addEvent('change', function (e) {
993
994		elTarget = $(e.target.getAttribute('data-target'));
995
996		if (elTarget) {
997			if (e.target.nodeName == 'SELECT') {
998				//dont toggle but look for value
999				if (e.target.value == 1) {
1000					elTarget.show();
1001				} else {
1002					elTarget.hide();
1003				}
1004			} else {
1005				elTarget.toggle();
1006			}
1007		}
1008
1009		if (this.options[this.selectedIndex].getAttribute('data-hide') != null) {
1010
1011			elHide = this.options[this.selectedIndex].getAttribute('data-hide').split('||');
1012
1013			for (var i = 0; i < elHide.length; i++) {
1014
1015				elToHide = $(elHide[i])
1016				elToHide.hide();
1017
1018				if (this.options[this.selectedIndex].getAttribute('data-required') == 'true') {
1019					$(elToHide.getAttribute('data-id')).required = false
1020				}
1021			}
1022
1023
1024		}
1025
1026		if (this.options[this.selectedIndex].getAttribute('data-reveal') != null) {
1027
1028			elReveal = this.options[this.selectedIndex].getAttribute('data-reveal').split('||');
1029
1030			for (var i = 0; i < elReveal.length; i++) {
1031
1032				elToShow = $(elReveal[i])
1033				elToShow.show();
1034
1035				if (this.options[this.selectedIndex].getAttribute('data-required') == 'true') {
1036					$(elToShow.getAttribute('data-id')).required = true
1037				}
1038			}
1039
1040
1041		}
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051	})
1052
1053
1054
1055
1056	/*------- HELP TOPICS ------*/
1057
1058	if ($('helpPanel')) {
1059
1060		var target = 'index.htm';
1061		var audience = 'admin';
1062
1063
1064		//get the page name
1065		aPage = window.location.pathname.split('/')
1066
1067		if (aPage[3] == '') {
1068			target = 'index.htm';
1069			audience = aPage[2];
1070		} else {
1071			target = aPage[3];
1072			audience = aPage[2]
1073		}
1074
1075		//create the pop to show the help in
1076
1077
1078		new Element('div', {
1079			class: 'popup',
1080			style: 'max-height:500px; overflow-y: auto',
1081			id: 'helpViewer',
1082			html: '<i id="helpViewerClose" class="fa fa-times fa-2x red floatright" data-toggle="helpViewerContainer"></i><section id="helpViewerContent" class="helpContent"></section>'
1083		}).inject(document.body, 'bottom')
1084
1085		$('helpViewerClose').addEvent('click', function (e) {
1086
1087			$('helpViewer').hide()
1088
1089		});
1090
1091		var helpLoad = new Request.JSON({
1092
1093			url: '../shared_functions/ajax/ajax_help_topics.htm',
1094			method: 'get',
1095
1096			onSuccess: function (results) {
1097
1098				if (results) {
1099
1100					results.each(function (msg) {
1101
1102						el = $('helpPanel');
1103
1104						elcontent = '<p><a href="javascript:void(0);" class="bold">' + msg.POST_TITLE + '</a><br /><span class="small">' + msg.POST_EXCERPT + '</span></p><section class="hideme" id="helpContent_' + msg.ID + '" data-title="' + msg.POST_TITLE + '">' + msg.POST_CONTENT + '</section>'
1105
1106						new Element('div', {
1107							'class': 'card-list-dark card-dark',
1108							'data-id': msg.ID,
1109							html: elcontent,
1110							events: {
1111								click: function () {
1112									//get the required id and inject the HTML
1113									var helpID = this.getAttribute('data-id');
1114
1115
1116									$('helpViewerContent').set('html', '<h4>' + $('helpContent_' + helpID).getAttribute('data-title') + '</h4>' + $('helpContent_' + helpID).get('html'));
1117									$('helpViewer').centreElFade();
1118
1119								}
1120							}
1121
1122						}).inject($('helpList'));
1123
1124					});
1125
1126				}
1127
1128			}
1129
1130		}).send('target=' + target + '&audience=' + audience);
1131
1132		//SETS UP THE AJAX SEARCH FOR THE HELP SEARCH
1133
1134		$('form-HelpSearch').addEvent('submit', function (e) {
1135
1136			e.stop();
1137			el = $('helpSearchResults');
1138			el.innerHTML = '';
1139			el.innerHTML = '<p class="centerText"><i class="fa fa-spin fa-circle-o-notch fa-lg white"></i></p>';
1140
1141			var searchString = $('searchHelp').value;
1142
1143			var helpSearchLoad = new Request.JSON({
1144
1145				url: '../shared_functions/ajax/ajax_help_topics.htm',
1146				method: 'get',
1147
1148				onSuccess: function (results) {
1149
1150					if (results) {
1151
1152						el.innerHTML = '';
1153
1154						results.each(function (msg) {
1155
1156							elcontent = '<p><a href="javascript:void(0);">' + msg.POST_TITLE + '</a><br /><span class="small">' + msg.POST_EXCERPT + '</span></p><section class="hideme" id="helpContent_' + msg.ID + '" data-title="' + msg.POST_TITLE + '">' + msg.POST_CONTENT + '</section>'
1157
1158							new Element('div', {
1159								'class': 'card-list-dark card-dark',
1160								'data-id': msg.ID,
1161								html: elcontent,
1162								events: {
1163									click: function () {
1164										//get the required id and inject the HTML
1165										var helpID = this.getAttribute('data-id');
1166
1167
1168										$('helpViewerContent').set('html', '<h4>' + $('helpContent_' + helpID).getAttribute('data-title') + '</h4>' + $('helpContent_' + helpID).get('html'));
1169										$('helpViewer').centreElFade();
1170
1171									}
1172								}
1173
1174							}).inject($('helpSearchResults'));
1175
1176						});
1177
1178					} else {
1179						el.innerHTML = '<p>Sorry, we cant find any help topics to match</p>';
1180					}
1181
1182				}
1183
1184			}).send('target=' + target + '&audience=' + audience + '&btnSearch=true&searchString=' + searchString);
1185
1186		});
1187
1188	}
1189
1190
1191
1192	//implement the reveal selects on change
1193	//add all the aria stuff so it is accessible
1194
1195	// NOTE this has to happen before we do any panel switching and whatnot as teh aria hidden attribute gets set again
1196
1197	Array.each($$('.hideme'), function (el) {
1198		el.setAttribute('aria-hidden', 'true');
1199	});
1200
1201	Array.each($$('.js-reveal'), function (el) {
1202
1203		//sort out accessiblity attributes
1204
1205		if (el.getAttribute('data-target')) {
1206			target = el.getAttribute('data-target');
1207			elTarget = $(target);
1208			el.setAttribute('aria-expanded', 'false');
1209			el.setAttribute('aria-controls', target);
1210			elTarget.setAttribute('aria-labelledby', el.id);
1211			elTarget.setAttribute('aria-hidden', 'true');
1212		}
1213
1214		el.addEvent('change', function (e) {
1215			elTarget = $(e.target.get('data-target'));
1216			elTarget.toggle();
1217
1218			//update accessibility attributes when button clicked
1219			if (el.getAttribute('aria-expanded')) {
1220				if (el.getAttribute('aria-expanded') == 'true') {
1221					el.setAttribute('aria-expanded', 'false')
1222				} else {
1223					el.setAttribute('aria-expanded', 'true')
1224				}
1225
1226			};
1227
1228			//update accessibility attributes when button clicked
1229			if (elTarget.getAttribute('aria-hidden')) {
1230				if (elTarget.getAttribute('aria-hidden') == 'true') {
1231					elTarget.setAttribute('aria-hidden', 'false')
1232				} else {
1233					elTarget.setAttribute('aria-hidden', 'true')
1234				}
1235
1236			};
1237
1238		});
1239
1240	});
1241
1242	Array.each($$('.js-toggle'), function (el) {
1243
1244		//sort out accessiblity attributes
1245		
1246
1247		if (el.getAttribute('data-target')) {
1248
1249			target = el.getAttribute('data-target');
1250			elTarget = $(target);
1251			el.setAttribute('aria-expanded', 'false');
1252			el.setAttribute('aria-controls', target);
1253
1254			if (elTarget) {
1255				elTarget.setAttribute('aria-hidden', 'true');
1256			}
1257
1258			if (el.id) {
1259				elTarget.setAttribute('aria-labelledby', el.id);
1260			}
1261		}
1262
1263		if (el.getAttribute('data-prefix')) {
1264
1265			if (el.getAttribute('data-prefix') == 'plus') { }
1266
1267		};
1268
1269		el.addEvent('click', function (e) {
1270			console.log('here');
1271			letBubble = this.get('data-letbubble');
1272
1273			if (!letBubble) {
1274				e.preventDefault();
1275			}
1276
1277			elSlide = $(this.get('data-slide'));
1278			elSlideDirection = this.get('data-slide-direction');
1279			elReveal = $(this.get('data-reveal'));
1280			elToggle = $(this.get('data-toggle'));
1281			elHide = this.get('data-hide');
1282            classHide = this.get('data-classhide');
1283			elCenter = this.get('data-center')
1284			elUnblur = $(this.get('data-unblur'));
1285			chevronFlip = this.get('data-chevronflip');
1286			elScrollTo = this.get('data-scroll');
1287			statusFlip = this.get('data-statusflip');
1288
1289			displayType = 'block';
1290			isTableCell = this.get('data-tablecell');
1291			if (isTableCell) {
1292				displayType = 'table-cell';
1293			}
1294
1295
1296			if (classHide) {
1297
1298				let classHideList = document.getElementsByClassName(classHide);
1299
1300				for (i = 0; i < classHideList.length; i++) {
1301					currentEl = $(classHideList[i]);
1302					currentEl.hide();
1303                }
1304			}
1305
1306			if (elHide) {
1307				//CHECK IF WE HAVE MORE THAN ONE ELEMENT TO HIDE#
1308				elements = elHide.split('|')
1309				for (i = 0; i < elements.length; i++) {
1310
1311					currentEl = $(elements[i]);
1312					currentEl.hide();
1313
1314					//also need to check for chevron flips here but need to know the title targets not the reveal targets!
1315
1316
1317					if (this.getAttribute('data-focuser')) {
1318						$(this.getAttribute('data-focuser')).focus();
1319					}
1320				}
1321
1322
1323
1324			}
1325
1326			if (elSlide) {
1327				slideElement(elSlide, this, { direction: elSlideDirection })
1328			}
1329			
1330
1331			if (elToggle) {
1332				toggleElement(elToggle, this, { center: elCenter, displayType: displayType })
1333			}
1334
1335
1336			if (elReveal) {
1337				revealElement(elReveal, this, { center: elCenter, scrollTo: elScrollTo, displayType: displayType })
1338			}
1339			
1340
1341			if (elUnblur) {
1342				elUnblur.setStyle('filter', 'blur(0)');
1343			}
1344
1345			
1346
1347			if (chevronFlip) {
1348				//find the chevron icon and then swap it
1349				//is the clicked element an icon
1350				//we are now using SVG icons sets from font awesome so switch the SVG class
1351
1352				if (this.tagName.toLowerCase() == 'svg') {
1353					if (this.hasClass('fa-chevron-down')) {
1354						this.swapClass('fa-chevron-down', 'fa-chevron-up');
1355					} else {
1356						this.swapClass('fa-chevron-up', 'fa-chevron-down');
1357					}
1358				} else {
1359
1360					
1361					icons = this.getElements('svg');
1362					firstIcon = icons[0];
1363					if (firstIcon.hasClass('fa-chevron-down')) {
1364						firstIcon.swapClass('fa-chevron-down', 'fa-chevron-up');
1365					} else {
1366						firstIcon.swapClass('fa-chevron-up', 'fa-chevron-down');
1367					}
1368				}
1369			}
1370
1371			if (statusFlip) {
1372				//this should just be a circle with a plus or minus in it
1373				if (this.innerHTML == '+') {
1374
1375					this.innerHTML = '&minus;';
1376					this.style.backgroundColor = '#990000';
1377
1378				} else if (this.innerHTML === '−') {
1379
1380					this.innerHTML = '&plus;';
1381					this.style.backgroundColor = '#77a22f';
1382				}
1383
1384			}
1385
1386			if (this.innerHTML.indexOf('▼') > -1) {
1387				this.innerHTML = '▲'
1388			} else if (this.innerHTML.indexOf('▲') > -1) {
1389				this.innerHTML = '▼'
1390			}
1391
1392
1393		});
1394
1395	});
1396
1397	/* Dialog Toggles */
1398
1399	const allDialogs = document.querySelectorAll('dialog');
1400	const allDialogsAction = document.querySelectorAll('.js-toggleDialog');
1401
1402
1403	//close dialogs when clicked outside of them
1404	for (var i = 0, len = allDialogs.length; i < len; i++) {
1405
1406		allDialogs[i].addEventListener('mousedown', (event) => {
1407			if (event.target.tagName == 'DIALOG') {
1408				event.target.close();
1409			}
1410		});
1411
1412	}
1413
1414	for (var i = 0, len = allDialogsAction.length; i < len; i++) {
1415		allDialogsAction[i].addEventListener('click', (event) => {
1416
1417			 
1418			let closeDialog = document.getElementById(event.currentTarget.dataset.hide);
1419			let openDialog = document.getElementById(event.currentTarget.dataset.show);
1420
1421			if (closeDialog) {
1422				closeDialog.close();
1423			}
1424
1425			if (openDialog) {
1426				openDialog.showModal();
1427			}
1428
1429		});
1430	}
1431
1432	/*===========================================================
1433	=================== TWO PANE VIEWS ==========================
1434	===========================================================*/
1435
1436	var elPanels = $$('.js-SettingsPanel');
1437	var elLinks = $$('.sideNav a.panelLinks');
1438
1439	//CHECK THE QUERYSTRING FOR A SAVED PANEL
1440
1441	if (getParameterByName('panel')) {
1442
1443		panel = getParameterByName('panel')
1444
1445		for (i = 0; i < elPanels.length; i++) {
1446			if (elPanels[i].id == panel) {
1447				elPanels[i].style.display = 'block';
1448				elPanels[i].setAttribute('aria-hidden', 'false');
1449			} else {
1450				elPanels[i].style.display = 'none';
1451				elPanels[i].setAttribute('aria-hidden', 'true');
1452			}
1453		}
1454
1455
1456		//set the active link
1457		for (i = 0; i < elLinks.length; i++) {
1458
1459			elLinks[i].removeClass('active');
1460			if (elLinks[i].get('data-target') == panel) {
1461				elLinks[i].addClass('active');
1462				elLinks[i].click();
1463			}
1464		}
1465
1466	} else {
1467		//lets make the first one appear
1468
1469		els = $$('.sideNavContent')
1470
1471		if (els.length > 0) {
1472			el = els[0].getElement('.js-SettingsPanel');
1473			if (el) {
1474				el.style.display = 'block';
1475				el.setAttribute('aria-hidden', 'false');
1476			}
1477		}
1478
1479	};
1480
1481
1482
1483
1484	$$('.sideNav a.panelLinks').addEvent('click', function (e) {
1485		//e.stop();
1486		for (i = 0; i < elPanels.length; i++) {
1487			//elPanels.hide();
1488			elPanels[i].style.display = 'none';
1489			elPanels[i].setAttribute('aria-hidden', 'true');
1490		}
1491
1492		for (i = 0; i < elLinks.length; i++) {
1493			elLinks[i].removeClass('active');
1494		}
1495
1496		this.addClass('active')
1497
1498		//$(this.get('data-target')).show()
1499		$(this.get('data-target')).style.display = 'block';
1500		$(this.get('data-target')).setAttribute('aria-hidden', 'false');
1501
1502	});
1503
1504	$$('a.panelLinksInline').addEvent('click', function (e) {
1505		e.stop();
1506		for (i = 0; i < elPanels.length; i++) {
1507			elPanels.hide();
1508		}
1509
1510		for (i = 0; i < elLinks.length; i++) {
1511			elLinks[i].removeClass('active');
1512		}
1513
1514		//this.addClass('active')
1515
1516		$(this.get('data-target')).show()
1517
1518		if (this.get('data-position')) {
1519
1520			//scroll to
1521			new Fx.Scroll(window).toElement($(this.get('data-position')));
1522		}
1523	});
1524
1525
1526
1527	//swap password fields to display password briefly
1528
1529	$$('.js-showPassword').addEvent('click', function (e) {
1530
1531		//grab the target element
1532		var targetel = document.getElementById(this.getAttribute('data-id'));
1533
1534		//make it text and then wait a while and turn it back
1535		targetel.type = 'text';
1536
1537		setTimeout(
1538			function () {
1539				targetel.type = 'password';
1540			}
1541			, 5000);
1542
1543	});
1544
1545
1546	//implement the reveal selects on change
1547	$$('.js-toggle-change').addEvent('change', function (e) {
1548
1549		e.stop();
1550
1551		elReveal = $(this.get('data-reveal'));
1552		elToggle = $(this.get('data-toggle'));
1553		elHide = $(this.get('data-hide'));
1554		elCenter = this.get('data-center')
1555
1556		if (elToggle) {
1557			$(elToggle).toggle();
1558		}
1559
1560		if (elReveal) {
1561			if (elCenter) {
1562				//have to make block and then hide to get dimensions
1563				$(elReveal).centreEl();
1564				$(elReveal).fade('in');
1565			} else {
1566				$(elReveal).show();
1567			}
1568		}
1569
1570		if (elHide) {
1571			$(elHide).hide();
1572		}
1573
1574	});
1575
1576	//have to use delegation for this..?
1577	$$('.js-CreateModal').addEvent('click', function (e) {
1578
1579		e.stop();
1580		createModal(this)
1581
1582	});
1583
1584
1585	//Also add a delegation for same function in case its dynamic
1586	if ($('js-DynamicContent')) {
1587		$('js-DynamicContent').addEvent("click:relay(.js-CreateModal)", function (event, element) {
1588
1589			event.preventDefault();
1590			createModal(element)
1591
1592		});
1593	}
1594
1595	function createModal(el) {
1596
1597		var modalTitle = el.getAttribute('data-title');
1598		var modalContent = el.getAttribute('data-content');
1599
1600		//create the modal
1601
1602		if (!$('js-CreatedModal')) {
1603
1604			mynew = new Element('div', {
1605				'styles': {
1606					'display': 'none',
1607					'border': '1px solid black',
1608					'height': '360px',
1609					'width': '760px',
1610					'overflow': 'auto',
1611					'position': 'absolute',
1612					'top': '0',
1613					'left': '0',
1614					'z-index': '100'
1615				},
1616
1617				'class': 'popup',
1618				'html': '<h3>' + modalTitle + '</h3><p>' + modalContent + '</p>',
1619				'id': 'js-CreatedModal',
1620
1621				'events': {
1622					'click': function () {
1623						this.dispose();
1624					}
1625
1626				}
1627
1628			}).inject($(document.body));
1629
1630		} else {
1631			$('js-CreatedModal').innerHTML = '<h3>' + modalTitle + '</h3><p>' + modalContent + '</p>';
1632		}
1633
1634
1635		$('js-CreatedModal').centreElFade();
1636	}
1637
1638	$$('.toggling').addEvent('click', function (e) {
1639
1640		e.stop();
1641
1642		var tgt = $(e.target)
1643		var elClickedstr = this.id.split('|');
1644		el = $("open_" + elClickedstr[0]);
1645
1646		if (el.hasClass('popup') && el.getStyle('display') == 'none') {
1647			//have to display block it and center it
1648			el.setStyles({
1649				opacity: 0,
1650				'display': 'block'
1651			});
1652			el.centreEl()
1653			el.setStyles({
1654				opacity: 0,
1655				'display': 'none'
1656			});
1657		};
1658
1659		el.ElToggleHide()
1660		//el.fade('toggle');
1661
1662		// myMask.hide();
1663
1664
1665	});
1666
1667	//set up the toggling flips so that one is visible
1668
1669	Array.each($$('.togglingFlip'), function (el) {
1670		if (el.checked) {
1671			var elClickedstr = el.id.split('|');
1672			$("open_" + elClickedstr[0]).show('block');
1673		}
1674	});
1675
1676	$$('.togglingFlip').addEvent('click', function (e) {
1677
1678		var tgt = e.target // IE doesn't use .target
1679		var elClickedstr = tgt.id.split('|');
1680		el = $("open_" + elClickedstr[0]);
1681		elClose = $("open_" + elClickedstr[1]);
1682
1683		if (el.hasClass('popup') && el.getStyle('display') == 'none') {
1684			//have to display block it and center it
1685			el.setStyles({
1686				opacity: 0,
1687				'display': 'block'
1688			});
1689			el.centreEl()
1690		};
1691
1692		el.show('block')
1693		elClose.hide()
1694
1695		//remove the overlay if it exists.
1696		o = $('overlay_');
1697		if (o) {
1698			o.dispose();
1699		};
1700
1701		// hide autosuggest if it exists
1702		a = $('autosuggest');
1703		if (a) {
1704			a.fade('out')
1705		} //dont destroy as may need it again
1706
1707	});
1708
1709	$$('.closeMe').addEvent('click', function (e) {
1710		//have to split at _ for unique IDs added after the string we need
1711		var tgt = $(e.target)
1712		var elClickedstr = tgt.id;
1713		pos = elClickedstr.indexOf('|');
1714		//capture that ID as an object
1715		if (pos != -1) {
1716			el = $("open_" + elClickedstr.substring(0, pos));
1717		} else {
1718			el = $("open_" + elClickedstr);
1719		}
1720		el.fade('out');
1721	});
1722
1723	$$('.togglingNC').addEvent('click', function (e) {
1724		//have to split at _ for unique IDs added after the string we need
1725		var tgt = e.target || e.srcElement; // IE doesn't use .target
1726		var elClickedstr = tgt.id;
1727		pos = elClickedstr.indexOf('|');
1728		//capture that ID as an object
1729		if (pos != -1) {
1730			el = $("open_" + elClickedstr.substring(0, pos));
1731		} else {
1732			el = $("open_" + elClickedstr);
1733		}
1734		el.fade('toggle');
1735	});
1736
1737	//====== CHECK FOR AND CONTROL LOGIN POPUP========//
1738
1739
1740	var isLogin = $('open_loginPopup')
1741
1742	if (isLogin) {
1743
1744		$('open_loginPopup').addEvent('mouseleave', function (e) {
1745			//check to see if a form has focus
1746			if (!lostFocus) {
1747				//fadeout the popup
1748				popup = $('open_loginPopup')
1749				popup.fade('out');
1750			};
1751		});
1752
1753		lostFocus = false
1754
1755		Array.each($$('.loginFrontToggle'), function (el) {
1756			el.addEvent('mouseover', function (e) {
1757				popup = $('open_loginPopup')
1758				posDiv = $('loginFrontToggle')
1759
1760				vPosPop = popup.getCoordinates();
1761				vPos = posDiv.getCoordinates();
1762
1763				//position login div
1764				popup.setStyles({
1765					'top': 0,
1766					'left': vPos.right - vPosPop.width
1767				});
1768				//pop up login div
1769				popup.fade('in');
1770			});
1771
1772		});
1773
1774		$$('.loseFocus').addEvent('focus', function (e) {
1775
1776			lostFocus = true
1777			//add a manual close button on the login form
1778			//this is all because we cannot guarantee that automcomplete=off works in FF, IE etc
1779			periodical = focusReset.periodical(2 * 1000, this);
1780
1781		});
1782
1783		var focusReset = (function () {
1784
1785			lostFocus = false;
1786			$clear(periodical);
1787
1788		});
1789
1790	};
1791
1792	// WHAT IS THIS DOING HERE ?????
1793	/*
1794	$$('.emailaddSchool').addEvent('click', function(e) {
1795
1796	e.stop();
1797
1798	var tgt = $(e.target)
1799	//stick in the values of theclicked number to the form
1800	var tgtArr = tgt.id.split('|')
1801	if(!tgtArr[0]){
1802	//get its parent instead
1803	var tgt = tgt.getParent();
1804	var tgtArr = tgt.id.split('|')
1805	};
1806
1807	$('eToAddress').value = tgtArr[0]
1808	//make the form appear in the middle
1809	$('open_emailform').centreEl();
1810
1811	//toggle off anyother open toggle targets and fade in the one we are interested in
1812	var myTogglingChain = new Chain();
1813
1814	myTogglingChain.chain(
1815	function(el) {$$('.toggleTgtCentre').fade('out'); this.callChain();},
1816	function(el) {$('open_emailform').fade('toggle'); this.callChain();}
1817	);
1818
1819	myTogglingChain.callChain('something');
1820
1821	Event.stop;
1822	});
1823
1824	 */
1825
1826	// DELEGATE THIS FOR ALL THE AJAX ADDED SECTIONS
1827
1828
1829	$$('.emailadd').addEvent('click', function (e) {
1830
1831		e.stop();
1832
1833		var tgt = $(e.target)
1834
1835		//SET EMAIL ALL TO ZERO AS WE ARE ONLY SENDING TO A SINGLE
1836		if ($('sendAllOnOpp')) {
1837			$('sendAllOnOpp').value = 0
1838		}
1839
1840		//LOOK FOR A TARGET
1841
1842		var emailTarget = 'volunteer';
1843
1844		if (this.getAttribute('data-target')) {
1845			emailTarget = this.getAttribute('data-target');
1846		}
1847
1848		//set the target on the form
1849		targetInput = $('eTarget');
1850		if (targetInput) { targetInput.value = emailTarget }
1851
1852
1853		//stick in the values of the entity(ies) to email
1854
1855		if (this.getAttribute('data-id')) {
1856
1857			$('eVolID').value = this.getAttribute('data-id')
1858
1859		} else {
1860
1861			var tgtArr = tgt.id.split('|')
1862
1863			if (!tgtArr[0]) {
1864				//get its parent instead
1865				var tgt = tgt.getParent();
1866				var tgtArr = tgt.id.split('|')
1867			};
1868
1869			$('eVolID').value = tgtArr[0]
1870
1871		}
1872
1873		//make the form appear in the middle
1874		if ($('open_emailform')) {
1875			$('open_emailform').centreEl();
1876			$('open_emailform').fade('toggle');
1877		}
1878
1879		if ($('open_emailformAll')) {
1880			$('open_emailformAll').centreEl();
1881			$('open_emailformAll').fade('toggle');
1882		}
1883
1884	});
1885
1886	$$('.emailaddGeneral').addEvent('click', function (e) {
1887
1888		e.stop();
1889		var tgt = $(e.target)
1890		//stick in the values of theclicked number to the form
1891		var tgtArr = tgt.id.split('|')
1892		if (!tgtArr[0]) {
1893			//get its parent instead
1894			var tgt = tgt.getParent();
1895			var tgtArr = tgt.id.split('|')
1896		};
1897
1898		$('eAddress').value = tgtArr[0];
1899		emailTarget = this.getAttribute('data-target');
1900
1901
1902
1903		//make the form appear in the middle
1904		//set the target attribute of the form
1905
1906		if ($('open_emailGeneralform')) {
1907			$('emailTarget').value = emailTarget;
1908			$('open_emailGeneralform').centreEl();
1909			$('open_emailGeneralform').fade('toggle');
1910		}
1911
1912	});
1913
1914
1915
1916
1917	$$('.emailaddProvider').addEvent('click', function (e) {
1918
1919		//convert this stupid stuff into this.get('data-email')
1920		//will need to update all the instances of emailAddProvider throughout to include data attributes
1921		e.stop();
1922		var tgt = $(e.target)
1923
1924		//stick in the values of theclicked number to the form
1925		var tgtArr = tgt.id.split('|')
1926
1927		if (!tgtArr[0]) {
1928			//get its parent instead
1929			var tgt = tgt.getParent();
1930			var tgtArr = tgt.id.split('|')
1931		};
1932
1933		$('ePEmail').value = tgtArr[1]//set the email address to this provider
1934		//make the form appear in the middle
1935		$('open_emailformprov').centreEl();
1936
1937		//toggle off anyother open toggle targets and fade in the one we are interested in
1938		var myTogglingChain = new Chain();
1939
1940		myTogglingChain.chain(
1941			function (el) {
1942				$$('.toggleTgtCentre').fade('out');
1943				this.callChain();
1944			},
1945			function (el) {
1946				$('open_emailformprov').fade('in');
1947				this.callChain();
1948			});
1949
1950		myTogglingChain.callChain('something');
1951
1952		Event.stop;
1953	});
1954
1955	$$('.textProvider').addEvent('click', function (e) {
1956
1957		e.stop();
1958
1959		var tgt = $(e.target)
1960		//stick in the values of theclicked number to the form
1961		var tgtArr = tgt.id.split('|')
1962		if (!tgtArr[0]) {
1963			//get its parent instead
1964			var tgt = tgt.getParent();
1965			var tgtArr = tgt.id.split('|')
1966		};
1967
1968		//make the form appear in the middle
1969		$('open_textform').centreEl();
1970
1971		//toggle off anyother open toggle targets and fade in the one we are interested in
1972		var myTogglingChain = new Chain();
1973
1974		myTogglingChain.chain(
1975			function (el) {
1976				$$('.toggleTgtCentre').fade('out');
1977				this.callChain();
1978			},
1979			function (el) {
1980				$('open_textform').fade('toggle');
1981				this.callChain();
1982			});
1983
1984		myTogglingChain.callChain('something');
1985
1986		Event.stop;
1987	});
1988
1989	$$('.btnSpinner').addEvent('click', function (e) {
1990		addSpinnerToButton(this);
1991	});
1992
1993}); //END OF DOM READY FUNCTION
1994
1995
1996
1997
1998/*====================================================
1999==== ALL THE TOGGLING/SLIDING FUNCTIONS FUNCTIONS ====
2000====================================================*/
2001
2002
2003function toggleElement(elToToggle, elParent, options) {
2004
2005	let defaults = {
2006		center: false,
2007		displayType: 'block'
2008	}
2009
2010	options = setDefaults(options, defaults);
2011
2012	//update accessibility attributes when button clicked
2013	if (elToToggle.getAttribute('aria-hidden')) {
2014		if (elToToggle.getAttribute('aria-hidden') == 'true') {
2015			elToToggle.setAttribute('aria-hidden', 'false')
2016		} else {
2017			elToToggle.setAttribute('aria-hidden', 'true')
2018		}
2019
2020	};
2021
2022	if (elParent.getAttribute('aria-expanded')) {
2023		if (elParent.getAttribute('aria-expanded') == 'true') {
2024			elParent.setAttribute('aria-expanded', 'false')
2025		} else {
2026			elParent.setAttribute('aria-expanded', 'true')
2027		}
2028
2029	};
2030
2031	if (options.center) {
2032		elToToggle.centreEl();
2033		elToToggle.setStyles({
2034			'visibility': 'visible',
2035			'opacity': 100,
2036			'display': options.displayType
2037		});
2038
2039	} else {
2040
2041		elToToggle.setStyle('visibility', 'visible');
2042		elToToggle.toggle();
2043
2044		if (elToToggle.getAttribute('data-hidden') == 'true') {
2045
2046			elToToggle.setAttribute('data-hidden', 'false');
2047
2048		} else {
2049
2050			elToToggle.setAttribute('data-hidden', 'true');
2051
2052		}
2053	}
2054
2055}
2056
2057
2058
2059function revealElement(elToReveal, elParent, options) {
2060
2061	let defaults = {
2062		center: false,
2063		scrollTo: false,
2064		displayType: 'block'
2065	}
2066
2067	options = setDefaults(options, defaults);
2068
2069	//update accessibility attributes when button clicked
2070	if (elToReveal.getAttribute('aria-hidden')) {
2071		if (elToReveal.getAttribute('aria-hidden') == 'true') {
2072			elToReveal.setAttribute('aria-hidden', 'false')
2073		} else {
2074			elToReveal.setAttribute('aria-hidden', 'true')
2075		}
2076
2077	};
2078
2079	if (elParent.getAttribute('aria-expanded')) {
2080		if (elParent.getAttribute('aria-expanded') == 'true') {
2081			elParent.setAttribute('aria-expanded', 'false')
2082		} else {
2083			elParent.setAttribute('aria-expanded', 'true')
2084		}
2085
2086	};
2087
2088	if (options.center) {
2089		//have to make block and then hide to get dimensions
2090		//got a bunch of sub functions mixed in here
2091		//also got mootools specific that needs removing.
2092
2093		elToReveal.centreEl();
2094		elToReveal.setStyle('visibility', 'visible');
2095		elToReveal.fade('in');
2096		elToReveal.setStyle('display', options.displayType);
2097
2098	} else {
2099		elToReveal.setStyle('visibility', 'visible');
2100		elToReveal.show();
2101		elToReveal.setStyle('display', options.displayType);
2102	}
2103
2104	if (options.scrollTo) {
2105		//Mootools remove
2106		new Fx.Scroll(window).toElement(elToReveal);
2107	}
2108
2109}
2110
2111
2112
2113
2114function slideElement(elToSlide, elParent, options) {
2115
2116	let defaults = {
2117		direction: 'right',
2118		distance: '-450px'
2119	}
2120
2121	options = setDefaults(options, defaults);
2122
2123
2124	if (options.direction == 'right') {
2125
2126		//sliding FROM THE RIGHT edge
2127
2128		if (elToSlide.getStyle('right') != '0px') {
2129
2130			//ELEMENT IS OFF TO THE RIGHT SO SLIDING ELEMENT INTO VIEW FROM RIGHT TO LEFT
2131
2132			elToSlide.setStyle('right', '0px');
2133			elToSlide.setAttribute('aria-hidden', 'false');
2134
2135			//have to pass focus to this element for keyboard controllers
2136
2137			elParent.focusedElBeforeOpen = document.activeElement;
2138
2139			focusableEl = elToSlide.querySelector('.firstFocusable');
2140			focusableEl.focus();
2141
2142			//also give this some data about what opened it
2143			focusableEl.setAttribute('data-focuser', elParent.focusedElBeforeOpen.id)
2144
2145		} else {
2146
2147			//ELEMENT IS IN VIEW SO SLIDING OUT OF VIEW FROM LEFT TO RIGHT
2148
2149			elToSlide.setStyle('right', options.width);
2150			elToSlide.setAttribute('aria-hidden', 'true');
2151
2152			if (elParent.getAttribute('data-focuser')) {
2153				$(elParent.getAttribute('data-focuser')).focus();
2154			}
2155		}
2156
2157	} else if (options.direction == 'left') {
2158
2159		//sliding FROM THE LEFT edge
2160
2161		if (elToSlide.getStyle('left') != '0px') {
2162
2163			//ELEMENT IS OFF TO THE LEFT SO SLIDING ELEMENT INTO VIEW FROM LEFT TO RIGHT
2164
2165			elToSlide.setStyle('left', '0px');
2166			elToSlide.setAttribute('aria-hidden', 'false');
2167
2168			//have to pass focus to this element for keyboard controllers
2169
2170			elParent.focusedElBeforeOpen = document.activeElement;
2171
2172			focusableEl = elToSlide.querySelector('.firstFocusable');
2173			focusableEl.focus();
2174
2175			//also give this some data about what opened it
2176			focusableEl.setAttribute('data-focuser', elParent.focusedElBeforeOpen.id)
2177
2178		} else {
2179
2180			//ELEMENT IS IN VIEW SO SLIDING OUT OF VIEW FROM LEFT TO RIGHT
2181
2182			elToSlide.setStyle('left', options.width);
2183			elToSlide.setAttribute('aria-hidden', 'true');
2184
2185			if (elParent.getAttribute('data-focuser')) {
2186				$(elParent.getAttribute('data-focuser')).focus();
2187			}
2188		}
2189
2190	}
2191
2192
2193}
2194
2195
2196//little ditty just to set default options in functions
2197function setDefaults(options, defaults) {
2198	if (typeof options === 'object') {
2199		Object.keys(options).forEach(function (key) {
2200			defaults[key] = options[key];
2201		});
2202	}
2203
2204	return defaults;
2205}
2206
2207
2208
2209//little ditty to create and set a node attribute
2210function createSetAttribute(target, name, value) {
2211	let att = document.createAttribute(name);
2212	att.value = value;
2213	target.setAttributeNode(att);
2214}
2215
2216
2217function checkMyPostcode(el, callBackFunction) {
2218
2219	var elTarget = el;
2220
2221	if (elTarget.id.indexOf('_') != -1) {
2222		a = elTarget.id.split('_')
2223		vSuf = a[1]
2224		elLat = $('vLat_' + vSuf)
2225		elLng = $('vLng_' + vSuf)
2226		elNotify = $('postcodeCheckText_' + vSuf)
2227		vNewNotify = 'postcodeCheckText_' + vSuf
2228		vNewLat = 'vLat_' + vSuf
2229		vNewLng = 'vLng_' + vSuf
2230	} else {
2231
2232		elLat = $('vLat')
2233		elLng = $('vLng')
2234		elNotify = $('postcodeCheckText')
2235		vNewNotify = 'postcodeCheckText'
2236		vNewLat = 'vLat'
2237		vNewLng = 'vLng'
2238
2239	}
2240	//stick up the spinner and text
2241	//check if it exists
2242
2243	//====================== CREATE THE ELEMENTS IF NECESSARY =======================
2244
2245	if (typeOf(elNotify) != 'element') {
2246
2247		var elNotify = new Element('span', {
2248			id: vNewNotify,
2249			'html': '&nbsp;&nbsp;<i class="fa fa-spinner fa-spin"></i> checking postcode',
2250			'class': 'invisible'
2251		});
2252		elNotify.inject(elTarget, 'after');
2253
2254	};
2255
2256	elNotify.set('html', '&nbsp;&nbsp;<i class="fa fa-spinner fa-spin"></i> checking postcode');
2257	elNotify.fade('in');
2258
2259	//CREATE HIDDEN FORM ELEMENTS EXIST
2260	if (typeOf(elLat) != 'element') {
2261		var elLat = new Element('input', {
2262			id: vNewLat,
2263			'name': 'vLat',
2264			'type': 'hidden'
2265		})
2266		var elLng = new Element('input', {
2267			id: vNewLng,
2268			'name': 'vLng',
2269			'type': 'hidden'
2270		})
2271		elLat.inject(elTarget, 'after');
2272		elLng.inject(elTarget, 'after');
2273	}
2274
2275	//grab postcode value
2276	// USING www.uk-postcodes.com for NOW via an ASP proxy page and ajax
2277	vPostcode = elTarget.value
2278	vPostcodeFixed = elTarget.value.toUpperCase().replace(' ', '');
2279
2280	var jsonRequest = new Request.JSON({
2281		url: '/' + cVKHome + '/shared_functions/ajax/ajax_getlatlng_postcode.htm',
2282		onSuccess: function (geoInfo) {
2283
2284			//===== check we have a match
2285			if (geoInfo.geo) {
2286				;
2287
2288				elLat.value = geoInfo.geo.lat;
2289				elLng.value = geoInfo.geo.lng;
2290				elTarget.value = vPostcodeFixed
2291				elNotify.set('html', '&nbsp;&nbsp;<i class="fa fa-check green"></i>');
2292				//CHECK IF THERE IS SOMETHING ELSE TO DO
2293				if (callBackFunction) {
2294					callBackFunction();
2295				}
2296
2297			} else {
2298				elNotify.set('html', '&nbsp;&nbsp;<i class="fa fa-times red"></i> not found');
2299				elLat.value = '';
2300				elLng.value = '';
2301				//alert("That Postcode has not been found, please check.");
2302				elTarget.flash();
2303			}
2304
2305		},
2306		onFailure: function (stuff) {
2307
2308			elNotify.set('html', '&nbsp;&nbsp;<i class="fa fa-times red"></i> not found');
2309			elLat.value = '';
2310			elLng.value = '';
2311			//alert("That Postcode has not been found, please check.");
2312			elTarget.flash();
2313		}
2314
2315	}).get('postcode=' + vPostcodeFixed);
2316
2317};
2318
2319function addAjaxSpinner(el) {
2320	//hide the button and place an ajax spinner in its place
2321	//create new element
2322	mySpinner = new Element('i', {
2323		'class': 'fa fa-cog fa-spin'
2324	});
2325	mySpinner.inject(el, 'before');
2326};
2327
2328function addSpinnerToButton(el) {
2329	var elIcon = el.getFirst('i');
2330	if (elIcon) {
2331		elIcon.set('class', '');
2332		elIcon.set('class', 'fas fa-circle-notch fa-spin');
2333	} else {
2334		//inset a spinner in the button
2335		new Element('i', { 'class': 'fas fa-circle-notch fa-spin', 'style': 'margin-right:5px;' }).inject(el, 'top');
2336    }
2337	
2338};
2339
2340function removeSpinnerToButton(el, icon) {
2341	var elIcon = el.getFirst('i');
2342
2343	if (!elIcon) {
2344		elIcon = el.getFirst('svg');
2345	}
2346
2347	if (elIcon) {
2348		elIcon.destroy();
2349    }
2350	
2351};
2352
2353/*
2354function rating(el){
2355
2356//ok set the value of the hidden field on the form
2357
2358var stars = el.id.match(/\d+/);
2359$('aRating').value = stars;
2360$('aRatingNew').value = stars;
2361
2362}
2363 */
2364
2365function saveNotes() {
2366
2367	vNotes = $('NNotes').value
2368	vVolID = $('NVolID').value
2369	upEl = $('volNotesText')
2370
2371	var myRequest = new Request({
2372		url: '../shared_functions/ajax/ajax_saveNotes.htm',
2373		method: 'post',
2374		data: {
2375			'eVolID': vVolID,
2376			'Notes': vNotes
2377		},
2378		onComplete: function () {
2379			//lets get rid of that column
2380			$('open_notesform').fade('out')
2381			//update notes if they exist
2382			if (!(typeof (upEl) == 'null')) {
2383				upEl.set('html', vNotes);
2384			};
2385
2386		}
2387
2388	});
2389	myRequest.send();
2390
2391	return false
2392};
2393
2394function sendText() {
2395	//pick up all the form elements
2396	//alert('ajax_sendtext.htm?'+$('textform').toQueryString()+'&tFromYou=0')
2397	var myRequest = new Request({
2398		url: '../shared_functions/ajax/ajax_sendtext.htm',
2399		method: 'post',
2400		data: {
2401			tMessage: $('tMessage').value,
2402			tNumber: $('tNumber').value,
2403			tVolID: $('tVolID').value,
2404			tFromYou: 0
2405		},
2406		onComplete: function (responseText) {
2407			roar.alert(responseText);
2408			//lets get rid of that column
2409			$('open_textmessageform').fade('out');
2410		}
2411
2412	});
2413	//alert('About to send the text request')
2414	myRequest.send();
2415
2416	return false
2417}
2418
2419function sendTextProvider() {
2420	//pick up all the form elements
2421	//alert('ajax_sendtext.htm?'+$('textform').toQueryString()+'&tFromYou=0')
2422	var myRequest = new Request({
2423		url: '/admin/ajax_sendtext.htm',
2424		method: 'post',
2425		data: {
2426			tMessage: $('tMessage').value,
2427			tNumber: $('tNumber').value,
2428			tVolID: $('tVolID').value,
2429			tFromYou: 0
2430		},
2431		onComplete: function (responseText) {
2432			alert(responseText);
2433			//lets get rid of that column
2434			$('open_textmessageform').fade('out');
2435		}
2436
2437	});
2438	//alert('About to send the text request')
2439	myRequest.send();
2440
2441	return false
2442}
2443
2444function sendEmailFromProvider() {
2445	//pick up all the form elements
2446
2447	//url = 'ajax_sendemail_from_provider.htm?'+$('emailform').toQueryString()
2448	//alert(url)
2449	var myRequest = new Request({
2450		//maintain this link as non relative so it
2451		//can pick up the provider/admin or regular version of the ajax file
2452		url: 'ajax_sendemail_from_provider.htm',
2453		method: 'post',
2454		data: {
2455			eMessage: $('eMessage').value,
2456			eSubject: $('eSubject').value,
2457			ePID: $('ePID').value,
2458			eVolID: $('eVolID').value
2459		},
2460
2461		onComplete: function (responseText) {
2462			//lets get rid of that form
2463			$('open_emailform').fade('out');
2464
2465			roar.alert('<p>Email has been sent successfully.</p>');
2466
2467		}
2468
2469	});
2470	myRequest.send();
2471
2472	return false;
2473
2474};
2475
2476function sendEmailToProvider() {
2477	//pick up all the form elements
2478
2479	//alert(url)
2480	var myRequest = new Request({
2481		//maintain this link as non relative so it
2482		//can pick up the provider/admin or regular version of the ajax file
2483		url: 'ajax_sendemail_to_provider.htm',
2484		method: 'post',
2485		data: {
2486			eVEmail: $('eVEmail').value,
2487			eVName: $('eVName').value,
2488			ePMessage: $('ePMessage').value,
2489			ePSubject: $('ePSubject').value,
2490			ePVolID: $('ePVolID').value,
2491			ePID: $('ePID').value,
2492			ePEmail: $('ePEmail').value
2493		},
2494
2495		onComplete: function (responseText) {
2496			//lets get rid of that form
2497			$('open_emailformprov').fade('out');
2498		}
2499
2500	});
2501	myRequest.send();
2502
2503	return false;
2504
2505};
2506
2507function sendEmail() {
2508
2509	eSelect = $('eFile');
2510	var eFiles = '';
2511	var fromAdmin = false;
2512
2513	//HAVE TO SORT OUT THE FILE STRING
2514
2515	if (eSelect) {
2516		for (x = 0; x < eSelect.options.length; x++) {
2517			if (eSelect[x].selected) {
2518				eFiles = eFiles + eSelect[x].value + ",";
2519			}
2520		}
2521	}
2522
2523	//check if we are sending to an entire opportunity
2524	var eSendToAll = 0
2525
2526	eAllOnOpp = $('sendAllOnOpp')
2527	if (eAllOnOpp) {
2528		eSendToAll = eAllOnOpp.value
2529	}
2530
2531	var ePID = 0
2532	eOpp = $('ePID')
2533	if (eOpp) {
2534		ePID = eOpp.value
2535	}
2536
2537	var providerID = 0
2538	var providerEmail = ''
2539	if ($('eProviderID')) {
2540		providerID = $('eProviderID').value;
2541		providerEmail = $('eProviderEmail').value;
2542	}
2543
2544
2545
2546	if (window.location.href.indexOf('/admin/') > 0) {
2547		fromAdmin = true;
2548	}
2549
2550	//pick up all the form elements
2551	var myRequest = new Request({
2552
2553		//maintain this link as non relative so it
2554		//need to tell if it comes from an admin page
2555
2556		url: '../shared_functions/ajax/ajax_sendemail.htm',
2557		method: 'post',
2558		data: {
2559			eMessage: $('eMessage').value,
2560			eSubject: $('eSubject').value,
2561			eVolID: $('eVolID').value,
2562			eFile: eFiles,
2563			PID: ePID,
2564			eProviderID: providerID,
2565			eProviderEmail: providerEmail,
2566			SendAll: eSendToAll,
2567			eTarget: $('eTarget').value,
2568			eSender: $('eSender').value,
2569			'fromAdmin': fromAdmin
2570		},
2571
2572		onComplete: function (returned) {
2573			//lets get rid of the possible forms
2574			if ($('open_emailform')) {
2575				$('open_emailform').fade('out')
2576			};
2577			if ($('open_emailformAll')) {
2578				$('open_emailformAll').fade('out')
2579			};
2580
2581			//SET EMAIL BACK TO SEND TO ALL
2582			if ($('sendAllOnOpp')) {
2583				$('sendAllOnOpp').value = 1
2584			}
2585			//pop up a roar saying we have sent it
2586			roar.alert('<p>Email has been sent successfully.</p>');
2587
2588
2589		}
2590
2591	});
2592	myRequest.send();
2593
2594	return false
2595
2596};
2597
2598function sendEmailToSession(elForm) {
2599
2600	eSelect = $('eFileSession');
2601
2602	if (eSelect) {
2603		var eFiles = '';
2604		//HAVE TO SORT OUT THE FILE STRING
2605
2606		for (x = 0; x < eSelect.options.length; x++) {
2607			if (eSelect[x].selected) {
2608				eFiles = eFiles + eSelect[x].value + ",";
2609			}
2610		}
2611	}
2612
2613	var providerID = 0;
2614	var providerEmail = '';
2615
2616	if ($('eProviderID')) {
2617		providerID = $('eProviderID').value;
2618		providerEmail = $('eProviderEmail').value;
2619	}
2620
2621
2622	//pick up all the form elements
2623	var myRequest = new Request({
2624		//maintain this link as non relative so it
2625		//can pick up the provider/admin or regular version of the ajax file
2626		url: '../shared_functions/ajax/ajax_sendemail.htm',
2627		method: 'post',
2628		data: {
2629			PID: $('PIDSession'),
2630			PSID: $('PSIDSession').value,
2631			eMessage: $('eMessageSession').value,
2632			eSubject: $('eSubjectSession').value,
2633			eFile: eFiles,
2634			eProviderID: providerID,
2635			eProviderEmail: providerEmail
2636		},
2637
2638		onComplete: function (returned) {
2639			//lets get rid of that form
2640			$(elForm).fade('out');
2641		}
2642
2643	});
2644	myRequest.send();
2645
2646	return false
2647
2648};
2649
2650function sendEmailGeneral() {
2651	//pick up all the form elements
2652
2653	var myRequest = new Request({
2654		//maintain this link as non relative so it
2655		//can pick up the provider/admin or regular version of the ajax file
2656		url: 'ajax_sendemail_general.htm',
2657		method: 'post',
2658		data: {
2659			eMessage: $('eMessage').value,
2660			eSubject: $('eSubject').value,
2661			eAddress: $('eAddress').value,
2662			eTarget: $('emailTarget').value
2663		},
2664
2665		onComplete: function (returned) {
2666			//lets get rid of that form
2667			$('open_emailGeneralform').fade('out');
2668		}
2669
2670	});
2671	myRequest.send();
2672
2673	return false
2674
2675};
2676
2677function sendInterview() {
2678
2679	//alert('/admin/ajax_sendinterview.htm'+$('interviewform').toQueryString());
2680
2681	//pick up all the form elements
2682	var myRequest = new Request({
2683		url: '../shared_functions/ajax/ajax_sendinterview.htm',
2684		method: 'post',
2685		onComplete: function (returned) {
2686			//lets get rid of that column
2687			$('open_interviewform').hide();
2688			rowid = $('iVolID').value
2689
2690			//this only works on the induction search page, on the other pages you dont want to remove the row so it isnt called interviewrow
2691			//we dont want to remove it but change it
2692			myRow = $('interviewrow_' + rowid)
2693			myDateRow = $('interviewDateRow_' + rowid)
2694			myTimeRow = $('interviewTimeRow_' + rowid)
2695			if (myRow) {
2696				myDateRow.set('html', $('iDate').value);
2697				myTimeRow.set('html', $('iHour').value + ':' + $('iMinutes').value);
2698				myRow.flash();
2699			}
2700
2701			roar.alert('New booking details have been emailed.');
2702
2703		}
2704
2705	});
2706	myRequest.send($('interviewform').toQueryString());
2707
2708	return false
2709}
2710
2711/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2712// CRB AjaxyUpload uploads a document via an iframe generated above and then saves document details for the volunteer
2713
2714function doCRBAjaxyUpload() {
2715	$('file_upload_form').onsubmit = function () {
2716		$('loadingIcon').set('html', '<img src="../shared_images/icon_loading_white.gif" align="absmiddle" />')
2717		$('file_upload_form').target = 'upload_target'; //'upload_target' is the name of the iframe
2718		$("upload_target").onload = uploadDone; //This function should be called when the iframe has compleated loading
2719		// That will happen when the file is completely upload
2720	}
2721}
2722
2723function uploadDone() {
2724	//retrieve the filename from the iFram - yuerk
2725	var ret = frames['upload_target'].document.getElementsByTagName("body")[0].innerHTML;
2726	var data = eval("(" + ret + ")"); //Parse JSON // Read the below explanations before passing judgment on me
2727
2728	//set the newly uploaded image as the src
2729
2730	sName = data.file_name.toString();
2731	sDescrip = data.file_description.toString();
2732	sExt = data.file_ext.toString();
2733
2734	vHtml = '<img class="floatleft" src="../shared_images/icon_file_' + sExt + '.png"><p class="notformNoClear"><a href="../shared_uploads/id/' + sName + '">' + sDescrip + '</a></p>'
2735
2736	$('loadingIcon').set('html', '');
2737	//inject a new document icon into the form
2738	el = $('currentScans')
2739	var newFile = new Element('div', {
2740		'html': vHtml,
2741		'class': 'floatleft float45 notifyTextGreen'
2742	}).inject(el);
2743	newFile.flash();
2744
2745	//remove the old description
2746	$('fileDescription').value = ''
2747	$('file').value = ''
2748	//flashup the helper text
2749	//move the help to the image area
2750
2751}
2752
2753///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2754
2755
2756//just a little thing for setting the selected value of a menu when you dont know the index
2757function setSelectedIndex(menuO, menuV) {
2758	for (var i = 0; i < menuO.options.length; i++) {
2759		if (menuO.options[i].value == menuV) {
2760			menuO.options[i].selected = true;
2761			return;
2762		}
2763	}
2764}
2765
2766function confirmFormSubmit(message) {
2767	var agree = confirm(message + '\n\nAre you sure you wish to continue and make these changes..?');
2768	if (agree) {
2769		return true
2770	} else {
2771		return false
2772	}
2773}
2774
2775function getParameterByName(name, url) {
2776	if (!url)
2777		url = window.location.href;
2778	name = name.replace(/[\[\]]/g, "\\$&");
2779	var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
2780		results = regex.exec(url);
2781	if (!results)
2782		return null;
2783	if (!results[2])
2784		return '';
2785	return decodeURIComponent(results[2].replace(/\+/g, " "));
2786}
2787
2788function colorscale(hexstr, scalefactor) {
2789	/* declared variables first, in order;
2790	afterwards, undeclared local variables */
2791	var r = scalefactor;
2792	var a,
2793		i;
2794
2795	if (r < 0 || typeof (hexstr) != 'string')
2796		return hexstr;
2797	hexstr = hexstr.replace(/[^0-9a-f]+/ig, '');
2798	if (hexstr.length == 3) {
2799		a = hexstr.split('');
2800	} else if (hexstr.length == 6) {
2801		a = hexstr.match(/(\w{2})/g);
2802	} else
2803		return hexstr;
2804	for (i = 0; i < a.length; i++) {
2805		if (a[i].length == 2)
2806			a[i] = parseInt(a[i], 16);
2807		else {
2808			a[i] = parseInt(a[i], 16);
2809			a[i] = a[i] * 16 + a[i];
2810		}
2811	}
2812
2813	var maxColor = parseInt('ff', 16);
2814
2815	function relsize(a) {
2816		if (a == maxColor)
2817			return Infinity;
2818		return a / (maxColor - a);
2819	}
2820
2821	function relsizeinv(y) {
2822		if (y == Infinity)
2823			return maxColor;
2824		return maxColor * y / (1 + y);
2825	}
2826
2827	for (i = 0; i < a.length; i++) {
2828		a[i] = relsizeinv(relsize(a[i]) * r);
2829		a[i] = Math.floor(a[i]).toString(16);
2830		if (a[i].length == 1)
2831			a[i] = '0' + a[i];
2832	}
2833	return a.join('');
2834}
2835
2836/**
2837 * Roar - Notifications
2838 *
2839 * Inspired by Growl
2840 *
2841 * version        1.0.1
2842 *
2843 * license        MIT-style license
2844 * author        Harald Kirschner <mail [at] digitarald.de>
2845 * copyright    Author
2846 */
2847
2848var Roar = new Class({
2849
2850	Implements: [Options, Events, Chain],
2851
2852	options: {
2853		duration: 4000,
2854		position: 'upperLeft',
2855		container: null,
2856		bodyFx: null,
2857		itemFx: null,
2858		margin: {
2859			x: 10,
2860			y: 10
2861		},
2862		offset: 10,
2863		className: 'roar',
2864		onShow: function () { },
2865		onHide: function () { },
2866		onRender: function () { }
2867	},
2868
2869	initialize: function (options) {
2870		this.setOptions(options);
2871		this.items = [];
2872		this.container = $(this.options.container) || document;
2873	},
2874
2875	alert: function (title, message, options) {
2876		var params = Array.link(arguments, {
2877			title: Type.isString,
2878			message: Type.isString,
2879			options: Type.isObject
2880		});
2881		var items = [new Element('h3', {
2882			'html': [params.title, ''].pick()
2883		})];
2884		if (params.message)
2885			items.push(new Element('p', {
2886				'html': params.message
2887			}));
2888		return this.inject(items, params.options);
2889	},
2890
2891	inject: function (elements, options) {
2892		if (!this.body)
2893			this.render();
2894		options = options || {};
2895
2896		var offset = [-this.options.offset, 0];
2897		var last = this.items.getLast();
2898		if (last) {
2899			offset[0] = last.retrieve('roar:offset');
2900			offset[1] = offset[0] + last.offsetHeight + this.options.offset;
2901		}
2902		var to = {
2903			'opacity': 1
2904		};
2905		to[this.align.y] = offset;
2906
2907		var item = new Element('div', {
2908			'class': this.options.className,
2909			'opacity': 0
2910		}).adopt(
2911			new Element('div', {
2912				'class': 'roar-bg',
2913				'opacity': 0.7
2914			}),
2915			elements);
2916
2917		item.setStyle(this.align.x, 0).store('roar:offset', offset[1]).set('morph', Object.merge({
2918			unit: 'px',
2919			link: 'cancel',
2920			onStart: Chain.prototype.clearChain,
2921			transition: Fx.Transitions.Back.easeOut
2922		}, this.options.itemFx))
2923
2924		// using the delay
2925		var remoaveDelay = this.remove.delay(this.options.duration, this, [item]);
2926		var remove = this.remove.bind(this, [item]);
2927
2928		this.items.push(item.addEvent('click', remove));
2929
2930		if (this.options.duration) {
2931			var over = false;
2932			var trigger = (function () {
2933				trigger = null;
2934				if (!over)
2935					remove();
2936			}).delay(this.options.duration);
2937			item.addEvents({
2938				mouseover: function () {
2939					over = true;
2940				},
2941				mouseout: function () {
2942					over = false;
2943					if (!trigger)
2944						remove();
2945				}
2946			});
2947		}
2948		item.inject(this.body).morph(to);
2949		return this.fireEvent('onShow', [item, this.items.length]);
2950	},
2951
2952	remove: function (item) {
2953		var index = this.items.indexOf(item);
2954		if (index == -1)
2955			return this;
2956		this.items.splice(index, 1);
2957		item.removeEvents();
2958		var to = {
2959			opacity: 0
2960		};
2961		to[this.align.y] = item.getStyle(this.align.y).toInt() - item.offsetHeight - this.options.offset;
2962		item.morph(to).get('morph').chain(item.destroy.bind(item));
2963		return this.fireEvent('onHide', [item, this.items.length]).callChain(item);
2964	},
2965
2966	empty: function () {
2967		while (this.items.length)
2968			this.remove(this.items[0]);
2969		return this;
2970	},
2971
2972	render: function () {
2973		this.position = this.options.position;
2974		if (typeOf(this.position) == 'string') {
2975			var position = {
2976				x: 'center',
2977				y: 'center'
2978			};
2979			this.align = {
2980				x: 'left',
2981				y: 'top'
2982			};
2983			if ((/left|west/i).test(this.position))
2984				position.x = 'left';
2985			else if ((/right|east/i).test(this.position))
2986				this.align.x = position.x = 'right';
2987			if ((/upper|top|north/i).test(this.position))
2988				position.y = 'top';
2989			else if ((/bottom|lower|south/i).test(this.position))
2990				this.align.y = position.y = 'bottom';
2991			this.position = position;
2992		}
2993		this.body = new Element('div', {
2994			'class': 'roar-body'
2995		}).inject(document.body);
2996		if (Browser.ie6)
2997			this.body.addClass('roar-body-ugly');
2998		this.moveTo = this.body.setStyles.bind(this.body);
2999		this.reposition();
3000		if (this.options.bodyFx) {
3001			var morph = new Fx.Morph(this.body, Object.merge({
3002				unit: 'px',
3003				chain: 'cancel',
3004				transition: Fx.Transitions.Circ.easeOut
3005			}, this.options.bodyFx));
3006			this.moveTo = morph.start.bind(morph);
3007		}
3008		var repos = this.reposition.bind(this);
3009		window.addEvents({
3010			scroll: repos,
3011			resize: repos
3012		});
3013		this.fireEvent('onRender', this.body);
3014	},
3015
3016	reposition: function () {
3017		var max = document.getCoordinates(),
3018			scroll = document.getScroll(),
3019			margin = this.options.margin;
3020		max.left += scroll.x;
3021		max.right += scroll.x;
3022		max.top += scroll.y;
3023		max.bottom += scroll.y;
3024		var rel = (typeOf(this.container) == 'element') ? this.container.getCoordinates() : max;
3025		this.moveTo({
3026			left: (this.position.x == 'right')
3027				? (Math.min(rel.right, max.right) - margin.x)
3028				: (Math.max(rel.left, max.left) + margin.x),
3029			top: (this.position.y == 'bottom')
3030				? (Math.min(rel.bottom, max.bottom) - margin.y)
3031				: (Math.max(rel.top, max.top) + margin.y)
3032		});
3033	}
3034
3035});
3036
3037//implement a standard ROAR notification
3038var roar = new Roar({
3039	position: 'upperleft',
3040	duration: 4000 // 4 seconds until message fades out,
3041});
3042
3043//implement a SHORT ROAR notification
3044var roarShort = new Roar({
3045	position: 'upperleft',
3046	duration: 1000 // 4 seconds until message fades out,
3047});
3048
3049
3050function alertoverlay(additionalheight, spinner) {
3051
3052	//create a div
3053	//make it the same size as the browser height (not window height)
3054	//transaprent background
3055	//fade it in
3056	//make sure it has a low z-index
3057
3058	if (spinner) {
3059
3060		mynew = new Element('div', {
3061			'styles': {
3062				'display': 'block',
3063				'border': '1px solid black',
3064				'height': window.getScrollHeight(),
3065				'width': '100%',
3066				'background': 'url(/images/background_trans_repeat.png) repeat',
3067				'position': 'absolute',
3068				'top': '0',
3069				'left': '0',
3070				'z-index': '100'
3071			}
3072		});
3073
3074	};
3075
3076	mynew = new Element('div', {
3077		'styles': {
3078			'display': 'block',
3079			'border': '1px solid black',
3080			'height': window.getScrollHeight(),
3081			'width': '100%',
3082			'background': 'url(/images/background_trans_repeat.png) repeat',
3083			'position': 'absolute',
3084			'top': '0',
3085			'left': '0',
3086			'z-index': '100'
3087		},
3088		'events': {
3089			'click': function () {
3090				this.dispose();
3091				//remove the popup as well
3092				//need to do a search for any with open_ in their name
3093				//$$('[^=open_]').fadeHide();
3094				Array.each($$('.popup'), function (el) {
3095					//alert(el);
3096					el.fade('out')
3097				});
3098
3099			},
3100			'mousedown': function () {
3101				//aaa
3102			}
3103		},
3104		'id': 'overlay_'
3105
3106	});
3107
3108	if (spinner) {
3109
3110		mySpinner = new Element('img', {
3111			'styles': {
3112				'position': 'absolute',
3113				'top': '0',
3114				'left': '0',
3115				'z-index': '100'
3116			},
3117			'src': '/shared_images/icon_loading_large.gif'
3118		});
3119
3120		mySpinner.injectInside($('overlay_'))
3121
3122	};
3123
3124	mynew.injectInside(document.body)
3125
3126};
3127
3128var SL_Hilight = new Class({
3129
3130	//implements
3131	Implements: [Options],
3132	origStyles: null, //for storing inactive field's styles (color, background color, and border color)
3133
3134	//options
3135	options: {
3136		transitionTime: 750, //transition time (1 second = 1000) for animation
3137		inputs: null, //form inputs you want to highlight on focus;  usually something like $$('input[type=text]', 'textarea')
3138		activeClass: null, //focused input's CSS class we'lll morph to (defined in CSS doc)
3139		initialFocus: false //flag for whether to focus on first input or not
3140	},
3141
3142	//initialization
3143	initialize: function (options) {
3144
3145		//set options
3146		this.setOptions(options);
3147		$$('#my_list > li').each(function (item, index) {
3148			item.addEvent('click', fn.bind(item));
3149		});
3150		this.options.inputs.each(function (el, i) {
3151			//FYI,  el = the element, i = the index
3152
3153			//get styles so we can revert to them on blur
3154			//'border-color' returns 4 colors, so we need to grab each (don't know 
3154why, but morph won't work)
3155			this.origStyles = el.getStyles('color', 'background-color', 'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color');
3156
3157			//setup animation styling
3158			el.set('morph', {
3159				duration: this.options.transitionTime,
3160				transition: 'cubic:out'
3161			});
3162
3163			el.addEvents({
3164				'focus': function (el) {
3165					//morph to a class doesnt seem to work with external domain hostined CSS files ???
3166					//el.morph("."+this.options.activeClass);
3167					el.morph({
3168						'background-color': '#eeffee',
3169						'border-color': '#0f0'
3170					})
3171				}
3172					.bind(this),
3173				'blur': function () {
3174					el.morph(this.origStyles);
3175				}
3176					.bind(this)
3177			});
3178
3179		}, this);
3180
3181		//focus on initial input field if set to true in options
3182		if (this.options.initialFocus != false) {
3183			this.options.inputs[0].focus();
3184		}
3185
3186	}
3187
3188});
3189
3190//===================== GOOGLE GRAPH FUNCTIONS ====================
3191
3192function createGraph(chartIndex, chartTitle, chartWidth, chartHeight, el, attachEv, chartType, ajaxLocation, startDate, endDate, id) {
3193
3194	//objColours = ["#405485","#A62B2B","#A62B5F","#68339C","#A62B93", "#2B716B", "#93528c", "#2BA631"]
3195	//objColours = ["#405485", "#93528c", "#2BA631","#A62B2B","#A62B5F","#68339C","#A62B93", "#2B716B"]
3196	objColours = ["#405485", "#A62B2B", "#93528C", "#2BA631", "#EC166A", "#D40690", "#B401B5", "#8F06D5", "#80F31F", "#A5DE0B", "#C7C101", "#E39E03", "#F6780F", "#FE5326", "#FB3244", "#ED1868", "#D5078E", "#B601B3", "#9106D3", "#6B16EC", "#472FFA", "#2850FE", "#1175F7", "#039BE5", "#01BECA", "#0ADCA8", "#1DF283", "#3AFD5D", "#5CFD3A", "#82F21E", "#A7DD0A", "#C9BF01", "#E49C03", "#F77610", "#FE5127", "#FB3046", "#EC166A", "#D40690", "#B401B5", "#8F06D5"]
3197
3198	if (!chartType) {
3199		chartType = 'Pie'
3200	};
3201	if (!ajaxLocation) {
3202		ajaxLocation = 'chart_KPI.htm'
3203	};
3204
3205	var elWidth = el.offsetWidth;
3206
3207	var myRequest = new Request({
3208		url: ajaxLocation,
3209		method: 'post',
3210		data: {
3211			'type': chartIndex,
3212			'startDate': startDate,
3213			'endDate': endDate,
3214			'id': id
3215		},
3216		onComplete: function (graphData) {
3217
3218			//var myJSON = '[{v:12, d:"65"},{v:10, d:"white"},{v:10, d:"black"}]'
3219			if (graphData.length > 2) {
3220
3221				var myJSON = graphData
3222				var object = JSON.decode(myJSON);
3223				//if(Object.getLength(object) > 0){
3224				drawVisualization(object, chartType);
3225				//}
3226
3227			} else {
3228				el.set('html', '<h3 align="center" class="red" style="height:' + (chartHeight - 100) + 'px; line-height:' + (chartHeight - 100) + 'px;">No Data To Display</h3>');
3229			}
3230
3231		}
3232
3233	});
3234
3235	myRequest.send();
3236
3237	function drawVisualization(serverData, chartType) {
3238
3239		var chartData = [];
3240
3241		if (chartType == 'Pie') {
3242
3243			var options = {
3244				chartArea: {
3245					top: 10,
3246					left: 100,
3247					right: 50,
3248					width: elWidth,
3249					height: '85%'
3250				},
3251				animation: {
3252					"startup": true,
3253					duration: 1000,
3254					easing: 'out',
3255				},
3256				pieSliceText: 'value',
3257				pieHole: 0.4,
3258				tooltip: {
3259					trigger: 'selection'
3260				}
3261			};
3262
3263			for (var i = 0; i < serverData.length; i++) {
3264				chartData.push([serverData[i].d, serverData[i].v]);
3265			}
3266
3267			var data = new google.visualization.DataTable();
3268			data.addColumn('string', 'WIP');
3269			data.addColumn('number', 'Percentage');
3270			data.addRows(chartData);
3271
3272			var newGraph = new google.visualization.PieChart(el);
3273
3274			google.visualization.events.addListener(newGraph, 'onmouseover', function (entry) {
3275				newGraph.setSelection([{
3276					row: entry.row
3277				}
3278				]);
3279			});
3280
3281			google.visualization.events.addListener(newGraph, 'onmouseout', function (entry) {
3282				newGraph.setSelection([]);
3283			});
3284
3285			newGraph.draw(data, options);
3286
3287		} else if (chartType == 'Area') {
3288
3289			for (var i = 0; i < serverData.length; i++) {
3290				chartData.push([serverData[i].d, serverData[i].v]);
3291			}
3292
3293			var data = new google.visualization.DataTable();
3294			data.addColumn('string', chartTitle);
3295			data.addColumn('number', chartTitle);
3296			data.addRows(chartData);
3297
3298			var newGraph = new google.visualization.AreaChart(el);
3299
3300			var options = {
3301				titleTextStyle: {
3302					color: "#606060",
3303					fontName: "Verdana"
3304				},
3305				pointSize: 3,
3306				hAxis: {
3307					slantedText: true,
3308					slantedTextAngle: 45
3309				},
3310				legend: {
3311					alignment: 'end'
3312				},
3313				title: chartTitle,
3314				colors: objColours,
3315				explorer: {
3316					actions: ['dragToZoom', 'rightClickToReset'],
3317					axis: 'horizontal',
3318					keepInBounds: true,
3319					maxZoomIn: 4.0
3320				}
3321
3322			}
3323
3324			newGraph.draw(data, options);
3325
3326		} else if (chartType == 'AreaMultiple') {
3327
3328			var data = google.visualization.arrayToDataTable(serverData);
3329
3330			// Create and draw the visualization.
3331			var newGraph = new google.visualization.AreaChart(el)
3332			newGraph.draw(data, {
3333				isStacked: true,
3334				titleTextStyle: {
3335					color: "#606060",
3336					fontName: "Verdana"
3337				},
3338				pointSize: 3,
3339				hAxis: {
3340					slantedText: true,
3341					slantedTextAngle: 90
3342				},
3343				title: chartTitle,
3344				width: chartWidth,
3345				height: chartHeight,
3346				colors: objColours
3347			});
3348
3349		} else if (chartType == 'Column') {
3350
3351			for (var i = 0; i < serverData.length; i++) {
3352				chartData.push([serverData[i].d, serverData[i].v]);
3353			}
3354
3355			var data = new google.visualization.DataTable();
3356			data.addColumn('string', chartTitle);
3357			data.addColumn('number', chartTitle);
3358			data.addRows(chartData);
3359
3360			var newGraph = new google.visualization.ColumnChart(el);
3361
3362			var options = {
3363				titleTextStyle: {
3364					color: "#606060",
3365					fontName: "Verdana"
3366				},
3367				hAxis: {
3368					slantedText: true,
3369					slantedTextAngle: 45
3370				},
3371				legend: {
3372					position: 'none'
3373				},
3374				title: chartTitle,
3375				width: chartWidth,
3376				height: chartHeight,
3377				colors: objColours,
3378				explorer: {
3379					actions: ['dragToZoom', 'rightClickToReset'],
3380					axis: 'horizontal',
3381					keepInBounds: true,
3382					maxZoomIn: 4.0
3383				}
3384			}
3385
3386			newGraph.draw(data, options);
3387
3388		} else if (chartType == 'Line') {
3389
3390			var options = {
3391				chartArea: {
3392					top: 10,
3393					left: 100,
3394					right: 50,
3395					width: elWidth,
3396					height: '85%'
3397				},
3398				legend: {
3399					position: 'in',
3400					alignment: 'center'
3401				},
3402				dataOpacity: 0.3,
3403				animation: {
3404					"startup": true,
3405					duration: 1000,
3406					easing: 'out',
3407				},
3408				pointSize: 8,
3409				dataOpacity: 0.3,
3410				curveType: 'function',
3411				vAxis: {
3412					viewWindow: {
3413						min: 0
3414					}
3415				},
3416
3417				explorer: {
3418					actions: ['dragToZoom', 'rightClickToReset'],
3419					axis: 'horizontal',
3420					keepInBounds: true,
3421					maxZoomIn: 100.0
3422				}
3423			};
3424
3425			var data = google.visualization.arrayToDataTable(serverData);
3426
3427			var newGraph = new google.visualization.LineChart(el);
3428
3429			var options = {
3430				titleTextStyle: {
3431					color: "#606060",
3432					fontName: "Verdana"
3433				},
3434				pointSize: 3,
3435				hAxis: {
3436					slantedText: true,
3437					slantedTextAngle: 45
3438				},
3439				legend: {
3440					position: 'in',
3441					alignment: 'end'
3442				},
3443				title: chartTitle,
3444				colors: objColours
3445			}
3446
3447			newGraph.draw(data, options);
3448
3449		} else if (chartType == 'Bar') {
3450
3451			var data = new google.visualization.DataTable();
3452			//adds what the colums will mean, its a string and its years
3453			data.addColumn('string', 'KPIs');
3454
3455			//adds the number of columns and their titles
3456			//tells it that they are going to be numbers
3457
3458			for (var i = 0; i < serverData.length; ++i) {
3459				data.addColumn('number', serverData[i].d);
3460				data.addColumn({
3461					type: 'string',
3462					role: 'tooltip'
3463				})
3464			}
3465
3466			//we only have one row ie each KPI for the current dataset
3467			data.addRows(1);
3468
3469			//adds the title for each year
3470			data.setValue(0, 0, 'KPIs');
3471			var j = 0
3472			for (var i = 0; i < serverData.length; ++i) {
3473				data.setValue(0, j + 1, serverData[i].v);
3474				data.setValue(0, j + 2, serverData[i].d + ' ' + serverData[i].v);
3475				j = j + 2
3476			}
3477
3478			var newGraph = new google.visualization.BarChart(el);
3479			newGraph.draw(data, {
3480				titleTextStyle: {
3481					color: "#606060",
3482					fontName: "Verdana"
3483				},
3484				hAxis: {
3485					slantedText: true,
3486					slantedTextAngle: 90,
3487					viewWindowMode: 'maximized'
3488				},
3489				legend: {
3490					position: 'right'
3491				},
3492				title: chartTitle,
3493				chartArea: {
3494					left: 0,
3495					top: 20
3496				},
3497				width: chartWidth,
3498				height: chartHeight,
3499				colors: objColours
3500			});
3501
3502		};
3503
3504		// Every time the table fires the "select" event, it should call your
3505		// selectHandler() function.
3506		if (attachEv) {
3507			google.visualization.events.addListener(newGraph, 'select', selectHandler);
3508		}
3509
3510		function selectHandler() {
3511
3512			//cal the function they send with parameters ??
3513
3514			var selection = newGraph.getSelection();
3515			var message = 'hello';
3516			for (var i = 0; i < selection.length; i++) {
3517				var item = selection[i];
3518
3519				if (item.row != null && item.column != null) {
3520					var str = data.getFormattedValue(item.row, item.column);
3521					message += '{row:' + item.row + ',column:' + item.column + '} = ' + str + '\n';
3522				} else if (item.row != null) {
3523					var str = data.getFormattedValue(item.row, 0);
3524					message += '{row:' + item.row + ', column:none}; value (col 0) = ' + str + '\n';
3525				} else if (item.column != null) {
3526					var str = data.getFormattedValue(0, item.column);
3527					message += '{row:none, column:' + item.column + '}; value (row 0) = ' + str + '\n';
3528				}
3529			}
3530			if (message == '') {
3531				message = 'nothing';
3532			}
3533			alert('You selected ' + message);
3534		}
3535
3536	}
3537
3538};
3539
3540/* ACCESSIBLE TOOLTIPS SCRIPT*/
3541
3542// NEED TO ADD ALIGN RIGHT TO LEFT OF TARGET IN CASE OF CLSOE TO EDGE OF SCREEN
3543
3544(function () {
3545	// Get all the toggletip buttons
3546	var toggletipTexts = document.querySelectorAll('span.toolTip');
3547
3548	// Iterate over them
3549	Array.prototype.forEach.call(toggletipTexts, function (toggletipText) {
3550		// Create the container element
3551		var container = document.createElement('span');
3552		container.setAttribute('class', 'toggletip-container');
3553
3554		// Put it before the original element in the DOM
3555		toggletipText.parentNode.insertBefore(container, toggletipText);
3556
3557		// Create the button element
3558		var toggletip = document.createElement('button');
3559		toggletip.setAttribute('type', 'button');
3560		toggletip.setAttribute('class', 'tipTrigger');
3561		toggletip.setAttribute('aria-label', 'more info');
3562		toggletip.setAttribute('data-toggletip-content', toggletipText.innerHTML);
3563		toggletip.textContent = '?';
3564
3565		// Place the button element in the container
3566		container.appendChild(toggletip);
3567
3568		// Create the live region
3569		var liveRegion = document.createElement('span');
3570		liveRegion.setAttribute('role', 'status');
3571		liveRegion.innerHTML = '&nbsp;';
3572
3573		// Place the live region in the container
3574		container.appendChild(liveRegion);
3575
3576		// Remove the original element
3577		toggletipText.parentNode.removeChild(toggletipText);
3578
3579		// Build `data-tooltip-content`
3580		var message = toggletip.getAttribute('data-toggletip-content');
3581
3582		toggletip.setAttribute('data-toggletip-content', message);
3583		toggletip.removeAttribute('title');
3584
3585		// Get the message from the data-content element
3586		var message = toggletip.getAttribute('data-toggletip-content');
3587
3588		// Get the live region element
3589		var liveRegion = toggletip.nextElementSibling;
3590
3591		//shift tooltip if its close to the window edge
3592		let isMobile = Math.min(window.screen.width, window.screen.height) < 768 || navigator.userAgent.indexOf("Mobi") > -1;
3593
3594		let myClass = 'alert alert-message-light toggletip-bubble toggletip-bubble-left';
3595		let bubbleStyle = '';
3596
3597		// Toggle the message
3598		toggletip.addEventListener('click', function (event) {
3599
3600			//event.stopPropagation();
3601
3602			//check where the windows are when we click it
3603			var posLeft = window.scrollX + toggletip.getBoundingClientRect().left
3604
3605			if (isMobile) {
3606				myClass = 'alert alert-message-light toggletip-bubble';
3607				bubbleStyle = 'left:-' + posLeft + 'px;';
3608            }
3609			else if (window.innerWidth - posLeft < 540) {
3610				myClass = 'alert alert-message-light toggletip-bubble toggletip-bubble-right';
3611			} else {
3612				myClass = 'alert alert-message-light toggletip-bubble toggletip-bubble-left';
3613			}
3614
3615			liveRegion.innerHTML = '';
3616			window.setTimeout(function () {
3617				liveRegion.innerHTML = '<span style="' + bubbleStyle +'" class="' + myClass + '">' + message + '</span>';
3618			}, 100);
3619		});
3620
3621		// Close on outside click
3622		document.addEventListener('click', function (e) {
3623			if (toggletip !== e.target) {
3624				liveRegion.innerHTML = '';
3625			}
3626		});
3627
3628		// Remove toggletip on ESC
3629		toggletip.addEventListener('keydown', function (e) {
3630			if ((e.keyCode || e.which) === 27)
3631				liveRegion.innerHTML = '';
3632		});
3633
3634		// Remove on blur
3635		toggletip.addEventListener('blur', function (e) {
3636			liveRegion.innerHTML = '';
3637		});
3638
3639	});
3640
3641}
3642	());
3643
3644
3645
3646
3647/*
3648	
3649<div class="tip-wrap" style="position: absolute; top: 281px; left: 452px; display: none;"><div class="tip-top"></div><div class="tip"><div class="tip-title">You have gained the rank Hall Of Famer</div><div class="tip-text">This is your achievement badge. Keep logging hours to achieve the top level badge and the honour of the rank Hall Of Famer!</div></div><div class="tip-bottom"></div></div>
3650*/
3651
3652
3653(function () {
3654	// Get all the toggletip buttons
3655
3656	var tipCount = 0
3657	var toggletipTexts = document.querySelectorAll('.Tips1');
3658
3659	// Iterate over them
3660	Array.prototype.forEach.call(toggletipTexts, function (toggletipText) {
3661
3662		tipCount++;
3663
3664		// Create the container element
3665
3666		var container = document.createElement('div');
3667		container.setAttribute('class', 'tip-wrap');
3668		toggletipText.setAttribute('aria-describedby', 'tipText-' + tipCount);
3669
3670		// Put it before the original element in the DOM
3671		toggletipText.parentNode.insertBefore(container, toggletipText);
3672
3673
3674		//need to add these aria things to the thing you roll over
3675		//toggletipText.setAttribute('type', 'button');
3676		toggletipText.setAttribute('aria-label', 'more info');
3677
3678
3679		// Place the button element in the container
3680		//container.appendChild(toggletip);
3681
3682		// Create the live region
3683		var liveRegion = document.createElement('span');
3684		liveRegion.setAttribute('id', 'tipText-' + tipCount);
3685		liveRegion.setAttribute('role', 'status');
3686
3687		// Place the live region in the container
3688		container.appendChild(liveRegion);
3689
3690
3691		// Build `data-tooltip-content`
3692		var message = toggletipText.getAttribute('rel');
3693
3694
3695
3696		//shift tooltip if its close to the window edge
3697		var myClass = 'toggletip-bubble toggletip-bubble-left';
3698
3699		// Toggle the message
3700		toggletipText.addEventListener('mouseover', function (event) {
3701
3702			//event.stopPropagation();
3703
3704			//check where the windows are when we click it
3705			var posLeft = window.scrollX + toggletipText.getBoundingClientRect().left + toggletipText.getBoundingClientRect().width
3706			var posTop = window.scrollY + toggletipText.getBoundingClientRect().top
3707
3708			var posMouseX = window.scrollX + event.clientX + 10
3709			var posMouseY = window.scrollY + event.clientY + 10
3710
3711
3712			if (window.innerWidth - posLeft < 540) {
3713				posLeft = posLeft - 540 - toggletipText.getBoundingClientRect().width;
3714			}
3715
3716			if (window.innerWidth - posMouseX < 500) {
3717				posMouseX = posMouseX - 510;
3718			}
3719
3720			liveRegion.innerHTML = '';
3721
3722			window.setTimeout(function () {
3723				liveRegion.innerHTML = '<span class="' + myClass + '">' + message + '</span>';
3724			}, 100);
3725
3726			//by object
3727			//container.setStyles({'left' : posLeft, 'top' : posTop, 'display' : 'block'});
3728
3729			//by mouse
3730			container.setStyles({ 'left': posMouseX, 'top': posMouseY, 'display': 'block' });
3731
3732		});
3733
3734
3735
3736		toggletipText.addEventListener('mouseout', function (event) {
3737
3738			//event.stopPropagation();
3739			container.setStyles({ 'left': -500, 'display': 'none' });
3740		});
3741
3742
3743	});
3744
3745}
3746	());
3747
3748
3749
3750// MAKE SURE ALL THE SECOND LEVEL MENUS ARE ACCESSIBLE VIA THE KEYBAORD
3751//ALSO ADD A DELAY ON THE MENU DISAPPEARING TO AID MOUSE CONTROL
3752
3753var menuItems = document.querySelectorAll('nav li.js-HasSubMenu');
3754var timer1;
3755
3756Array.prototype.forEach.call(menuItems, function (el, i) {
3757
3758	//this reveals the drop down but then slows down its hide
3759	//no good cos it doesnt work if you have multiple menus open
3760
3761
3762	/*
3763	el.addEventListener("mouseover", function(event){
3764	this.className = "js-HasSubMenu openMenu";
3765	clearTimeout(timer1);
3766	});
3767
3768	el.addEventListener("mouseout", function(event){
3769	timer1 = setTimeout(function(event){
3770	document.querySelector("nav li.js-HasSubMenu.openMenu").className = "js-HasSubMenu";
3771	}, 300);
3772	});
3773	 */
3774
3775	//this enables a click event on the header items to reveal the sub menu
3776
3777	el.querySelector('a').addEventListener("click", function (event) {
3778		if (this.parentNode.className == "js-HasSubMenu") {
3779			this.parentNode.className = "js-HasSubMenu openMenu";
3780			this.setAttribute('aria-expanded', "true");
3781		} else {
3782			this.parentNode.className = "js-HasSubMenu";
3783			this.setAttribute('aria-expanded', "false");
3784		}
3785		event.preventDefault();
3786		return false;
3787	});
3788
3789});
3790
3791
3792
3793
3794//universal search self invoking function
3795
3796(function () {
3797
3798
3799	//lets check for notifications
3800	if ($('adminUniversalSearchInput')) {
3801
3802
3803		var typingTimer; //timer identifier
3804		var doneTypingInterval = 250; //time in ms, 5 second for example
3805		var counter = 1;
3806		var listPosition = 0;
3807		var listResultLength = 0;
3808		var current;
3809		var currentDetails = '';
3810		var resultCounter = 0;
3811		var volCount = 0, proCount = 0, oppCount = 0;
3812		var searchInput = document.getElementById('adminUniversalSearchInput');
3813
3814
3815
3816
3817		/*Event handlers on the search input. One to perform the search and the other to deal with the keyboard interaction*/
3818
3819		searchInput.addEvent('input', function (event) {
3820
3821			clearTimeout(typingTimer);
3822
3823			searchStr = searchInput.value;
3824
3825			typingTimer = setTimeout(function () {
3826
3827
3828				searchInput.removeAttribute('aria-activedescendant');
3829
3830				/*If statement to start the search only after 2 characters have been enter. This  number can be higher or lower depending on your preference*/
3831				if (searchStr.length >= 2) {
3832
3833					//lets do the search here
3834					fetchUniversalSearchResults(event)
3835
3836				} else {
3837
3838					//empty out that search results 
3839					$('adminUniversalSearch').hide();
3840
3841				}
3842			}, doneTypingInterval);
3843		});
3844
3845		searchInput.addEvent('keydown', function (event) {
3846			doKeypress(event);
3847		});
3848
3849
3850
3851
3852
3853
3854
3855		var universalSearchRequest = new Request.JSON({
3856
3857			url: '../shared_functions/ajax/ajax_universal_search.htm',
3858			method: 'get',
3859			onComplete: function (results) {
3860
3861				//clear old results
3862				$('adminUniversalSearchResults').set('html', ''); //clear old results
3863
3864				var noResult = true;
3865
3866
3867				if (results.volunteers) {
3868
3869					new Element('p', {
3870						'class': 'universalSearchResultTitle',
3871						html: '<i class="fa fa-users" style="padding:0; margin-right: 10px; color:#555;"></i> Volunteers'
3872					}).inject($('adminUniversalSearchResults'));
3873
3874					results.volunteers.each(function (vol) {
3875
3876						vClass = 'universalSearchResult'
3877						if (vol.Cleared == 2) {
3878							vClass = 'universalSearchResult universalSearchResultBad';
3879							vScreenReaderText = " not cleared"
3880						} else if (vol.Cleared == 1) {
3881							vClass = 'universalSearchResult universalSearchResultGood';
3882							vScreenReaderText = " cleared"
3883						} else if (vol.Cleared == 0) {
3884							vClass = 'universalSearchResult universalSearchResultUnknown';
3885							vScreenReaderText = " not cleared"
3886						}
3887
3888						var elcontent = vol.name
3889
3890
3891						linkhref = 'volunteer_details.htm?id=' + vol.VolID
3892
3893
3894						if (window.location.href.indexOf('adminCentral') != -1) {
3895							linkhref = '../admin/volunteer_details.htm?id=' + vol.VolID
3896						}
3897
3898
3899						new Element('a', {
3900							rel: vol.name,
3901							href: '#',
3902							'class': vClass,
3903							href: linkhref,
3904							'tab-index': '-1',
3905							'data-listNumber': resultCounter,
3906							'data-details': elcontent + vScreenReaderText,
3907							html: '<img style="display:inline-block; margin-right: 10px; width:20px; height:20px; border-radius:20px; border:1px solid #d0d0d0;" src="https://s3.eu-west-2.amazonaws.com/teamkinetic-images/profile-pic/' + vol.AssetID + '-thumb.jpg" />' + elcontent + '<span class="screenreader-only">' + vScreenReaderText + '</span>'
3908						}).inject($('adminUniversalSearchResults'));
3909
3910						resultCounter++;
3911
3912					});
3913
3914					noResult = false;
3915					volCount = resultCounter;
3916
3917
3918
3919
3920				}
3921
3922				if (results.opps) {
3923
3924					//add the opp line
3925					new Element('p', {
3926						'class': 'universalSearchResultTitle',
3927						html: '<i class="fa fa-certificate" style="padding:0; margin-right: 10px; color:#555;"></i> Opportunities'
3928					}).inject($('adminUniversalSearchResults'));
3929
3930					results.opps.each(function (opp) {
3931
3932						vClass = 'universalSearchResult'
3933						if (opp.Closed == 1) {
3934							vClass = 'universalSearchResult universalSearchResultBad';
3935							vScreenReaderText = " closed"
3936						} else {
3937							vClass = 'universalSearchResult universalSearchResultGood';
3938							vScreenReaderText = " open"
3939						}
3940
3941						linkhref = 'placements_info.htm?pid=' + opp.PID
3942
3943						if (window.location.href.indexOf('adminCentral')) {
3944							linkhref = '../admin/placements_info.htm?pid=' + opp.PID
3945						}
3946
3947						new Element('a', {
3948							href: '#',
3949							'class': vClass,
3950							href: linkhref,
3951							'tab-index': '-1',
3952							'data-listNumber': resultCounter,
3953							'data-details': opp.Name + vScreenReaderText,
3954							html: '<i class="fa fa-certificate" style="padding:0; margin-right: 10px; color:#555;"></i> ' + opp.Name + '<span class="screenreader-only">' + vScreenReaderText + '</span>'
3955						}).inject($('adminUniversalSearchResults'));
3956
3957						resultCounter++;
3958
3959					});
3960
3961					noResult = false;
3962					proCount = resultCounter - volCount;
3963
3964
3965				}
3966
3967				if (results.providers) {
3968
3969					new Element('p', {
3970						'class': 'universalSearchResultTitle',
3971						html: '<i class="fa fa-user-plus" style="padding:0; margin-right: 10px; color:#555;"></i> Providers'
3972					}).inject($('adminUniversalSearchResults'));
3973
3974					results.providers.each(function (provider) {
3975
3976						vClass = 'universalSearchResult'
3977						if (provider.Approved == 'False') {
3978							vClass = 'universalSearchResult universalSearchResultBad';
3979							vScreenReaderText = " not cleared"
3980						}
3981						if (provider.Approved == 'True' && provider.Removed == 'False') {
3982							vClass = 'universalSearchResult universalSearchResultGood';
3983							vScreenReaderText = " cleared"
3984						}
3985
3986						linkhref = 'placements_editprovider.htm?prid=' + provider.ProID
3987
3988						if (window.location.href.indexOf('adminCentral')) {
3989							linkhref = '../admin/placements_editprovider.htm?prid=' + provider.ProID
3990						}
3991
3992						new Element('a', {
3993							href: '#',
3994							'class': vClass,
3995							href: linkhref,
3996							'tab-index': '-1',
3997							'data-listNumber': resultCounter,
3998							'data-details': provider.Name + vScreenReaderText,
3999							html: '<i class="fa fa-user-plus" style="padding:0; margin-right: 10px; color:#555;"></i> ' + provider.Name + '<span class="screenreader-only">' + vScreenReaderText + '</span>'
4000						}).inject($('adminUniversalSearchResults'));
4001
4002						resultCounter++;
4003
4004					});
4005
4006					noResult = false;
4007					oppCount = resultCounter - volCount - proCount;
4008
4009
4010
4011				}
4012
4013				if (noResult) {
4014
4015					$('adminUniversalSearchResults').set('html', '<p>No results</p>');
4016
4017				} else {
4018
4019					//announce the volunteer results
4020					$('announce').innerHTML = 'We have found ' + volCount + ' volunteers, ' + proCount + ' providers, and ' + oppCount + ' opportunities. ' + resultCounter + ' total results found, use up and down to cycle through the results, return to follow the link and esc to close the results window.';
4021
4022
4023				}
4024
4025			}
4026
4027		})
4028
4029
4030		function fetchUniversalSearchResults(e) {
4031
4032			//cancel any existing request
4033			universalSearchRequest.cancel
4034
4035			//reset the result counts
4036			resultCounter = 0, volCount = 0, proCount = 0, oppCount = 0;
4037
4038
4039			var search = searchInput.value;
4040			var providerLimit = searchInput.getAttribute('data-provider');
4041
4042
4043			//fire off the new one
4044			universalSearchRequest.send('search=' + search + '&providerLimit=' + providerLimit);
4045
4046
4047
4048			$('adminUniversalSearchResults').set('html', '<p align="center" class="universalSearchResultTitle"><i class="fa fa-spin fa-circle-o-notch"></i></p>')
4049
4050			//make it appear..?
4051			el = $('adminUniversalSearch');
4052			elCoords = el.getCoordinates();
4053
4054			el.position({
4055				offset: {
4056					x: 2,
4057					y: 14
4058				},
4059				relativeTo: searchInput,
4060				position: 'bottomRight',
4061				edge: 'topRight'
4062			});
4063			el.show();
4064
4065
4066		};
4067
4068
4069
4070
4071		//Function to deal with the keyborad interactions for the auto-suggest and highlight the currently selected option
4072		function doKeypress(event) {
4073
4074			var currentylHighlighted = false;
4075			currentylHighlighted = document.querySelector('div#adminUniversalSearchResults a.universalSearchResultSelected');
4076
4077
4078			switch (event.key) {
4079
4080				case 'esc':
4081					searchInput.removeAttribute('aria-activedescendant');
4082					//$('hint').val('');
4083					$('adminUniversalSearch').hide();
4084					$('announce').empty();
4085					//remove all the highlights
4086
4087					if (currentylHighlighted) {
4088						currentylHighlighted.removeClass('universalSearchResultSelected');
4089						currentylHighlighted = false;
4090						current = null;
4091					}
4092
4093					break;
4094
4095
4096				case 'tab':
4097
4098					searchInput.removeAttribute('aria-activedescendant');
4099					$('adminUniversalSearch').remove();
4100					$('announce').empty();
4101
4102					if (currentylHighlighted) {
4103						currentylHighlighted.removeClass('universalSearchResultSelected');
4104						currentylHighlighted = false;
4105						current = null;
4106					}
4107
4108					break;
4109
4110				case 'enter':
4111
4112					if (currentylHighlighted) {
4113
4114						event.preventDefault();
4115						event.stopPropagation();
4116						return selectOption(currentylHighlighted)
4117
4118					} else {
4119
4120						event.preventDefault();
4121						event.stopPropagation();
4122						fetchUniversalSearchResults(event);
4123
4124					}
4125
4126					break;
4127
4128				case 'up':
4129					event.preventDefault();
4130					event.stopPropagation();
4131					return moveUp(currentylHighlighted);
4132					break;
4133
4134				case 'down':
4135					event.preventDefault();
4136					event.stopPropagation();
4137					return moveDown(currentylHighlighted);
4138					break;
4139
4140				default:
4141					return;
4142			}
4143		}
4144
4145
4146
4147
4148		/*Function to move the user up the list of suggestions*/
4149		function moveUp(currentylHighlighted) {
4150
4151
4152			//need to hold the ID of the current selected element
4153			//plus the first selected element
4154
4155			searchInput.removeAttribute('aria-activedescendant');
4156			current = document.querySelector('div#adminUniversalSearchResults a.universalSearchResultSelected');
4157
4158
4159
4160			if (currentylHighlighted && current.getAttribute('data-listNumber') > 0) {
4161
4162				currentylHighlighted.setAttribute('aria-selected', false);
4163				currentylHighlighted.removeClass('universalSearchResultSelected')
4164
4165
4166				//grab the next A item in this list
4167				previousItem = currentylHighlighted.previousSibling;
4168
4169				//skip over any non A elements in list
4170				//iterative function here...check it cant ever go for ever
4171				if (previousItem.nodeName != 'A') {
4172					previousItem = previousItem.previousSibling;
4173				}
4174
4175				previousItem.addClass('universalSearchResultSelected');
4176				previousItem.setAttribute('aria-selected', true);
4177
4178
4179				searchInput.setAttribute('aria-activedescendant', previousItem.getAttribute('id'));
4180
4181				currentylHighlighted = false;
4182
4183				currentDetails = previousItem.getAttribute('data-details');
4184
4185
4186
4187			} else {
4188
4189				//if this is the first key down event current will be empty
4190				if (current) {
4191					currentylHighlighted.setAttribute('aria-selected', false);
4192					currentylHighlighted.removeClass('universalSearchResultSelected')
4193				}
4194				//Go back to the bottom of the list
4195
4196				currentylHighlighted = $('adminUniversalSearchResults').querySelector('a.universalSearchResult:last-of-type');
4197
4198				currentylHighlighted.classList.add('universalSearchResultSelected');
4199				currentylHighlighted.setAttribute('aria-selected', true);
4200				searchInput.setAttribute('aria-activedescendant', currentylHighlighted.getAttribute('id'));
4201
4202				currentDetails = currentylHighlighted.getAttribute('data-details');
4203
4204
4205			}
4206
4207			//Announce the current position
4208
4209			$('announce').innerHTML = 'You have highlighted, ' + currentDetails;
4210
4211		}
4212
4213		/*Function to move the user down the list of suggestions*/
4214		function moveDown(currentylHighlighted) {
4215
4216
4217			searchInput.removeAttribute('aria-activedescendant');
4218
4219			// need check here that they are not at the bottom of the list already
4220
4221
4222			if (currentylHighlighted && resultCounter - 1 > currentylHighlighted.getAttribute('data-listNumber')) {
4223
4224				currentylHighlighted.setAttribute('aria-selected', false);
4225				currentylHighlighted.removeClass('universalSearchResultSelected')
4226
4227
4228				//grab the next A item in this list
4229				nextItem = currentylHighlighted.nextSibling;
4230
4231				//skip over any non A elements in list
4232				//iterative function here...check it cant ever go for ever
4233				if (nextItem.nodeName != 'A') {
4234					nextItem = nextItem.nextSibling;
4235				}
4236
4237
4238				nextItem.addClass('universalSearchResultSelected');
4239				nextItem.setAttribute('aria-selected', true);
4240
4241				searchInput.setAttribute('aria-activedescendant', nextItem.getAttribute('id'));
4242
4243				currentylHighlighted = false;
4244
4245				currentDetails = nextItem.getAttribute('data-details');
4246
4247			} else {
4248
4249				//if this is the first key down event current will be empty
4250				if (currentylHighlighted) {
4251					currentylHighlighted.setAttribute('aria-selected', false);
4252					currentylHighlighted.removeClass('universalSearchResultSelected')
4253				}
4254
4255				//Go back to the top of the list
4256				currentylHighlighted = $('adminUniversalSearchResults').querySelector('a.universalSearchResult:first-of-type');
4257
4258				currentylHighlighted.classList.add('universalSearchResultSelected');
4259				currentylHighlighted.setAttribute('aria-selected', true);
4260				searchInput.setAttribute('aria-activedescendant', currentylHighlighted.getAttribute('id'));
4261
4262
4263				currentDetails = currentylHighlighted.getAttribute('data-details');
4264
4265			}
4266
4267			$('announce').innerHTML = 'You have highlighted, ' + currentDetails;
4268
4269		}
4270
4271		/*Function to select the users chosen option*/
4272		function selectOption(currentylHighlighted) {
4273
4274
4275			if (currentylHighlighted) {
4276
4277				searchInput.removeAttribute('aria-activedescendant');
4278
4279				currentLink = currentylHighlighted.getAttribute('href');
4280
4281				$('adminUniversalSearch').remove();
4282				$('announce').empty();
4283
4284				roar.alert('Loading...');
4285				//move them along
4286				window.location.href = currentLink;
4287
4288
4289
4290			} else {
4291
4292				return;
4293			}
4294		}
4295
4296
4297
4298	}
4299
4300})();
4301
4302// end of self invoking function for universal search
4303
4304
4305
4306(function () {
4307
4308	//lets check for notifications
4309	if ($('notificationsPanel')) {
4310
4311		var notificationsLoad = new Request.JSON({
4312
4313			url: '../shared_functions/ajax/ajax_check_notifications.htm',
4314			method: 'get',
4315
4316			onSuccess: function (results) {
4317
4318				if (results) {
4319
4320					var newNotification = false;
4321
4322					if (results.new) {
4323
4324						results.new.each(function (msg) {
4325
4326							el = $('notificationsList');
4327							var msgID = msg.MESSAGEID
4328							var msgType = msg.TYPE
4329
4330							elcontent = '<a href="JavaScript:Void(0);" class="floatright hideMessage closeDark" data-type="' + msg.TYPE + '" data-id="' + msg.MESSAGEID + '" id="message' + msg.MESSAGEID + '">X</a><p class="small">' + msg.BROADCASTFROMDATE + '</p><p>' + msg.MESSAGE + '</p>'
4331
4332							new Element('div', {
4333								'class': 'card-list-dark card-dark',
4334								html: elcontent
4335							}).inject($('notificationsList'));
4336
4337							newNotification = true;
4338
4339							$('message' + msg.MESSAGEID).addEvent('click', function (e) {
4340
4341								var myRequest = new Request({
4342									url: '../shared_functions/ajax/ajax_clear_new_notification.htm',
4343									data: {
4344										msgID: msgID,
4345										msgType: msgType
4346									},
4347
4348									onComplete: function (returned) {
4349										roar.alert('<p>This message has been marked as read and won\'t be auto-displayed. You can still view all current notifications by clicking the notification icon in the top menu bar.</p>');
4350										$('message' + msg.MESSAGEID).destroy();
4351									},
4352								}).send();
4353
4354							});
4355
4356						});
4357
4358					}
4359
4360					if (results.old) {
4361
4362						results.old.each(function (msg) {
4363
4364							el = $('notificationsList');
4365
4366							elcontent = '<p class="small">' + msg.BROADCASTFROMDATE + '</p><p>' + msg.MESSAGE + '</p>'
4367
4368							new Element('div', {
4369								'class': 'card-list-dark card-dark',
4370								html: elcontent
4371							}).inject($('notificationsList'));
4372
4373						});
4374
4375					}
4376
4377					if (newNotification && !sessionStorage.getItem('seenNotifications')) {
4378
4379						elPanel = document.getElementById("notificationsPanel");
4380						elPanel.style.right = "0"
4381						elPanel.setAttribute('aria-hidden', 'false');
4382
4383						//place focus
4384						focusableEl = elPanel.querySelector('.firstFocusable');
4385						focusableEl.focus();
4386
4387						//set a session store to show that we have read it
4388						sessionStorage.setItem('seenNotifications', true);
4389
4390					}
4391
4392				}
4393
4394			}
4395
4396		}).send();
4397
4398	}
4399
4400}
4401
4402	());
4403
4404//table building functions
4405
4406function placeElement(element, target, position) {
4407
4408	//need to return something to say it had to be shifted cos didnt fit
4409
4410	let shiftedUp = false,
4411		shiftedDown = false;
4412	let targetPosition = target.getPosition();
4413	let placeAt = 'top';
4414
4415	if (position) {
4416		placeAt = position
4417	}
4418
4419	//default position
4420	element.setStyle('display', 'block');
4421	element.position({
4422		relativeTo: target,
4423		position: 'upperLeft',
4424		edge: 'upperRight'
4425	});
4426
4427	let height = (document.documentElement.clientHeight || window.innerHeight) + (document.documentElement.scrollTop || document.body.scrollTop)
4428
4429	//need to split based on position
4430
4431	if (placeAt == 'top') {
4432
4433		if (height - (targetPosition.y + 10) < element.offsetHeight) {
4434
4435			element.position({
4436				relativeTo: target,
4437				position: 'upperLeft',
4438				edge: 'bottomRight'
4439			});
4440
4441			/*
4442			let space = window.innerHeight - (window.innerHeight - target.offsetTop)
4443			let rect = target.getBoundingClientRect()
4444			let addedSpace = window.innerHeight - rect.top;
4445			element.setStyles({'bottom':document.documentElement.scrollHeight - (document.documentElement.scrollTop + Math.max(document.documentElement.clientHeight, window.innerHeight || 0)) + addedSpace - 10 , 'top':'auto'})
4446			 */
4447
4448			shiftedUp = true;
4449
4450		}
4451
4452	}
4453
4454	return {
4455		shiftedUp: shiftedUp,
4456		shiftedDown: shiftedDown,
4457	};
4458
4459}
4460
4461function addTableRow(tableID, styleClass, styleRaw) {
4462	// Get a reference to the table
4463	let tableRef = document.getElementById(tableID);
4464
4465	// Insert a row at the end of the table
4466	let newRow = tableRef.insertRow(-1);
4467
4468	if (styleClass != null) {
4469		newRow.classList.add(styleClass);
4470	}
4471
4472	if (styleRaw != null) {
4473		newRow.setAttribute('style', styleRaw);
4474	}
4475
4476	return newRow
4477
4478}
4479
4480function addRowCol(row, content, styleClass, styleRaw) {
4481
4482	let newCell = row.insertCell(-1);
4483
4484	// Append a text node to the cell
4485	//let newText = document.createTextNode(content);
4486	//newCell.appendChild(newText);
4487	newCell.innerHTML = content;
4488
4489	if (styleClass != null) {
4490		//check string for multiple classes separated by space
4491		var classArray = styleClass.split(' ');
4492		for (var i = 0; i < classArray.length; i++) {
4493			newCell.classList.add(classArray[i]);
4494		}
4495	}
4496
4497	if (styleRaw != null) {
4498		newCell.setAttribute('style', styleRaw);
4499	}
4500
4501}
4502
4503function pagenatingTable(options) {
4504
4505	let currentPage = 0,
4506		currentTotalPages = 0,
4507		recordCount = 100,
4508		firstRecord = 0,
4509		lastRecord = 0,
4510		currentTotalRecords = 0,
4511		batchContainerHidden = true,
4512		checkedBatchCount = 0,
4513		elementMoreOptions = options.moreOptionsContainer,
4514		currentMoreOptionID = 0;
4515
4516	//THIS NEEDS TO BE AN OPTION
4517	formTarget = document.forms['formSearch'];
4518
4519	//SET THE METHOD AS GET
4520	if (formTarget) {
4521		formTarget.method = 'get';
4522	}
4523
4524
4525
4526	//submitQuery : function() {
4527	this.submitQuery = function () {
4528
4529		roarShort.alert('Searching.....');
4530
4531		//need to check for logged in status
4532
4533		//clear current views causes a visual blip..try without
4534		//need to catch no records and then empty it
4535
4536		//remove any overlays
4537		if (options.useBatchOptions == true) {
4538			options.batchOptionContainer.setStyle('visibility', 'hidden');
4539		}
4540
4541		if (options.useMoreOptions == true) {
4542			options.moreOptionsContainer.setStyle('display', 'none');
4543		}
4544
4545		if (options.useFiltering == true) {
4546
4547			//we need to submit the form and do the paging filter actions
4548
4549			//document.getElementById('resultsBody').innerHTML = '';
4550			document.getElementById('totalRecordDisplay').innerHTML = document.getElementById('totalRecordDisplay').innerHTML + '&nbsp;<i class="fa fa-spin fa-circle-o-notch"></i>';
4551			document.getElementById('showAllRecords').setStyle('display', 'none');
4552
4553			//cant use fetch here yet - look into polyfills
4554
4555
4556			var filteringQuerystring = formTarget.toQueryString();
4557
4558			var fetchResults = new Request({
4559				url: formTarget.action + '&page=' + currentPage + '&records=' + recordCount + '&' + filteringQuerystring,
4560				method: 'post',
4561				data: {
4562					'ajaxAction': options.ajaxAction,
4563					'tableName': options.tableName
4564				},
4565
4566				onComplete: function (response) {
4567
4568					var objResults = JSON.parse(response);
4569
4570					if (objResults.length > 0) {
4571
4572						roar.remove();
4573
4574						//calculate the records
4575						firstRecord = currentPage * recordCount;
4576						lastRecord = firstRecord + recordCount;
4577
4578						currentTotalRecords = objResults[0]['TOTALRECORDS']
4579						currentTotalPages = Math.floor(currentTotalRecords / recordCount);
4580
4581						if (lastRecord > currentTotalRecords) {
4582							lastRecord = currentTotalRecords;
4583						}
4584
4585						//add the show all if its not a crazy amount
4586
4587						if (currentTotalRecords < 4001) {
4588							document.getElementById('showAllRecords').setStyle('display', 'block');
4589						}
4590
4591						document.getElementById('totalRecordDisplay').innerHTML = 'Showing ' + (firstRecord + 1) + ' - ' + lastRecord + ' of ' + currentTotalRecords;
4592
4593						//this callback should be provided by the options
4594						buildRowsFromResults(objResults)
4595
4596						// Add an item to the history log
4597
4598						/*
4599						if (window.history && window.history.pushState){
4600							history.pushState(null, null, formTarget.action + '&historyState=true&page=' + currentPage + '&records=' + recordCount + '&' + filteringQuerystring);
4601							//this gives us a URL we can use to rebuild the query..perhaps!
4602						}
4603						*/
4604
4605					} else {
4606						//clear the results cos we dont have any
4607
4608						options.resultsElement.innerHTML = '';
4609						document.getElementById('totalRecordDisplay').innerHTML = 'Showing 0 - 0 of 0';
4610					}
4611
4612				}
4613
4614			}).send();
4615
4616
4617		} else {
4618
4619			//just a simple AJAX request for all the info
4620			//submit to the URL with the tableName property
4621			var myTableRequest = new Request({
4622				url: options.submissionURL + '?' + options.submissionParameter,
4623				method: 'post',
4624				data: {
4625					'ajaxAction': options.ajaxAction,
4626					'tableName': options.tableName
4627				},
4628
4629				onComplete: function (response) {
4630
4631					tryParseJSON
4632
4633					var objResults = tryParseJSON(response);
4634
4635					if (objResults) {
4636						roar.remove();
4637						//this callback should be provided by the options
4638						buildRowsFromResults(objResults)
4639					} else {
4640						//empty the table cos we have no results
4641						options.resultsElement.innerHTML = '';
4642					}
4643				}
4644			}).send();
4645
4646		}
4647
4648	}
4649
4650	if (options.useFiltering == true) {
4651		if (options.filterContainer.innerHTML == '') {
4652			options.filterSubmit.setStyle('visibility', 'hidden');
4653		}
4654	}
4655
4656	//setup the nav bar thing based on option
4657
4658	if (options.usePaging == true) {
4659
4660		//create the paging elements
4661
4662		//need to create the buttons and their actions
4663		//need to create the drop down and its action
4664		//need to create the label text
4665
4666
4667		//create containing element
4668		pagingDiv = new Element('div', {
4669			styles: {
4670				padding: '10px',
4671				float: 'left'
4672			}
4673		}).inject(options.pagingContainer);
4674
4675
4676		if (options.useDownload == true) {
4677			//create the download button
4678			downloadButton = new Element('a', {
4679				id: 'pagingDownload',
4680				class: 'btnPagination btnAccent',
4681				href: 'javascript:void(0)',
4682				html: '&#709; Download Results',
4683				events: {
4684					click: function (e) {
4685
4686						//check if the field exists first
4687
4688						if (!document.getElementById('csv_inserted_form_field')) {
4689
4690							var insertField = new Element('input', {
4691								id: 'csv_inserted_form_field',
4692								name: 'csv',
4693								value: 'true',
4694								class: 'hideme'
4695							}).inject(formTarget);
4696
4697						}
4698
4699						formTarget.submit()
4700
4701						//remove CSV field
4702						$('csv_inserted_form_field').destroy();
4703
4704					}
4705				}
4706
4707			}).inject(pagingDiv, 'bottom');
4708		}
4709
4710
4711		//create the previous button
4712		previousButton = new Element('a', {
4713			id: 'pagingPrevious',
4714			class: 'btnPagination',
4715			href: 'javascript:void(0)',
4716			html: '&lt; Previous',
4717			events: {
4718				click: function (e) {
4719					e.stop();
4720					if (currentPage > 0) {
4721						--currentPage
4722						this.submitQuery();
4723					};
4724				}.bind(this)
4725			}
4726
4727		}).inject(pagingDiv, 'bottom');
4728
4729		//create the next button
4730		nextButton = new Element('a', {
4731			id: 'pagingNext',
4732			class: 'btnPagination',
4733			href: 'javascript:void(0)',
4734			html: 'Next &gt;',
4735			events: {
4736				click: function (e) {
4737					e.stop();
4738					if (currentPage < currentTotalPages) {
4739						++currentPage
4740						this.submitQuery();
4741					}
4742				}.bind(this)
4743			}
4744
4745		}).inject(pagingDiv, 'bottom');
4746
4747		//create the rows select
4748		selectRows = new Element('select', {
4749			name: 'recordNumber',
4750			id: 'recordNumber',
4751			class: 'recordsPagination',
4752			html: '<option value="100">Show 100</option><option value="200">Show 200</option><option value="500">Show 500</option><option value="1000">Show 1000</option><option id="showAllRecords" class="hideme" value="10000">Show All</option>',
4753			events: {
4754				change: function (e) {
4755					e.stop();
4756					//roarShort.alert('Fetching.....');
4757					recordCount = parseInt(e.target.value);
4758					//need to reset the page number if we are showing everything
4759					if (recordCount >= currentTotalRecords) {
4760						currentPage = 0;
4761					}
4762
4763					this.submitQuery();
4764				}.bind(this)
4765			}
4766
4767		}).inject(pagingDiv, 'bottom');
4768
4769		//create the label for the select
4770		new Element('label', {
4771			class: 'screenreader-only',
4772			'for': 'recordNumber',
4773			html: 'Select record count to show'
4774		}).inject(pagingDiv, 'bottom');
4775
4776
4777		//create the text display
4778		recordCountDisplay = new Element('span', {
4779			id: 'totalRecordDisplay',
4780			class: 'darkgrey',
4781			html: 'Showing 0 - 0 of 0'
4782		}).inject(pagingDiv, 'bottom');
4783
4784
4785
4786	}
4787
4788	//setup the filter stuff
4789
4790	if (options.useFiltering == true) {
4791
4792		options.filterSubmit.addEventListener('click', function (event) {
4793
4794			event.preventDefault();
4795			currentPage = 0
4796			this.submitQuery(currentPage);
4797
4798		}
4799			.bind(this));
4800
4801
4802
4803		var autoSelect = true;
4804
4805		options.filterSelection.addEvent('keydown', function (e) {
4806
4807			var keyPressed = e.keyCode || e.which || e.code;
4808
4809			if (keyPressed == 40 || keyPressed == 38) {
4810				autoSelect = false;
4811			} else {
4812				autoSelect = true;
4813			}
4814		});
4815
4816
4817
4818
4819		options.filterAddFilter.addEvent('click', function (e) {
4820
4821			e.stop();
4822			//make sure the apply filter button is visible
4823			options.filterSubmit.setStyle('visibility', 'visible');
4824
4825
4826			var e = options.filterSelection;
4827			var optionSelected = e.options[e.selectedIndex];
4828			fieldValue = optionSelected.value;
4829			fieldType = optionSelected.getAttribute('data-type');
4830			fieldCustom = optionSelected.getAttribute('data-custom');
4831			fieldCustomid = optionSelected.getAttribute('data-customid');
4832			fieldColName = optionSelected.getAttribute('data-col');
4833
4834			randomID = Math.floor(Math.random() * Math.floor(1000))
4835
4836			if (fieldType == 'select') {
4837
4838				//just grab the HTML from the ajax page and squirt it in
4839
4840				//farm these div creations off to a sub function
4841
4842				new Element('div', {
4843					id: 'container-' + randomID,
4844					html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><span id="random-' + randomID + '"><i class="fa fa-circle-o-notch fa-spin"></i></span></p>',
4845					style: 'float:left;
4845 width:200px; margin-right:10px;'
4846
4847				}).inject(options.filterContainer);
4848
4849				$('random-' + randomID).load(options.submissionURL + '?ajaxAction=getSelectBox&name=' + fieldValue + '&custom=' + fieldCustom + '&customid=' + fieldCustomid + '&' + options.submissionParameter);
4850
4851			} else if (fieldType == 'binary') {
4852
4853				new Element('div', {
4854					id: 'container-' + randomID,
4855					html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><select class="inputFullWidth" name="number|standard|col_fields|' + fieldColName + '|' + randomID + '"><option value="0">No</option><option value="1" selected>Yes</option></select></p>',
4856					style: 'float:left; width:100px; margin-right:10px;'
4857
4858				}).inject(options.filterContainer);
4859
4860			} else if (fieldType == 'date') {
4861
4862				new Element('div', {
4863					id: 'container-' + randomID,
4864					html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><select name="rangeSelector_' + fieldColName + '_' + randomID + '" id="" data-id="' + randomID + '" class="numberRangeSelector"><option value="equal">equals</option><option value="greater">after</option><option value="less">before</option><option value="between">between</option></select>&nbsp;<input type="text" size="9" name="number|standard|col_fields|' + fieldColName + '|' + randomID + '" id="number|standard|col_fields|' + fieldColName + '|' + randomID + '" /><span style="display:inline-block; visibility: hidden;" id="upperRange_' + randomID + '">&nbsp;and <input type="text" size="9" name="upperRange_' + fieldColName + '_' + randomID + '" id="upperRange_' + fieldColName + '_' + randomID + '" /></span></p>',
4865					style: 'float:left; width:auto; margin-right:10px;'
4866
4867				}).inject(options.filterContainer);
4868
4869				//new Picker.Date($$('input.date_toggled[type=text]'), {
4870				new Picker.Date($$('number|standard|col_fields|' + fieldColName + '|' + randomID, 'upperRange_' + fieldColName + '_' + randomID), {
4871					pickerClass: 'datepicker_vk',
4872					openLastView: true
4873				});
4874
4875			} else if (fieldType == 'number') {
4876
4877				//need to add in equals between
4878
4879
4880				//split based on if its custom or not
4881				if (fieldCustom === 'true') {
4882
4883					new Element('div', {
4884						id: 'container-' + randomID,
4885						html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><input type="text" class="inputFullWidth" name="number|custom|custom_fields|' + fieldCustomid + '" /></p>',
4886						style: 'float:left; width:200px; margin-right:10px;'
4887
4888					}).inject(options.filterContainer);
4889
4890				} else {
4891
4892					new Element('div', {
4893						id: 'container-' + randomID,
4894						html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><select name="rangeSelector_' + fieldColName + '_' + randomID + '" id="" data-id="' + randomID + '" class="numberRangeSelector"><option value="equal">equals</option><option value="greater">more than</option><option value="less">less than</option><option value="between">between</option></select>&nbsp;<input type="text" size="6" name="number|standard|col_fields|' + fieldColName + '|' + randomID + '" /><span style="display:inline-block; visibility: hidden;" id="upperRange_' + randomID + '">&nbsp;and <input type="text" size="6" name="upperRange_' + fieldColName + '_' + randomID + '" /></span></p>',
4895						style: 'float:left; width:auto; margin-right:10px;'
4896
4897					}).inject(options.filterContainer);
4898
4899				}
4900
4901			} else if (fieldType == 'text') {
4902
4903				//split based on if its custom or not
4904				if (fieldCustom === 'true') {
4905
4906					new Element('div', {
4907						id: 'container-' + randomID,
4908						html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><input type="text" class="inputFullWidth" name="text|custom|custom_fields|' + fieldCustomid + '" /></p>',
4909						style: 'float:left;
4909 width:200px; margin-right:10px;'
4910
4911					}).inject(options.filterContainer);
4912
4913				} else {
4914
4915					new Element('div', {
4916						id: 'container-' + randomID,
4917						html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><input type="text" class="inputFullWidth" name="text|standard|col_fields|' + fieldColName + '|' + randomID + '" /></p>',
4918						style: 'float:left; width:200px; margin-right:10px;'
4919
4920					}).inject(options.filterContainer);
4921				}
4922
4923			} else {
4924				new Element('div', {
4925					id: 'container-' + randomID,
4926					html: '<p><label>' + fieldValue + ' <a href="javascript:void(0);" class="removeFilter" data-id="container-' + randomID + '"><i class="fa fa-times red"></i><span class="screenreader-only">remove the ' + fieldValue + ' filter</span></a></label><br /><input type="text" class="inputFullWidth" name="text|custom|custom_fields|' + fieldCustomid + '" /></p>',
4927					style: 'float:left; width:200px; margin-right:10px;'
4928
4929				}).inject(options.filterContainer);
4930			}
4931
4932			//reset the select position to the select option
4933
4934			this.selectedIndex = 0;
4935
4936
4937
4938		});
4939
4940
4941
4942
4943
4944		$('filtersRemove').addEvent('click', function (e) {
4945
4946			e.stop();
4947			$('filterSection').empty();
4948			//hide filter button
4949			options.filterSubmit.setStyle('visibility', 'hidden');
4950			//redo search
4951			this.submitQuery();
4952
4953
4954		}
4955			.bind(this));
4956
4957
4958
4959
4960		$('containerFilters').addEvent("click:relay(.removeFilter)", function (event, element) {
4961
4962			var id = element.get('data-id');
4963			$(id).destroy();
4964
4965			//reset show number if the query bar is now empty
4966			if ($('filterSection').innerHTML.trim() == '') {
4967				//hide filter button
4968				options.filterSubmit.setStyle('visibility', 'hidden');
4969				recordCount = 100;
4970				pageNumber = 0;
4971				$('recordNumber').selectedIndex = 0;
4972			}
4973
4974			//redo search
4975			this.submitQuery();
4976
4977		}
4978			.bind(this))
4979
4980
4981
4982
4983
4984		$('containerFilters').addEvent("change:relay(.numberRangeSelector)", function (event, element) {
4985
4986			id = element.getAttribute('data-id');
4987
4988			if (element.value == 'between') {
4989				$('upperRange_' + id).setStyle('visibility', 'visible');
4990			} else {
4991				$('upperRange_' + id).setStyle('visibility', 'hidden');
4992			}
4993
4994		})
4995
4996
4997
4998	}
4999
5000	//set up the batch options container
5001
5002
5003	//set up the checkboxes stuff
5004
5005	if (options.useBatchOptions == true) {
5006
5007		options.resultsElement.addEvent('click:relay(.batchCheck)', function (event, element) {
5008
5009			//hide the more options window if it exists
5010
5011			if (options.useMoreOptions == true) {
5012				options.moreOptionsContainer.setStyle('display', 'none');
5013			}
5014
5015			if (element.checked) {
5016				checkedBatchCount++
5017				if (batchContainerHidden) {
5018					options.batchOptionContainer.setStyle('visibility', 'visible');
5019					batchContainerHidden = false;
5020				}
5021
5022			} else {
5023				checkedBatchCount--
5024				if (checkedBatchCount == 0) {
5025					options.batchOptionContainer.setStyle('visibility', 'hidden');
5026					batchContainerHidden = true;
5027				}
5028			}
5029
5030		})
5031
5032		$('selectAllCheckBox').addEvent('click', function (e) {
5033
5034			if (this.checked) {
5035				checkedBatchCount = currentTotalRecords;
5036				options.batchOptionContainer.setStyle('visibility', 'visible');
5037				batchContainerHidden = false;
5038			} else {
5039				checkedBatchCount = 0;
5040				options.batchOptionContainer.setStyle('visibility', 'hidden');
5041				batchContainerHidden = true;
5042			}
5043
5044		});
5045
5046		//add the batch items forms
5047
5048
5049		var elBatchActionsForms = document.getElementsByClassName('batchActionsForm');
5050
5051		for (var i = 0; i < elBatchActionsForms.length; i++) {
5052
5053			elBatchActionsForms[i].addEventListener('submit', function (e) {
5054
5055				/*===============================================
5056				=== we have bound outer THIS inside here and again
5057				=== in the request complete function so that we
5058				=== have access to the submitQuery function defined
5059				=== in the outer context.
5060				==================================================*/
5061
5062				//prevent submitting of the link IE fix at end
5063				e.preventDefault ? e.preventDefault() : (e.returnValue = false);
5064
5065				roarShort.alert('Working...');
5066
5067				querystring = e.target.toQueryString();
5068				container = $(e.target.getAttribute('data-container'));
5069				refreshAfterPost = e.target.getAttribute('data-refresh');
5070				showRefreshLink = e.target.getAttribute('data-show-refresh-link');
5071				submitNormally = e.target.getAttribute('data-submitNormally');
5072				submitDataArray = e.target.getAttribute('data-submitArray');
5073
5074				var checkedArray = [];
5075				$$("input.batchCheck[type=checkbox]:checked").each(function (i) {
5076					checkedArray.push(i.getAttribute('data-id'));
5077				});
5078
5079
5080
5081				if (submitNormally == 'true') {
5082
5083					$(submitDataArray).value = checkedArray.join(',');
5084					e.target.submit();
5085
5086					container.hide();
5087
5088					//also hide the row more options popup
5089					if (options.useMoreOptions == true) {
5090						options.moreOptionsContainer.setStyle('display', 'none');
5091					}
5092
5093
5094					if ($('refreshNotification') && showRefreshLink) {
5095						$('refreshNotification').setStyle('display', 'block');
5096					}
5097
5098
5099
5100
5101
5102				} else {
5103
5104
5105					var myRequest = new Request({
5106						method: 'post',
5107						url: options.submissionURL + '?' + querystring + '&' + options.submissionParameter,
5108						data: {
5109							'checked': checkedArray.join(',')
5110						},
5111						onComplete: function (returned) {
5112
5113							container.hide();
5114
5115							//we only want to do this if necessary
5116							if (refreshAfterPost == 'true') {
5117								this.submitQuery();
5118
5119								//need to hide the batch options continer as we are refershing the table so the boxes are deselected
5120								options.batchOptionContainer.setStyle('visibility', 'hidden');
5121								batchContainerHidden = true;
5122
5123							} else {
5124								roarShort.alert('Finished.');
5125
5126								//this is still undecided - should we hide the bar and deselect or maintain the selection and the bar..?
5127
5128								/*
5129								//hide batch options as everything is now unselected
5130								options.batchOptionContainer.setStyle('visibility', 'hidden');
5131								batchContainerHidden = true;
5132								
5133								*/
5134
5135							}
5136
5137							//also hide the row more options popup
5138							if (options.useMoreOptions == true) {
5139								options.moreOptionsContainer.setStyle('display', 'none');
5140							}
5141
5142
5143
5144							if ($('refreshNotification') && showRefreshLink) {
5145								$('refreshNotification').setStyle('display', 'block');
5146							}
5147
5148
5149
5150						}
5151							.bind(this)
5152
5153					}).send();
5154
5155				}
5156
5157
5158
5159
5160			}
5161				.bind(this));
5162
5163		}
5164
5165	}
5166
5167	//set up the more options window
5168	if (options.useMoreOptions == true) {
5169
5170		options.resultsElement.addEvent("click:relay(.moreOptions)", function (event, element) {
5171
5172			//default overlay options
5173			options.moreOptionsContainer.classList.remove("boxArrowBottomRight");
5174			options.moreOptionsContainer.classList.add("boxArrowTopRight");
5175
5176			if (currentMoreOptionID == element.getAttribute('data-id')) {
5177
5178				options.moreOptionsContainer.setStyle('display', 'none');
5179				currentMoreOptionID = 0;
5180
5181			} else {
5182
5183				var placed = placeElement(options.moreOptionsContainer, element);
5184
5185				if (placed.shiftedUp) {
5186					options.moreOptionsContainer.classList.remove("boxArrowTopRight");
5187					options.moreOptionsContainer.classList.add("boxArrowBottomRight");
5188				}
5189
5190				currentMoreOptionID = element.getAttribute('data-id');
5191
5192				//update all the a tags in the more options with the currently selected volunteer
5193				elOptionAnchors = $$('#moreTableOptions a');
5194				elOptionAnchors.forEach(function (element) {
5195					element.setAttribute('data-id', currentMoreOptionID);
5196				});
5197			}
5198
5199		});
5200
5201	}
5202
5203	//set up the ordering columns
5204
5205
5206	var elOrdering = document.getElementsByClassName('orderingTitle');
5207
5208	for (var i = 0; i < elOrdering.length; i++) {
5209
5210		elOrdering[i].addEventListener('click', function (e) {
5211
5212			//prevent submitting of the link IE fix at end
5213			e.preventDefault ? e.preventDefault() : (e.returnValue = false);
5214
5215			//have to update the order by col and submit the query
5216			$('colOrder').value = e.currentTarget.getAttribute('data-col');
5217
5218			//reset the page number of we are reordering...?
5219			currentPage = 0;
5220			this.submitQuery();
5221
5222		}
5223			.bind(this));
5224	}
5225
5226	this.submitQuery();
5227
5228	//include some methods here so that people can get record count etc out if they need it for something else.
5229
5230}
5231
5232function tryParseJSON(jsonString) {
5233	try {
5234		var o = JSON.parse(jsonString);
5235
5236		// Handle non-exception-throwing cases:
5237		// Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
5238		// but... JSON.parse(null) returns null, and typeof null === "object",
5239		// so we must check for that, too. Thankfully, null is falsey, so this 
5239suffices:
5240		if (o && typeof o === "object") {
5241			return o;
5242		}
5243	} catch (e) { }
5244
5245	return false;
5246};
5247
5248
5249
5250//vanilla js filter on array
5251function filter(array, conditionFunction) {
5252	var validValues = [];
5253	for (var index = 0; index < array.length; index++) {
5254		if (conditionFunction(array[index])) {
5255			validValues.push(array[index]);
5256		}
5257	}
5258	return validValues;
5259}
5260
5261//read a specific cookie store API is still not widely supported
5262function getCookie(name) {
5263	// Split cookie string and get all individual name=value pairs in an array
5264	var cookieArr = document.cookie.split(";");
5265
5266	// Loop through the array elements
5267	for (var i = 0; i < cookieArr.length; i++) {
5268		var cookiePair = cookieArr[i].split("=");
5269
5270		/* Removing whitespace at the beginning of the cookie name
5271		and compare it with the given string */
5272		if (name == cookiePair[0].trim()) {
5273			// Decode the cookie value and return
5274			return decodeURIComponent(cookiePair[1]);
5275		}
5276	}
5277
5278	// Return null if not found
5279	return null;
5280}
5281
5282
5283//QUICK TABLE FILTERING
5284function createTableFilter({ table, filters = [], globalFilter = null, resetBtn, debounceMs = 200 }) {
5285
5286	const rows = Array.from(document.querySelectorAll(`${table} tbody tr`));
5287
5288
5289	// --- debounce helper ---
5290	function debounce(fn, delay) {
5291		let timer;
5292		const wrapped = (...args) => {
5293			clearTimeout(timer);
5294			timer = setTimeout(() => fn(...args), delay);
5295		};
5296		wrapped.cancel = () => clearTimeout(timer);
5297		return wrapped;
5298	}
5299
5300	// --- highlight text in a cell without destroying HTML ---
5301	function highlightCell(cell, query) {
5302		// reset first
5303		cell.querySelectorAll('mark').forEach(m =>
5304			m.replaceWith(document.createTextNode(m.textContent))
5305		);
5306		cell.normalize();
5307
5308		if (!query) return;
5309
5310		const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
5311		const regex = new RegExp(escaped, 'gi');
5312
5313		const walker = document.createTreeWalker(cell, NodeFilter.SHOW_TEXT);
5314		const textNodes = [];
5315		let node;
5316		while ((node = walker.nextNode())) {
5317			if (node.nodeValue.trim()) textNodes.push(node);
5318		}
5319
5320		textNodes.forEach(textNode => {
5321			const parts = textNode.nodeValue.split(regex);
5322			const matches = textNode.nodeValue.match(regex);
5323			if (!matches) return;
5324
5325			const frag = document.createDocumentFragment();
5326			parts.forEach((part, i) => {
5327				frag.appendChild(document.createTextNode(part));
5328				if (i < matches.length) {
5329					const mark = document.createElement('mark');
5330					mark.textContent = matches[i];
5331					frag.appendChild(mark);
5332				}
5333			});
5334			textNode.replaceWith(frag);
5335		});
5336	}
5337
5338
5339	// --- clear all highlights in a row ---
5340	function clearRowHighlights(row) {
5341		row.querySelectorAll('mark').forEach(m => {
5342			m.replaceWith(document.createTextNode(m.textContent));
5343		});
5344		row.normalize();
5345	}
5346
5347	// --- apply filters ---
5348	function applyFilters() {
5349		// FIX 1: use destructured `globalFilter`, not `options.globalFilter`
5350		const gInput = globalFilter ? document.querySelector(globalFilter) : null;
5351		const gValue = gInput?.value.trim() ?? '';
5352
5353		rows.forEach(row => {
5354			let visible = true;
5355
5356			// --- GLOBAL SEARCH ---
5357			if (gValue) {
5358				const found = Array.from(row.cells).some(cell =>
5359					cell.textContent.toLowerCase().includes(gValue.toLowerCase())
5360				);
5361				if (!found) visible = false;
5362			}
5363
5364			// --- COLUMN FILTERS ---
5365			if (visible) {
5366				filters.forEach(f => {
5367					const inputEl = document.querySelector(f.input);
5368					if (!inputEl) return;
5369
5370					const value = inputEl.value.trim();
5371					if (!value) return;
5372
5373					const cell = row.cells[f.column];
5374					const cellText = cell.textContent.trim();
5375					const cellNum = parseFloat(cellText);
5376					const numVal = parseFloat(value);
5377
5378					if (f.type === 'text' && !cellText.toLowerCase().includes(value.toLowerCase())) {
5379						visible = false;
5380					}
5381					if (f.type === 'min' && !isNaN(numVal) && (isNaN(cellNum) || cellNum < numVal)) {
5382						visible = false;
5383					}
5384					if (f.type === 'max' && !isNaN(numVal) && (isNaN(cellNum) || cellNum > numVal)) {
5385						visible = false;
5386					}
5387				});
5388			}
5389
5390			row.style.display = visible ? '' : 'none';
5391
5392			if (!visible) {
5393				// FIX 3: clear stale highlights on hidden rows
5394				clearRowHighlights(row);
5395				return;
5396			}
5397
5398			// --- highlight column text filters ---
5399			filters.forEach(f => {
5400				if (f.type !== 'text') return;
5401				const inputEl = document.querySelector(f.input);
5402				const query = inputEl?.value.trim();
5403				highlightCell(row.cells[f.column], query || '');
5404			});
5405
5406			// --- GLOBAL HIGHLIGHT ---
5407			if (gValue) {
5408				Array.from(row.cells).forEach(cell => highlightCell(cell, gValue));
5409			}
5410		});
5411	}
5412
5413	const debouncedApply = debounce(applyFilters, debounceMs);
5414
5415	// attach listeners to column filters
5416	filters.forEach(f => {
5417		const el = document.querySelector(f.input);
5418		if (el) el.addEventListener('input', debouncedApply);
5419	});
5420
5421	// FIX 2: attach listener to the global filter input
5422	if (globalFilter) {
5423		const gEl = document.querySelector(globalFilter);
5424		if (gEl) gEl.addEventListener('input', debouncedApply);
5425	}
5426
5427	// --- reset button ---
5428	if (resetBtn) {
5429		const btn = document.querySelector(resetBtn);
5430		btn?.addEventListener('click', (event) => {
5431
5432			event.preventDefault();
5433
5434			roar.alert('Resetting filters..');
5435
5436			debouncedApply.cancel();
5437
5438			filters.forEach(f => {
5439				const el = document.querySelector(f.input);
5440				if (el) el.value = '';
5441			});
5442
5443			// FIX 1 again: use `globalFilter`, not `options.globalFilter`
5444			if (globalFilter) {
5445				const g = document.querySelector(globalFilter);
5446				if (g) g.value = '';
5447			}
5448
5449			rows.forEach(row => {
5450				row.style.display = '';
5451				clearRowHighlights(row);
5452			});
5453		});
5454	}
5455}
5456
5457
5458
5459// CONFIRM DANGEROUS OR DESTRUCTIVE CLICKS
5460(function () {
5461
5462	var confirmLinks = document.querySelectorAll('.js-ConfirmAction');
5463
5464	for (var i = 0, len = confirmLinks.length; i < len; i++) {
5465
5466		let customMessage = confirmLinks[i].getAttribute("data-message");
5467		if (!customMessage) {
5468			customMessage = "Are you sure you want to do this?";
5469		}
5470
5471
5472		confirmLinks[i].onclick = function () {
5473			var check = confirm(customMessage);
5474			if (check == true) {
5475				return true;
5476			}
5477			else {
5478				return false;
5479			}
5480		};
5481	}
5482
5483}()
5484);
5485
5486
5487//PROFILE CUSTOM QUESTIONS THAT ARE CHECKBOX GROUPS BUT REQUIRED
5488(function () {
5489
5490	//we only need the ones that are required to have at least one item checked
5491	let checkboxGroups = document.getElementsByClassName('checkboxMultiGroupContainerRequired');
5492
5493	for (var i = 0; i < checkboxGroups.length; i++) {
5494
5495		//add event to the form
5496		let containerForm = checkboxGroups[i].form;
5497		let formSubmit = containerForm.querySelectorAll('button[type=submit]')[0];
5498		formSubmit.addEventListener('click', deRequireCb.bind(null, checkboxGroups[i]));
5499	}
5500
5501	function deRequireCb(elContainer) {
5502
5503		let el = elContainer.querySelectorAll('div input[type="checkbox"]');
5504
5505		var atLeastOneChecked = false; //at least one cb is checked
5506
5507		for (i = 0; i < el.length; i++) {
5508			if (el[i].checked === true) {
5509				atLeastOneChecked = true;
5510			}
5511		}
5512
5513		if (atLeastOneChecked === true) {
5514			for (i = 0; i < el.length; i++) {
5515				el[i].required = false;
5516				el[i].setCustomValidity('');
5517			}
5518		} else {
5519			for (i = 0; i < el.length; i++) {
5520				el[i].required = true;
5521				el[i].setCustomValidity('Please select at least one option');
5522			}
5523		}
5524	}
5525})();

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.