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 = '−'; 1376 this.style.backgroundColor = '#990000'; 1377 1378 } else if (this.innerHTML === 'â') { 1379 1380 this.innerHTML = '+'; 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': ' <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', ' <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', ' <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', ' <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', ' <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 = ' '; 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 + ' <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: '˅ 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: '< 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 >', 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> <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 + '"> 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> <input type="text" size="6" name="number|standard|col_fields|' + fieldColName + '|' + randomID + '" /><span style="display:inline-block; visibility: hidden;" id="upperRange_' + randomID + '"> 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.