1"use strict"; 2 3function FxBSizeWizard() 4{ 5 return undefined; 6} 7 8(function ($) 9{ 10 FxBSizeWizard._MobileThreshold = 768; 11 FxBSizeWizard._MobileClass = "fxb_mobile"; 12 FxBSizeWizard._DesktopClass = "fxb_desktop"; 13 FxBSizeWizard._CurrentClass = null; 14 15 FxBSizeWizard._GetCurrentSizeClass = function () 16 { 17 if (window.innerWidth < FxBSizeWizard._MobileThreshold) 18 { 19 return FxBSizeWizard._MobileClass; 20 } 21 return FxBSizeWizard._DesktopClass; 22 }; 23 24 FxBSizeWizard._UpdateSizeClassification = function () 25 { 26 var lNewClass = FxBSizeWizard._GetCurrentSizeClass(); 27 if (lNewClass !== FxBSizeWizard._CurrentClass) 28 { 29 if (FxBSizeWizard._CurrentClass !== null) 30 { 31 $('body').removeClass(FxBSizeWizard._CurrentClass); 32 } 33 FxBSizeWizard._CurrentClass = lNewClass; 34 $('body').addClass(FxBSizeWizard._CurrentClass); 35 36 // run callbacks here? 37 } 38 }; 39 40 FxBSizeWizard._Init = function () 41 { 42 var lLocalMobileThreshold = $("body").css("--FxB-MobileThreshold"); 43 if (!FBUtilities.IsParameterUndefinedOrEmpty(lLocalMobileThreshold)) 44 { 45 FxBSizeWizard._MobileThreshold = Number(lLocalMobileThreshold); 46 } 47 FxBSizeWizard._UpdateSizeClassification(); 48 }; 49 50 // considering DOMContentLoaded for this, but would need jQuery free code. 51 $(window).on('load', FxBSizeWizard._Init); 52 $(window).resize(FxBSizeWizard._UpdateSizeClassification); 53}(jQuery)); 54 55 56// ----------------------------------------------------------------------------------------------------- 57// Foxbright CMS commonly-used functions v1.0 58// Created: 2009-09-10 (AW) 59// ----------------------------------------------------------------------------------------------------- 60 61function FBUtilities() 62{ 63 return undefined; 64} 65 66function FBQuickAjax() 67{ 68} 69 70function FBMenuManager() 71{ 72 return undefined; 73} 74 75function ThumbnailUtilities() 76{ 77 return undefined; 78} 79 80function FoxAjaxContent() 81{ 82 return undefined; 83} 84 85function FoxEncoder() 86{ 87 return undefined; 88} 89 90function VideoUtilities() 91{ 92 return undefined; 93} 94 95function FBLightbox() 96{ 97 return undefined; 98} 99 100var fb_js_debug = false; 101 102/////////////////////////////////////////////////////////////////////////////// 103// FBCommon functions 104/////////////////////////////////////////////////////////////////////////////// 105 106var FBCommon_1_2 = 107{ 108 dumpCollection: function (name, collection) 109 { 110 var key; 111 window.console.log(name); 112 if (collection) 113 { 114 for (key in collection) 115 { 116 if (collection.hasOwnProperty(key)) 117 { 118 window.console.log("%s: %s", key, collection[key]); 119 } 120 } 121 } 122 }, 123 // Try use replaceChars() instead going forward (AW: 2010-10-01) 124 // Params: 125 // Required: words (string) 126 // Required: character (string to remove) 127 // Return vals: words (string with character removed) 128 // Notes: Remove all instances of character from words 129 removeCharacters: function (parameters) 130 { 131 var words, character, chars, x; 132 133 words = parameters.words; 134 character = (parameters.character === undefined ? ' ' : parameters.character); 135 chars = words.length; 136 137 for (x = 0; x < chars; x += 1) 138 { 139 words = words.replace(character, ""); 140 } 141 return words; 142 }, 143 144 // Return true if we are in an editor page. 145 isInEditor: function () 146 { 147 if (jQuery('body.fbcms_editmode').length === 1) 148 { 149 return true; 150 } 151 return false; 152 }, 153 154 155 /** 156 * Encodes html tag characters 157 * @param {string} text 158 */ 159 htmlTagEncode: function (text) 160 { 161 let encoded; 162 if (text === undefined || text === null) 163 { 164 encoded = ''; 165 } 166 else 167 { 168 encoded = text.replaceAll('<', '<').replaceAll('>', '>'); 169 } 170 return encoded; 171 }, 172 173 // --[ html Encode/Decode ]------------------------------------------------------------------------- 174 // Params: 175 // text - the text to encode/decode. 176 // Returns: 177 // the text, encoded or decoded. 178 htmlEncode: function (text) 179 { 180 return jQuery('<div/>').text(text).html(); 181 }, 182 183 htmlEncodeMinimal: function (str) 184 { 185 if (str === undefined || str === null || typeof (str) !== 'string' || str.length === 0) 186 { 187 return str; 188 } 189 190 let buffer = []; 191 for (let i = 0; i < str.length; i++) 192 {
193 let iC = str[i].charCodeAt(); 194 if (iC === 38) 195 { 196 buffer.push('&'); 197 } 198 else if (iC === 60) 199 { 200 buffer.push('<'); 201 } 202 else if (iC === 62) 203 { 204 buffer.push('>'); 205 } 206 else if (iC === 34) 207 { 208 buffer.push('"'); 209 } 210 // NOPE, ignore these please! 211 /*else if (iC < 65 212 || iC > 127 213 || (iC > 90 214 && iC < 97)) { 215 buffer.push('&#'); 216 buffer.push(iC); 217 buffer.push(';'); 218 }*/ 219 else 220 { 221 buffer.push(str[i]); 222 } 223 } 224 return buffer.join(''); 225 }, 226 227 htmlEncodeKludgy: function(str) 228 { 229 if (str === undefined || str === null || typeof (str) !== 'string' || str.length) 230 { 231 return str; 232 } 233 let aRet = [] 234 235 for (let i = 0; i < str.lenght; i++) 236 { 237 let iC = str[i].charCodeAt(); 238 if (iC < 65 239 || iC > 127 240 || (iC > 90 241 && iC < 97)) 242 { 243 aRet.push('&#'); 244 aRet.push(iC); 245 aRet.push(';'); 246 } 247 else 248 { 249 aRet.push(str[i]); 250 } 251 }//endwhile 252 return aRet.join(''); 253 }, 254 255 htmlDecode: function (text) 256 { 257 return jQuery('<div/>').html(text).text(); 258 }, 259 260 PairCountrySelectWithStateSelect: function (countryCodeId, stateCodeId) 261 { 262 const countrySelector = `#${countryCodeId}`; 263 const stateSelector = `#${stateCodeId}`; 264 function updateStateCodeSelect() 265 { 266 const selectedCountryCode = $(countrySelector).val(); 267 268 $(stateSelector).find('option').each(function () 269 { 270 const country = $(this).data('country_code'); 271 if (selectedCountryCode === '' || country === '' || country === selectedCountryCode) 272 { 273 $(this).prop('hidden', false); 274 } 275 else 276 { 277 $(this).prop('hidden', true); 278 if ($(this).prop('selected')) 279 { 280 $(this).prop('selected', false); 281 } 282 } 283 }); 284 } 285 286 $(countrySelector).on('change', updateStateCodeSelect); 287 updateStateCodeSelect.call($(countrySelector).get(0)); 288 }, 289 290 // Example calls: 291 // addSearchBoxTriggers({}); 292 // addSearchBoxTriggers({ fieldId : 'myField', defaultText : 'enter search criteria' }); 293 // Params: 294 // Optional: ID of search field 295 // Optional: Default text 296 // Optional: CSS class for empty field 297 // Return vals: None 298 // Notes: Clear search field on focus if empty / return to default state on blur if empty 299 addSearchBoxTriggers: function (parameters) 300 { 301 var defaultText, emptyClass, fieldId; 302 303 fieldId = (parameters.fieldId === undefined) ? 'search_string' : parameters.fieldId; 304 defaultText = (parameters.defaultText === undefined) ? '' : parameters.defaultText; 305 emptyClass = (parameters.emptyClass === undefined) ? 'empty' : parameters.emptyClass; 306 307 jQuery("#" + fieldId).focus(function () 308 { 309 jQuery(this).removeClass(emptyClass); 310 if (jQuery(this).val() === defaultText) 311 { 312 jQuery(this).val(''); 313 } 314 }).blur(function () 315 { 316 if (FBCommon_1_2.removeCharacters({ words: jQuery(this).val() }) === '') 317 { 318 jQuery(this).addClass('empty'); 319 jQuery(this).val(defaultText); 320 } 321 }); 322 323 // Ensure empty class is removed if page is refreshed while search f
323ield contains text 324 if (jQuery("#" + fieldId).val() !== defaultText) 325 { 326 jQuery("#" + fieldId).removeClass(emptyClass); 327 } 328 }, 329 330 // Example calls: 331 // setQuickJumpMenu({}); 332 // setQuickJumpMenu({ quickJumpSpeed : 'slow', quickJumpDelay : 300 }); 333 // Params: 334 // Optional: quickJumpID: ID of the QuickJump menu. 335 // Optional: quickJumpButtonClass: Class of quick jump button 336 // Optional: quickJumpDropClass: Class of quick jump drop menu 337 // Optional: quickJumpDelay: milliseconds before QJD hides 338 // Optional: quickJumpSpeed: milliseconds QJD hide/show transition takes 339 // Optional: quickJumpOpenClass: class to put on the overall element when the menu is open 340 // Return vals: none 341 // Notes: Adds show/hide triggers to quick jump menu 342 // Requires: jQuery.timer, jQuery.clearTimer 343 setQuickJumpMenu: function (parameters) 344 { 345 var defaults, options, quickJumpTimer, quickJumpButton, quickJumpDrop; 346 347 defaults = 348 { 349 quickJumpID: 'myQuickJump' 350 , quickJumpButtonClass: 'quickJumpButton' 351 , quickJumpDropClass: 'quickJumpDrop' 352 , quickJumpDelay: 300 353 , quickJumpSpeed: 0 354 , quickJumpClickActive: true 355 , quickJumpHoverActive: false 356 , quickJumpOpenClass: 'quickJumpOpen' 357 }; 358 359 options = jQuery.extend( 360 defaults, 361 parameters 362 ); 363 364 quickJumpTimer = null; 365 quickJumpButton = jQuery("#" + options.quickJumpID + ' .' + options.quickJumpButtonClass); 366 quickJumpDrop = jQuery("#" + options.quickJumpID + ' .' + options.quickJumpDropClass); 367 368 369 function openQuickJumpMenu() 370 { 371 quickJumpDrop.slideDown(options.quickJumpSpeed); 372 if (!FBUtilities.IsParameterUndefinedOrEmpty(options.quickJumpOpenClass)) 373 { 374 jQuery("#" + options.quickJumpID).addClass(options.quickJumpOpenClass); 375 } 376 }//end openQuickJumpMenu 377 378 function closeQuickJumpMenu() 379 { 380 quickJumpDrop.slideUp(options.quickJumpSpeed); 381 if (!FBUtilities.IsParameterUndefinedOrEmpty(options.quickJumpOpenClass)) 382 { 383 jQuery("#" + options.quickJumpID).removeClass(options.quickJumpOpenClass); 384 } 385 }//end closeQuickJumpMenu 386 387 if (quickJumpButton.length === 0 || quickJumpDrop.length === 0) 388 { 389 return; 390 } 391 392 if (options.quickJumpClickActive === true) 393 { 394 quickJumpButton.click( 395 function () 396 { 397 if (quickJumpDrop.is(':hidden')) 398 { 399 openQuickJumpMenu(); 400 } 401 else 402 { 403 closeQuickJumpMenu(); 404 } 405 } 406 ); 407 } 408 409 quickJumpButton.hover( 410 function () 411 { 412 if (options.quickJumpHoverActive === true) 413 { 414 if (quickJumpDrop.is(':hidden')) 415 { 416 jQuery('.' + options.quickJumpDropClass).slideUp(options.quickJumpSpeed); 417 openQuickJumpMenu(); 418 } 419 } 420 421 if (quickJumpTimer !== null) 422 { 423 jQuery.clearTimer(quickJumpTimer); 424 } 425 }, 426 function () 427 { 428 quickJumpTimer = jQuery.timer( 429 options.quickJumpDelay, 430 function () 431 { 432 closeQuickJumpMenu(); 433 } 434 ); 435 } 436 ); 437 438 quickJumpDrop.hover( 439 function () 440 { 441 if (quickJumpTimer !== null) 442 { 443 jQuery.clearTimer(quickJumpTimer); 444 } 445 }, 446 function () 447 { 448 quickJumpTimer = jQuery.timer( 449 options.quickJumpDelay, 450 function () 451 { 452 closeQuickJumpMenu(); 453 } 454 ); 455 } 456 ); 457 458 459 460 }, //end setQuickJumpMenu
461 462 initCmsAlert: function (aParentId, aChildClass) 463 { 464 const $alert = $(`#${aParentId}`); 465 const noAlertToShow = $alert.find(`.${aChildClass}`).length === 0; 466 if (noAlertToShow) { 467 return; 468 } 469 470 function fnHideCmsAlert() { 471 $alert.attr('aria-hidden', "true").hide(); 472 473 jQuery('#fbcms_ea_shadowBox').remove(); // close trigger 474 var jFirst = jQuery('.skip_link').first(); 475 if (jFirst.length === 0) { 476 jFirst = jQuery(':tabbable').first(); 477 } 478 jFirst.focus(); 479 return false; 480 }; 481 482 jQuery('body') 483 .prepend('<div id="fbcms_ea_shadowBox"></div>'); 484 485 jQuery('#fbcms_ea_shadowBox') 486 .height(jQuery(document).height() + 'px') 487 .click(fnHideCmsAlert); 488 489 const labbelledById = `${aParentId}-header`; 490 $alert.find('.fbcms_contentheader .contentheader_item.fbcms_news_headlines_title').attr('id', labbelledById); 491 492 const describedById = `${aParentId}-content`; 493 $alert.find('.fbcms_headline_list_content ').attr('id', describedById); 494 495 $alert 496 .prepend(`<button type="button" title="Close alert" aria-labelledby="closeAlert-label" id="closeAlert"><i class="fas fa-times" aria-hidden="true"></i> <span id="closeAlert-label" class="visually-hidden">Close alert</span></button>`) 497 .attr('role', 'alertdialog') 498 .attr('aria-labelledby', labbelledById) 499 .attr('aria-describedby', describedById) 500 .attr('aria-hidden', "false") 501 .show(); 502 503 $alert 504 .find('#closeAlert') 505 .on('click', fnHideCmsAlert) 506 .on('keypress', function (event) { 507 if (event.keyCode === 13 /*enter*/ || event.keyCode === 27 /*escape*/) { 508 event.preventDefault(); 509 fnHideCmsAlert(); 510 } 511 }) 512 .focus(); 513 514 515 let tababble = $alert.find(':tabbable'); 516 tababble.first().on('keydown', function (event) { 517 if (event.keyCode === 9 && event.shiftKey === true) { 518 event.preventDefault(); 519 $alert.find(':tabbable').last().focus(); 520 } 521 522 }); 523 524 tababble.last().on('keydown', function (event) { 525 if (event.keyCode === 9 && event.shiftKey === false) { 526 event.preventDefault(); 527 $alert.find(':tabbable').first().focus(); 528 } 529 530 }); 531 }, 532 533 /* 534 FBCommon_1_2.initTabs(); 535 536 Initializes tab events (and cleanup). 537 A Tabset is identified by .fbcms_tabset 538 Two containers must be found inside, for the titles (.tabset_titlecontainer) and content (.tabset_contentcontainer) 539 If only one title (.tabset_title) is found, nothing further is done. 540 Active titles and content are indicated by the active class (.active). 541 This should be set in the markup on the desired set to be initially displayed. 542 Each title must have data-tabselector attribute set with a selector for the matching content element inside the content container. 543 Content and Tab elments must have id attributes set. 544 If two or more are titles are present: 545 Each title is checked if it is empty of Text (not markup). 546 If blank or otherwise empty, the title and matching content elements are removed - unless Active (see extra options). 547 If text is present, the title and content elements are labelled with ARIA attributes. 548 549 Extra options: 550 Clear All Empty (default: false) This will cause a title/content element to be removed EVEN IF IT IS ACTIVE. 551 This can be specified by a data attribute on the tabset container: data-tabset-clearallempty 552 Setting this to 'true' will activate this setting, all other values will result in the default behavior. 553 554 Unprocessed, initial markup example: 555 556 <div class="fbcms_tabset" data-tabset-clearallempty="false"> 557 <ul class="tabset_titlecontainer" role="tablist"> 558 <li id="tabtitle1" class="tabset_title active" data-tab-selector="#tab1" role="tab"> 559 </li><!-- .tabset_title //--> 560 <li id="tabtitle2" class="tabset_title" data-tab-selector="#tab2" role="tab"> 561 </li><!-- .tabset_title //--> 562 </ul><!-- .tabset_titlecontainer //--> 563 <div class="tabset_contentcontainer"> 564 <div id="tab1" class="tabset_content active" role="tabpanel"> 565 </div><!-- .tabset_content //--> 566 <div id="tab2" class="tabset_content" role="tabpanel"> 567 </div><!-- .tabset_content //--> 568 </div><!-- .tabset_contentcontainer //--> 569 </div> 570 */ 571 initTabs: function () 572 { 573 function activateTabSetTitle(aTarget, aCleanAnchorHash) 574 { 575 const jCurrentTab = $(aTarget).closest('.tabset_title'); 576 if (jCurrentTab.hasClass('active')) 577 { 578 return; 579 } 580 581 const contentSelector = jCurrentTab.data('tab-selector'); 582 if (contentSelector === undefined || contentSelector === null || contentSelector.length === 0) 583 { 584 return; 585 } 586 587 const jTabSet = jCurrentTab.closest('.fbcms_tabset'); 588 const jContentContainers = jTabSet.find('.tabset_contentcontainer'); 589 const jContent = jContentContainers.find(contentSelector); 590 if (jContent.length === 0) 591 { 592 return; 593 } 594 595 const jTitleContainers = jTabSet.find('.tabset_titlecontainer'); 596 597 jTitleContainers.find('.tabset_title').removeClass('active').attr('aria-selected', 'false'); 598 jContentContainers.find('.tabset_content').removeClass('active'); 599 jCurrentTab.addClass('active').attr('aria-selected', 'true'); 600 jContent.addClass('active'); 601 602 if (!FBUtilities.IsParameterUndefinedOrEmpty(aCleanAnchorHash)) 603 { 604 // was given an anchor, use it. 605 window.location.hash = `#${aCleanAnchorHash}`; 606 } 607 else if (!FBUtilities.IsParameterUndefinedOrEmpty(window.location.hash)) 608 { 609 // is the current hash inside this hashset? in active content? in t
609itles? 610 const inTabset = jTabSet.find(window.location.hash).length !== 0 611 const inActiveContent = jContent.find(window.location.hash).length !== 0; 612 const inTitles = jTitleContainers.find(window.location.hash).length !== 0; 613 614 if (inTabset && !inActiveContent && !inTitles) 615 { 616 const cleanedUrl = window.location.href.split('#')[0]; 617 window.history.replaceState(null, null, cleanedUrl); 618 } 619 } 620 621 const cleanAnchorHash = !FBUtilities.IsParameterUndefinedOrEmpty(aCleanAnchorHash) ? aCleanAnchorHash : undefined; 622 setTimeout(function () 623 { 624 if (cleanAnchorHash !== undefined) 625 { 626 // was given an anchor, use it. 627 const cleanedUrl = window.location.href.split('#')[0]; 628 window.history.replaceState(null, null, cleanedUrl); 629 window.location.hash = `#${cleanAnchorHash}`; 630 } 631 632 const masons = jContent.find('.masonry'); 633 if (masons.length !== 0 && masons.masonry !== undefined) 634 { 635 masons.masonry("layout"); 636 } 637 }, 1); 638 } 639 640 const tabSets = $('.fbcms_tabset'); 641 if (tabSets.length === 0) 642 { 643 return; 644 } 645 646 const isEditMode = FBCommon_1_2.isInEditor(); 647 648 tabSets.each(function () 649 { 650 const $tabSet = $(this); 651 const $titleContainers = $tabSet.find('.tabset_titlecontainer'); 652 const $contentContainers = $tabSet.find('.tabset_contentcontainer'); 653 654 if ($titleContainers.length > 0 && $contentContainers.length > 0) 655 { 656 const clearAllEmpty = $tabSet.data('tabset-clearallempty'); 657 const keepEmpty = $tabSet.data('tabset-keepempty'); 658 const $titles = $titleContainers.find('.tabset_title'); 659 if ($titles.length < 2) 660 { 661 $titleContainers.on('click', '.tabset_title', function (aEvent) { 662 aEvent.preventDefault(); 663 return false; 664 }); 665 666 if ($tabSet.find('.tabset_title').length === 0) { 667 $tabSet.remove(); 668 } 669 return; 670 } 671 672 if (isEditMode === false) 673 { 674 $.each($titles, function (aIndex, aValue)//ignore jslint 675 { 676 const $title = $(aValue); 677 const isActive = $title.hasClass('active'); 678 const contentSelector = $title.data('tab-selector'); 679 680 if (FBUtilities.IsParameterUndefinedOrEmpty(contentSelector)) 681 { 682 return; 683 } 684 685 const $content = $contentContainers.find(contentSelector); 686 if ($content.length === 0) 687 { 688 return; 689 } 690 691 if (keepEmpty !== true 692 && FBUtilities.IsStringEmptyOrWhitespace($title.text()) === true 693 && (isActive === false || clearAllEmpty === true) 694 ) 695 { 696 $title.remove(); 697 $content.remove(); 698 if ($tabSet.find('.tabset_title').length === 0) { 699 $tabSet.remove(); 700 } 701 return; 702 } 703 704 const tabId = $title.attr('id'); 705 const contentId = $content.attr('id'); 706 if (FBUtilities.IsStringEmptyOrWhitespace(tabId) === true 707 || FBUtilities.IsStringEmptyOrWhitespace(contentId) === true) 708 { 709 return; 710 } 711 $title.attr('aria-controls', contentId); 712 $title.attr('aria-selected', isActive); 713 $content.attr('aria-labelledby', tabId); 714 }); 715 } 716 717 $titleContainers.on('click', '.tabset_title', (event) => 718 { 719 event.preventDefault(); 720 const tabSet = event.target; 721 activateTabSetTitle(tabSet); 722 return false; 723 }); 724 } 725 726 window.addEventListener("hashchange", (event) => 727 {
728 selectHashRequestedTab($titleContainers); 729 }); 730 731 selectHashRequestedTab($titleContainers); 732 }); 733 734 function selectHashRequestedTab(aTabWrapper) 735 { 736 const rawAnchorHash = window.location.hash; 737 if (rawAnchorHash.lastIndexOf('#') === -1) 738 { 739 return; 740 } 741 742 const cleanAnchorHash = rawAnchorHash.substring(rawAnchorHash.lastIndexOf('#') + 1); 743 const jDirect = aTabWrapper.find(`.tabset_title[data-tab-selector="${rawAnchorHash}"]`); 744 if (jDirect.length !== 0) 745 { 746 if (jDirect.length === 1) 747 { 748 activateTabSetTitle(jDirect, cleanAnchorHash); 749 } 750 return 751 } 752 753 const jTarget = $(`#${cleanAnchorHash}`); 754 if (jTarget.length !== 1) 755 { 756 return; 757 } 758 759 const jTabsetContent = jTarget.closest('.tabset_content'); 760 if (jTabsetContent.length !== 1) 761 { 762 return; 763 } 764 765 const parentTabContentId = jTabsetContent.attr('id'); 766 const jTitlesToActivate = aTabWrapper.find('.tabset_title[data-tab-selector="#' + parentTabContentId + '"]') 767 if (jTitlesToActivate.length !== 1) 768 { 769 return; 770 } 771 772 activateTabSetTitle(jTitlesToActivate, cleanAnchorHash); 773 }//end selectHashRequestedTab 774 },//end initTabs 775 776 getJQueryDialogButton: function (dialog_selector, button_name) 777 { 778 var buttons = $(dialog_selector + ' .ui-dialog-buttonpane button'); 779 for (var i = 0; i < buttons.length; ++i) 780 { 781 var jButton = $(buttons[i]); 782 if (jButton.text() === button_name) 783 { 784 return jButton; 785 } 786 } 787 788 return null; 789 }, 790 791 disableJQueryDialogButton: function (dialog_selector, button_name) 792 { 793 var button = FBCommon_1_2.getJQueryDialogButton(dialog_selector, button_name); 794 if (button !== null) 795 { 796 button.attr('disabled', 'disabled').addClass('ui-state-disabled'); 797 } 798 }, 799 800 enableJQueryDialogButton: function (dialog_selector, button_name) 801 { 802 var button = FBCommon_1_2.getJQueryDialogButton(dialog_selector, button_name); 803 if (button !== null) 804 { 805 button.removeAttr('disabled').removeClass('ui-state-disabled'); 806 } 807 } 808}; 809 810/////////////////////////////////////////////////////////////////////////////// 811// FBCommon_1_2 Function Aliases 812/////////////////////////////////////////////////////////////////////////////// 813 814var isInEditor = FBCommon_1_2.isInEditor; 815var PairCountrySelectWithStateSelect = FBCommon_1_2.PairCountrySelectWithStateSelect; 816var addSearchBoxTriggers = FBCommon_1_2.addSearchBoxTriggers; //clarenceville & vansingel(!) 817var setQuickJumpMenu = FBCommon_1_2.setQuickJumpMenu; //fruitport2015 & mioausable 818 819 820/////////////////////////////////////////////////////////////////////////////// 821// jQuery Timer Plugin 822/////////////////////////////////////////////////////////////////////////////// 823 824(function () 825{ 826 /* 827 * jQuery Timer Plugin 828 * http://www.evanbot.com/article/jquery-timer-plugin/23 829 * 830 * @version 1.0 831 * @copyright 2009 Evan Byrne (http://www.evanbot.com) 832 */ 833 834 jQuery.timer = function (time, func, callback) 835 { 836 var a = { 837 timer: setTimeout(func, time), 838 callback: null 839 }; 840 841 if (typeof callback === 'function') 842 { 843 a.callback = callback; 844 } 845 return a; 846 }; 847 848 jQuery.clearTimer = function (a) 849 { 850 if (a === null) 851 { 852 return this; 853 } 854 clearTimeout(a.timer); 855 if (typeof (a.callback) === 'function') 856 { 857 a.callback(); 858 } 859 return this; 860 }; 861}(jQuery)); 862
863/////////////////////////////////////////////////////////////////////////////// 864// A real string replaceAll function 865/////////////////////////////////////////////////////////////////////////////// 866 867//(function () 868//{ 869// // http://www.codedigest.com/CodeDigest/75-String-ReplaceAll-function-in-JavaScript.aspx 870// String.prototype.replaceAll = function (stringToFind, stringToReplace) 871// { 872// var temp, index; 873 874// temp = this.toString(); 875// index = temp.indexOf(stringToFind); 876 877// while (index !== -1) 878// { 879// temp = temp.replace(stringToFind, stringToReplace); 880// index = temp.indexOf(stringToFind); 881// } 882// return temp; 883// }; 884//}(jQuery)); 885 886/////////////////////////////////////////////////////////////////////////////// 887// FoxEncoder 888/////////////////////////////////////////////////////////////////////////////// 889 890(function () 891{ 892 //---------------------------------------------------------------------------- 893 // FoxEncoder Javascript functions. 894 // http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html 895 //---------------------------------------------------------------------------- 896 897 FoxEncoder.keyStr64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 898 FoxEncoder.base64RegexTest = /[^A-Za-z0-9\+\/\=]/g; 899 900 FoxEncoder.encodeUTF8andBase64 = function (input) 901 { 902 return FoxEncoder.encodeUTF8andBase64worker(input, FoxEncoder.keyStr64); 903 }; 904 905 FoxEncoder.encodeUTF8andBase64worker = function (input, keyStr64) 906 { 907 var output = "", 908 chr1, 909 chr2, 910 chr3 = "", 911 enc1, 912 enc2, 913 enc3, 914 enc4 = "", 915 i = 0; 916 917 if (FBUtilities.IsParameterUndefinedOrEmpty(input)) 918 { 919 return output; 920 } 921 922 input = FoxEncoder.encodeUTF8(input); 923 924 do 925 { 926 chr1 = input.charCodeAt(i); 927 i += 1; 928 chr2 = input.charCodeAt(i); 929 i += 1; 930 chr3 = input.charCodeAt(i); 931 i += 1; 932 933 enc1 = chr1 >> 2; //ignore jslint 934 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); //ignore jslint 935 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); //ignore jslint 936 enc4 = chr3 & 63; //ignore jslint 937 938 if (isNaN(chr2)) 939 { 940 enc3 = enc4 = 64; 941 } 942 else if (isNaN(chr3)) 943 { 944 enc4 = 64; 945 } 946 947 output = output + 948 keyStr64.charAt(enc1) + 949 keyStr64.charAt(enc2) + 950 keyStr64.charAt(enc3) + 951 keyStr64.charAt(enc4); 952 chr1 = chr2 = chr3 = ""; 953 enc1 = enc2 = enc3 = enc4 = ""; 954 } 955 while (i < input.length); 956 957 return output; 958 }; //end FoxEncoder.encodeUTF8andBase64worker 959 960 FoxEncoder.decodeBase64andUTF8 = function (input) 961 { 962 return FoxEncoder.decodeBase64andUTF8worker(input, FoxEncoder.keyStr64, FoxEncoder.base64RegexTest); 963 }; 964 965 FoxEncoder.decodeBase64andUTF8worker = function (input, keyStr64, base64RegexTest) 966 { 967 var output = "", 968 chr1, chr2, chr3 = "", 969 enc1, enc2, enc3, enc4 = "", 970 i = 0; 971 972 // remove all characters that are not in the key string. 973 if (base64RegexTest.exec(input)) 974 { 975 return null; 976 } 977 input = input.replace(base64RegexTest, ""); 978 979 do 980 { 981 enc1 = keyStr64.indexOf(input.charAt(i)); 982 i += 1; 983 enc2 = keyStr64.indexOf(input.charAt(i)); 984 i += 1; 985 enc3 = keyStr64.indexOf(input.charAt(i)); 986 i += 1; 987 enc4 = keyStr64.indexOf(input.charAt(i)); 988 i += 1; 989 990 chr1 = (enc1 << 2) | (enc2 >> 4); //ignore jslint 991 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); //ignore jslint 992 chr3 = ((enc3 & 3) << 6) | enc4; //ignore jslint 993 994 output = output + String.fromCharCode(chr1); 995 996 if (enc3 !== 64) 997 { 998 output = output + String.fromCharCode(chr2); 999 } 1000 if (enc4 !== 64) 1001 { 1002 output = output + String.fromCharCode(chr3); 1003 } 1004 1005 chr1 = chr2 = chr3 = ""; 1006 enc1 = enc2 = enc3 = enc4 = ""; 1007 } 1008 while (i < input.length); 1009 1010 output = FoxEncoder.decodeUTF8(output); 1011 return output; 1012 }; //end FoxEncoder.decodeBase64andUTF8 1013 1014 // private method for UTF-8 encoding 1015 FoxEncoder.encodeUTF8 = function (string) 1016 { 1017 var utftext = "", 1018 n, 1019 c; 1020
1021 string = string.replace(/\r\n/g, "\n"); 1022 1023 1024 for (n = 0; n < string.length; n += 1) 1025 { 1026 1027 c = string.charCodeAt(n); 1028 1029 if (c < 128) 1030 { 1031 utftext += String.fromCharCode(c); 1032 } 1033 else if ((c > 127) && (c < 2048)) 1034 { 1035 utftext += String.fromCharCode((c >> 6) | 192); //ignore jslint 1036 utftext += String.fromCharCode((c & 63) | 128); //ignore jslint 1037 } 1038 else 1039 { 1040 utftext += String.fromCharCode((c >> 12) | 224); //ignore jslint 1041 utftext += String.fromCharCode(((c >> 6) & 63) | 128); //ignore jslint 1042 utftext += String.fromCharCode((c & 63) | 128); //ignore jslint 1043 } 1044 1045 } 1046 1047 return utftext; 1048 }; 1049 1050 // private method for UTF-8 decoding 1051 FoxEncoder.decodeUTF8 = function (utftext) 1052 { 1053 var string = "", 1054 i = 0, 1055 c = 0, 1056 c2 = 0, 1057 c3 = 0; 1058 1059 while (i < utftext.length) 1060 { 1061 1062 c = utftext.charCodeAt(i); 1063 1064 if (c < 128) 1065 { 1066 string += String.fromCharCode(c); 1067 i += 1; 1068 } 1069 else if ((c > 191) && (c < 224)) 1070 { 1071 c2 = utftext.charCodeAt(i + 1); 1072 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); //ignore jslint 1073 i += 2; 1074 } 1075 else 1076 { 1077 c2 = utftext.charCodeAt(i + 1); 1078 c3 = utftext.charCodeAt(i + 2); 1079 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); //ignore jslint 1080 i += 3; 1081 } 1082 1083 } 1084 1085 return string; 1086 }; 1087}(jQuery)); 1088 1089/////////////////////////////////////////////////////////////////////////////// 1090// FoxAjaxContent 1091/////////////////////////////////////////////////////////////////////////////// 1092 1093(function () 1094{ 1095 // "Static" Variables 1096 ////////////////////////////////////////////////////////////////////////////////////////////////// 1097 // Variables defined here are used by all fox ajax content instances on the page. 1098 1099 // class of the div wrapper 1100 FoxAjaxContent.loading_class = "fb_ajax_loading"; 1101 FoxAjaxContent.content_class = "fb_ajax_content"; 1102 1103 FoxAjaxContent.support_animate = true; 1104 1105 ////////////////////////////////////////////////////////////////////////////////////////////////// 1106 1107 1108 // "Static" Methods 1109 ////////////////////////////////////////////////////////////////////////////////////////////////// 1110 // Functions defined here are used by all fox ajax content instances on the page. 1111 1112 FoxAjaxContent.createFoxAjaxContent = function (guid, pagecontent_id, fullpath, oncompletecallback) 1113 { 1114 if (guid === undefined) 1115 { 1116 FBUtilities.LogMessage("FoxAjaxContent: creation error - guid undefined"); 1117 return null; 1118 } 1119 1120 if (pagecontent_id === undefined) 1121 { 1122 FBUtilities.LogMessage("FoxAjaxContent: creation error - pagecontent_id undefined"); 1123 return null; 1124 } 1125 1126 if (fullpath === undefined) 1127 { 1128 FBUtilities.LogMessage("FoxAjaxContent: creation error - fullpath undefined"); 1129 return null; 1130 } 1131 1132 if ('v' == '\v' /*jQuery.browser.msie*/) //ignore jslint 1133 { 1134 FoxAjaxContent.support_animate = false; 1135 } 1136 1137 var my_content = new FoxAjaxContent(); 1138 my_content.guid = guid; 1139 my_content.pagecontent_id = pagecontent_id; 1140 my_content.fullpath = fullpath; 1141 if (oncompletecallback !== undefined) 1142 { 1143 if (oncompletecallback !== undefined && typeof oncompletecallback === "function") 1144 { 1145 my_content.oncompletecallback = oncompletecallback; 1146 } 1147 } 1148 return my_content; 1149 }; 1150 1151 1152 // "Object" Variables
1153 ////////////////////////////////////////////////////////////////////////////////////////////////// 1154 // Variables defined here are used as unique copies in each instance of fox ajax content. 1155 // they are defined with these defaults, and may be modified after being instanciated 1156 // without effecting others. 1157 1158 1159 // id of the div where content is to be placed. 1160 FoxAjaxContent.prototype.guid = null; 1161 // name of the section which the contains the content. 1162 FoxAjaxContent.prototype.pagecontent_id = null; 1163 // url where the section is found (usually the current url) 1164 FoxAjaxContent.prototype.fullpath = null; 1165 1166 1167 ////////////////////////////////////////////////////////////////////////////////////////////////// 1168 1169 // Loads the requested content into the area, sending along requested parameters, if any. 1170 FoxAjaxContent.prototype.loadRequestedContent = function (params) 1171 { 1172 var lContentLoader, content_selector, loading_selector, fullpath, data, prop; 1173 1174 lContentLoader = this; 1175 content_selector = '#' + lContentLoader.guid + ' .' + FoxAjaxContent.content_class; 1176 loading_selector = '#' + lContentLoader.guid + ' .' + FoxAjaxContent.loading_class; 1177 1178 // animate fade out. 1179 if (FoxAjaxContent.support_animate) 1180 { 1181 jQuery(content_selector).animate( 1182 { opacity: 0.4 }, 1183 { duration: 250 }); 1184 } 1185 jQuery(loading_selector).show(250); 1186 1187 fullpath = lContentLoader.fullpath; 1188 data = { 1189 fco: '1', 1190 pcid: lContentLoader.pagecontent_id 1191 }; 1192 1193 if (params !== undefined) 1194 { 1195 if (typeof params === "object") 1196 { 1197 for (prop in params) 1198 { 1199 if (params.hasOwnProperty(prop)) 1200 { 1201 data[prop] = params[prop]; 1202 } 1203 } //endfor 1204 } 1205 //else if ( typeof ( params ) === "function" ) 1206 //{ 1207 // // function 1208 //} 1209 //else 1210 //{ 1211 // // number, string, or boolean 1212 //} 1213 } 1214 jQuery(content_selector).load(fullpath, data, function () 1215 { 1216 FBUtilities.initializeLoadables($(content_selector).get(0)); 1217 if (lContentLoader.oncompletecallback !== undefined) 1218 { 1219 if (typeof (lContentLoader.oncompletecallback) === "function") 1220 { 1221 lContentLoader.oncompletecallback(content_selector); 1222 } 1223 } 1224 // animate fade back 1225 if (FoxAjaxContent.support_animate) 1226 { 1227 jQuery(content_selector).animate( 1228 { opacity: 1.0 }, 1229 { duration: 250 }); 1230 } 1231 jQuery(loading_selector).hide(250); 1232 }); 1233 }; 1234}(jQuery)); 1235 1236/////////////////////////////////////////////////////////////////////////////// 1237// ThumbnailUtilities
1238/////////////////////////////////////////////////////////////////////////////// 1239 1240(function ($) 1241{ 1242 ThumbnailUtilities.RandomParamName = 'r'; 1243 ThumbnailUtilities.MaxWidthParamName = 'w'; 1244 ThumbnailUtilities.MaxHeightParamName = 'h'; 1245 ThumbnailUtilities.CropperOptionParamName = 'c'; 1246 ThumbnailUtilities.FullCropperOptionValue = 'f'; 1247 ThumbnailUtilities.ThumbnailCropperOptionValue = 't'; 1248 1249 ThumbnailUtilities.GetThumbnailUrl = function (aParameters) 1250 { 1251 1252 if (FBUtilities.IsParameterUndefinedOrEmpty(aParameters)) 1253 { 1254 FBUtilities.LogMessage('ThumbnailUtilities: Null or empty parameters sent.'); 1255 return; 1256 } 1257 1258 var lDefaults, lParameters, lUrl, lThumbnailParams; 1259 1260 lDefaults = { 1261 Url: null 1262 , MaxWidth: null 1263 , MaxHeight: null 1264 , AddRandomParam: false 1265 }; 1266 1267 lParameters = $.extend(lDefaults, aParameters); 1268 1269 if (FBUtilities.IsParameterUndefinedOrEmpty(lParameters.Url)) 1270 { 1271 FBUtilities.LogMessage('ThumbnailUtilities: Url not set.'); 1272 return; 1273 } 1274 1275 lUrl = lParameters.Url; 1276 lThumbnailParams = {}; 1277 lThumbnailParams[ThumbnailUtilities.CropperOptionParamName] = ThumbnailUtilities.ThumbnailCropperOptionValue; 1278 1279 if (!FBUtilities.IsParameterUndefinedOrEmpty(lParameters.MaxWidth)) 1280 { 1281 lThumbnailParams[ThumbnailUtilities.MaxWidthParamName] = lParameters.MaxWidth; 1282 } 1283 1284 if (!FBUtilities.IsParameterUndefinedOrEmpty(lParameters.MaxHeight)) 1285 { 1286 lThumbnailParams[ThumbnailUtilities.MaxHeightParamName] = lParameters.MaxHeight; 1287 } 1288 1289 if (lParameters.AddRandomParam === true) 1290 { 1291 lThumbnailParams[ThumbnailUtilities.RandomParamName] = Math.random(); 1292 } 1293 1294 return FBUtilities.BuildGetUrl(lUrl, lThumbnailParams); 1295 }; //end GetThumbnailUrl 1296 1297}(jQuery)); 1298 1299/////////////////////////////////////////////////////////////////////////////// 1300// FBUtilities
1301/////////////////////////////////////////////////////////////////////////////// 1302 1303(function ($) 1304{ 1305 FBUtilities.DebugMode = false; 1306 1307 let allowedTldArray = null; 1308 const defaultAllowedTlds = 'com,org,net,edu,gov,mil,us,academy,education,school'; 1309 1310 FBUtilities.GetAllowedTLDs = function () 1311 { 1312 if (allowedTldArray === null) 1313 { 1314 const allowed = FBUtilities.IsStringEmptyOrWhitespace(cmsAllowedEmailTlds) ? defaultAllowedTlds : cmsAllowedEmailTlds; 1315 let items = allowed.split(/[\s,;]+/) 1316 let update = []; 1317 for (let i = 0; i < items.length; i++) 1318 { 1319 let value = items[i]; 1320 if (value !== undefined && value !== null && (typeof value === 'string') && value.length !== 0) 1321 { 1322 update.push(value); 1323 } 1324 } 1325 1326 allowedTldArray = update; 1327 } 1328 1329 return allowedTldArray; 1330 }; 1331 1332 FBUtilities.IsParameterUndefined = function (aParameter) 1333 { 1334 if (aParameter === undefined) 1335 { 1336 return true; 1337 } 1338 return false; 1339 };//end IsParameterUndefined 1340 1341 FBUtilities.IsParameterUndefinedOrNull = function (aParameter) 1342 { 1343 return (aParameter === undefined || aParameter === null); 1344 };//end IsParameterUndefinedOrNull 1345 1346 FBUtilities.IsParameterUndefinedOrEmpty = function (aParameter) 1347 { 1348 return (aParameter === undefined || aParameter === null || aParameter.length === 0); 1349 };//end IsParameterUndefinedOrEmpty 1350 1351 FBUtilities.IsStringEmptyOrWhitespace = function (aParameter) 1352 { 1353 return (aParameter === undefined || aParameter === null || aParameter.length === 0 || $.trim(aParameter) === ''); 1354 };//end IsStringEmptyOrWhitespace 1355 1356 FBUtilities.AreStringsEqual = function (aFirst, aSecond, aCaseInsensitive) 1357 { 1358 if (typeof aFirst !== "string") 1359 { 1360 return false; 1361 } 1362 1363 if (typeof aSecond !== "string") 1364 { 1365 return false; 1366 } 1367 1368 let first = (aCaseInsensitive === true) ? aFirst.toLowerCase() : aFirst; 1369 let second = (aSecond === true) ? aFirst.toLowerCase() : aSecond; 1370 1371 return first === second; 1372 }; 1373 1374 1375 FBUtilities.GetIntOrNull = function (aParameter) 1376 { 1377 if (FBUtilities.IsParameterUndefinedOrEmpty(aParameter)) 1378 { 1379 return null; 1380 } 1381 1382 var lInt = parseInt(aParameter, 10); 1383 if (isNaN(lInt)) 1384 { 1385 return null; 1386 } 1387 1388 return lInt; 1389 };//end GetIntOrNull 1390 1391 FBUtilities.GetBoolOrNull = function (aParameter) 1392 { 1393 if (FBUtilities.IsParameterUndefinedOrEmpty(aParameter)) 1394 { 1395 return null; 1396 } 1397 1398 var lInput = aParameter; 1399 if (typeof lInput === 'string') 1400 { 1401 lInput = lInput.toLowerCase(); 1402 } 1403 switch (lInput) 1404 { 1405 case true: 1406 case "true": 1407 case 1: 1408 case "1": 1409 case "on": 1410 case "yes": 1411 return true; 1412 case false: 1413 case "false": 1414 case 0: 1415 case "0": 1416 case "off": 1417 case "no": 1418 return false; 1419 default: 1420 return null; 1421 }//endswitch 1422 }; //end GetBoolOrNull 1423 1424 FBUtilities.GetCallbackOrNull = function (aCallbacks, aName) 1425 { 1426 if (FBUtilities.IsParameterUndefinedOrEmpty(aCallbacks)) 1427 { 1428 return null; 1429 } 1430 1431 if (FBUtilities.IsParameterUndefinedOrNull(aCallbacks[aName])) 1432 { 1433 return null; 1434 } 1435 return aCallbacks[aName]; 1436 };//end GetCallbackOrNull 1437 1438 FBUtilities.HasCallback = function (aCallbacks, aName) 1439 { 1440 var lCallback = FBUtilities.GetCallbackOrNull(aCallbacks, aName); 1441 if (lCallback === null) 1442 { 1443 return false; 1444 } 1445 return true; 1446 };//end HasCallback 1447 1448 FBUtilities.RunCallback = function (aCallbacks, aName) 1449 { 1450 var lIndex, lCallback, lPassOnArgs; 1451 1452 FBUtilities.LogMessage('RunCallback - "' + aName + '"'); 1453
1454 lCallback = FBUtilities.GetCallbackOrNull(aCallbacks, aName); 1455 if (lCallback === null) 1456 { 1457 FBUtilities.LogMessage('RunCallback - "' + aName + '" - Not Found'); 1458 return; 1459 } 1460 1461 if (arguments.length > 2) 1462 { 1463 lPassOnArgs = []; 1464 for (lIndex = 2; (lIndex < arguments.length); lIndex += 1) 1465 { 1466 lPassOnArgs.push(arguments[lIndex]); 1467 } 1468 lCallback.apply(this, lPassOnArgs); 1469 } 1470 else 1471 { 1472 lCallback(); 1473 } 1474 };//end RunCallback 1475 1476 // DEPRECATED -- TODO REEVALUATE KEEPING THIS. // 1477 FBUtilities.YesNoValue = function (aElement) 1478 { 1479 if (FBUtilities.IsParameterUndefinedOrNull(aElement)) 1480 { 1481 return; 1482 } 1483 1484 var lId, lIsRadio; 1485 1486 lId = aElement.attr('id'); 1487 lIsRadio = aElement.hasClass('yesnoradio'); 1488 1489 if (FBUtilities.IsParameterUndefinedOrEmpty(lId)) 1490 { 1491 return; 1492 } 1493 1494 if (lIsRadio) 1495 { 1496 if (aElement.find('#' + lId + '_yes:checked').length === 1) 1497 { 1498 return true; 1499 } 1500 if (aElement.find('#' + lId + '_no:checked').length === 1) 1501 { 1502 return false; 1503 } 1504 } 1505 1506 return null; 1507 };//end YesNoValue 1508 1509 // Replaces an item in an array with a replacement item. 1510 // Assumes uniqueness, i.e. only the first item will 1511 // be replaced. 1512 // Array: Array to act on, changes are made in place. 1513 // If undefined or null, returns. 1514 // Parameters: (If undefined or null, returns.) 1515 // Item - Item in the array to replace, if not defined 1516 // (or not found), the Replacement will be put 1517 // at the end of the array. 1518 // Replacement - Replacement item for the array. If 1519 // undefined, the Item will simply be deleted. 1520 FBUtilities.ReplaceArrayItem = function (aArray, aParameters) 1521 { 1522 if (FBUtilities.IsParameterUndefinedOrNull(aArray)) 1523 { 1524 return; 1525 } 1526 1527 if (FBUtilities.IsParameterUndefinedOrNull(aParameters)) 1528 { 1529 return; 1530 } 1531 1532 var lDeleteCount, lStart, lIndex; 1533 1534 lDeleteCount = 0; 1535 lStart = aArray.length; 1536 1537 if (!FBUtilities.IsParameterUndefined(aParameters.Item)) 1538 { 1539 lDeleteCount = 1; 1540 } 1541 1542 if (!FBUtilities.IsParameterUndefined(aParameters.Replacement)) 1543 { 1544 for (lIndex = 0; lIndex < aArray.length; lIndex += 1) 1545 { 1546 if (aArray[lIndex] === aParameters.Replacement) 1547 { 1548 lStart = lIndex; 1549 break; 1550 } 1551 }//endfor 1552 1553 aArray.splice(lStart, lDeleteCount, aParameters.Replacement); 1554 } 1555 else 1556 { 1557 aArray.splice(lStart, lDeleteCount); 1558 } 1559 }; //end ReplaceArrayItem 1560 1561 // Converts a hash array into a string using the separators given. 1562 // Parameters: 1563 // aHashArray - (If undefined, null or empty, blank is returned.) 1564 // aEntrySeparator - Separator to appear between each entry. 1565 // (If undefined, null, or blank, ';' is used.) 1566 // aPairSeparator - Separator to appear between the key and value in each pair. 1567 // (If undefined, null, or blank, '=' is used.) 1568 // 1569 // Example: 1570 // "key1=value1;key2=value2" 1571 FBUtilities.JoinHashArray = function (aHashArray, aEntrySeparator, aPairSeparator) 1572 { 1573 var lResult = '', 1574 lEntrySeparator = ';', 1575 lPairSeparator = '=', 1576 lKey; 1577 1578 if (FBUtilities.IsParameterUndefinedOrEmpty(aHashArray)) 1579 { 1580 return lResult; 1581 } 1582 1583 if (!FBUtilities.IsParameterUndefinedOrEmpty(aEntrySeparator)) 1584 { 1585 lEntrySeparator = aEntrySeparator; 1586 } 1587 1588 if (!FBUtilities.IsParameterUndefinedOrEmpty(aPairSeparator)) 1589 { 1590 lPairSeparator = aPairSeparator; 1591 } 1592 1593 for (lKey in aHashArray) 1594 { 1595 if (aHashArray.hasOwnProperty(lKey)) 1596 { 1597 lResult += lKey; 1598 lResult += lPairSeparator; 1599 lResult += aHashArray[lKey]; 1600 lResult += lEntrySeparator; 1601 } 1602 }//endfor 1603 1604 return lResult; 1605 };//end JoinHashArray 1606 1607 // Converts a hash array into a GET url string. 1608 // Parameters: 1609 // aUrl - The url the parameters are to be appended to. 1610 // (If undefined or null it is returned. If empty or 1611 // full, parameters [if any] are appended) 1612 // aParameters - GET params to be appended to the url. 1613 FBUtilities.BuildGetUrl = function (aUrl, aParameters) 1614 { 1615 var lResult, lParamString; 1616 1617 lResult = aUrl;
1618 if (FBUtilities.IsParameterUndefinedOrNull(aUrl)) 1619 { 1620 FBUtilities.LogMessage('BuildGetUrl: Null or undefined url.'); 1621 return lResult; 1622 } 1623 1624 if (FBUtilities.IsParameterUndefinedOrNull(aParameters)) 1625 { 1626 FBUtilities.LogMessage('BuildGetUrl: Null or undefined parameters.'); 1627 return lResult; 1628 } 1629 1630 lParamString = FBUtilities.JoinHashArray(aParameters, '&'); 1631 if (lParamString.length > 0) 1632 { 1633 lParamString = '?' + lParamString; 1634 } 1635 1636 return lResult + lParamString; 1637 }; //end BuildGetUrl 1638 1639 FBUtilities.CombinePath = function (...segments) 1640 { 1641 let combined = ''; 1642 for (const segment of segments) 1643 { 1644 if (!FBUtilities.IsStringEmptyOrWhitespace(segment)) 1645 { 1646 combined = combined.replace(/\/+$/, '') + '/' + segment.replace(/^\/+/, ''); 1647 } 1648 } 1649 return combined; 1650 }; 1651 FBUtilities.LogMessage = function (aMessage) 1652 { 1653 if (FBUtilities.DebugMode === false) 1654 { 1655 return; 1656 } 1657 1658 if (window.console 1659 && window.console.log) 1660 { 1661 window.console.log(aMessage); 1662 } 1663 }; //end LogMessage 1664 1665 1666 FBUtilities.GetPageSize = function () 1667 { 1668 var lXScroll, 1669 lYScroll, 1670 lWindowWidth, 1671 lWindowHeight, 1672 lPageWidth, 1673 lPageHeight, 1674 self = window, 1675 lArrayPageSize; 1676 1677 if (window.innerHeight 1678 && window.scrollMaxY) 1679 { 1680 lXScroll = document.body.scrollWidth; 1681 lYScroll = window.innerHeight + window.scrollMaxY; 1682 } 1683 else if (document.body.scrollHeight > document.body.offsetHeight) 1684 { 1685 // all but Explorer Mac 1686 lXScroll = document.body.scrollWidth; 1687 lYScroll = document.body.scrollHeight; 1688 } 1689 else 1690 { 1691 // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari 1692 lXScroll = document.body.offsetWidth; 1693 lYScroll = document.body.offsetHeight; 1694 } 1695 1696 1697 if (self.innerHeight) 1698 { 1699 // all except Explorer 1700 lWindowWidth = self.innerWidth; 1701 lWindowHeight = self.innerHeight; 1702 } 1703 else if (document.documentElement 1704 && document.documentElement.clientHeight) 1705 { 1706 // Explorer 6 Strict Mode 1707 lWindowWidth = document.documentElement.clientWidth; 1708 lWindowHeight = document.documentElement.clientHeight; 1709 } 1710 else if (document.body) 1711 { 1712 // other Explorers 1713 lWindowWidth = document.body.clientWidth; 1714 lWindowHeight = document.body.clientHeight; 1715 } 1716 1717 // for small pages with total height less then height of the viewport 1718 if (lYScroll < lWindowHeight) 1719 { 1720 lPageHeight = lWindowHeight; 1721 } 1722 else 1723 { 1724 lPageHeight = lYScroll; 1725 } 1726 1727 // for small pages with total width less then width of the viewport 1728 if (lXScroll < lWindowWidth) 1729 { 1730 lPageWidth = lWindowWidth; 1731 } 1732 else 1733 { 1734 lPageWidth = lXScroll; 1735 } 1736 1737 lArrayPageSize = [lPageWidth, lPageHeight, lWindowWidth, lWindowHeight]; 1738 return lArrayPageSize; 1739 };//end GetPageSize 1740 1741 FBUtilities.GetPageScroll = function () 1742 { 1743 var lYScroll, 1744 self = window, 1745 lArrayPageScroll; 1746 1747 if (self.pageYOffset) 1748 { 1749 lYScroll = self.pageYOffset; 1750 } 1751 else if (document.documentElement 1752 && document.documentElement.scrollTop) 1753 { 1754 // Explorer 6 Strict 1755 lYScroll = document.documentElement.scrollTop; 1756 } 1757 else if (document.body) 1758 { 1759 // all other Explorers 1760 lYScroll = document.body.scrollTop; 1761 } 1762 1763 lArrayPageScroll = ['', lYScroll]; 1764 return lArrayPageScroll; 1765 };//end GetPageScroll 1766 1767 FBUtilities.SetupStickyNav = function (aHeaderSelector, aStickyNav
1767Selector) 1768 { 1769 var lHeader = $(aHeaderSelector); 1770 if (lHeader.length === 0) 1771 { 1772 return; 1773 } 1774 1775 var lStickyNav = $(aStickyNavSelector); 1776 if (lStickyNav.length === 0) 1777 { 1778 return; 1779 } 1780 1781 var lHeaderHeight = lHeader.outerHeight(); 1782 var lStickyNavHeight = lStickyNav.outerHeight(); 1783 1784 if (lHeaderHeight === 0 1785 || lStickyNavHeight === 0 1786 || lHeaderHeight < lStickyNavHeight) 1787 { 1788 return; 1789 } 1790 1791 var lAboveHeight = lHeaderHeight; 1792 1793 1794 var lUpdateStickyNav = function () 1795 { 1796 //if the page size is too small, remove modifiers 1797 if (window.innerWidth < 768) 1798 { 1799 lStickyNav.removeClass('fixed_menu'); 1800 } 1801 else 1802 { 1803 lHeaderHeight = lHeader.outerHeight(); 1804 lAboveHeight = lHeaderHeight; 1805 } 1806 }; 1807 1808 $(window).scroll( 1809 function () 1810 { 1811 //if (Modernizr.mq('(max-width: 767px)')) { 1812 if ($(window).width() < 768) 1813 { 1814 return; 1815 } 1816 1817 //if scrolled down more than the headerâs height 1818 if ($(window).scrollTop() > lAboveHeight) 1819 { 1820 // if yes, add sticky class to the sticky nav 1821 lStickyNav.addClass('fixed_menu'); 1822 $('.main_menu .top_level_item > .drop_down').css('max-height', 'calc(100vh - ' + lStickyNavHeight + 'px'); 1823 } 1824 else 1825 { 1826 // when scroll up or less than lAboveHeight, remove the sticky class 1827 lStickyNav.removeClass('fixed_menu'); 1828 } 1829 } 1830 ); 1831 1832 $(window).resize(lUpdateStickyNav); 1833 lUpdateStickyNav(); 1834 };//end SetupStickyNav 1835 1836 FBUtilities.SetupStickyHeader = function (aHeaderSelector, aPaddingSelector) 1837 { 1838 var lHeader = $(aHeaderSelector); 1839 if (lHeader.length === 0) 1840 { 1841 return; 1842 } 1843 1844 var lPaddedElement = $(aPaddingSelector); 1845 if (lPaddedElement.length === 0) 1846 { 1847 return; 1848 } 1849 1850 var lHeaderHeight = lHeader.outerHeight(); 1851 1852 if (lHeaderHeight === 0) 1853 { 1854 return; 1855 } 1856 1857 var lMainNavClass = 'nav-main'; 1858 if ($('.' + lMainNavClass).length === 0) 1859 { 1860 lMainNavClass = 'main-nav'; 1861 } 1862 if ($('.' + lMainNavClass).length === 0) 1863 { 1864 lMainNavClass = null; 1865 } 1866 1867 var lUpdateStickyHeader = function () 1868 { 1869 //if the page size is too small, remove modifiers 1870 if (window.innerWidth < 768) 1871 { 1872 lHeader.removeClass('fixed_header'); 1873 $('.fixed_header_padded').css('padding-top', ''); 1874 if (lMainNavClass !== null) 1875 { 1876 $('.' + lMainNavClass + ' .top_level_item > .drop').css('max-height', 'none'); 1877 } 1878 lPaddedElement.removeClass('fixed_header_padded'); 1879 //if there might be some other dynamic styling, set the styled bits to "". 1880 } 1881 else 1882 { 1883 // if yes, modify the stuff 1884 lHeader.addClass('fixed_header'); 1885 lPaddedElement.addClass('fixed_header_padded'); 1886 1887 // remove shrink class before measuring header height 1888 lHeader.removeClass('shrink'); 1889 lHeaderHeight = lHeader.outerHeight(); 1890 $("body").css("--StickyHeader-Height", "" + lHeaderHeight + "px"); 1891 1892 if ($(document).scrollTop() > 50) 1893 { 1894 lHeader.addClass("shrink"); 1895 } 1896 1897 $('.fixed_header_padded').css('padding-top', lHeaderHeight + 'px'); 1898 if (lMainNavClass !== null) 1899 { 1900 //$('.' + lMainNavClass + ' .top_level_item > .drop').attr("tabindex", "1");// Not sure why this was here. Removed for #16028 1901 $('.' + lMainNavClass + ' .top_level_item > .drop').css('max-height', 'calc(100vh - ' + lHeaderHeight + 'px'); 1902 } 1903 } 1904 }; 1905 1906 // https://codepen.io/tomdurkin/pen/nvAjd 1907 $(document).on("scroll", function () 1908 { 1909 if 1910 ($(document).scrollTop() > 50) 1911 { 1912 lHeader.addClass("shrink"); 1913 } 1914 else 1915 { 1916 lHeader.removeClass("shrink"); 1917 } 1918 }); 1919 1920 $(window).resize(lUpdateStickyHeader); 1921 lUpdateStickyHeader(); 1922 };//end SetupStickyHeader 1923 1924 // Sticky Header and Focus area with content that scrolls up between the two 1925 // - lUpdateFocusHeight helps define dimensions of a rotator 1926 // which doesn't have a height of its own when sticky due to absolute positioned images 1927 // - This does require some skin-level css 1928 FBUtilities.SetupStickyFocus = function (aHeaderSelector, aFocusWrapperSelector, aFocusSelector) 1929 { 1930 var lHeader = $(aHeaderSelector); 1931 if (lHeader.length === 0) 1932 { 1933 return; 1934 } 1935 1936 var lFocusWrapperElement = $(aFocusWrapperSelector); 1937 if (lFocusWrapperElement.length === 0) 1938 { 1939 return; 1940 } 1941 1942 var lFocusElement = $(aFocusSelector); 1943 if (lFocusElement.length === 0) 1944 { 1945 return; 1946 } 1947 1948 var lHeaderHeight = lHeader.outerHeight(); 1949 1950 if (lHeaderHeight === 0) 1951 { 1952 return; 1953 } 1954 1955 var lFocusHeight = 0; 1956 1957 var lUpdateFocusHeight = function () 1958 { 1959 lFocusWrapperElement.removeClass('fixed_focus_wrapper'); 1960 lFocusElement.removeClass('fixed_focus'); 1961 lFocusHeight = lFocusElement.outerHeight(); 1962 if (lFocusHeight === 0) 1963 { 1964 return; 1965 } 1966 } 1967 1968 var lMainNavClass = 'nav-main'; 1969 if ($('.' + lMainNavClass).length === 0) 1970 { 1971 lMainNavClass = 'main-nav'; 1972 } 1973 if ($('.' + lMainNavClass).length === 0) 1974 { 1975 lMainNavClass = null; 1976 } 1977 1978 var lUpdateStickyContent = function () 1979 { 1980 //if the page size is too small, remove modifiers 1981 if (window.innerWidth < 768) 1982 { 1983 lHeader.removeClass('fixed_header'); 1984 $('.fixed_focus_wrapper').css('padding-bottom', ''); 1985 if (lMainNavClass !== null) 1986 { 1987 $('.' + lMainNavClass + ' .top_level_item > .drop').css('max-height', 'none'); 1988 } 1989 lFocusWrapperElement.removeClass('fixed_focus_wrapper'); 1990 lFocusElement.removeClass('fixed_focus'); 1991 //if there might be some other dynamic styling, set the styled bits to "". 1992 } 1993 else 1994 { 1995 // if yes, modify the stuff 1996 lHeader.addClass('fixed_header'); 1997 lUpdateFocusHeight(); 1998 lFocusWrapperElement.addClass('fixed_focus_wrapper'); 1999 lHeaderHeight = lHeader.outerHeight(); 2000 $('.fixed_focus_wrapper').css('padding-bottom', lFocusHeight + 'px'); 2001 lFocusElement.addClass('fixed_focus'); 2002 $('.home_focus').css('padding-bottom', '0'); 2003 if (lMainNavClass !== null) 2004 { 2005 //$('.' + lMainNavClass + ' .top_level_item > .drop').attr("tabindex", "1");// Not sure why this was here. Removed for #16028 2006 $('.' + lMainNavClass + ' .top_level_item > .drop').css('max-height', 'calc(100vh - ' + lHeaderHeight + 'px'); 2007 } 2008 } 2009 }; 2010 2011 // https://codepen.io/tomdurkin/pen/nvAjd 2012 $(document).on("scroll", function () 2013 { 2014 if 2015 ($(document).scrollTop() > 50) 2016 { 2017 $("header").addClass("shrink"); 2018 } 2019 else 2020 { 2021 $("header").removeClass("shrink"); 2022 } 2023 }); 2024 2025 $(window).resize(lUpdateStickyContent); 2026 lUpdateStickyContent(); 2027 };//end SetupStickyFocus 2028 2029 // Date related functions. 2030 const REGEX_TIME_24 = new RegExp(/^([0-2][0-9]):([0-5][0-9])$/); 2031 const REGEX_TIME_12 = new RegExp(/^(?:1[0-2]|0?[1-9]):[0-5][0-9] [aApP][mM]$/); 2032 2033 FBUtilities.IsDateBeforeOrEqual = function (startDateString, endDateString, granularity) 2034 { 2035 if (FBUtilities.IsStringEmptyOrWhitespace(startDateString) || FBUtilities.IsStringEmptyOrWhitespace(endDateString)) 2036 { 2037 return false; 2038 } 2039 2040 const luxonStart = FBUtilities.ParseDateString(startDateString); 2041 const luxonEnd = FBUtilities.ParseDateString(endDateString); 2042 return luxonStart.isValid && luxonEnd.isValid && (luxonStart.startOf(granularity) <= luxonEnd.startOf(granularity)); 2043 }; 2044 2045 FBUtilities.IsDateAndTimeBeforeOrEqual = function (startDate, startTime, endDate, endTime, granularity) 2046 { 2047 if (FBUtilities.IsStringEmptyOrWhitespace(startDate) 2048 || FBUtilities.IsStringEmptyOrWhitespace(startTime) 2049 || FBUtilities.IsStringEmptyOrWhitespace(endDate) 2050 || FBUtilities.IsStringEmptyOrWhitespace(endTime) 2051 ) 2052 { 2053 return false; 2054 } 2055 2056 const luxonStart = FBUtilities.ParseDateTimeString(`${startDate} ${startTime}`); 2057 const luxonEnd = FBUtilities.ParseDateTimeString(`${endDate} ${endTime}`); 2058 return luxonStart.isValid && luxonEnd.isValid && (luxonStart.startOf(granularity) <= luxonEnd.startOf(granularity)); 2059 }; 2060 2061
2062 FBUtilities.IsTimeString = function (timeString) 2063 { 2064 return !FBUtilities.IsStringEmptyOrWhitespace(timeString) && (REGEX_TIME_24.test(timeString) || REGEX_TIME_12.test(timeString)); 2065 }; 2066 2067 FBUtilities.ParseDateTimeString = function (dateTimeString) 2068 { 2069 const formats = [ 2070 'yyyy-MM-dd HH:mm', 2071 'MM-dd-yyyy HH:mm', 2072 'yyyy-MM-dd H:mm', 2073 'MM-dd-yyyy H:mm', 2074 'yyyy-MM-dd hh:mm a', 2075 'MM-dd-yyyy hh:mm a', 2076 'yyyy-MM-dd h:mm a', 2077 'MM-dd-yyyy h:mm a' 2078 ]; 2079 let dateTime = luxon.DateTime.invalid; 2080 for(const format of formats) 2081 { 2082 dateTime = luxon.DateTime.fromFormat(`${dateTimeString}`, format); 2083 if (dateTime.isValid) 2084 { 2085 break; 2086 } 2087 } 2088 return dateTime; 2089 }; 2090 2091 FBUtilities.ParseDateString = function (dateString) 2092 { 2093 const formats = ['MM/dd/yyyy', 'MM-dd-yyyy', 'yyyy-MM-dd']; 2094 let date = luxon.DateTime.invalid; 2095 for(const format of formats) 2096 { 2097 date = luxon.DateTime.fromFormat(`${dateString}`, format); 2098 if (date.isValid) 2099 { 2100 break; 2101 } 2102 } 2103 return date; 2104 }; 2105 2106 FBUtilities.IsDateString = function (dateString) 2107 { 2108 return FBUtilities.ParseDateString(dateString).isValid; 2109 }; 2110 2111 FBUtilities.ReformatToStandardDateString = function (dateString) 2112 { 2113 const date = FBUtilities.ParseDateString(dateString); 2114 return date.toFormat('MM/dd/yyyy'); 2115 }; 2116 2117 FBUtilities.ReformatToLongDateString = function (dateString) 2118 { 2119 const date = FBUtilities.ParseDateString(dateString); 2120 return date.toFormat('"cccc, MMMM d yyyy'); 2121 }; 2122 2123 FBUtilities.ParseTimeString = function (timeString) 2124 { 2125 const formats = ['HH:mm', 'H:mm', 'hh:mm a', 'h:mm a']; 2126 let time = luxon.DateTime.invalid; 2127 for(const format of formats) 2128 { 2129 time = luxon.DateTime.fromFormat(`${timeString}`, format); 2130 if (time.isValid) 2131 { 2132 break; 2133 } 2134 } 2135 return time; 2136 }; 2137
2138 FBUtilities.ReformatToStandardTimeString = function (timeString) 2139 { 2140 const date = FBUtilities.ParseTimeString(timeString); 2141 return date.toFormat('h:mm a'); 2142 }; 2143 2144 FBUtilities.IsHtmlDateField = function (aField) 2145 { 2146 let isHtmlDateField; 2147 if (aField === undefined) 2148 { 2149 isHtmlDateField = false; 2150 } 2151 else if (aField === null) 2152 { 2153 isHtmlDateField = false; 2154 } 2155 else if ($(aField).attr('type') !== 'date') 2156 { 2157 isHtmlDateField = false; 2158 } 2159 else if ($(aField).prop('type') !== 'date') 2160 { 2161 isHtmlDateField = false; 2162 } 2163 else 2164 { 2165 isHtmlDateField = true; 2166 } 2167 return isHtmlDateField; 2168 }; 2169 2170 FBUtilities.IsHtmlTimeField = function (aField) 2171 { 2172 let isTimeField; 2173 if (aField === undefined) 2174 { 2175 isTimeField = false; 2176 } 2177 else if (aField === null) 2178 { 2179 isTimeField = false; 2180 } 2181 else if ($(aField).attr('type') !== 'time') 2182 { 2183 isTimeField = false; 2184 } 2185 else if ($(aField).prop('type') !== 'time') 2186 { 2187 isTimeField = false; 2188 } 2189 else 2190 { 2191 isTimeField = true; 2192 } 2193 return isTimeField; 2194 }; 2195 2196 2197 2198 2199 /** 2200 * Updates the style of the widget overlay underneath a jquery dialog. This method 2201 * ensures that the overlay has a reasonable zindex and is semi-opaque. 2202 * @param {any} the jquery dialog. 2203 */ 2204 FBUtilities.UpdateWidgetOverlayStyle = function (dialog) 2205 { 2206 let dialogIndex = window.getComputedStyle(dialog).getPropertyValue('z-index'); 2207 if (!Number.isInteger(dialogIndex)) 2208 { 2209 dialogIndex = $(dialog)[0].style.zIndex; 2210 if (!Number.isInteger(dialogIndex)) 2211 { 2212 dialogIndex = 100; 2213 } 2214 } 2215 2216 let overlayIndex = dialogIndex - 1; 2217 $(".ui-widget-overlay").attr('style', `background-color: #000; opacity:0.6; z-index:${overlayIndex};`); 2218 }; 2219 2220 // appends the markup given to the DOM element given. 2221 // Does nothing if either is null or markup is whitespace. 2222 FBUtilities.AppendMarkup = function (aElement, aMarkup) 2223 { 2224 if (FBUtilities.IsParameterUndefinedOrNull(aElement) === true) 2225 { 2226 return; 2227 } 2228 var lNewElement = FBUtilities.BuildDomElement(aMarkup); 2229 if (lNewElement === null) 2230 { 2231 return; 2232 } 2233 aElement.appendChild(lNewElement); 2234 }; 2235 2236 // Returns a loose DOM element (child of a Template) built from the markup given. 2237 // Returns null if markup is null or whitespace. 2238 FBUtilities.BuildDomElement = function (aMarkup) 2239 { 2240 if (FBUtilities.IsStringEmptyOrWhitespace(aMarkup) === true) 2241 { 2242 return null; 2243 } 2244 var tempDiv = document.createElement('template'); 2245 tempDiv.innerHTML = aMarkup.trim(); 2246 return tempDiv.content.firstChild; 2247 }; 2248 2249 // Returns valid Foxbright Icons markup. 2250 // Returns an empty string if the icon url or title are null or empty. 2251 FBUtilities.BuildFBIconMarkup = function (aIconUrl, aTitle, aAdditionalClasses) 2252 { 2253 if (FBUtilities.IsStringEmptyOrWhitespace(aIconUrl) === true 2254 || FBUtilities.IsStringEmptyOrWhitespace(aTitle) === true) 2255 { 2256 return ''; 2257 } 2258 let lAdditionalClasses = ''; 2259 if (FBUtilities.IsStringEmptyOrWhitespace(aAdditionalClasses) === false) 2260 { 2261 lAdditionalClasses = ' ' + aAdditionalClasses.trim(); 2262 } 2263 return `<span class="fb-icon${lAdditionalClasses}" title="${aTitle}"><load-file replaceWith src="${aIconUrl}"></load-file></span>`; 2264 }; 2265 2266 function _getVersionedStorageObjectKey(itemName) 2267 { 2268 const version = typeof cmsVersion !== 'undefined' ? cmsVersion : "website"; 2269 return `${itemName}_${version}`; 2270 } 2271 2272 FBUtilities.getLocalStorageObject = function (itemName) 2273 { 2274 let result = undefined;
2275 const key = _getVersionedStorageObjectKey(itemName); 2276 const item = localStorage.getItem(key); 2277 if (item !== null) 2278 { 2279 const jsonString = FoxEncoder.decodeBase64andUTF8(item); 2280 result = JSON.parse(jsonString); 2281 } 2282 return result; 2283 }; 2284 2285 FBUtilities.setLocalStorageObject = function (itemName, dataObject) 2286 { 2287 const key = _getVersionedStorageObjectKey(itemName); 2288 const jsonString = JSON.stringify(dataObject); 2289 const base64value = FoxEncoder.encodeUTF8andBase64(jsonString); 2290 localStorage.setItem(key, base64value); 2291 }; 2292 2293 FBUtilities.removeLocalStorageObject = function (itemName) 2294 { 2295 const key = _getVersionedStorageObjectKey(itemName); 2296 localStorage.removeItem(key); 2297 }; 2298 2299 let lastServerCheckedTime = null; 2300 2301 function _showCheckServerAlert(message) 2302 { 2303 const alertClasses = [ 2304 'alert-primary', 2305 'alert-secondary', 2306 'alert-success', 2307 'alert-danger', 2308 'alert-warning', 2309 'alert-info', 2310 'alert-light', 2311 'alert-dark', 2312 ]; 2313 2314 const alertElement = $('#admincp_alert'); 2315 const wantClass = 'alert-warning'; 2316 const previouslyShown = !alertElement.hasClass("d-none"); 2317 const previouslySameClass = alertElement.hasClass(wantClass); 2318 const previouslySameMessage = alertElement.html() === message; 2319 2320 if (!previouslySameClass) 2321 { 2322 alertClasses.forEach(classname => 2323 { 2324 if (classname !== wantClass) 2325 { 2326 alertElement.removeClass(classname) 2327 } 2328 }); 2329 alertElement.addClass(wantClass); 2330 } 2331 2332 if (!previouslySameMessage) 2333 { 2334 alertElement.html(message); 2335 } 2336 2337 if (!previouslyShown) 2338 { 2339 alertElement.removeClass("d-none"); 2340 } 2341 2342 if (!previouslyShown || !previouslySameClass || !previouslySameMessage) 2343 { 2344 alert(message); 2345 } 2346 } 2347 2348 function _checkServer() 2349 { 2350 $.ajax({
2351 type: "get", 2352 url: "/Admin/Home/Check", 2353 dataType: "json", 2354 async: true, 2355 error: function (jqXHR, textStatus, errorThrown) 2356 { 2357 if (jqXHR.status === 401 || jqXHR.status === 403) 2358 { 2359 console.info(`Logging out. No longer authorized by server.`); 2360 document.location = '/Admin/Logout'; 2361 return; 2362 } 2363 console.log(`${textStatus}: ${errorThrown}`); 2364 }, 2365 success: function (data, _textStatus, _jqXHR) 2366 { 2367 if (data.version !== undefined && data.version !== cmsVersion) 2368 { 2369 console.info(`Logging out. Server was upgraded to version ${data.version}.`); 2370 document.location = '/Admin/Logout'; 2371 return; 2372 } 2373 2374 if (data.status !== undefined && data.status !== 'ok') 2375 { 2376 console.info(`_checkServer: ${data.status} ${data.message}`); 2377 _showCheckServerAlert(data.message); 2378 } 2379 }, 2380 complete: function () 2381 { 2382 const currentTime = Date.now(); 2383 if (lastServerCheckedTime !== null) 2384 { 2385 var elapsedTime = currentTime - lastServerCheckedTime; 2386 if (elapsedTime > cmsCheckServerMaxEllapsedMilli) 2387 { 2388 console.info(`Logging out. Server last checked ${elapsedTime}ms ago.`); 2389 document.location = '/Admin/Logout'; 2390 return; 2391 } 2392 } 2393 lastServerCheckedTime = currentTime; 2394 } 2395 }); 2396 setTimeout(_checkServer, 15000); 2397 }; 2398 2399 FBUtilities.startCheckServer = function () 2400 { 2401 const pathname = document.location.pathname; 2402 if (pathname.toLowerCase().startsWith('/admin/')) 2403 { 2404 setTimeout(_checkServer, 10); 2405 } 2406 }; 2407 2408}(jQuery)); 2409 2410/////////////////////////////////////////////////////////////////////////////// 2411// FBAjaxDialog 2412/////////////////////////////////////////////////////////////////////////////// 2413function FBAjaxDialog() 2414{ 2415 this._vars = { 2416 AjaxRequestObject: null, 2417 BackdropClass: "backdrop", 2418 CloseButtonClass: 'fbd_close', 2419 CurrentCallbacks: null, 2420 DataOptionsName: "fbd-dialog-options", 2421 DialogClass: 'fbd_dialog', 2422 DialogId: 'fbd_ajaxdialog', 2423 TitleClass: 'fbd_title' 2424 }; 2425 2426 this.options = { 2427 ActionType: 'GET', 2428 AjaxUrl: null, 2429 Data: null, 2430 ErrorContent: null, 2431 ErrorDialogCallbacks: null, 2432 ErrorDialogTitle: 'Error', 2433 ExtraDialogClasses: null, 2434 LoadingContent: null, 2435 LoadingDialogCallbacks: null, 2436 LoadingDialogTitle: 'Loading...', 2437 OnCloseCallback: null, 2438 SuccessDialogCallbacks: null, 2439 SuccessDialogTitle: 'Detail', 2440 ParentSelector: "body", 2441 SelectionElement: null 2442 }; 2443} 2444 2445(function ($) 2446{ 2447 FBAjaxDialog._activeDialogs = { 2448 }; 2449 2450 FBAjaxDialog.FindAndClose = function (aDialogId) 2451 { 2452 let dialogId = aDialogId === undefined ? 'fbd_ajaxdialog' : aDialogId; 2453 if (FBAjaxDialog._activeDialogs[dialogId] !== undefined) 2454 { 2455 FBAjaxDialog._activeDialogs[dialogId].Close(); 2456 } 2457 }; 2458 2459 FBAjaxDialog.prototype.Start = function (options) 2460 { 2461 let self = this; 2462 self.options = $.extend({}, self.options, options); 2463 2464 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.LoadingContent)) 2465 { 2466 console.debug("The LoadingContent value was not specified."); 2467 return; 2468 } 2469 2470 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.AjaxUrl)) 2471 { 2472 console.debug("The AjaxUrl value was not specified."); 2473 return; 2474 } 2475 2476 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.ErrorContent)) 2477 { 2478 console.debug("The ErrorContent value was not specified."); 2479 return; 2480 } 2481 2482 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.ActionType)) 2483 { 2484 console.debug("The ActionType value was not specified."); 2485 return; 2486 } 2487 2488 self.options.Data = self.options.Data === undefined ? {} : self.options.Data; 2489 self._showLoadingContent(); 2490 self._vars.AjaxRequestObject = $.ajax( 2491 self.options.AjaxUrl, 2492 { 2493 success: function (aData, _aTextStatus, _aJqXHR) 2494 { 2495 self._showSuccessContent(aData); 2496 }, 2497 error: function (_aJqXHR, _aTextStatus, _aErrorThrown) 2498 { 2499 self._showErrorContent(); 2500 }, 2501 complete: function (_aData, _aTextStatus, _aJqXHR) 2502 { 2503 self._vars.AjaxRequestObject = null; 2504 }, 2505 type: self.options.ActionType, 2506 data: self.options.Data 2507 }); 2508 }; 2509 2510 FBAjaxDialog.prototype.Close = function () 2511 { 2512 let dialog = $(`#${this._vars.DialogId}`); 2513 if (dialog.length === 0) 2514 { 2515 return; 2516 } 2517 2518 if (this._vars.AjaxRequestObject !== undefined && this._vars.AjaxRequestObject !== null) 2519 { 2520 this._vars.AjaxRequestObject.abort(); 2521 this._vars.AjaxRequestObject = null; 2522 } 2523 2524 if (dialog.is(':visible')) 2525 { 2526 dialog.hide(); 2527 dialog.next('.backdrop').remove(); 2528 } 2529 2530 FBUtilities.RunCallback(this._vars.CurrentCallbacks, 'OnClose', dialog); 2531 2532 if (this._vars.OnCloseCallback !== undefined && this._vars.OnCloseCallback !== null && typeof this._vars.OnCloseCallback === 'function') 2533 { 2534 this._vars.OnCloseCallback(); 2535 } 2536 2537 $(dialog).vpFocusManager("dropFocus"); 2538 $(dialog).vpFocusManager("destroy"); 2539 dialog.remove(); 2540 delete FBAjaxDialog._activeDialogs[this._vars.DialogId];
2541 2542 2543 }; 2544 2545 FBAjaxDialog.prototype._showErrorContent = function () 2546 { 2547 this._show( 2548 this.options.ErrorContent, 2549 { 2550 ExtraDialogClasses: this.options.ExtraDialogClasses, 2551 Title: this.options.ErrorDialogTitle, 2552 CloseButtonText: 'Close', 2553 Callbacks: this.options.ErrorDialogCallbacks, 2554 OnCloseCallback: this.options.OnCloseCallback 2555 } 2556 ); 2557 }; 2558 2559 FBAjaxDialog.prototype._showSuccessContent = function (content) 2560 { 2561 this._show( 2562 content, 2563 { 2564 ExtraDialogClasses: this.options.ExtraDialogClasses, 2565 Title: this.options.SuccessDialogTitle, 2566 CloseButtonText: 'Close', 2567 Callbacks: this.options.SuccessDialogCallbacks, 2568 OnCloseCallback: this.options.OnCloseCallback 2569 } 2570 ); 2571 }; 2572 2573 FBAjaxDialog.prototype._showLoadingContent = function () 2574 { 2575 this._show( 2576 this.options.LoadingContent, 2577 { 2578 ExtraDialogClasses: this.options.ExtraDialogClasses, 2579 Title: this.options.LoadingDialogTitle, 2580 CloseButtonText: 'Cancel', 2581 Callbacks: this.options.LoadingDialogCallbacks, 2582 OnCloseCallback: this.options.OnCloseCallback 2583 } 2584 ); 2585 }; 2586 2587 FBAjaxDialog.prototype._show = function (content, parameters) 2588 { 2589 2590 let self = this; 2591 FBAjaxDialog._activeDialogs[self._vars.DialogId] = this; 2592 let dialog = $(`#${self._vars.DialogId}`); 2593 if (dialog.length === 0) 2594 { 2595 const labelId = `${self._vars.DialogId}-label`; 2596 const contentId = `${self._vars.DialogId}-content`; 2597 dialog = $(`<dialog id="${self._vars.DialogId}" role="alertdialog" class="${self._vars.DialogClass}" aria-labelledby="${labelId}" aria-describedby="${contentId}"></dialog>`); 2598 2599 $(self.options.ParentSelector).prepend(dialog); 2600 2601 dialog = $(`.${self._vars.DialogClass}`); 2602 if (typeof dialogPolyfill !== 'undefined') 2603 { 2604 dialogPolyfill.registerDialog(dialog.get(0)); 2605 } 2606 2607 dialog.on('click', `.${self._vars.CloseButtonClass}`, function (aEvent) 2608 { 2609 aEvent.preventDefault(); 2610 self.Close(); 2611 return false; 2612 }); 2613 2614 //dialog.append(`<div class="fbd_header"><span class="${self._vars.TitleClass}"></span><a href="javascript:" aria-label="Close Dialog" class="${self._vars.CloseButtonClass}"><span class="fas fa-window-close"></span><span class="screen-reader-text">Close Dialog</span></a></div>`); 2615 dialog.append(`<div class="fbd_header"><span id="${labelId}" class="${self._vars.TitleClass}"></span><a href="javascript:" aria-label="Close Dialog" class="${self._vars.CloseButtonClass}"><img src="/img/dialog-icon-close.svg"/><span class="screen-reader-text">Close Dialog</span></a></div>`); 2616 dialog.append(`<div id="${contentId}" class="fbd_content fbcms_content"></div>`); 2617 } 2618 else 2619 { 2620 if (dialog.is(':visible')) 2621 { 2622 dialog.hide(); 2623 dialog.next(`.${self._vars.BackdropClass}`).remove(); 2624 } 2625 dialog.find('.fbd_content').html(''); 2626 } 2627 2628 this._vars.CurrentCallbacks = parameters.Callbacks; 2629 this._vars.OnCloseCallback = parameters.OnCloseCallback; 2630 if (!FBUtilities.IsParameterUndefinedOrEmpty(parameters.ExtraDialogClasses)) 2631 { 2632 dialog.addClass(parameters.ExtraDialogClasses); 2633 } 2634 2635 dialog.find(`.${self._vars.TitleClass}`).html(parameters.Title); 2636 dialog.find('.fbd_content').html(content); 2637 dialog.find(`.${self._vars.CloseButtonClass}`).attr('title', `${parameters.CloseButtonText} ${parameters.Title} dialog.`); 2638 2639 FBUtilities.RunCallback(this._vars.CurrentCallbacks, 'OnInit', dialog); 2640
2641 if (!dialog.is(':visible')) 2642 { 2643 dialog.after(`<div class="backdrop"></div>`); 2644 dialog.show(); 2645 } 2646 2647 if ($(dialog).vpFocusManager("instance") === undefined) 2648 { 2649 $(dialog).vpFocusManager( 2650 { 2651 ExitFocusSpecificElement : self.options.SelectionElement 2652 , OnEscapeCallback : function() { self.Close(); } 2653 } 2654 ); 2655 } 2656 $(dialog).vpFocusManager("takeFocus"); 2657 2658 FBUtilities.RunCallback(self._vars.CurrentCallbacks, 'OnShow', dialog); 2659 }; 2660}(jQuery)); 2661 2662/////////////////////////////////////////////////////////////////////////////// 2663// FBModal widget 2664/////////////////////////////////////////////////////////////////////////////// 2665 2666function FBModal() 2667{ 2668 this._vars = { 2669 // true if it's initialized 2670 IsDialogInit: false, 2671 // true if open or closing, false otherwise 2672 IsDialogOpen: false, 2673 // true if opening. 2674 IsDialogOpening: false, 2675 // true if closing. 2676 IsDialogClosing: false, 2677 DialogClass: 'fbd_dialog', 2678 TitleClass: 'fbd_title', 2679 CloseButtonClass: 'fbd_close', 2680 OnCloseCallback: null, 2681 CurrentCallbacks: null, 2682 ButtonCallbacks: {}, 2683 AjaxDefaults: { 2684 ActionType: 'GET', 2685 AjaxUrl: null, 2686 Data: null, 2687 ErrorContent: null, 2688 ErrorDialogCallbacks: null, 2689 ErrorDialogTitle: 'Error', 2690 LoadingContent: null, 2691 LoadingDialogCallbacks: null, 2692 LoadingDialogTitle: 'Loading...', 2693 SuccessDialogCallbacks: null, 2694 SuccessDialogTitle: 'Detail' 2695 } 2696 }; 2697 2698 this.options = { 2699 DialogId: 'fbd_modaldialog', 2700 ParentSelector: "body", 2701 ExtraDialogClasses: null, 2702 Title: null, 2703 CloseButtonText: 'Close', 2704 AddFooterClose: false, 2705 Callbacks: null, 2706 OnCloseCallback: null, 2707 Buttons: null, 2708 Content: null, 2709 UseAjaxLoader: false, 2710 AjaxOptions: { 2711 ActionType: 'GET', 2712 AjaxUrl: null, 2713 Data: null, 2714 ErrorContent: null, 2715 ErrorDialogCallbacks: null, 2716 ErrorDialogTitle: 'Error', 2717 LoadingContent: null, 2718 LoadingDialogCallbacks: null, 2719 LoadingDialogTitle: 'Loading...', 2720 SuccessDialogCallbacks: null, 2721 SuccessDialogTitle: 'Detail' 2722 } 2723 }; 2724} 2725 2726(function ($) 2727{ 2728 FBModal._activeDialogs = {}; 2729 2730 FBModal.FindAndClose = function (aDialogId) 2731 { 2732 let dialogId = aDialogId === undefined ? 'fbd_modaldialog' : aDialogId; 2733 if (FBModal._activeDialogs[dialogId] !== undefined) 2734 { 2735 FBModal._activeDialogs[dialogId].CloseDialog(); 2736 } 2737 }; 2738 2739 FBModal.FindAndUpdate = function (aDialogId) 2740 { 2741 let dialogId = aDialogId === undefined ? 'fbd_modaldialog' : aDialogId; 2742 if (FBModal._activeDialogs[dialogId] !== undefined) 2743 { 2744 FBModal._activeDialogs[dialogId].UpdateDialog(); 2745 } 2746 }; 2747 2748 FBModal.prototype.Start = function (options) 2749 { 2750 let self = this; 2751 self.options = $.extend({}, self.options, options); 2752 if (this.options.UseAjaxLoader === true) 2753 { 2754 this.options.AjaxOptions = $.extend({}, this._vars.AjaxDefaults, this.options.AjaxOptions); 2755 this._useDialogForAjax(); 2756 } 2757 else 2758 { 2759 this._startShowDialog(); 2760 } 2761 }; 2762 2763 FBModal.prototype.CloseDialog = function () 2764 { 2765 this._closeDialog(); 2766 }; 2767 2768 FBModal.prototype.UpdateDialog = function () 2769 { 2770 this._updateDialog(); 2771 }; 2772 2773 FBModal.prototype._getDialog = function () 2774 { 2775 return $(`#${this.options.DialogId}`); 2776 }; 2777 2778 FBModal.prototype._useDialogForAjax = function () 2779 { 2780 let self = this; 2781 2782 FBUtilities.LogMessage('_useDialogForAjax - START'); 2783 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.AjaxOptions.LoadingContent)) 2784 { 2785 FBUtilities.LogMessage('_useDialogForAjax - REJECT - no loading content'); 2786 return; 2787 } 2788 2789 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.AjaxOptions.AjaxUrl)) 2790 { 2791 FBUtilities.LogMessage('_useDialogForAjax - REJECT - no ajax url'); 2792 return; 2793 } 2794 2795 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.AjaxOptions.ErrorContent)) 2796 { 2797 FBUtilities.LogMessage('_useDialogForAjax - REJECT - no error content'); 2798 return; 2799 } 2800 2801 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.AjaxOptions.ActionType)) 2802 { 2803 FBUtilities.LogMessage('_useDialogForAjax - REJECT - no action type'); 2804 return; 2805 } 2806 2807 self.options.AjaxOptions.Data === undefined ? {} : self.options.AjaxOptions.Data; 2808 2809 self._vars.AjaxRequestObject = $.ajax(self.options.AjaxOptions.AjaxUrl, 2810 { 2811 success: function (aData, _aTextStatus, _aJqXHR)//ignore jslint 2812 { 2813 FBUtilities.LogMessage('_useDialogForAjax - SUCCESS callback'); 2814 self.options.Content = aData; 2815 self.options.Title = self.options.AjaxOptions.SuccessDialogTitle; 2816 self.options.Callbacks = self.options.AjaxOptions.SuccessDialogCallbacks; 2817 self._startShowDialog(); 2818 }, 2819 error: function (_aJqXHR, _aTextStatus, _aErrorThrown) //ignore jslint 2820 { 2821 FBUtilities.LogMessage('_useDialogForAjax - ERROR callback'); 2822 self.options.Content = self.options.AjaxOptions.ErrorContent; 2823 self.options.Title = self.options.AjaxOptions.ErrorDialogTitle; 2824 self.options.Callbacks = self.options.AjaxOptions.ErrorDialogCallbacks; 2825 self._startShowDialog(); 2826 }, 2827 complete: function (_aData, _aTextStatus, _aJqXHR)//ignore jslint 2828 { 2829 FBUtilities.LogMessage('_useDialogForAjax - COMPLETE callback'); 2830 self._vars.AjaxRequestObject = null; 2831 }, 2832 type: self.options.AjaxOptions.ActionType, 2833 data: self.options.AjaxOptions.Data 2834 }); 2835 FBUtilities.LogMessage('_useDialogForAjax- COMPLETE'); 2836 }; 2837 2838 FBModal.prototype._startShowDialog = function () 2839 { 2840 let self = this; 2841 FBUtilities.LogMessage('ShowDialog - START'); 2842 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.Content)) 2843 { 2844 FBUtilities.LogMessage('ShowDialog - REJECT - no content'); 2845 return; 2846 } 2847 2848 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.Title)) 2849 { 2850 //needs a title, don't null or undefine this thing. 2851 FBUtilities.LogMessage('ShowDialog - REJECT - no title'); 2852 return; 2853 } 2854 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.CloseButtonText)) 2855 { 2856 //needs a text, don't null or undefine this thing. 2857 FBUtilities.LogMessage('ShowDialog - REJECT - no close button text'); 2858 return; 2859 } 2860 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.AddFooterClose)) 2861 { 2862 //needs a value, don't null or undefine this thing. 2863 FBUtilities.LogMessage('ShowDialog - REJECT - bad footer close value'); 2864 return; 2865 } 2866 2867 self._initDialog(); 2868 }; 2869 2870 FBModal.prototype._initDialog = function () 2871 { 2872 let self = this; 2873 // we're here for business, let's see what's going on. 2874 FBUtilities.LogMessage('_initDialog - START'); 2875 2876 // something is initialized... let's get it out of the way. 2877 if (self._vars.IsDialogInit === true) 2878 { 2879 FBUtilities.LogMessage('_initDialog - There\'s an existing dialog.'); 2880 2881 // it's opening or open (this includes closing)... 2882 if (self._vars.IsDialogOpening === true || self._vars.IsDialogOpen === true) 2883 { 2884 let dialog = self._getDialog(); 2885 // add a callback to get this show on the road once the old one is removed. 2886 dialog.on('hidden.bs.modal', function (e) 2887 { 2888 FBUtilities.LogMessage('_initDialog Callback for initialization'); 2889 self._setupDialogHtml(); 2890 }); 2891 2892 // if it's not already closing, start that now. 2893 if (self._vars.IsDialogClosing === false) 2894 { 2895 FBUtilities.LogMessage('_initDialog - Request it cease to be. (Callback will initialize)'); 2896 self._closeDialog(); 2897 } 2898 return; 2899 } 2900 2901 FBUtilities.LogMessage('_initDialog - It\'s only initalized, destroy it.'); 2902 self._destroyDialog(); 2903 } 2904 FBUtilities.LogMessage('_initDialog - Init the dialog markup and events.'); 2905 2906 // hey, nothing in the way, just set things to work. 2907 self._setupDialogHtml(); 2908 }; 2909 2910 FBModal.prototype._setupDialogHtml = function () 2911 { 2912 let self = this; 2913 2914 FBUtilities.LogMessage('_setupDialogHtml - START.'); 2915 2916 2917 let dialog = $(`<div id="${self.options.DialogId}" class="modal fade ${this._vars.DialogClass}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true"></div>`); 2918 2919 $(self.options.ParentSelector).prepend(dialog); 2920 2921 dialog = self._getDialog(); 2922 2923 let footerMarkup = ''; 2924 let buttonMarkup = ''; 2925 if (!FBUtilities.IsParameterUndefinedOrEmpty(self.options.Buttons)) 2926 { 2927 let hasValidButtons = false; 2928 for (var index in self.options.Buttons) 2929 { 2930 let buttonDeets = self.options.Buttons[index]; 2931 if (FBUtilities.IsParameterUndefinedOrEmpty(buttonDeets['text']) || FBUtilities.IsParameterUndefinedOrEmpty(buttonDeets['click'])) 2932 { 2933 continue; 2934 } 2935 2936 let btnClasses = 'vp-btn-secondary'; 2937 if (!FBUtilities.IsParameterUndefinedOrEmpty(buttonDeets['class'])) 2938 { 2939 btnClasses = buttonDeets['class']; 2940 } 2941 2942 let id = `bbdm_btn_${index}`; 2943 if (!FBUtilities.IsParameterUndefinedOrEmpty(buttonDeets['id'])) 2944 { 2945 id = buttonDeets.id; 2946 } 2947 2948 buttonMarkup += ` <button id="${id}" type="button" class="vp-btn ${btnClasses} bbdm_btn">${buttonDeets['text']}</button>`; 2949 2950 self._vars.ButtonCallbacks[id] = buttonDeets['click']; 2951 hasValidButtons = true; 2952 }//endfor 2953 2954 if (hasValidButtons === true) 2955 { 2956 dialog.on('click', '.bbdm_btn', function (e) 2957 { 2958 let button = $(e.target).closest('.bbdm_btn'); 2959 let buttonId = button.attr('id'); 2960 self._vars.ButtonCallbacks[buttonId](e); 2961 }); 2962 } 2963 } 2964 2965 if (self.options.AddClose === true) 2966 { 2967 buttonMarkup += ` <button type="button" class="vp-btn vp-btn-secondary" data-dismiss="modal">${self.options.CloseButtonText}</button>`; 2968 } 2969 2970 if (buttonMarkup.length > 0) 2971 { 2972 footerMarkup = ` <div class="modal-footer">${buttonMarkup}</div>`; 2973 } 2974 2975 let dialogBody = `<div class="modal-dialog modal-lg modal-dialog-centered modal
2975-dialog-scrollable" role="document"> 2976 <div class="modal-content"> 2977 <div class="modal-header"> 2978 <h5 class="modal-title ${self._vars.TitleClass}">Dialog Title</h5> 2979 <button type="button" class="close ${self._vars.CloseButtonClass}" data-dismiss="modal" aria-label="Close"> 2980 <img src="/img/dialog-icon-close.svg" class="fbd_close-icon"/> 2981 </button> 2982 </div> 2983 <div class="modal-body fbd_content"> 2984 <div class="container-fluid"> 2985 </div> 2986 </div> 2987 ${footerMarkup} 2988 </div> 2989</div>`; 2990 dialog.append(dialogBody); 2991 2992 /* bootstrap events */ 2993 dialog.off('shown.bs.modal').on('shown.bs.modal', function (e) 2994 { 2995 FBUtilities.RunCallback(self._vars.CurrentCallbacks, 'OnShow', dialog); 2996 self._vars.IsDialogOpening = false; 2997 self._vars.IsDialogOpen = true; 2998 FBUtilities.LogMessage('FBModal - dialog shown.'); 2999 }); 3000 3001 dialog.off('hidden.bs.modal').on('hidden.bs.modal', function (e) 3002 { 3003 FBUtilities.RunCallback(self._vars.CurrentCallbacks, 'OnClose', dialog); 3004 3005 if (self._vars.OnCloseCallback !== undefined 3006 && self._vars.OnCloseCallback !== null 3007 && typeof self._vars.OnCloseCallback === 'function') 3008 { 3009 self._vars.OnCloseCallback(); 3010 } 3011 self._vars.IsDialogOpen = false; 3012 self._vars.IsDialogClosing = false; 3013 self._destroyDialog(); 3014 3015 FBUtilities.LogMessage('FBModal - dialog hidden.'); 3016 }); 3017 /* bootstrap events */ 3018 3019 self._vars.IsDialogInit = true; 3020 3021 // just to be thorough. Nothing from before should still exist. 3022 self._vars.CurrentCallbacks = self.options.Callbacks; 3023 self._vars.OnCloseCallback = self.options.OnCloseCallback; 3024 3025 if (!FBUtilities.IsParameterUndefinedOrEmpty(self.options.ExtraDialogClasses)) 3026 { 3027 dialog.addClass(self.options.ExtraDialogClasses); 3028 } 3029 3030 dialog.find(`.${self._vars.TitleClass}`).html(self.options.Title); 3031 dialog.find('.fbd_content').html(self.options.Content); 3032 dialog.find(`.${self._vars.CloseButtonClass}`).attr('title', `${self.options.CloseButtonText} ${self.options.Title} dialog.`); 3033 3034 FBUtilities.RunCallback(self._vars.CurrentCallbacks, 'OnInit', dialog); 3035 self._showDialog(); 3036 3037 FBModal._activeDialogs[self.options.DialogId] = self; 3038 3039 FBUtilities.LogMessage('initDialogWorker - COMPLETE.'); 3040 return dialog; 3041 }; 3042 3043 FBModal.prototype._showDialog = function () 3044 { 3045 let self = this; 3046 FBUtilities.LogMessage('_showDialog - START'); 3047 if (self._vars.IsDialogInit === false) 3048 { 3049 FBUtilities.LogMessage('_showDialog - REJECT'); 3050 return; 3051 } 3052 3053 let dialog = $(`.${self._vars.DialogClass}`); 3054 //dialog.after(`<div class="backdrop"></div>`); 3055 dialog.on('shown.bs.modal', function () 3056 { 3057 FBUtilities.RunCallback(self._vars.CurrentCallbacks, 'OnShown', dialog); 3058 }); 3059 dialog.modal('show'); 3060 3061 self._vars.IsDialogOpening = true; 3062 dialog.find('.modal-header button').focus(); 3063 FBUtilities.LogMessage('_showDialog - COMPLETE (Requested)'); 3064 }; 3065 3066 FBModal.prototype._closeDialog = function () 3067 { 3068 FBUtilities.LogMessage('_closeDialog - START'); 3069 if (this._vars.IsDialogInit === false) 3070 { 3071 FBUtilities.LogMessage('_closeDialog - REJECT'); 3072 return; 3073 } 3074 3075 if (this._vars.IsDialogOpen === true || this._vars.IsDialogOpening === true) 3076 { 3077 let dialog = this._getDialog(); 3078 dialog.modal('hide'); 3079 this._vars.IsDialogClosing = true; 3080 } 3081 FBUtilities.LogMessage('_closeDialog - COMPLETE (Requested)'); 3082 }; 3083 3084 FBModal.prototype._destroyDialog = function () 3085 { 3086 FBUtilities.LogMessage('_destroyDialog - START'); 3087 if (this._vars.IsDialogInit === false) 3088 { 3089 FBUtilities.LogMessage('_destroyDialog - REJECT'); 3090 return; 3091 } 3092 3093 let dialog = this._getDialog(); 3094 dialog.off('shown.bs.modal'); 3095 dialog.off('hidden.bs.modal'); 3096 dialog.off('click', '.bbdm_btn'); 3097 this._vars.OnCloseCallback = null; 3098 this._vars.CurrentCallbacks = null; 3099 this._vars.ButtonCallbacks = {}; 3100 dialog.next('.backdrop').remove(); 3101 dialog.remove(); 3102 this._vars.IsDialogInit = false; 3103 3104 delete FBModal._activeDialogs[this.options.DialogId];
3105 FBUtilities.LogMessage('_destroyDialog - COMPLETE'); 3106 }; 3107 3108 FBModal.prototype._updateDialog = function () 3109 { 3110 FBUtilities.LogMessage('_updateDialog - START'); 3111 if (this._vars.IsDialogInit === false) 3112 { 3113 FBUtilities.LogMessage('_updateDialog - REJECT'); 3114 return; 3115 } 3116 3117 if (this._vars.IsDialogOpen === true && this._vars.IsDialogClosing === false) 3118 { 3119 this._getDialog().modal('handleUpdate'); 3120 } 3121 3122 FBUtilities.LogMessage('_updateDialog - COMPLETE'); 3123 }; 3124}(jQuery)); 3125 3126/////////////////////////////////////////////////////////////////////////////// 3127// FBMenuManager - Menu Manager 3128/////////////////////////////////////////////////////////////////////////////// 3129 3130(function ($) 3131{ 3132 // Callbacks are OnSuccess, OnError, OnComplete 3133 FBMenuManager.LoadMenu = function (aParameters) 3134 { 3135 var lDefaults, lOptions, lData; 3136 3137 lDefaults = 3138 { 3139 AjaxUrl: '/Core/Menu/' 3140 , Tagname: null 3141 , CurrentUrl: null 3142 , TemplatePrefix: null 3143 , Preview: false 3144 , Callbacks: null 3145 }; 3146 3147 lOptions = $.extend(lDefaults, aParameters); 3148 3149 if (FBUtilities.IsParameterUndefinedOrEmpty(lOptions.AjaxUrl)) 3150 { 3151 return; 3152 } 3153 if (FBUtilities.IsParameterUndefinedOrEmpty(lOptions.Tagname)) 3154 { 3155 return; 3156 } 3157 3158 lData = 3159 { 3160 tagname: lOptions.Tagname 3161 }; 3162 3163 if (!FBUtilities.IsParameterUndefinedOrEmpty(lOptions.CurrentUrl)) 3164 { 3165 lData.currenturl = lOptions.CurrentUrl; 3166 } 3167 if (!FBUtilities.IsParameterUndefinedOrEmpty(lOptions.TemplatePrefix)) 3168 { 3169 lData.templateprefix = lOptions.TemplatePrefix; 3170 } 3171 if (!FBUtilities.IsParameterUndefinedOrEmpty(lOptions.Preview) 3172 && lOptions.Preview === true) 3173 { 3174 lData.preview = true; 3175 } 3176 3177 FBMenuManager.AjaxRequestObject = $.ajax(lOptions.AjaxUrl, 3178 { 3179 data: lData, 3180 success: function (aData, aTextStatus, aJqXHR) 3181 { 3182 FBUtilities.LogMessage('Load Menu - Success'); 3183 FBUtilities.RunCallback(lOptions.Callbacks, 'OnSuccess', aData, aTextStatus, aJqXHR); 3184 }, 3185 error: function (aJqXHR, aTextStatus, aErrorThrown) 3186 { 3187 FBUtilities.LogMessage('Load Menu - Error'); 3188 FBUtilities.RunCallback(lOptions.Callbacks, 'OnError', aJqXHR, aTextStatus, aErrorThrown); 3189 }, 3190 complete: function (aJqXHR, aTextStatus) 3191 { 3192 FBUtilities.LogMessage('Load Menu - Complete'); 3193 FBUtilities.RunCallback(lOptions.Callbacks, 'OnComplete', aJqXHR, aTextStatus); 3194 }, 3195 type: 'GET' 3196 }); 3197 };//end LoadMenu 3198 3199}(jQuery)); 3200 3201/////////////////////////////////////////////////////////////////////////////// 3202// FBDateSelector 3203/////////////////////////////////////////////////////////////////////////////// 3204 3205(function ($) 3206{ 3207 $.widget("ui.FBDateSelector", 3208 { 3209 options: 3210 { 3211 ClearInputButtonClass: 'clear_input' 3212 , ClearInputButtonContent: '<span class="fas fa-times-circle"></span>' 3213 , ClearInputButtonLabel: 'Clear Input' 3214 , OnChangeCallback: null 3215 , DateFormat: null 3216 }, 3217 3218 _destroy: function () 3219 { 3220 return undefined; 3221 }, 3222 3223 _init: function () 3224 { 3225 return undefined; 3226 }, 3227 3228 _create: function () 3229 { 3230 var self = this, 3231 jElement = $(self.element), 3232 lPickerArgs = {}, 3233 lParentElement, 3234 lClearInputButton; 3235 3236 if (self.options.ClearInputButtonClass === null 3237 || self.options.ClearInputButtonContent === null) 3238 { 3239 return; 3240 } 3241 3242 3243 lPickerArgs.gotoCurrent = true; 3244 if (self.options.DateFormat !== null) 3245 { 3246 if (self.options.DateFormat === 'ISO_8601') 3247 { 3248 lPickerArgs.dateFormat = $.datepicker.ISO_8601; 3249 } 3250 } 3251 3252 if (jElement.prop('type') !== 'date') 3253 { 3254 jElement.datepicker(lPickerArgs); 3255 } 3256 3257 if (!FBUtilities.IsParameterUndefinedOrEmpty(self.options.OnChangeCallback)) 3258 { 3259 jElement.change(function (aEvent) 3260 { 3261 self.options.OnChangeCallback(aEvent); 3262 }); 3263 } 3264 3265 lParentElement = jElement.parent(); 3266 lParentElement.append('<span class="' + self.options.ClearInputButtonClass + '">' + self.options.ClearInputButtonContent + '</span>'); 3267 lClearInputButton = lParentElement.find('.' + self.options.ClearInputButtonClass); 3268 lClearInputButton.attr('role', 'button'); 3269 lClearInputButton.attr('tabindex', '0'); 3270 lClearInputButton.attr('aria-controls', jElement.attr('id')); 3271 if (!FBUtilities.IsParameterUndefinedOrEmpty(self.options.ClearInputButtonLabel)) 3272 { 3273 lClearInputButton.attr('aria-label', self.options.ClearInputButtonLabel); 3274 } 3275 lClearInputButton.click( 3276 function (aEvent) 3277 { 3278 aEvent.preventDefault(); 3279 jElement.val(''); 3280 return false; 3281 } 3282 ); 3283 } 3284 }); 3285}(jQuery)); 3286
3287/////////////////////////////////////////////////////////////////////////////// 3288// Expandable Content Sections 3289/////////////////////////////////////////////////////////////////////////////// 3290 3291function FBExpando() 3292{ 3293 return undefined; 3294} 3295 3296$(function () 3297{ 3298 3299 function _ExpandingContent_OpenWorker(container) 3300 { 3301 if (container.hasClass('fbcms_ec_collapsed')) 3302 { 3303 container.removeClass("fbcms_ec_collapsed"); 3304 $(container).find('.fbcms_ec_title').attr("aria-expanded", true); 3305 $(container).find('.fbcms_ec_titleicon').attr("aria-pressed", true); 3306 let masons = container.find('.fbcms_ec_title ~ *.masonry, .fbcms_ec_title ~ .fbcms_pgc_gallery > .masonry'); 3307 if (masons.length !== 0) 3308 { 3309 masons.masonry("layout"); 3310 } 3311 } 3312 } 3313 3314 function _ExpandingContent_CloseWorker(container) 3315 { 3316 if (!container.hasClass('fbcms_ec_collapsed')) 3317 { 3318 container.addClass("fbcms_ec_collapsed"); 3319 $(container).find('.fbcms_ec_title').attr("aria-expanded", false); 3320 $(container).find('.fbcms_ec_titleicon').attr("aria-pressed", false); 3321 } 3322 } 3323 3324 function _ExpandingContent_ToggleWorker(container) 3325 { 3326 if (!container.hasClass('fbcms_ec_collapsed')) 3327 { 3328 _ExpandingContent_CloseWorker(container); 3329 } 3330 else 3331 { 3332 _ExpandingContent_OpenWorker(container); 3333 } 3334 } 3335 3336 function toggleExpandingContent(event) 3337 { 3338 let parent = $(event.target).parents('.fbcms_ec'); 3339 _ExpandingContent_ToggleWorker(parent); 3340 } 3341 3342 FBExpando.toggleExpandingContent = toggleExpandingContent 3343 3344 function _determineExpandableContainerToOpen() 3345 { 3346 let hash = $(location).attr('hash'); 3347 let result = undefined; 3348 if (hash && hash !== '' && hash !== '#') 3349 { 3350 let name = hash.substring(1); 3351 let targetedBlock = null; 3352 try 3353 { 3354 targetedBlock = $(`.fbcms_content#${name}`); 3355 } 3356 catch (ignore) 3357 { 3358 } 3359 3360 if (targetedBlock !== null) 3361 { 3362 if (targetedBlock.hasClass('fbcms_ec')) 3363 { 3364 result = targetedBlock; 3365 } 3366 } 3367 } 3368 return result; 3369 } 3370 3371 $(document).on('click', '.fbcms_ec .fbcms_ec_title', function (event) 3372 { 3373 event.preventDefault(); 3374 toggleExpandingContent(event); 3375 return false; 3376 }); 3377 3378 function _handleHome(event) 3379 { 3380 let startId = $(event.target).parent('.fbcms_ec').siblings('.fbcms_ec').first().attr('aria-labelledby'); 3381 if (startId !== undefined) 3382 { 3383 setTimeout(function () 3384 { 3385 $(`#${startId}`).get(0).focus(); 3386 }, 100); 3387 } 3388 } 3389 3390 function _handleEnd(event) 3391 { 3392 let endId = $(event.target).parent('.fbcms_ec').siblings('.fbcms_ec').last().attr('aria-labelledby'); 3393 if (endId !== undefined) 3394 { 3395 setTimeout(function () 3396 { 3397 $(`#${endId}`).get(0).focus(); 3398 }, 100); 3399 } 3400 } 3401 3402 function _handlePrevious(event) 3403 { 3404 let previousId = $(event.target).parent('.fbcms_ec').prev('.fbcms_ec').attr('aria-labelledby'); 3405 if (previousId === undefined) 3406 { 3407 _handleEnd(event); 3408 } 3409 else 3410 { 3411 setTimeout(function () 3412 { 3413 $(`#${previousId}`).get(0).focus(); 3414 }, 100); 3415 } 3416 } 3417 3418 function _handleNext(event) 3419 { 3420 let nextId = $(event.target).parent('.fbcms_ec').next('.fbcms_ec').attr('aria-labelledby'); 3421 3422 if (nextId === undefined) 3423 { 3424 _handleHome(event); 3425 } 3426 else 3427 { 3428 setTimeout(function () 3429 { 3430 $(`#${nextId}`).get(0).focus(); 3431 }, 100); 3432 } 3433 } 3434 3435 $(document).on('keydown', '.fbcms_ec .fbcms_ec_title', function (event) 3436 { 3437 if (event.altKey || event.shiftKey || event.ctrlKey) 3438 { 3439 return; 3440 } 3441 else if (event.keyCode === 13 || event.keyCode === 32) 3442 { 3443 toggleExpandingContent(event); 3444 } 3445 else if (event.keyCode === 36) 3446 { 3447 _handleHome(event); 3448 } 3449 else if (event.keyCode === 38) 3450 { 3451 _handlePrevious(event); 3452 } 3453 else if (event.keyCode === 40) 3454 { 3455 _handleNext(event); 3456 } 3457 else if (event.keyCode === 35) 3458 { 3459 _handleEnd(event); 3460 } 3461 else 3462 { 3463 return; 3464 } 3465 3466 event.preventDefault(); 3467 event.stopPropagation(); 3468 return false; 3469 });
3470 3471 //webkit hash change fix. 3472 //https://www.nczonline.net/blog/2013/01/15/fixing-skip-to-content-links/ 3473 window.addEventListener( 3474 "hashchange", 3475 function (/*event*/) 3476 { 3477 let element = document.getElementById(location.hash.substring(1)); 3478 if (element) 3479 { 3480 if (!/^(?:a|select|input|button|textarea)$/i.test(element.tagName)) 3481 { 3482 element.tabIndex = -1; 3483 } 3484 3485 element.focus(); 3486 } 3487 3488 let jMyExpandable = _determineExpandableContainerToOpen(); 3489 if (jMyExpandable !== undefined) 3490 { 3491 _ExpandingContent_OpenWorker(jMyExpandable); 3492 } 3493 3494 let jFixedHeader = $('body .navbar-fixed-top'); 3495 if (jFixedHeader.length !== 0) 3496 { 3497 setTimeout(function () 3498 { 3499 window.scrollTo(window.scrollX, window.scrollY - jFixedHeader.height()); 3500 }, 1); 3501 } 3502 }, 3503 false 3504 ); 3505 3506 // INITIALIZE EXPANDABLE CONTENT // 3507 3508 let jExpandable = _determineExpandableContainerToOpen(); 3509 let jExpandableContentAreas = $('.fbcms_ec').not(jExpandable); 3510 3511 if (jExpandableContentAreas.length !== 0) 3512 { 3513 $.each( 3514 jExpandableContentAreas, 3515 function (_index, item) 3516 { 3517 if (!$(item).hasClass('fbcms_ec_collapsed')) 3518 { 3519 if (jExpandable !== undefined) 3520 { 3521 $('html,body').scrollTop(jExpandable.offset().top); 3522 jExpandable.removeClass("fbcms_ec_collapsed"); 3523 } 3524 } 3525 } 3526 ); 3527 } 3528 3529 $('.fbcms_ec .fbcms_ec_title').next().attr('tabindex', 0); 3530 3531 if (jExpandable !== undefined) 3532 { 3533 if (jExpandable.hasClass('fbcms_ec_collapsed')) 3534 { 3535 jExpandable.removeClass("fbcms_ec_collapsed"); 3536 } 3537 $('html,body').scrollTop(jExpandable.offset().top); 3538 } 3539}); 3540 3541/////////////////////////////////////////////////////////////////////////////// 3542// VP-Accordion 3543/////////////////////////////////////////////////////////////////////////////// 3544 3545function VPAccordion() 3546{ 3547 return undefined; 3548} 3549 3550$(function () 3551{ 3552 function _handleToggleEvent(event) 3553 { 3554 let $item = $(event.target).closest('.vp-accordion-item'); 3555 let $toggler = $item.children(".vp-accordion-header").children(".vp-accordion-toggler"); 3556 let $siblings = $item.siblings('.vp-accordion-item').not(`.vp-accordion-expanded-always`); 3557 3558 let wasExpanded = $item.hasClass('vp-accordion-expanded'); 3559 3560 $siblings.removeClass('vp-accordion-expanded'); 3561 $siblings.children(".vp-accordion-header").children(".vp-accordion-toggler").prop("ariaExpanded", false); 3562 3563 if (wasExpanded) 3564 { 3565 $item.removeClass('vp-accordion-expanded'); 3566 $toggler.prop("ariaExpanded", false); 3567 } 3568 else 3569 { 3570 $item.addClass('vp-accordion-expanded'); 3571 $toggler.prop("ariaExpanded", true); 3572 } 3573 } 3574 3575 function _initialize(selector) 3576 { 3577 $(selector).filter('.vp-accordion').each(function () 3578 { 3579 $(this) 3580 .children('.vp-accordion-item') 3581 .not(`.vp-accordion-expanded-always`) 3582 .children('.vp-accordion-header') 3583 .children('.vp-accordion-toggler') 3584 .on('click', _handleToggleEvent); 3585 }); 3586 } 3587 3588 VPAccordion.initialize = _initialize; 3589 3590 _initialize(".vp-accordion"); 3591 3592}); 3593/////////////////////////////////////////////////////////////////////////////// 3594// FBRSearchBox - Foxbright Responsive Search Box 3595/////////////////////////////////////////////////////////////////////////////// 3596 3597(function ($) 3598{ 3599 /* 3600 FBRSearchBox - Foxbright Responsive Search Box 3601 3602 Modifies the search form to use the submit button as an "opener" when the viewport 3603 width is below a given threshold. An HTML class will placed on the form when opened, 3604 styling transitions can be used to animate a change. Once the form is open, the 3605 submit button will function as a normal submit button. At or above the viewport 3606 width threshold, the button will act normally. 3607 3608 Options: 3609 3610 OpenerAsSubmitterOnDesktop default: true 3611 The opener button should behave as a normal submit button at or above 3612 the DesktopWidthMinimum. If true, DesktopWidthMinimum must be set. 3613 DesktopWidthMinimum default: 768 3614 Size, in pixels, that normal behavior will be resumed. Required if 3615 OpenerAsSubmitterOnDesktop is set to true. 3616 FormActivatedClass default: 'opened' 3617 Required. Class to add to the form to indicate/activate the open state.
3618 SubmitButtonClass default: 'submit' 3619 Required. Class to be used to select the submit button(s) *inside* the form element. 3620 InputFieldClass default: 'search-input' 3621 Required. Class to be used to select the search-input(s) *inside* the form element. 3622 3623 Methods: 3624 3625 The widget is fully functional on its own, but can be remotely activated with the following 3626 methods. 3627 3628 ActivateSearch 3629 Called to open the form for searching. 3630 DeactivateSearch 3631 Called to close the form. 3632 3633 Examples: 3634 3635 Since the function is built as a jQuery Widget, simply call the functions on the 3636 form element directly. 3637 3638 $('.search-form').FBRSearchBox(); 3639 3640 $('.search-form').FBRSearchBox({ FormActivatedClass : 'my_open_class' }); 3641 */ 3642 $.widget("ui.FBRSearchBox", 3643 { 3644 options: 3645 { 3646 OpenerAsSubmitterOnDesktop: true 3647 , DesktopWidthMinimum: 768 3648 , FormActivatedClass: 'opened' 3649 , SubmitButtonClass: 'submit' 3650 , InputFieldClass: 'search-input' 3651 }, 3652 3653 _destroy: function () 3654 { 3655 return undefined; 3656 }, 3657 3658 _init: function () 3659 { 3660 return undefined; 3661 }, 3662 3663 _create: function () 3664 { 3665 var self = this; 3666 var jElement = $(self.element); 3667 3668 //check options. 3669 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.FormActivatedClass) 3670 || FBUtilities.IsStringEmptyOrWhitespace(self.options.SubmitButtonClass) 3671 || FBUtilities.IsStringEmptyOrWhitespace(self.options.InputFieldClass)) 3672 { 3673 FBUtilities.LogMessage('FBRSearchBox - required settings null or empty.'); 3674 return; 3675 } 3676 3677 if (self.options.OpenerAsSubmitterOnDesktop === true 3678 && (FBUtilities.GetIntOrNull(self.options.DesktopWidthMinimum) === null 3679 || FBUtilities.GetIntOrNull(self.options.DesktopWidthMinimum) <= 0)) 3680 { 3681 FBUtilities.LogMessage('FBRSearchBox - desktop threshold not set as requested.'); 3682 return; 3683 } 3684 3685 //set events 3686 jElement.find(`.${self.options.SubmitButtonClass}`) 3687 .on('click', function (aEvent) 3688 { 3689 aEvent.preventDefault(); 3690 self._ClickOpener(); 3691 return false; 3692 }); 3693 3694 jElement.find(`.${self.options.InputFieldClass}`) 3695 .on('keypress', function (aEvent) 3696 { 3697 if (aEvent.which === 13) 3698 { 3699 jElement.submit(); 3700 return false; 3701 } 3702 }) 3703 .on('keydown', function (aEvent) 3704 { 3705 if (aEvent.which === 27) 3706 { 3707 self.DeactivateSearch(); 3708 jElement.find(`.${self.options.InputFieldClass}`).val('') 3709 jElement.find(`.${self.options.SubmitButtonClass}`).focus(); 3710 return false; 3711 } 3712 }); 3713 3714 jElement.on('focusout', function (aEvent) 3715 { 3716 setTimeout(function () 3717 { 3718 if ($(self.element).has($(document.activeElement)).length == 0) 3719 { 3720 self.DeactivateSearch(); 3721 $(self.element).find(`.${self.options.InputFieldClass}`).val('') 3722 } 3723 }, 0); 3724 3725 }); 3726 3727 $(window).on('resize', function (aEvent) 3728 { 3729 self._OnResize(); 3730 }); 3731 self._OnResize(); 3732 }, 3733 3734 _OnResize: function () 3735 { 3736 var self = this; 3737 var jElement = $(self.element); 3738 3739 var lViewportWidth = FBUtilities.GetIntOrNull($("body").innerWidth()); 3740 3741 if (lViewportWidth < self.options.DesktopWidthMinimum) 3742 { 3743 jElement.find(`.${self.options.InputFieldClass}`).attr('tabindex', "-1"); 3744 } 3745 else 3746 { 3747 jElement.find(`.${self.options.InputFieldClass}`).removeAttr('tabindex'); 3748 } 3749 }, 3750 3751 _ClickOpener: function () 3752 { 3753 var self = this; 3754 var jElement = $(self.element); 3755 var lViewportWidth = FBUtilities.GetIntOrNull($("body").innerWidth()); 3756 3757 if (lViewportWidth >= self.options.DesktopWidthMinimum) 3758 { 3759 jElement.submit(); 3760 } 3761 else if (false === jElement.is(`.${self.options.FormActivatedClass}`)) 3762 { 3763 self.ActivateSearch(); 3764 } 3765 else if (false === FBUtilities.IsStringEmptyOrWhitespace(jElement.find(`.${self.options.InputFieldClass}`).val())) 3766 { 3767 jElement.submit(); 3768 } 3769 else 3770 { 3771 self.DeactivateSearch(); 3772 } 3773 }, 3774 3775 ActivateSearch: function () 3776 { 3777 let jElement = $(this.element); 3778 jElement.addClass(this.options.FormActivatedClass); 3779 jElement.find(`.${this.options.InputFieldClass}`).focus(); 3780 }, 3781 3782 DeactivateSearch: function () 3783 { 3784 $(this.element).removeClass(this.options.FormActivatedClass); 3785 } 3786 }); 3787}(jQuery)); 3788
3789/////////////////////////////////////////////////////////////////////////////// 3790// FBRSlideOut - Foxbright Responsive Menu Slideout 3791/////////////////////////////////////////////////////////////////////////////// 3792 3793(function ($) 3794{ 3795 /* 3796 FBRSlideOut - Foxbright Responsive Menu Slideout 3797 3798 Javascript controller for a responsive menu slideout. 3799 Options can create buttons for activation and place content in them. 3800 3801 The slider element is checked for display mode attributes. If either 3802 is not found, is found to be blank, or is found not to be "none" or 3803 one of the key values present in DisplayModeClasses, the Compatibility 3804 mode is activated. All options listed below with a compatibility 3805 value will be overwritten with that value in compatibility mode. 3806 All classes are present in compatibility mode unless otherwise noted. 3807 3808 Options: 3809 3810 SliderClass default: 'nav-slider'; compatibility: 'nav_slider' 3811 Required. The class that should be added to the selected 3812 element for CSS styling and transistions. 3813 3814 SlideoutClass default: 'fbcms_rslideout' 3815 Required. The class that will be added upon initialization. 3816 Change at your peril. 3817 3818 LinerClass default: 'slide-liner'; compatibility: 'slide_liner' 3819 Required. The class to be put on the element that will wrap all content 3820 inside the containing element. 3821 3822 SliderOpenClass default: 'slide-open'; compatibility: 'slideropen' 3823 Required. The class to indicate the slider is open. 3824 3825 SliderOpenContainerSelector default: 'body' 3826 A selector to use to place a class on indicating the slider 3827 details. 3828 3829 SliderContainerActiveClass default: 'nav-slider-active' 3830 A class to add to the container to indicate that there is a 3831 working slider in place. 3832 Not present in compatibility mode. 3833 3834 SliderContainerInactiveClass default: 'nav-slider-deactivated' 3835 A class to add to the container to indicate that the slider is 3836 non-working. 3837 Not present in compatibility mode. 3838 3839 SliderOpenContainerClass default: 'nav-slider-open'; compatibility: 'navslideropen' 3840 A class to place on the element(s) found by 3841 SliderOpenContainerSelector. 3842 3843 AddSliderButton default: true 3844 True to add a slider button for opening the slider. If set to 3845 true, SliderButtonClass must be set. 3846 3847 SliderButtonClass default: 'nav-slider-button'; compatibility: 'slider-opener' 3848 Required if AddSliderButton is set to true. The class to be 3849 added to the slider opener/closer button(s) created. 3850 3851 SliderButtonActivatedClass default: 'activated' 3852 A class to be added to the slider opener/closer button(s) when 3853 activated (the slider open). 3854 3855 SliderButtonContent default: '<span></span><span class="screen-reader-text">Website Menu</span>' 3856 Content to be displayed in the slider opener/closer button(s). 3857 3858 SliderButtonExtraClasses default: 'slider-button'; compatibility: 'changerbutton' 3859 Extra classes to be added to the slider opener/closer 3860 button(s). 3861 3862 AdditionalButtonContainerSelector default: null 3863 An additional container selector to add a slider opener/closer 3864 button(s) to. 3865
3866 AdditionalSliderButtonClass default: 'slider-button-secondary'; compatibility: 'secondary-opener' 3867 An additional class to add to additional slider opener/closer 3868 button(s). 3869 3870 AdditionalSliderButtonContent default: '<span></span><span class="screen-reader-text">Website Menu</span>' 3871 Content to be displayed in the additional slider opener/closer 3872 button(s). 3873 3874 AdditionalSliderButtonExtraClasses default: 'slider-button'; compatibility: 'changerbutton' 3875 Extra classes to be added to the additional slider 3876 opener/closer button(s). 3877 3878 DisplayModeThreshold default: 768 3879 Threshold at which to switch between display modes. 3880 3881 DisplayModeClasses default: { 'slideout': 'navslideout', 'overlay': 'navoverlay' } 3882 List of display modes with classes to indicate their use. 3883 Not present in compatibility mode. 3884 3885 Methods: 3886 3887 The widget is fully functional on its own, but can be remotely activated with the following 3888 methods. 3889 3890 ToggleSlider 3891 Called to toggle the slider open or closed. 3892 OpenSlider 3893 Called to open the slider (or do nothing if the slider is already open). 3894 CloseSlider 3895 Called to close the slider (or do nothing if the slider is already closed). 3896 3897 Examples: 3898 3899 Since the function is built as a jQuery Widget, simply call the functions on the 3900 container element directly. 3901 3902 $('.header_navigation').FBRSlideOut(); 3903 3904 $('.header_navigation').FBRSlideOut( 3905 { 3906 AdditionalButtonContainerSelector : '#header' 3907 } 3908 ); 3909 */ 3910 $.widget("ui.FBRSlideOut", 3911 { 3912 options: 3913 { 3914 SliderClass: 'nav-slider' //'nav_slider' 3915 , SlideoutClass: 'fbcms_rslideout' 3916 , LinerClass: 'slide-liner' //'slide_liner' 3917 , SliderOpenClass: 'slide-open' //'slideropen' 3918 , SliderOpenContainerSelector: 'body' 3919 , SliderContainerActiveClass: 'nav-slider-active' 3920 , SliderContainerInactiveClass: 'nav-slider-deactivated' 3921 , SliderOpenContainerClass: 'nav-slider-open' //'navslideropen' 3922 , AddSliderButton: true 3923 , SliderButtonClass: 'nav-slider-button' //'slider-opener' 3924 , SliderButtonActivatedClass: 'activated' 3925 , SliderButtonContent: '<span></span><span class="screen-reader-text">Close Website Menu</span>' 3926 , SliderButtonExtraClasses: 'slider-button' //'changerbutton' 3927 , AddAdditionalButton: true 3928 , AdditionalButtonContainerSelector: null 3929 , AdditionalSliderButtonClass: 'slider-button-secondary' //'secondary-opener' 3930 , AdditionalSliderButtonId: 'navigation-slider-opener-button' 3931 , AdditionalSliderButtonContent: '<span></span><span class="screen-reader-text">Open Website Menu</span>' 3932 , AdditionalSliderButtonExtraClasses: 'slider-button' //'changerbutton' 3933 , DisplayModeThreshold: 768 3934 , DisplayModeClasses: { 'slider': 'navslideout', 'overlay': 'navoverlay' } 3935 , SkipToNavigationLinkId: 'skip-to-navigation' 3936 }, 3937 3938 _prevFocusItem: null, 3939 _myExternalOpenerButtonItem: null, 3940 3941 _prevTabbableItem: null, 3942 _myFirstTabbableItem: null, 3943 _myLastTabbableItem: null, 3944 _nextTabbableItem: null, 3945 _lastBelowTheThreshold: false, 3946 _DesktopDisplayClass: null, 3947 _DesktopUseTabbingLoop: null, 3948 _MobileDisplayClass: false, 3949 _MobileUseTabbingLoop: false, 3950 3951 _destroy: function () 3952 { 3953 return undefined; 3954 }, 3955 3956 _init: function () 3957 { 3958 return undefined; 3959 }, 3960 3961 _create: function () 3962 { 3963 var self = this; 3964 var jElement = $(self.element); 3965 3966 if ($('body.page_bodyonly').length === 1) 3967 { 3968 jElement.remove(); 3969 return; 3970 } 3971 3972 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderClass) 3973 || FBUtilities.IsStringEmptyOrWhitespace(self.options.SlideoutClass) 3974 || FBUtilities.IsStringEmptyOrWhitespace(self.options.LinerClass) 3975 || FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderOpenClass)) 3976 { 3977 FBUtilities.LogMessage('FBRSlideOut - required settings null or empty.'); 3978 return; 3979 } 3980 3981 if (self.options.AddSliderButton === true 3982 && FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderButtonClass)) 3983 { 3984 FBUtilities.LogMessage('FBRSlideOut - slider button setting not set as requested.'); 3985 return; 3986 } 3987 3988 var lMobileDisplayMode = jElement.data('slider-mobiledisplaymode'); 3989 var lDesktopDisplayMode = jElement.data('slider-
3989desktopdisplaymode'); 3990 if (FBUtilities.IsParameterUndefinedOrEmpty(lDesktopDisplayMode) === false 3991 && FBUtilities.IsParameterUndefinedOrEmpty(self.options.DisplayModeClasses[lDesktopDisplayMode]) === false) 3992 { 3993 self._DesktopDisplayClass = self.options.DisplayModeClasses[lDesktopDisplayMode]; 3994 self._DesktopUseTabbingLoop = true; 3995 } 3996 else if (lDesktopDisplayMode === "none") 3997 { 3998 self._DesktopDisplayClass = 'none'; 3999 } 4000 if (FBUtilities.IsParameterUndefinedOrEmpty(lMobileDisplayMode) === false 4001 && FBUtilities.IsParameterUndefinedOrEmpty(self.options.DisplayModeClasses[lMobileDisplayMode]) === false) 4002 { 4003 self._MobileDisplayClass = self.options.DisplayModeClasses[lMobileDisplayMode]; 4004 self._MobileUseTabbingLoop = true; 4005 } 4006 else if (lMobileDisplayMode === "none") 4007 { 4008 self._MobileDisplayClass = 'none'; 4009 } 4010 4011 if (FBUtilities.IsParameterUndefinedOrNull(self._DesktopDisplayClass) 4012 || FBUtilities.IsParameterUndefinedOrNull(self._MobileDisplayClass)) 4013 { 4014 // trigger compatibility mode... 4015 self.options.SliderClass = 'nav_slider'; 4016 self.options.LinerClass = 'slide_liner'; 4017 self.options.SliderOpenClass = 'slideropen'; 4018 self.options.SliderOpenContainerClass = 'navslideropen'; 4019 self.options.SliderButtonClass = 'slider-opener'; 4020 self.options.SliderButtonExtraClasses = 'changerbutton'; 4021 self.options.AdditionalSliderButtonClass = 'secondary-opener'; 4022 self.options.AdditionalSliderButtonExtraClasses = 'changerbutton'; 4023 } 4024 4025 //window.console.log('FBRSlideOut - DesktopMode: "' + self._DesktopDisplayClass + '"; MobileMode: "' + self._MobileDisplayClass + '"'); 4026 4027 if (self.options.AddSliderButton === true) 4028 { 4029 jElement.prepend('<a class="' + self.options.SliderButtonClass + '" href="#"></a>'); 4030 4031 let lMenuButton = jElement.children('.' + self.options.SliderButtonClass); 4032 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderButtonExtraClasses) === false) 4033 { 4034 lMenuButton.addClass(self.options.SliderButtonExtraClasses); 4035 } 4036 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderButtonContent) === false) 4037 { 4038 lMenuButton.html(self.options.SliderButtonContent); 4039 } 4040 4041 if (self.options.AddAdditionalButton === true) 4042 { 4043 let container = $(self.options.AdditionalButtonContainerSelector); 4044 let haveContainer = (container.length > 0); 4045 let html = `<a id="${self.options.AdditionalSliderButtonId}" class="${self.options.SliderButtonClass}" tabindex="0" href="javascript:"></a>`; 4046 let button; 4047 if (haveContainer) 4048 { 4049 let firstChild = container.children().first(); 4050 if (firstChild.length !== 0 && firstChild.attr('id') === "accessibility") 4051 { 4052 firstChild.after(html); 4053 } 4054 else 4055 { 4056 container.prepend(html); 4057 } 4058 button = container.children(`.${self.options.SliderButtonClass}`); 4059 } 4060 else 4061 { 4062 button = $(html); 4063 } 4064 4065 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.AdditionalSliderButtonClass)) 4066 { 4067 button.addClass(self.options.AdditionalSliderButtonClass); 4068 } 4069 4070 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.AdditionalSliderButtonExtraClasse
4070s)) 4071 { 4072 button.addClass(self.options.AdditionalSliderButtonExtraClasses); 4073 } 4074 4075 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.AdditionalSliderButtonContent)) 4076 { 4077 button.html(self.options.AdditionalSliderButtonContent); 4078 } 4079 4080 if (!haveContainer) 4081 { 4082 jElement.before(button); 4083 } 4084 } 4085 } 4086 4087 if (self.options.AddSliderButton === true) 4088 { 4089 jElement.find(`.${self.options.SliderButtonClass}`).on( 4090 'click', 4091 function (_event) 4092 { 4093 self.CloseSlider(); 4094 return false; 4095 } 4096 ); 4097 4098 if (self.options.AddAdditionalButton === true) 4099 { 4100 self._myExternalOpenerButtonItem = $(`.${self.options.AdditionalSliderButtonClass}`); 4101 4102 $(`.${self.options.AdditionalSliderButtonClass}`).on( 4103 'click', 4104 function (_event) 4105 { 4106 self.ToggleSlider($(this).closest(`.${self.options.AdditionalSliderButtonClass}`)); 4107 return false; 4108 } 4109 ); 4110 } 4111 } 4112 4113 jElement.on("keydown", function (e) 4114 { 4115 var lViewportWidth = FBUtilities.GetIntOrNull($("body").innerWidth()); 4116 if ($(self.options.SliderOpenContainerSelector).hasClass(self.options.SliderContainerInactiveClass)) 4117 { 4118 return true; 4119 } 4120 4121 if (e.key === "Escape") // Escape 4122 { 4123 4124 if (jElement.hasClass(self.options.SliderOpenClass)) 4125 { 4126 e.preventDefault(); 4127 e.stopPropagation(); 4128 self.CloseSlider(); 4129 return false; 4130 } 4131 } 4132 4133 return true; 4134 }); 4135 4136 // skip this if we're in compatibility mode. 4137 if (FBUtilities.IsParameterUndefinedOrNull(self._DesktopDisplayClass) === false 4138 && FBUtilities.IsParameterUndefinedOrNull(self._MobileDisplayClass) === false) 4139 { 4140 if (self._DesktopDisplayClass !== self._MobileDisplayClass) 4141 { 4142 $(window).resize(function () 4143 { 4144 self._updateOnPageResizeOrLoad(); 4145 }); 4146 } 4147 self._updateOnPageResizeOrLoad(); 4148 } 4149 4150 // reconfigure jump to navigation link. 4151 $(`#${self.options.SkipToNavigationLinkId}`).on('click', function (e) 4152 { 4153 let viewportWidth = FBUtilities.GetIntOrNull(window.innerWidth); 4154 if ((viewportWidth < self.options.DisplayModeThreshold && self._MobileUseTabbingLoop) 4155 || (viewportWidth >= self.options.DisplayModeThreshold && self._DesktopUseTabbingLoop)) 4156 { 4157 e.preventDefault(); 4158 document.location = `#${self.options.AdditionalSliderButtonId}`; 4159 return false; 4160 } 4161 }); 4162 4163 jElement.addClass(self.options.SliderClass); 4164 jElement.wrapInner('<div class="' + self.options.LinerClass + '"></div>'); 4165 $(self.options.SliderOpenContainerSelector).addClass(self.options.SliderContainerClass); 4166 4167 4168 self._lastBelowTheThreshold = self._isBelowThresehold(); 4169 4170 $(window).on("resize", function () 4171 { 4172 let isBelow = self._isBelowThresehold(); 4173 4174 if (isBelow != self._lastBelowTheThreshold) 4175 { 4176 self._lastBelowTheThreshold = isBelow; 4177 if (self._DesktopUseTabbingLoop !== self._MobileUseTabbingLoop) 4178 { 4179 self._updateTabbability(); 4180 } 4181 } 4182 }); 4183 4184 jElement.on("fb:changevisibility", function (aEvent) 4185 { 4186 self._updateTabbability(); 4187 console.log('changevisibility caught: "' + aEvent.detail.name + '"');// TODO: seems to trigger on every TAB through the menu... 4188 }); 4189 4190 setTimeout(function () 4191 { 4192 self._updateTabbability(); 4193 }, 1) 4194 4195 jElement.addClass(self.options.SlideoutClass); 4196 }, 4197 4198 _updateOnPageResizeOrLoad() 4199 { 4200 var self = this; 4201 4202 if (FBUtilities.IsParameterUndefinedOrNull(self._DesktopDisplayClass) 4203 || FBUtilities.IsParameterUndefinedOrNull(self._MobileDisplayClass)) 4204 {
4205 // drop out if this is somehow called in compatibility mode. 4206 return; 4207 } 4208 4209 let viewportWidth = FBUtilities.GetIntOrNull(window.innerWidth); 4210 if (viewportWidth >= self.options.DisplayModeThreshold) 4211 { 4212 self._updateContainerClass(self._MobileDisplayClass, self._DesktopDisplayClass); 4213 } 4214 else 4215 { 4216 self._updateContainerClass(self._DesktopDisplayClass, self._MobileDisplayClass); 4217 } 4218 }, 4219 4220 _updateContainerClass: function (aRemoveClass, aAddClass) 4221 { 4222 var self = this; 4223 4224 var lContainerElement = $(self.options.SliderOpenContainerSelector); 4225 4226 // does it start inactive? 4227 var lStartInactive = (aRemoveClass === "none"); 4228 // should it finish inactive? 4229 var lFinishInactive = (aAddClass === "none"); 4230 4231 // (in)active classes... 4232 // if it doesn't have the class it should for the finish... updated it. 4233 if (lFinishInactive === true 4234 && lContainerElement.hasClass(self.options.SliderContainerInactiveClass) === false) 4235 { 4236 lContainerElement.removeClass(self.options.SliderContainerActiveClass).addClass(self.options.SliderContainerInactiveClass) 4237 } 4238 else if (lFinishInactive === false 4239 && lContainerElement.hasClass(self.options.SliderContainerActiveClass) === false) 4240 { 4241 lContainerElement.removeClass(self.options.SliderContainerInactiveClass).addClass(self.options.SliderContainerActiveClass) 4242 } 4243 // otherwise no changes are necessary... 4244 4245 // is there a class to remove? 4246 if (lStartInactive === false) 4247 { 4248 lContainerElement.removeClass(aRemoveClass); 4249 } 4250 // is there a class to add? 4251 if (lFinishInactive === false) 4252 { 4253 lContainerElement.addClass(aAddClass); 4254 } 4255 }, 4256 _isBelowThresehold: function () 4257 { 4258 return FBUtilities.GetIntOrNull(window.innerWidth) < this.options.DisplayModeThreshold; 4259 }, 4260 _isSliderActive: function () 4261 { 4262 if (FBUtilities.IsParameterUndefinedOrNull(this._DesktopDisplayClass) 4263 || FBUtilities.IsParameterUndefinedOrNull(this._MobileDisplayClass)) 4264 { 4265 return this._isBelowThresehold(); 4266 } 4267 return (false === $(this.options.SliderOpenContainerSelector).hasClass(this.options.SliderContainerInactiveClass)); 4268 }, 4269 4270 _isSliderOpened: function () 4271 { 4272 return $(this.element).hasClass(this.options.SliderOpenClass); 4273 }, 4274 _doBypass: function () 4275 { 4276 return this._isSliderActive() && !this._isSliderOpened(); 4277 }, 4278 _doInternalLoop: function () 4279 { 4280 return this._isSliderActive() && this._isSliderOpened(); 4281 }, 4282 _updateTabbability: function () 4283 { 4284 // all the tabbing events. 4285 var self = this; 4286 var jElement = $(self.element); 4287 4288 4289 if (self._prevTabbableItem !== null) 4290 { 4291 self._prevTabbableItem.off('keydown'); 4292 } 4293 4294 if (self._nextTabbableItem !== null) 4295 { 4296 self._nextTabbableItem.off('keydown'); 4297 } 4298 4299 if (self._myFirstTabbableItem !== null) 4300 { 4301 self._myFirstTabbableItem.off('keydown'); 4302 } 4303 4304 if (self._myFirstTabbableItem !== null) 4305 { 4306 self._myLastTabbableItem.off('keydown'); 4307 } 4308 4309 if (!self._isSliderActive()) 4310 { 4311 return; 4312 } 4313 4314 var lAllTabbableItems = $(':tabbable'); 4315 4316 self._myFirstTabbableItem = jElement.find(':tabbable').first(); 4317 self._myLastTabbableItem = jElement.find(':tabbable').last(); 4318 4319 var lMyFirstItemIndex = parseInt(lAllTabbableItems.index(self._myFirstTabbableItem), 10); 4320 var lPrevItemIndex = lMyFirstItemIndex - 1; 4321 if (lPrevItemIndex < 0) 4322 { 4323 lPrevItemIndex = lAllTabbableItems.length - 1; 4324 } 4325 self._prevTabbableItem = lAllTabbableItems.eq(lPrevItemIndex); 4326 4327 var lMyLastItemIndex = parseInt(lAllTabbableItems.index(self._myLastTabbableItem), 10); 4328 var lNextItemIndex = lMyLastItemIndex + 1; 4329 if (lNextItemIndex < 0) 4330 { 4331 lNextItemIndex = 0; 4332 } 4333 self._nextTabbableItem = lAllTabbableItems.eq(lNextItemIndex); 4334 4335 // set up the bypass if the slider is closed... 4336 // before to after.
4337 self._prevTabbableItem.on("keydown", function (e) 4338 { 4339 let propagate = true; 4340 if (e.keyCode === 9 && e.shiftKey === false && self._doBypass()) 4341 { 4342 e.preventDefault(); 4343 e.stopPropagation(); 4344 self._nextTabbableItem.focus(); 4345 propagate = false; 4346 } 4347 return propagate; 4348 }); 4349 // after to before. 4350 self._nextTabbableItem.on("keydown", function (e) 4351 { 4352 let propagate = true; 4353 if (e.keyCode === 9 && e.shiftKey === true && self._doBypass()) 4354 { 4355 e.preventDefault(); 4356 e.stopPropagation(); 4357 self._prevTabbableItem.focus(); 4358 propagate = false; 4359 } 4360 return propagate; 4361 }); 4362 4363 // set up the internal loop if the slider is closed... 4364 // bottom to top. 4365 self._myLastTabbableItem.on("keydown", function (e) 4366 { 4367 let propagate = true; 4368 if (e.keyCode === 9 && e.shiftKey === false && self._doInternalLoop()) 4369 { 4370 e.preventDefault(); 4371 e.stopPropagation(); 4372 self._myFirstTabbableItem.focus(); 4373 propagate = false; 4374 } 4375 return propagate; 4376 }); 4377 // top to bottom. 4378 self._myFirstTabbableItem.on("keydown", function (e) 4379 { 4380 let propagate = true; 4381 if (e.keyCode === 9 && e.shiftKey === true && self._doInternalLoop()) 4382 { 4383 e.preventDefault(); 4384 e.stopPropagation(); 4385 self._myLastTabbableItem.focus(); 4386 propagate = false; 4387 } 4388 return propagate; 4389 }); 4390 }, 4391 4392 ToggleSlider: function (aActivatingElement) 4393 { 4394 var self = this; 4395 var jElement = $(self.element); 4396 4397 // toggle all the classes on the markup. 4398 jElement.toggleClass(self.options.SliderOpenClass); 4399 4400 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderOpenContainerSelector) 4401 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderOpenContainerClass)) 4402 { 4403 $(self.options.SliderOpenContainerSelector).toggleClass(self.options.SliderOpenContainerClass); 4404 } 4405 4406 jElement.children(`.${self.options.LinerClass}`).children(`.${self.options.SliderButtonClass}`).toggleClass(self.options.SliderButtonActivatedClass); 4407 4408 // and in the buttons... 4409 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.AdditionalButtonContainerSelector) === false) 4410 { 4411 let lAdditionalButtonContainers = $(self.options.AdditionalButtonContainerSelector); 4412 if (lAdditionalButtonContainers.length > 0) 4413 { 4414 $.each( 4415 lAdditionalButtonContainers, 4416 function (_index, aValue) 4417 { 4418 $(aValue).children(`.${self.options.SliderButtonClass}`).toggleClass(self.options.SliderButtonActivatedClass); 4419 } 4420 ); 4421 } 4422 } 4423 4424 // based on the open status (class changes)... 4425 if (self.IsSliderOpen() === true) 4426 { 4427 // if we're now open... 4428 if (FBUtilities.IsParameterUndefinedOrEmpty(aActivatingElement) === false) 4429 { 4430 // if an activated item had been submitted...
4431 self._prevFocusItem = aActivatingElement; 4432 // save any submitted activating element for return to focus when closed. 4433 } 4434 else 4435 { 4436 // if no item has been submitted, clear the variable. 4437 self._prevFocusItem = null; 4438 } 4439 // set focus on our starting item. 4440 self._GetStartingFocusItem().focus(); 4441 } 4442 else 4443 { 4444 // if we're now closed... 4445 if (self._prevFocusItem === null) 4446 { 4447 // and no activating item was submitted... 4448 if (self._myExternalOpenerButtonItem !== null) 4449 { 4450 // set focus on our external opener button (if any) 4451 self._myExternalOpenerButtonItem.focus(); 4452 } 4453 else 4454 { 4455 // set focus on the tabbable item immediately previous to the menu. 4456 self._prevTabbableItem.focus(); 4457 } 4458 } 4459 else 4460 { 4461 // an activating item was set, set focus there and clear the variable. 4462 self._prevFocusItem.focus(); 4463 self._prevFocusItem = null; 4464 } 4465 } 4466 }, 4467 4468 OpenSlider: function (aActivatingElement) 4469 { 4470 var self = this, 4471 jElement = $(self.element), 4472 lAdditionalButtonContainers; 4473 4474 jElement.addClass(self.options.SliderOpenClass); 4475 4476 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderOpenContainerSelector) 4477 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderOpenContainerClass)) 4478 { 4479 $(self.options.SliderOpenContainerSelector).addClass(self.options.SliderOpenContainerClass); 4480 } 4481 4482 jElement.children('.' + self.options.LinerClass).children('.' + self.options.SliderButtonClass).addClass(self.options.SliderButtonActivatedClass); 4483 4484 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.AdditionalButtonContainerSelector) === false) 4485 { 4486 lAdditionalButtonContainers = $(self.options.AdditionalButtonContainerSelector); 4487 if (lAdditionalButtonContainers.length > 0) 4488 { 4489 $.each( 4490 lAdditionalButtonContainers, 4491 function (aIndex, aValue)//ignore jslint 4492 { 4493 var lValue = $(aValue); 4494 lValue.children('.' + self.options.SliderButtonClass).addClass(self.options.SliderButtonActivatedClass); 4495 } 4496 ); 4497 } 4498 } 4499 4500 // we're now open... 4501 if (FBUtilities.IsParameterUndefinedOrEmpty(aActivatingElement) === false) 4502 { 4503 // if an activated item had been submitted...
4504 self._prevFocusItem = aActivatingElement; 4505 // save any submitted activating element for return to focus when closed. 4506 } 4507 else 4508 { 4509 // if no item has been submitted, clear the variable. 4510 self._prevFocusItem = null; 4511 } 4512 // set focus on our starting item. 4513 self._GetStartingFocusItem().focus(); 4514 }, 4515 4516 IsSliderOpen: function () 4517 { 4518 return $(this.element).hasClass(this.options.SliderOpenClass); 4519 }, 4520 4521 _GetStartingFocusItem: function () 4522 { 4523 return $(this.element).find(':tabbable').not('.' + this.options.SliderButtonClass).first(); 4524 }, 4525 4526 CloseSlider: function () 4527 { 4528 var self = this, 4529 jElement = $(self.element), 4530 lAdditionalButtonContainers; 4531 4532 jElement.removeClass(self.options.SliderOpenClass); 4533 4534 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderOpenContainerSelector) 4535 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderOpenContainerClass)) 4536 { 4537 $(self.options.SliderOpenContainerSelector).removeClass(self.options.SliderOpenContainerClass); 4538 } 4539 4540 jElement.children('.' + self.options.LinerClass).children('.' + self.options.SliderButtonClass).removeClass(self.options.SliderButtonActivatedClass); 4541 4542 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.AdditionalButtonContainerSelector) === false) 4543 { 4544 lAdditionalButtonContainers = $(self.options.AdditionalButtonContainerSelector); 4545 if (lAdditionalButtonContainers.length > 0) 4546 { 4547 $.each( 4548 lAdditionalButtonContainers, 4549 function (aIndex, aValue)//ignore jslint 4550 { 4551 var lValue = $(aValue); 4552 lValue.children('.' + self.options.SliderButtonClass).removeClass(self.options.SliderButtonActivatedClass); 4553 } 4554 ); 4555 } 4556 } 4557 4558 // we're now closed... 4559 if (self._prevFocusItem === null) 4560 { 4561 // and no activating item was submitted...
4562 if (self._myExternalOpenerButtonItem !== null) 4563 { 4564 // set focus on our external opener button (if any) 4565 self._myExternalOpenerButtonItem.focus(); 4566 } 4567 else 4568 { 4569 // set focus on the tabbable item immediately previous to the menu. 4570 self._prevTabbableItem.focus(); 4571 } 4572 } 4573 else 4574 { 4575 // an activating item was set, set focus there and clear the variable. 4576 self._prevFocusItem.focus(); 4577 self._prevFocusItem = null; 4578 } 4579 } 4580 4581 }); 4582}(jQuery)); 4583 4584 4585/////////////////////////////////////////////////////////////////////////////// 4586// FBRMainDropNav - Foxbright Responsive Main Drop Navigation 4587/////////////////////////////////////////////////////////////////////////////// 4588 4589(function ($) 4590{ 4591 /* 4592 FBRMainDropNav - Foxbright Responsive Main Drop Navigation 4593 4594 Javascript controller for the responsive main drop menu that changes 4595 form/functionality below 768 pixels for mobile and tablet touch screen use. 4596 4597 Options: 4598 4599 MenuClass default: 'fbcms_rmainmenu' 4600 Required. Class to put in place when the menu is initialized. 4601 MenuOpenClass default: 'menuopen' 4602 Required. Class to put in place when the menu is open. 4603 AddDropOpenerToMenuButton default: true 4604 True to add a opener button for the whole menu. Primarily intended to be 4605 shown in mobile (below 768px viewport width) mode. 4606 MenuButtonSelector default: '.menu_title' 4607 Required if AddDropOpenerToMenuButton is true or AllowMenuOpenClose is true 4608 AND MenuButtonClass is not set. 4609 MenuButtonClass default: 'main-opener' 4610 Required if AddDropOpenerToMenuButton is true or AllowMenuOpenClose is true 4611 AND MenuButtonSelector is not set. 4612 MenuTopLevelContainerClass default: 'top_level' 4613 Required. Class to be used to locate the top level container (already in 4614 markup). 4615 MenuTopLevelItemClass default: 'top_level_item' 4616 Required. Class to be used to locate the top level menu items (already in 4617 markup). 4618 MenuSublistItemClass default: 'sublist_item' 4619 Required. Class to be used to locate menu items in sub menus (already in 4620 markup). 4621 MenuItemActiveClass default: 'active' 4622 Required. Class to be used to identify the currently active menu item 4623 (already in markup). 4624 DropOpenerClass default: 'main-drop-opener' 4625 Required. Class to be put into the buttons used to open the top level menu 4626 item sub menus. 4627 OpenDropContent default: '<span class="fas fa-plus"></span>' 4628 Content to be shown when a opener button is closed and may be opened. 4629 Whatever content is put into place, the following content is added afterward. 4630 <span class="screen-reader-text">Open {Link Text} Menu Subpages</span> 4631 CloseDropContent default: '<span class="fas fa-minus"></span>' 4632 Content to be shown when a opener button is open and may be closed. 4633 Whatever content is put into place, the following content is added afterward. 4634 <span class="screen-reader-text">Close {Link Text} Menu Subpages</span> 4635 MenuLinkClass default: 'item_link' 4636 Required. Class to be used to identify the menu link inside a menu item 4637 (already in markup). 4638 MenuLinkWrapperClass default: 'link_pair' 4639 Required. This is a class to be attached to a new element that will wrap 4640 the menu links. Inside, the link will have the opener button added with it 4641 (if that option is turned on). 4642 MenuDropClass default: 'drop' 4643 Required. Class to be used to identify the sub menu (if any) inside a menu 4644 item (already in markup). 4645 InitOpenActiveItems default: true 4646 True to open active menu items by default when the menu is loaded. This 4647 will open the menu items all the way down to the current page. 4648 MenuDefaultOpen default: true 4649 True to open the overall menu by default. 4650 HonorDefaultOpenOnActiveOpen default: false 4651 True to honor the MenuDefaultOpen setting is the InitOpenActiveItems setting 4652 is true. False to open if any active items are present and the 4653 InitOpenActiveItems setting is true, regardless of the MenuDefaultOpen 4654 setting. 4655 AllowMenuOpenClose default: true 4656 True to allow the menu to be opened or closed. 4657 AllowMultipleItemsOpen default: true 4658 True to allow multiple menu items to be open, false to close others when one 4659 is opened. 4660 4661 Methods: 4662 4663 The widget is fully functional on its own, but can be remotely activated
4663with the following 4664 methods. 4665 4666 ToggleMenu 4667 Called to toggle the menu open or closed. 4668 OpenMenu 4669 Called to open the menu (or do nothing if the menu is already open). 4670 CloseMenu 4671 Called to close the menu (or do nothing if the menu is already closed). 4672 ToggleNavItem 4673 Called to toggle a menu item open or closed. 4674 4675 Examples: 4676 4677 Since the function is built as a jQuery Widget, simply call the functions on the 4678 container element directly. 4679 4680 $('nav.main-nav').FBRMainDropNav(); 4681 */ 4682 $.widget("ui.FBRMainDropNav", 4683 { 4684 options: 4685 { 4686 MenuClass: 'fbcms_rmainmenu' 4687 , MenuOpenClass: 'menuopen' 4688 , AddDropOpenerToMenuButton: true 4689 , MenuButtonSelector: '.menu_title' 4690 , MenuButtonClass: 'main-opener' 4691 , MenuTopLevelContainerClass: 'top_level' 4692 , MenuTopLevelItemClass: 'top_level_item' 4693 , MenuTopLevelOpenClass: 'dropfocus' 4694 , MenuSublistItemClass: 'sublist_item' 4695 , MenuItemActiveClass: 'active' 4696 , DropOpenerClass: 'main-drop-opener' 4697 , OpenDropContent: '<span class="fas fa-plus"></span>' 4698 , CloseDropContent: '<span class="fas fa-minus"></span>' 4699 , MenuLinkClass: 'item_link' 4700 , MenuLinkWrapperClass: 'link_pair' 4701 , MenuDropClass: 'drop' 4702 , InitOpenActiveItems: true 4703 , MenuDefaultOpen: true 4704 , HonorDefaultOpenOnActiveOpen: false 4705 , AllowMenuOpenClose: true 4706 , AllowMultipleItemsOpen: true 4707 }, 4708 4709 _destroy: function () 4710 { 4711 return undefined; 4712 }, 4713 4714 _init: function () 4715 { 4716 return undefined; 4717 }, 4718 4719 _create: function () 4720 { 4721 var self = this, 4722 jElement = $(self.element), 4723 lMenuButton, 4724 lButton; 4725 4726 if ($('body.page_bodyonly').length === 1) 4727 { 4728 jElement.remove(); 4729 return; 4730 } 4731 4732 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuClass) 4733 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuOpenClass) 4734 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuTopLevelContainerClass) 4735 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuTopLevelItemClass) 4736 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuSublistItemClass) 4737 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuItemActiveClass) 4738 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropOpenerClass) 4739 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuLinkClass) 4740 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuLinkWrapperClass) 4741 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuDropClass)) 4742 { 4743 FBUtilities.LogMessage('FBRMainDropNav - primary required option null or empty.'); 4744 return; 4745 } 4746 4747 if ((self.options.AllowMenuOpenClose === true 4748 || self.options.AddDropOpenerToMenuButton === true) 4749 && (FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuButtonSelector) 4750 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuButtonClass))) 4751 { 4752 FBUtilities.LogMessage('FBRMainDropNav - menu button settings in disagreement.'); 4753 return; 4754 } 4755 4756 4757 lMenuButton = jElement.find(self.options.MenuButtonSelector); 4758 if (self.options.AllowMenuOpenClose === true 4759 && lMenuButton.length === 0) 4760 { 4761 FBUtilities.LogMessage('FBRMainDropNav - menu button not found as requested by settings.'); 4762 return; 4763 } 4764 4765 if (self.options.AllowMenuOpenClose === true) 4766 { 4767 lMenuButton.addClass(self.options.MenuButtonClass); 4768 lMenuButton.wrapInner('<span class="menu_title_text"></span>'); 4769 if (self.options.AddDropOpenerToMenuButton === true) 4770 { 4771 lMenuButton.append('<a href="#" class="' + self.options.DropOpenerClass + '"></a>'); 4772 lButton = lMenuButton.children('.' + self.options.DropOpenerClass); 4773 self._setNavItemButtonText(lButton, jElement); 4774 } 4775 } 4776 4777 $.each( 4778 jElement.find('.' + self.options.MenuTopLevelItemClass + ',.' + self.options.MenuSublistItemClass) 4779 , function (aIndex, aValue)//ignore jslint 4780 { 4781 var lValue, lLink, lLinkWrapper, lDrop, lMyButton; 4782 4783 lValue = $(aValue); 4784 4785 lLink = lValue.children('.' + self.options.MenuLinkClass); 4786 lLink.wrap('<div class="' + self.options.MenuLinkWrapperClass + '"></div>'); 4787 lLinkWrapper = lValue.children('.' + self.options.MenuLinkWrapperClass); 4788 lDrop = lValue.children('.' + self.options.MenuDropClass); 4789 4790 if (lDrop.length === 1) 4791 { 4792 lLinkWrapper.append('<a href="#" class="' + self.options.DropOpenerClass + '"></a>'); 4793 lMyButton = lLinkWrapper.children('.' + self.options.DropOpenerClass); 4794 self._setNavItemButtonText(lMyButton, lValue); 4795 } 4796 } 4797 ); 4798 4799 jElement.on( 4800 'click' 4801 , '.' + self.options.DropOpenerClass 4802 , function (aEvent) 4803 { 4804 var lTarget, lItemToToggle; 4805 4806 aEvent.preventDefault(); 4807 lTarget = $(aEvent.target); 4808 lItemToToggle = lTarget.closest('.' + self.options.MenuSublistItemClass); 4809 if (lItemToToggle.length === 0) 4810 { 4811 lItemToToggle = lTarget.closest('.' + self.options.MenuTopLevelItemClass); 4812 } 4813 if (lItemToToggle.length === 0) 4814 { 4815 self.ToggleMenu(); 4816 return false; 4817 } 4818 self.ToggleNavItem(lItemToToggle); 4819 return false; 4820 } 4821 ); 4822 4823 //if (self.options.AllowMenuOpenClose) 4824 //{ 4825 // lMenuButtonSelector = '.' + self.options.MenuButtonClass; 4826 // if (self.options.AddDropOpenerToMenuButton === true) 4827 // { 4828 // lMenuButtonSelector += ',.' + self.options.MenuButtonClass + ' .' + self.options.DropOpenerClass; 4829 // } 4830 //} 4831 4832 if (self.options.InitOpenActiveItems) 4833 { 4834 self._openActiveNavItems();
4835 } 4836 if (self.options.MenuDefaultOpen) 4837 { 4838 self.OpenMenu(); 4839 } 4840 4841 var lMainNavClass = 'nav-main'; 4842 if ($('.' + lMainNavClass).length === 0) 4843 { 4844 lMainNavClass = 'main-nav'; 4845 } 4846 if ($('.' + lMainNavClass).length === 0) 4847 { 4848 return; 4849 } 4850 4851 jElement.find('.' + self.options.MenuTopLevelItemClass).DropFocusManager( 4852 { 4853 TitleOpenerSelector: '> .' + self.options.MenuLinkWrapperClass + ' > .' + self.options.MenuLinkClass 4854 , DropLinksSelector: '> .' + self.options.MenuDropClass + ' a' 4855 } 4856 ); 4857 4858 function handleTabKey(e) 4859 { 4860 if (false === $('.secondary-opener').is(':visible')) 4861 { 4862 // ignore tab events on full menu. 4863 } 4864 else if ($(this).hasClass('main-drop-opener')) 4865 { 4866 if (false === $(this).parent().hasClass('main-opener')) 4867 { 4868 if ($(this).parent().parent().hasClass('top_level_item')) 4869 { 4870 if ($(this).parent().parent().next('.top_level_item').length === 0) 4871 { 4872 let jTabbable = jElement.parent().find(':tabbable'); 4873 let index = jTabbable.index(this); 4874 if (index === -1 || (index + 1) >= jTabbable.length) 4875 { 4876 jTabbable.first().get(0).focus(); 4877 e.preventDefault(); 4878 e.stopPropagation(); 4879 return false; 4880 } 4881 } 4882 } 4883 else if ($(this).parent().parent().next('.sublist_item').length === 0) 4884 { 4885 let jSublist = $(this).parent('.link_pair').parent('.sublist_item'); 4886 if (!jSublist.hasClass('menuopen')) 4887 { 4888 let next = jSublist.parent('.main_sublist').parent('.drop').prev('.link_pair').find('.main-drop-opener').get(0); 4889 if ($(next).is(':tabbable')) 4890 { 4891 next.focus(); 4892 e.preventDefault(); 4893 e.stopPropagation(); 4894 return false; 4895 } 4896 } 4897 } 4898 } 4899 } 4900 else if ($(this).hasClass('top_level_link')) 4901 { 4902 let jTabbable = jElement.parent().find(':tabbable'); 4903 let index = jTabbable.index(this); 4904 if (index === -1 || (index + 1) >= jTabbable.length) 4905 { 4906 jTabbable.first().get(0).focus(); 4907 e.preventDefault(); 4908 e.stopPropagation(); 4909 return false; 4910 } 4911 } 4912 else if ($(this).hasClass('item_link')) 4913 { 4914 if (false === $(this).next().hasClass('main-drop-opener') && $(this).parent().parent().next('.sublist_item').length === 0) 4915 { 4916 let next = $(this) 4917 .parent('.link_pair') 4918 .parent('.sublist_item') 4919 .parent('.main_sublist') 4920 .parent('.drop') 4921 .prev('.link_pair') 4922 .find('.main-drop-opener') 4923 .get(0); 4924 4925 if ($(next).is(':tabbable')) 4926 { 4927 next.focus(); 4928 e.preventDefault(); 4929 e.stopPropagation(); 4930 return false; 4931 } 4932 } 4933 } 4934 return true; 4935 } 4936 4937 function handleEscapeKey(e) 4938 { 4939 let lClosestOpenParentMenu = $(this).closest('.menuopen'); 4940 if (lClosestOpenParentMenu.length !== 0) 4941 { 4942 if (false === lClosestOpenParentMenu.hasClass(lMainNavClass)) 4943 { 4944 let lClosestParentOpenDrop = $(this).closest('.drop'); 4945 lClosestParentOpenDrop.prev('.link_pair') 4946 .find('.main-drop-opener') 4947 .focus() 4948 .click(); 4949 e.preventDefault(); 4950 e.stopPropagation(); 4951 return false; 4952 } 4953 } 4954 return true; 4955 } 4956 4957 // handle escape on links. 4958 jElement.find('a').on('keydown', function (e) 4959 { 4960 if (e.keyCode === 9 && false === e.shiftKey) 4961 { 4962 handleTabKey.call(this, e); 4963 } 4964 else if (e.key === "Escape") 4965 { 4966 handleEscapeKey.call(this, e); 4967 } 4968 return true; 4969 }); 4970 4971 jElement.addClass(self.options.MenuClass); 4972 }, 4973 4974 ToggleMenu: function () 4975 { 4976 var self = this, 4977 jElement = $(self.element), 4978 lMenuButton, 4979 lButton; 4980 4981 jElement.toggleClass(self.options.MenuOpenClass); 4982 if (self.options.AddDropOpenerToMenuButton === true) 4983 { 4984 lMenuButton = jElement.find(self.options.MenuButtonSelector); 4985 lButton = lMenuButton.children('.' + self.options.DropOpenerClass); 4986 self._setNavItemButtonText(lButton, jElement); 4987 } 4988 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRMainDropNav:ToggleMenu' } })); 4989 }, 4990 4991 OpenMenu: function () 4992 { 4993 var self = this, 4994 jElement = $(self.element), 4995 lMenuButton, 4996 lButton; 4997 4998 jElement.addClass(self.options.MenuOpenClass); 4999 5000 if (self.options.AddDropOpenerToMenuButton === true) 5001 { 5002 lMenuButton = jElement.find(self.options.MenuButtonSelector); 5003 lButton = lMenuButton.children('.' + self.options.DropOpenerClass); 5004 self._setNavItemButtonText(lButton, jElement); 5005 } 5006 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRMainDropNav:Ope
5006nMenu' } })); 5007 }, 5008 5009 CloseMenu: function () 5010 { 5011 var self = this, 5012 jElement = $(self.element), 5013 lMenuButton, 5014 lButton; 5015 5016 jElement.removeClass(self.options.MenuOpenClass); 5017 if (self.options.AddDropOpenerToMenuButton === true) 5018 { 5019 lMenuButton = jElement.find(self.options.MenuButtonSelector); 5020 lButton = lMenuButton.children('.' + self.options.DropOpenerClass); 5021 self._setNavItemButtonText(lButton, jElement); 5022 } 5023 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRMainDropNav:CloseMenu' } })); 5024 }, 5025 5026 ToggleNavItem: function (aNavItem) 5027 { 5028 var self = this; 5029 5030 if (aNavItem.hasClass(self.options.MenuOpenClass) === false) 5031 { 5032 self.OpenNavItem(aNavItem); 5033 } 5034 else 5035 { 5036 self.CloseNavItem(aNavItem); 5037 } 5038 }, 5039 5040 OpenNavItem: function (aNavItem) 5041 { 5042 var self = this, 5043 jElement = $(self.element), 5044 lButton = aNavItem.children('.' + self.options.MenuLinkWrapperClass).find('.' + self.options.DropOpenerClass); 5045 5046 if (self.options.AllowMultipleItemsOpen === false) 5047 { 5048 var lAllOpenItems = jElement.find('.' + self.options.MenuSublistItemClass + '.has_subitems.' + self.options.MenuOpenClass); 5049 var lParentOpenItems = aNavItem.parents('.' + self.options.MenuSublistItemClass + '.has_subitems.' + self.options.MenuOpenClass); 5050 var lFilteredOpenItems = lAllOpenItems.not(lParentOpenItems); 5051 $.each( 5052 lFilteredOpenItems, 5053 function (aIndex, aValue) 5054 { 5055 self.CloseNavItem($(aValue)); 5056 } 5057 ); 5058 } 5059 5060 self._openNavItem(lButton, aNavItem); 5061 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: aNavItem, name: 'FBRMainDropNav:OpenNavItem' } })); 5062 }, 5063 5064 _openNavItem: function (aButton, aNavItem) 5065 { 5066 var self = this; 5067 5068 aNavItem.addClass(self.options.MenuOpenClass); 5069 self._setNavItemButtonText(aButton, aNavItem); 5070 }, 5071 5072 CloseNavItem: function (aNavItem) 5073 { 5074 var self = this, 5075 lButton = aNavItem.children('.' + self.options.MenuLinkWrapperClass).find('.' + self.options.DropOpenerClass); 5076 5077 self._closeNavItem(lButton, aNavItem); 5078 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: aNavItem, name: 'FBRMainDropNav:CloseNavItem' } })); 5079 }, 5080 5081 _closeNavItem: function (aButton, aNavItem) 5082 { 5083 var self = this; 5084 5085 aNavItem.removeClass(self.options.MenuOpenClass); 5086 self._setNavItemButtonText(aButton, aNavItem); 5087 }, 5088 5089 _setNavItemButtonText: function (aButton, aNavItem) 5090 { 5091 var self = this, 5092 lLink = aNavItem.children('.' + self.options.MenuLinkWrapperClass).children('.' + self.options.MenuLinkClass); 5093 5094 if (aNavItem.is('.' + self.options.MenuOpenClass)) 5095 { 5096 aButton.html(self.options.CloseDropContent + '<span class="screen-reader-text">Close ' + lLink.text() + ' Menu Subpages</span>'); 5097 } 5098 else 5099 { 5100 aButton.html(self.options.OpenDropContent + '<span class="screen-reader-text">Open ' + lLink.text() + ' Menu Subpages</span>'); 5101 } 5102 }, 5103 5104 _openActiveNavItems: function () 5105 { 5106 var self = this, 5107 jElement = $(self.element), 5108 lActiveItems = jElement.find('.' + self.options.MenuTopLevelItemClass + '.' + self.options.MenuItemActiveClass + ',.' + self.options.MenuSublistItemClass + '.' + self.options.MenuItemActiveClass); 5109 5110 5111 if (self.options.HonorDefaultOpenOnActiveOpen === false 5112 && lActiveItems.length > 0) 5113 { 5114 self.OpenMenu(); 5115 } 5116 5117 $.each( 5118 lActiveItems, 5119 function (aIndex, aValue)//ignore jslint 5120 { 5121 var lValue = $(aValue), 5122 lButton = lValue.children('.' + self.options.MenuLinkWrapperClass).find('.' + self.options.DropOpenerClass); 5123 5124 self._openNavItem(lButton, lValue); 5125 } 5126 ); 5127 } 5128 5129 }); 5130}(jQuery)); 5131
5132/////////////////////////////////////////////////////////////////////////////// 5133// FBRListNav - Foxbright Responsive List Navigation 5134/////////////////////////////////////////////////////////////////////////////// 5135 5136(function ($) 5137{ 5138 /* 5139 FBRListNav - Foxbright Responsive List Navigation 5140 5141 Javascript controller for the responsive simple menu that changes 5142 form/functionality below 768 pixels for mobile and tablet touch screen use. 5143 5144 If the class fbcms_rlistmenu is used as a menu class, the menu will be a simple list 5145 menu in the desktop view, and a stack of menu items that can be closed using their 5146 title as a button. 5147 5148 If the class fbcms_rdropmenu is used as a menu class, them menu will be a drop menu 5149 in the desktop view as well. 5150 5151 Options: 5152 5153 MenuClass default: 'fbcms_rlistmenu' 5154 Required. A class to be added to the menu once the widget has successfully 5155 completed. May be default or changed as noted above to change behavior. 5156 MenuInitClass default: 'fbcms_simplemenu' 5157 Required. A class to be added to the menu once the widget has successfully 5158 completed. Change this at your peril. 5159 MenuOpenClass default: 'menuopen' 5160 Required. A class to indicate when the menu is open, to be added or removed 5161 by the widget as appropriate. 5162 MenuTitleClass default: 'menu_title' 5163 Required. A class selector for finding the title element of the menu in the 5164 menu element. If the menu title is empty, the widget will do nothing. 5165 AddMenuButton default: false 5166 If true, add a button to the menu title with events to open and close the 5167 menu. If true, MenuButtonClass, OpenMenuContent, and CloseMenuContent are 5168 all required. 5169 MenuButtonClass default: 'menu_opener' 5170 Required if AddMenuButton is true. A class used to identify the button added 5171 to the menu title. 5172 OpenMenuContent default: '<span class="fas fa-chevron-down"></span>' 5173 Required if AddMenuButton is true. Content to appear in the menu button when 5174 the menu is closed and may be opened. 5175 Whatever content is put into place, the following content is added afterward. 5176 <span class="screen-reader-text">Open {Menu Title} Menu</span> 5177 CloseMenuContent default: '<span class="fas fa-chevron-up"></span>' 5178 Required if AddMenuButton is true. Content to appear in the menu button when 5179 the menu is open and may be closed. 5180 Whatever content is put into place, the following content is added afterward. 5181 <span class="screen-reader-text">Close {Menu Title} Menu</span> 5182 MenuContainerClass default: 'simplemenu_container' 5183 Required. A class that should be found in the markup on the element wrapping 5184 the menu items. 5185 InitOpen default: false 5186 If true, the menu will initialize open. 5187 MenuClickActive default: true 5188 If true, the menu button will be activated on mouse click events. 5189 MenuHoverActive default: false 5190 If true, the menu button will be activated on mouse hover events, closing on 5191 hover out after a delay (MenuHoverDelay) if not hovered over in that time. 5192 MenuHoverDelay default: 300 5193 A hover delay for use if the MenuHoverActive is true. 5194 5195 Methods: 5196 5197 The widget is fully functional on its own, but can be remotely activated
5197with the following 5198 methods. 5199 5200 ToggleMenu 5201 Called to toggle the menu open or closed. 5202 OpenMenu 5203 Called to open the menu (or do nothing if the menu is already open). 5204 CloseMenu 5205 Called to close the menu (or do nothing if the menu is already closed). 5206 5207 Examples: 5208 5209 Since the function is built as a jQuery Widget, simply call the functions on the 5210 container element directly. 5211 5212 $('.list-nav.menu_school').FBRListNav( 5213 { 5214 AddMenuButton : true 5215 ,InitOpen : true 5216 } 5217 ); 5218 5219 $('.drop-nav.menu_subpages').FBRListNav( 5220 { 5221 MenuClass: 'fbcms_rdropmenu' 5222 ,AddMenuButton : true 5223 } 5224 ); 5225 */ 5226 $.widget("ui.FBRListNav", 5227 { 5228 options: 5229 { 5230 MenuClass: 'fbcms_rlistmenu' 5231 , MenuInitClass: 'fbcms_simplemenu' 5232 , MenuOpenClass: 'menuopen' 5233 , MenuTitleClass: 'menu_title' 5234 , AddMenuButton: false 5235 , MenuButtonClass: 'menu_opener' 5236 , OpenMenuContent: '<span class="fas fa-chevron-down"></span>' 5237 , CloseMenuContent: '<span class="fas fa-chevron-up"></span>' 5238 , MenuContainerClass: 'simplemenu_container' 5239 , InitOpen: false 5240 , MenuClickActive: true 5241 , MenuHoverActive: false 5242 , MenuHoverDelay: 300 5243 }, 5244 5245 _hoverTimer: null, 5246 5247 _destroy: function () 5248 { 5249 return undefined; 5250 }, 5251 5252 _init: function () 5253 { 5254 return undefined; 5255 }, 5256 5257 _create: function () 5258 { 5259 var self = this; 5260 var jElement = $(self.element); 5261 5262 if ($('body.page_bodyonly').length === 1) 5263 { 5264 jElement.remove(); 5265 return; 5266 } 5267 5268 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuClass) 5269 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuInitClass) 5270 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuOpenClass) 5271 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuTitleClass) 5272 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuContainerClass)) 5273 { 5274 FBUtilities.LogMessage('FBRListNav - required settings null or empty.'); 5275 return; 5276 } 5277 5278 if (self.options.AddMenuButton === true 5279 && (FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuButtonClass) 5280 || FBUtilities.IsStringEmptyOrWhitespace(self.options.OpenMenuContent) 5281 || FBUtilities.IsStringEmptyOrWhitespace(self.options.CloseMenuContent))) 5282 { 5283 FBUtilities.LogMessage('FBRListNav - menu button settings not set as requested.'); 5284 return; 5285 } 5286 5287 let lTitleElement = jElement.find(`.${self.options.MenuTitleClass}`); 5288 5289 if (lTitleElement.length === 0) 5290 { 5291 FBUtilities.LogMessage('FBRListNav - menu title not found.'); 5292 return; 5293 } 5294 lTitleElement.attr("aria-expanded", false); 5295 5296 self._MenuTitle = lTitleElement.text(); 5297 5298 if (self.options.AddMenuButton === true) 5299 { 5300 lTitleElement.append('<span class="' + self.options.MenuButtonClass + '"></span>'); 5301 self._setMenuButtonContent(); 5302 } 5303 5304 let lButtonEventSelector = '.' + self.options.MenuTitleClass; 5305 if (self.options.AddMenuButton === true) 5306 { 5307 lButtonEventSelector = lButtonEventSelector + ',.' + self.options.MenuButtonClass; 5308 } 5309 5310 if (self.options.MenuClickActive === true) 5311 { 5312 jElement.on( 5313 'click', 5314 lButtonEventSelector, 5315 function (aEvent) 5316 { 5317 aEvent.preventDefault(); 5318 self.ToggleMenu(); 5319 return false; 5320 } 5321 ); 5322 } 5323 5324 if (self.options.MenuHoverActive === true) 5325 { 5326 jElement.hover( 5327 function () 5328 { 5329 self.OpenMenu(); 5330 5331 if (self._hoverTimer !== null) 5332 { 5333 $.clearTimer(self._hoverTimer); 5334 } 5335 } 5336 , function () 5337 { 5338 self._hoverTimer = $.timer( 5339 self.options.MenuHoverDelay, 5340 function () 5341 { 5342 self.CloseMenu(); 5343 } 5344 ); 5345 } 5346 ); 5347 } 5348 5349 if (self.options.InitOpen) 5350 { 5351 self.OpenMenu(); 5352 } 5353 5354 jElement.DropFocusManager( 5355 { 5356 HoverFocusClass: self.options.MenuOpenClass 5357 , OpenOnHoverFocus: false 5358 , TitleOpenerSelector: '.' + self.options.MenuTitleClass 5359 , DropLinksSelector: '.' + self.options.MenuContainerClass + ' a' 5360 } 5361 ); 5362 5363 jElement.addClass(self.options.MenuClass); 5364 jElement.addClass(self.options.MenuInitClass); 5365 }, 5366 5367 _MenuTitle: null, 5368 5369 ToggleMenu: function () 5370 { 5371 var self = this, 5372 jElement = $(self.element); 5373 5374 jElement.toggleClass(self.options.MenuOpenClass); 5375 jElement.find(`.${self.options.MenuTitleClass}`).attr("aria-expanded", jElement.hasClass(self.options.MenuOpenClass)); 5376 5377 self._setMenuButtonContent(); 5378 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRListNav:ToggleMenu' } })); 5379 }, 5380 5381 OpenMenu: function () 5382 { 5383 var self = this, 5384 jElement = $(self.element); 5385 5386 jElement.addClass(self.options.MenuOpenClass); 5387 jElement.find(`.${self.options.MenuTitleClass}`).attr("aria-expanded", true); 5388 5389 self._setMenuButtonContent(); 5390 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRListNav:OpenMenu' } })); 5391 }, 5392 5393 CloseMenu: function () 5394 { 5395 var self = this, 5396 jElement = $(self.element); 5397 5398 jElement.removeClass(self.options.MenuOpenClass); 5399 jElement.find(`.${self.options.MenuTitleClass}`).attr("aria-expanded", false); 5400 5401 self._setMenuButtonContent(); 5402 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRListNav:CloseMenu' } })); 5403 }, 5404 5405 _setMenuButtonContent: function () 5406 { 5407 var self = this, 5408 jElement = $(self.element), 5409 lMenuButton; 5410 5411 if (self.options.AddMenuButton === true) 5412 { 5413 lMenuButton = jElement.find('.' + self.options.MenuButtonClass); 5414 5415 if (jElement.is('.' + self.options.MenuOpenClass)) 5416 { 5417 lMenuButton.html(self.options.CloseMenuContent + '<span class="screen-reader-text">Close ' + self._MenuTitle + ' Menu</span>'); 5418 } 5419 else 5420 { 5421 lMenuButton.html(self.options.OpenMenuContent + '<span class="screen-reader-text">Open ' + self._MenuTitle + ' Menu</span>'); 5422 } 5423 } 5424 } 5425 5426 }); 5427}(jQuery)); 5428
5429/////////////////////////////////////////////////////////////////////////////// 5430// VisualNavManager - Visual Nav/"Mobile Menu" Manager 5431/////////////////////////////////////////////////////////////////////////////// 5432 5433function VisualNavManager_Functions() 5434{ 5435 return undefined; 5436} 5437 5438VisualNavManager_Functions._ExtraMenuButtonHandler = function (aEvent) 5439{ 5440 aEvent.preventDefault(); 5441 $(aEvent.target).closest('.visual_nav_wrapper').VisualNavManager('ToggleMenu'); 5442 return false; 5443}; 5444 5445VisualNavManager_Functions._ExtraMenuEscapeHandler = function (aEvent) 5446{ 5447 if (aEvent.keyCode === 27 /*escape*/) 5448 { 5449 aEvent.preventDefault(); 5450 var jNav = $(aEvent.target).closest('.visual_nav_wrapper'); 5451 jNav.VisualNavManager('CloseMenu'); 5452 jNav.find('.visual_nav_extraopener').focus();// warning, class from options here!!! 5453 return false; 5454 } 5455}; 5456 5457VisualNavManager_Functions._ExtraMenuLoopBackHandler = function (aEvent) 5458{ 5459 if (aEvent.keyCode === 9 && aEvent.shiftKey === false) 5460 { 5461 aEvent.preventDefault(); 5462 var jNav = $(aEvent.target).closest('.visual_nav_wrapper'); 5463 jNav.find('.visual_nav_liner_extra .visual_nav_item_link').first().focus();// warning, class from options here!!! 5464 } 5465}; 5466 5467VisualNavManager_Functions._ExtraMenuLoopFrontHandler = function (aEvent) 5468{ 5469 if (aEvent.keyCode === 9 && aEvent.shiftKey === true) 5470 { 5471 aEvent.preventDefault(); 5472 var jNav = $(aEvent.target).closest('.visual_nav_wrapper'); 5473 jNav.find('.visual_nav_liner_extra .visual_nav_item_link').last().focus();// warning, class from options here!!! 5474 } 5475}; 5476 5477VisualNavManager_Functions._ExtraMenuGlobalFocusHandler = function (aEvent) 5478{ 5479 if ($(aEvent.target).closest('.visual_nav_wrapper .visual_nav_liner_extra').length === 0) 5480 { 5481 var jNav = $('.visual_nav_wrapper'); 5482 jNav.VisualNavManager('CloseMenu'); 5483 if (jQuery.contains( jNav.find('.visual_nav_extraopener'), aEvent.target ) === false) 5484 { 5485 jNav.VisualNavManager('CloseMenu'); 5486 } 5487 } 5488}; 5489 5490(function ($) 5491{ 5492 /* 5493 VisualNavManager - Visual Nav/"Mobile Menu" Manager 5494 5495 Javascript controller for any active components of the VisualNav menus. 5496 This currently consists of the Extra/Overflow menu. 5497 5498 Options: 5499 5500 MenuOpenClass default: 'visual_nav_open' 5501 Required. A class to indicate when the menu is open, to be added or removed 5502 by the widget as appropriate. 5503 MenuButtonClass default: 'visual_nav_extraopener' 5504 Required if AddMenuButton is true. A class used to identify the button added 5505 to the menu title. 5506 MenuContainerClass default: 'visual_nav_liner_extra' 5507 Required. A class that should be found in the markup on the element wrapping 5508 the menu items. 5509 5510 Methods: 5511 5512 The widget is fully functional on its own, but can be remotely activated with the following 5513 methods. 5514 5515 ToggleMenu 5516 Called to toggle the menu open or closed. 5517 OpenMenu 5518 Called to open the menu (or do nothing if the menu is already open). 5519 CloseMenu 5520 Called to close the menu (or do nothing if the menu is already closed). 5521 5522 Examples: 5523 5524 Since the function is built as a jQuery Widget, simply call the functions on the 5525 container element directly. 5526 5527 $('.visual_nav_wrapper').VisualNavManager(); 5528 5529 */ 5530 $.widget("ui.VisualNavManager", 5531 { 5532 options: 5533 { 5534 MenuOpenClass: 'visual_nav_open' 5535 , MenuButtonClass: 'visual_nav_extraopener' 5536 , MenuContainerClass: 'visual_nav_liner_extra' 5537 , MenuLinkClass: 'visual_nav_item_link' 5538 }, 5539 5540 _hoverTimer: null, 5541 5542 _destroy: function () 5543 { 5544 var self = this; 5545 var jElement = $(self.element); 5546 5547 jElement.off( 5548 'click', 5549 '.' + self.options.MenuButtonClass, 5550 VisualNavManager_Functions._ExtraMenuButtonHandler 5551 ); 5552 5553 let jExtraMenuOpener = jElement.find('.visual_nav_extraopener'); 5554 let jExtraMenu = jElement.find('.visual_nav_liner_extra'); 5555 if (jExtraMenuOpener.length > 0 5556 && jExtraMenu.length > 0) 5557 { 5558 let lExtraMenu = jExtraMenu.get(0); 5559 let jExtraLinks = jExtraMenu.find('.visual_nav_item_link'); 5560 5561 jExtraLinks.off('keydown', VisualNavManager_Functions._ExtraMenuEscapeHandler); 5562 5563 jExtraLinks.first().off('keydown', VisualNavManager_Functions._ExtraMenuLoopFrontHandler); 5564 5565 jExtraLinks.last().off('keydown', VisualNavManager_Functions._ExtraMenuLoopBackHandler); 5566 5567 $('body').off('click', VisualNavManager_Functions._ExtraMenuGlobalFocusHandler); 5568 } 5569 5570 return undefined; 5571 }, 5572 5573 _init: function () 5574 { 5575 return undefined; 5576 }, 5577 5578 _create: function () 5579 { 5580 var self = this; 5581 var jElement = $(self.element); 5582 5583 //TODO: should this remain??? 5584 if ($('body.page_bodyonly').length === 1) 5585 { 5586 jElement.remove(); 5587 return; 5588 } 5589 5590 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuOpenClass) 5591 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuButtonClass) 5592 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuContainerClass) 5593 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MenuLinkClass)) 5594 { 5595 FBUtilities.LogMessage('FBRListNav - required settings null or empty.'); 5596 return; 5597 } 5598 5599 jElement.on( 5600 'click', 5601 '.' + self.options.MenuButtonClass, 5602 VisualNavManager_Functions._ExtraMenuButtonHandler 5603 ); 5604 5605 var lElement = jElement.get(0); 5606 $("body").css("--VisualNav-Height", "" + lElement.offsetHeight + "px"); 5607 5608 let jExtraMenuOpener = jElement.find('.visual_nav_extraopener'); 5609 let jExtraMenu = jElement.find('.visual_nav_liner_extra'); 5610 if (jExtraMenuOpener.length > 0 5611 && jExtraMenu.length > 0) 5612 { 5613 let lExtraMenu = jExtraMenu.get(0); 5614 let jExtraLinks = jExtraMenu.find('.visual_nav_item_link'); 5615 5616 // if it's ESC, close menu. 5617 jExtraLinks.on('keydown', VisualNavManager_Functions._ExtraMenuEscapeHandler); 5618 5619 5620 // on first item, loop to last on backward tab. 5621 jExtraLinks.first().on('keydown', VisualNavManager_Functions._ExtraMenuLoopFrontHandler); 5622 5623 // on last item, loop to first on forward tab. 5624 jExtraLinks.last().on('keydown', VisualNavManager_Functions._ExtraMenuLoopBackHandler); 5625 5626 5627 // on focus loss, close menu? 5628 jExtraMenu.on('focusout', function(event) 5629 { 5630 // unknown if this is usefully populated. 5631 if (jQuery.contains( lExtraMenu, event.relatedTarget ) === false) 5632 { 5633 self.CloseMenu(); 5634 } 5635 }); 5636 $('body').on('click', VisualNavManager_Functions._ExtraMenuGlobalFocusHandler); 5637 } 5638 }, 5639 5640 ToggleMenu: function () 5641 { 5642 var self = this, 5643 jElement = $(self.element); 5644 5645 jElement.toggleClass(self.options.MenuOpenClass); 5646 5647 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'VisualNavManager:ToggleMenu' } })); 5648 }, 5649 5650 OpenMenu: function () 5651 { 5652 var self = this, 5653 jElement = $(self.element); 5654 5655 jElement.addClass(self.options.MenuOpenClass); 5656 5657 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'VisualNavManager:OpenMenu' } })); 5658 }, 5659 5660 CloseMenu: function () 5661 { 5662 var self = this, 5663 jElement = $(self.element); 5664 5665 jElement.removeClass(self.options.MenuOpenClass); 5666 5667 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'VisualNavManager:CloseMenu' } })); 5668 } 5669 }); 5670 5671 $(window).on('load', function () 5672 { 5673 $('.visual_nav_wrapper').VisualNavManager(); 5674 });
5675}(jQuery)); 5676 5677 5678/////////////////////////////////////////////////////////////////////////////// 5679// FBRFlyUp - Foxbright Responsive Flyup 5680/////////////////////////////////////////////////////////////////////////////// 5681 5682(function ($) 5683{ 5684 /* 5685 FBRFlyUp - Foxbright Responsive Flyup 5686 5687 Fly-up widget. 5688 5689 The element selected by the widget (container element) will have a class added to it 5690 to indicate that it is opened (OpenClass). Selecting the fly-up tab or mouse hovering 5691 over any part of the slider will open the fly-up and put the class in place. 5692 5693 Options: 5694 5695 FlyupTitleSelector default: null - must be set to a valid selector. 5696 Required. A selector to be used to find the title element(s) inside the element. 5697 ContainerClass default: 'flyup_container' 5698 Required. The class to be set to the widget element. 5699 OpenClass default: 'flyup_expanded' 5700 Required. The class to be set on the drawer element when open. 5701 DrawerClass default: 'flyup_drawer' 5702 Required. The class to be set on a content wrapper that does all the sliding. 5703 This element will be added to the DOM by the widget. 5704 TabWrapperClass default: 'flyup_tabcontainer' 5705 Required. The class to be set on a wrapper around the tab. 5706 This element will be added to the DOM by the widget. 5707 TabClass default: 'flyup_tab' 5708 Required. The class to be added to the flyup title element. 5709 SlideClass default: 'flyup_slide' 5710 Required. The class for the element to be wrapped around all content under the 5711 flyup title. This element will be added to the DOM by the widget. 5712 AnimationSpeed default: 500 5713 Required. Number of milliseconds that the slide animation should take. 5714 UseClickOnly default: false 5715 Required. True if the flyup should work only on click instead of by hover. 5716 5717 Methods: 5718 5719 The widget is fully functional on its own, but can be remotely activated with the following 5720 methods. 5721 5722 ToggleFlyup 5723 Called to toggle the widget open or closed. 5724 OpenFlyup 5725 Called to open the widget (or do nothing if the widget is already open). 5726 CloseFlyup 5727 Called to close the widget (or do nothing if the widget is already closed). 5728 5729 Examples: 5730 5731 Since the function is built as a jQuery Widget, simply call the functions on the 5732 container element directly. New markup and classes will be added in place. This example 5733 has the markup followed by the jQuery call to activate it. 5734 5735 <div class="slider_box"> 5736 <h2 class="slider_box_title">{TITLE CONTENT}</h2> 5737 {SLIDER CONTENT - Must be HTML elements, may be multiple.} 5738 </div> 5739 5740 $('.slider_box').FBRFlyUp( 5741 { 5742 FlyupTitleSelector : '.slider_box_title' 5743 } 5744 ); 5745 */ 5746 $.widget("ui.FBRFlyUp", 5747 { 5748 options: 5749 { 5750 FlyupTitleSelector: null 5751 , ContainerClass: 'flyup_container' 5752 , OpenClass: 'flyup_expanded' 5753 , DrawerClass: 'flyup_drawer' 5754 , TabWrapperClass: 'flyup_tabcontainer' 5755 , TabClass: 'flyup_tab' 5756 , SlideClass: 'flyup_slide' 5757 , AnimationSpeed: 500 5758 , UseClickOnly: false 5759 }, 5760 5761 _destroy: function () 5762 { 5763 var self, jElement, lTitleElement, lIsEditMode, lTab, lDrawer, lSlide; 5764 5765 self = this; 5766 jElement = $(self.element); 5767 lTitleElement = jElement.find(self.options.FlyupTitleSelector); 5768 if (lTitleElement.length === 0) 5769 { 5770 return; 5771 } 5772 5773 lIsEditMode = FBCommon_1_2.isInEditor(); 5774 lTab = jElement.find('.' + self.options.TabClass); 5775 lDrawer = jElement.find('.' + self.options.DrawerClass); 5776 lSlide = jElement.find('.' + self.options.SlideClass); 5777 5778 if (lTab.length === 0 5779 || lDrawer.length === 0 5780 || lSlide.length === 0) 5781 { 5782 return; 5783 } 5784 5785 if (lIsEditMode === false 5786 && FBUtilities.IsStringEmptyOrWhitespace(lTab.text())) 5787 { 5788 jElement.show(); 5789 return; 5790 } 5791 5792 jElement.css( 5793 { 5794 position: '' 5795 } 5796 ); 5797 5798 lDrawer.css( 5799 { 5800 position: '', 5801 top: '' 5802 } 5803 ); 5804 5805 jQuery(document).off('click'); 5806 lTab.off('keypress'); 5807 5808 if (self.options.UseClickOnly) 5809 { 5810 lTab.off('click', self.ToggleFlyup); 5811 } 5812 else 5813 { 5814 jElement.off( 5815 "mouseout", 5816 '.' + self.options.DrawerClass 5817 ); 5818 jElement.off( 5819 "mouseover", 5820 '.' + self.options.TabClass 5821 ); 5822 } 5823 5824 jElement.off( 5825 "focusin", 5826 '.' + self.options.SlideClass 5827 ); 5828 5829 5830 lTitleElement.unwrap(); 5831 lTitleElement.removeAttr('tabindex'); 5832 lTitleElement.removeClass(self.options.TabClass); 5833 jElement.find('.' + self.options.DrawerClass).unwrap(); 5834 jElement.find('.' + self.options.SlideClass).children().unwrap(); 5835 jElement.removeClass(self.options.ContainerClass); 5836 }, 5837 5838 _init: function () 5839 { 5840 return undefined; 5841 }, 5842 5843 _create: function () 5844 { 5845 var self, jElement, lTitleElement, lTab, lDrawer, lSlide; 5846 5847 self = this; 5848 jElement = $(self.element); 5849 5850 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.FlyupTitleSelector) 5851 || FBUtilities.IsStringEmptyOrWhitespace(self.options.ContainerClass) 5852 || FBUtilities.IsStringEmptyOrWhitespace(self.options.OpenClass) 5853 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DrawerClass) 5854 || FBUtilities.IsStringEmptyOrWhitespace(self.options.TabWrapperClass) 5855 || FBUtilities.IsStringEmptyOrWhitespace(self.options.TabClass) 5856 || FBUtilities.IsStringEmptyOrWhitespace(self.options.SlideClass) 5857 || FBUtilities.IsParameterUndefined(self.options.AnimationSpeed) 5858 || FBUtilities.IsParameterUndefined(self.options.UseClickOnly)) 5859 {
5860 FBUtilities.LogMessage('FBRFlyUp - required settings null or empty.'); 5861 jElement.hide(); 5862 return; 5863 } 5864 5865 lTitleElement = jElement.find(self.options.FlyupTitleSelector); 5866 if (lTitleElement.length === 0) 5867 { 5868 jElement.hide(); 5869 return; 5870 } 5871 5872 lTitleElement.wrap($('<div></div>').addClass(self.options.TabWrapperClass)); 5873 lTitleElement.addClass(self.options.TabClass); 5874 lTitleElement.attr('tabindex', '0'); 5875 jElement.children().not('.' + self.options.TabWrapperClass).wrapAll($('<div></div>').addClass(self.options.SlideClass)); 5876 jElement.children().wrapAll($('<div></div>').addClass(self.options.DrawerClass)); 5877 jElement.addClass(self.options.ContainerClass); 5878 5879 5880 lTab = jElement.find('.' + self.options.TabClass); 5881 lDrawer = jElement.find('.' + self.options.DrawerClass); 5882 lSlide = jElement.find('.' + self.options.SlideClass); 5883 5884 if (lTab.length === 0 5885 || lDrawer.length === 0) 5886 { 5887 jElement.hide(); 5888 return; 5889 } 5890 5891 if (FBCommon_1_2.isInEditor() === false 5892 && FBUtilities.IsStringEmptyOrWhitespace(lTab.text())) 5893 { 5894 jElement.hide(); 5895 return; 5896 } 5897 5898 if (lSlide.length === 0) 5899 { 5900 jElement.hide(); 5901 return; 5902 } 5903 5904 jElement.css( 5905 { 5906 position: 'relative' 5907 } 5908 ); 5909 5910 lDrawer.css( 5911 { 5912 position: 'absolute', 5913 top: -lTab.innerHeight() 5914 } 5915 ); 5916 5917 jQuery(document).click( 5918 function (aEvent) 5919 { 5920 var lTarget = jQuery(aEvent.target); 5921 if (!lTarget.parents().is(lDrawer)) 5922 { 5923 self.CloseFlyup(); 5924 } 5925 } 5926 ); 5927 5928 lTab.keypress( 5929 function (aEvent) 5930 { 5931 if (aEvent.which === 13) 5932 { 5933 self.ToggleFlyup(); 5934 return false; 5935 } 5936 } 5937 ); 5938 5939 if (self.options.UseClickOnly) 5940 { 5941 lTab.on('click', self.ToggleFlyup); 5942 } 5943 else 5944 { 5945 jElement.on( 5946 "mouseout", 5947 '.' + self.options.DrawerClass, 5948 function (aEvent) 5949 { 5950 var lDrawerParent = $(aEvent.relatedTarget).closest('.' + self.options.DrawerClass); 5951 if (lDrawerParent.length === 1 5952 && lDrawerParent.get(0) === lDrawer.get(0)) 5953 { 5954 return false; 5955 } 5956 self.CloseFlyup(); 5957 } 5958 ); 5959 jElement.on( 5960 "mouseover", 5961 '.' + self.options.TabClass, 5962 function (/*aEvent*/) 5963 { 5964 self.OpenFlyup(); 5965 } 5966 ); 5967 } 5968 5969 jElement.on( 5970 "focusin", 5971 '.' + self.options.SlideClass, 5972 function (/*aFIEvent*/) 5973 { 5974 self.OpenFlyup(); 5975 lSlide.on( 5976 "focusout", 5977 function (aFOEvent) 5978 { 5979 var lSlideParent = $(aFOEvent.target).closest('.' + self.options.SlideClass); 5980 if (lSlideParent.length === 1 5981 && lSlideParent.get(0) === lSlide.get(0)) 5982 { 5983 return false; 5984 } 5985 5986 self.CloseFlyup(); 5987 lSlide.off("focusout"); 5988 } 5989 ); 5990 } 5991 ); 5992 }, 5993 5994 ToggleFlyup: function () 5995 { 5996 var self, jElement, lDrawer; 5997 5998 self = this; 5999 jElement = $(self.element); 6000 lDrawer = jElement.find('.' + self.options.DrawerClass); 6001 6002 if (lDrawer.hasClass(self.options.OpenClass)) 6003 { 6004 self.CloseFlyup(); 6005 } 6006 else 6007 { 6008 self.OpenFlyup(); 6009 } 6010 }, 6011 6012 OpenFlyup: function () 6013 { 6014 var self, jElement, lDrawer; 6015 6016 self = this; 6017 jElement = $(self.element); 6018 lDrawer = jElement.find('.' + self.options.DrawerClass); 6019 6020 lDrawer.animate({
6021 top: -lDrawer.innerHeight() 6022 }, { 6023 queue: false, 6024 duration: self.options.AnimationSpeed, 6025 complete: function () 6026 { 6027 lDrawer.addClass(self.options.OpenClass); 6028 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRFlyUp:OpenFlyup' } })); 6029 } 6030 }); 6031 }, 6032 6033 CloseFlyup: function () 6034 { 6035 var self, jElement, lTab, lDrawer; 6036 6037 self = this; 6038 jElement = $(self.element); 6039 lTab = jElement.find('.' + self.options.TabClass); 6040 lDrawer = jElement.find('.' + self.options.DrawerClass); 6041 6042 lDrawer.animate({ 6043 top: -lTab.innerHeight() 6044 }, { 6045 queue: false, 6046 duration: self.options.AnimationSpeed, 6047 complete: function () 6048 { 6049 lDrawer.removeClass(self.options.OpenClass); 6050 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBRFlyUp:CloseFlyup' } })); 6051 } 6052 }); 6053 } 6054 6055 }); 6056}(jQuery)); 6057 6058/////////////////////////////////////////////////////////////////////////////// 6059// DropFocusManager - Foxbright Drop Focus Manager 6060/////////////////////////////////////////////////////////////////////////////// 6061 6062(function ($) 6063{ 6064 /* 6065 DropFocusManager - Foxbright Drop Focus Manager 6066 6067 Javascript controller for managing simple drop logic and incorporating keyboard focus 6068 into the drop behavior as well. 6069 6070 The element selected by the widget (container element) will have a class added to it 6071 to indicate that it is opened (HoverFocusClass). Selecting or focusing on the element 6072 or elements indicated by TitleOpenerSelector will put the class in place. Selection 6073 of the element(s) indicated by DropLinksSelector will keep the open status in place. 6074 A delay for closing the element (FocusCloseDelay) is available for tuning the 6075 behavior of the widget and ensuring time for events to propagate. 6076 6077 Options: 6078 6079 HoverFocusClass default: 'hoverfocus' 6080 Required. A class to be added to the element when focu
6080s is in the element. 6081 OpenOnHoverFocus default: true 6082 Required. True if the hoverfocus class is to be added on hover as well. 6083 FocusCloseDelay default: 10 6084 Required. The number of milliseconds after loss of focus to wait before 6085 closing the element. Necessary to give time for new focus events that occur 6086 inside the element to propagate and stop the closure. 6087 TitleOpenerSelector default: null 6088 Required. A jQuery selector indicating the element or elements to use as an 6089 opener button for the element. 6090 DropLinksSelector default: null 6091 Required. A jQuery selector indicating the elements inside the element that 6092 should keep the element open if selected. 6093 6094 Methods: 6095 6096 The widget is fully functional on its own, but can be remotely activated with the following 6097 methods. 6098 6099 ToggleDrop 6100 Called to toggle the widget open or closed. 6101 OpenDrop 6102 Called to open the widget (or do nothing if the widget is already open). 6103 CloseDrop 6104 Called to close the widget (or do nothing if the widget is already closed). 6105 6106 Examples: 6107 6108 Since the function is built as a jQuery Widget, simply call the functions on the 6109 container element directly. 6110 6111 $('.list-nav.menu_quicklinks').DropFocusManager( 6112 { 6113 TitleOpenerSelector : '.menu_title' 6114 ,DropLinksSelector : '.drop a' 6115 } 6116 ); 6117 */ 6118 $.widget("ui.DropFocusManager", 6119 { 6120 options: 6121 { 6122 HoverFocusClass: 'hoverfocus' 6123 , OpenOnHoverFocus: true 6124 , FocusCloseDelay: 10 6125 , TitleOpenerSelector: null 6126 , DropLinksSelector: null 6127 }, 6128 6129 _focusTimer: null, 6130 6131 _destroy: function () 6132 { 6133 return undefined; 6134 }, 6135 6136 _init: function () 6137 { 6138 return undefined; 6139 }, 6140 6141 _create: function () 6142 { 6143 var self, jElement; 6144 6145 self = this; 6146 jElement = $(self.element); 6147 6148 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.HoverFocusClass) 6149 || FBUtilities.IsStringEmptyOrWhitespace(self.options.TitleOpenerSelector) 6150 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropLinksSelector)) 6151 { 6152 FBUtilities.LogMessage('DropFocusManager - required settings null or empty.'); 6153 return; 6154 } 6155 6156 jElement.on( 6157 "focusin", 6158 self.options.TitleOpenerSelector, 6159 function (/*aEvent*/) 6160 { 6161 if (self.options.OpenOnHoverFocus === true) 6162 { 6163 $.clearTimer(self._focusTimer); 6164 self.OpenDrop(); 6165 } 6166 } 6167 ); 6168 6169 jElement.on( 6170 "focusin", 6171 self.options.DropLinksSelector, 6172 function (/*aEvent*/) 6173 { 6174 $.clearTimer(self._focusTimer); 6175 self.OpenDrop(); 6176 } 6177 ); 6178 6179 jElement.on( 6180 "focusout", 6181 self.options.TitleOpenerSelector + ',' + self.options.DropLinksSelector, 6182 function (/*aEvent*/) 6183 { 6184 self._focusTimer = $.timer( 6185 self.options.FocusCloseDelay, 6186 function () 6187 { 6188 self.CloseDrop(); 6189 } 6190 ); 6191 } 6192 ); 6193 6194 }, 6195 6196 ToggleDrop: function () 6197 { 6198 var self, jElement; 6199 6200 self = this; 6201 jElement = $(self.element); 6202 jElement.toggleClass(self.options.HoverFocusClass); 6203 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'DropFocusManager:ToggleDrop' } })); 6204 }, 6205 6206 OpenDrop: function () 6207 { 6208 var self, jElement; 6209 6210 self = this; 6211 jElement = $(self.element); 6212 6213 if (jElement.hasClass(self.options.HoverFocusClass)) 6214 { 6215 return; 6216 } 6217 jElement.addClass(self.options.HoverFocusClass); 6218 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'DropFocusManager:OpenDrop' } })); 6219 }, 6220 6221 CloseDrop: function () 6222 { 6223 var self, jElement; 6224 6225 self = this; 6226 jElement = $(self.element); 6227 jElement.removeClass(self.options.HoverFocusClass); 6228 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'DropFocusManager:CloseDrop' } })); 6229 } 6230 6231 }); 6232}(jQuery)); 6233
6234/////////////////////////////////////////////////////////////////////////////// 6235// ItemFocusManager - Foxbright Item Focus Manager 6236/////////////////////////////////////////////////////////////////////////////// 6237 6238(function ($) 6239{ 6240 /* 6241 ItemFocusManager - Foxbright Item Focus Manager 6242 6243 Javascript controller for managing simple drop logic and incorporating keyboard focus 6244 into the drop behavior as well. Based on DropFocusManager. 6245 6246 The element selected by the widget (container element) will have a class added to it 6247 to indicate that it is opened (HoverFocusClass). Selecting or focusing on the element 6248 or elements inside it will put the class in place. 6249 A delay for closing the element (FocusCloseDelay) is available for tuning the 6250 behavior of the widget and ensuring time for events to propagate. 6251 6252 Options: 6253 6254 HoverFocusClass default: 'hoverfocus' 6255 Required. A class to be added to the element when focu
6255s is in the element. 6256 OpenOnHoverFocus default: true 6257 Required. True if the hoverfocus class is to be added on hover as well. 6258 FocusCloseDelay default: 10 6259 Required. The number of milliseconds after loss of focus to wait before 6260 closing the element. Necessary to give time for new focus events that occur 6261 inside the element to propagate and stop the closure. 6262 6263 Methods: 6264 6265 The widget is fully functional on its own, but can be remotely activated with the following 6266 methods. 6267 6268 ToggleDrop 6269 Called to toggle the widget open or closed. 6270 OpenDrop 6271 Called to open the widget (or do nothing if the widget is already open). 6272 CloseDrop 6273 Called to close the widget (or do nothing if the widget is already closed). 6274 6275 Examples: 6276 6277 Since the function is built as a jQuery Widget, simply call the functions on the 6278 container element directly. 6279 6280 $('.item').ItemFocusManager(); 6281 */ 6282 $.widget("ui.ItemFocusManager", 6283 { 6284 options: 6285 { 6286 HoverFocusClass: 'hoverfocus' 6287 , OpenOnHoverFocus: true 6288 , FocusCloseDelay: 10 6289 }, 6290 6291 _focusTimer: null, 6292 6293 destroy: function () 6294 { 6295 return undefined; 6296 }, 6297 6298 _init: function () 6299 { 6300 return undefined; 6301 }, 6302 6303 _create: function () 6304 { 6305 var self, jElement; 6306 6307 self = this; 6308 jElement = $(self.element); 6309 6310 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.HoverFocusClass)) 6311 { 6312 FBUtilities.LogMessage('ItemFocusManager - required settings null or empty.'); 6313 return; 6314 } 6315 6316 jElement.on( 6317 "focusin", 6318 function (/*aEvent*/) 6319 { 6320 if (self.options.OpenOnHoverFocus === true) 6321 { 6322 $.clearTimer(self._focusTimer); 6323 self.OpenDrop(); 6324 } 6325 } 6326 ); 6327 6328 jElement.on( 6329 "focusout", 6330 function (/*aEvent*/) 6331 { 6332 self._focusTimer = $.timer( 6333 self.options.FocusCloseDelay, 6334 function () 6335 { 6336 self.CloseDrop(); 6337 } 6338 ); 6339 } 6340 ); 6341 6342 }, 6343 6344 ToggleDrop: function () 6345 { 6346 var self, jElement; 6347 6348 self = this; 6349 jElement = $(self.element); 6350 jElement.toggleClass(self.options.HoverFocusClass); 6351 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'ItemFocusManager:ToggleDrop' } })); 6352 }, 6353 6354 OpenDrop: function () 6355 { 6356 var self, jElement; 6357 6358 self = this; 6359 jElement = $(self.element); 6360 6361 if (jElement.hasClass(self.options.HoverFocusClass)) 6362 { 6363 return; 6364 } 6365 jElement.addClass(self.options.HoverFocusClass); 6366 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'ItemFocusManager:OpenDrop' } })); 6367 }, 6368 6369 CloseDrop: function () 6370 { 6371 var self, jElement; 6372 6373 self = this; 6374 jElement = $(self.element); 6375 jElement.removeClass(self.options.HoverFocusClass); 6376 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'ItemFocusManager:CloseDrop' } })); 6377 } 6378 6379 }); 6380}(jQuery)); 6381
6382/////////////////////////////////////////////////////////////////////////////// 6383// jQuery functions extensions. 6384/////////////////////////////////////////////////////////////////////////////// 6385 6386(function ($) 6387{ 6388 // --[ Truncate text ]------------------------------------------------------------------------- 6389 6390 jQuery.fn.truncate = function (max, settings) 6391 { 6392 settings = jQuery.extend({ 6393 chars: /\s/, 6394 trail: ["...", ""] 6395 }, settings); 6396 6397 6398 var myResults = {}, 6399 ie = jQuery.browser.msie; 6400 6401 function fixIE(o) 6402 { 6403 if (ie) 6404 { 6405 o.style.removeAttribute("filter"); 6406 } 6407 } 6408 return this.each(function () 6409 { 6410 var jQuerythis = jQuery(this), 6411 myStrOrig = jQuerythis.html().replace(/\r\n/gim, ""), 6412 myStr = myStrOrig, 6413 myRegEx = /<\/?[^<>]*\/?>/gim, 6414 myRegExArray, 6415 myRegExHash = {}, 6416 myResultsKey = jQuery("*").index(this), 6417 c, 6418 endCap = 0, 6419 eachEl; 6420 6421 6422 //while ( ( myRegExArray = myRegEx.exec( myStr ) ) !== null ) 6423 for (myRegExArray = myRegEx.exec(myStr); myRegExArray !== null; myRegExArray = myRegEx.exec(myStr)) 6424 { 6425 myRegExHash[myRegExArray.index] = myRegExArray[0]; 6426 } 6427 6428 myStr = jQuery.trim(myStr.split(myRegEx).join("")); 6429 if (myStr.length > max) 6430 { 6431 while (max < myStr.length) 6432 { 6433 c = myStr.charAt(max); 6434 if (c.match(settings.chars)) 6435 { 6436 myStr = myStr.substring(0, max); 6437 break; 6438 } 6439 max -= 1; 6440 } 6441 6442 if (myStrOrig.search(myRegEx) !== -1) 6443 { 6444 endCap = 0; 6445 for (eachEl in myRegExHash) 6446 { 6447 if (myRegExHash.hasOwnProperty(eachEl)) 6448 { 6449 myStr = [myStr.substring(0, eachEl), myRegExHash[eachEl], myStr.substring(eachEl, myStr.length)].join(""); 6450 if (eachEl < myStr.length) 6451 { 6452 endCap = myStr.length; 6453 } 6454 } 6455 } 6456 jQuerythis.html([myStr.substring(0, endCap), myStr.substring(endCap, myStr.length).replace(/<(\w+)[^>]*>.*<\/\1>/gim, "").replace(/<(br|hr|img|input)[^<>]*\/?>/gim, "")].join("")); 6457 } else 6458 { 6459 jQuerythis.html(myStr); 6460 } 6461 myResults[myResultsKey] = myStrOrig; 6462 jQuerythis.html(["<div class='truncate_less'>", jQuerythis.html(), settings.trail[0], "</div>"].join("")) 6463 .find(".truncate_show", this).click(function () 6464 { 6465 if (jQuerythis.find(".truncate_more").length === 0) 6466 { 6467 jQuerythis.append(["<div class='truncate_more' style='display: none;'>", myResults[myResultsKey], settings.trail[1], "</div>"].join("")) 6468 .find(".truncate_hide").click(function () 6469 { 6470 jQuerythis.find(".truncate_more").css("background", "#fff").fadeOut("normal", function () 6471 { 6472 jQuerythis.find(".truncate_less").css("background", "#fff").fadeIn("normal", function () 6473 { 6474 fixIE(this); 6475 jQuery(this).css("background", "none"); 6476 }); 6477 fixIE(this); 6478 }); 6479 return false; 6480 }); 6481 } 6482 jQuerythis.find(".truncate_less").fadeOut("normal", function () 6483 { 6484 jQuerythis.find(".truncate_more").fadeIn("normal", function () 6485 { 6486 fixIE(this); 6487 }); 6488 fixIE(this); 6489 }); 6490 jQuery(".truncate_show", jQuerythis).click(function () 6491 { 6492 jQuerythis.find(".truncate_less").css("background", "#fff").fadeOut("normal", function () 6493 { 6494 jQuerythis.find(".truncate_more").css("background", "#fff").fadeIn("normal", function () 6495 { 6496 fixIE(this); 6497 jQuery(this).css("background", "none"); 6498 }); 6499 fixIE(this); 6500 }); 6501 return false; 6502 }); 6503 return false; 6504 }); 6505 } 6506 }); 6507 }; 6508 6509 $.fn.extend({ 6510 getRadioValue: function () 6511 { 6512 return $(this).filter(':checked').val(); 6513 }, 6514 getYesNoRadioIsYes: function (alternateYesValue) 6515 {
6516 var yesValue, jCheckedElement; 6517 yesValue = (alternateYesValue === undefined) ? "True" : alternateYesValue; 6518 if ($(this).is('[type=hidden]')) 6519 { 6520 return ($(this).val() === yesValue); 6521 } 6522 jCheckedElement = $(this).filter(':checked'); 6523 return (jCheckedElement.length !== 0 && jCheckedElement.val() === yesValue); 6524 }, 6525 getYesNoCheckIsYes: function (alternateYesValue) 6526 { 6527 var yesValue, jCheckedElement; 6528 yesValue = (alternateYesValue === undefined) ? "True" : alternateYesValue; 6529 if ($(this).is('[type=hidden]')) 6530 { 6531 return ($(this).val() === yesValue); 6532 } 6533 jCheckedElement = $(this).filter(':checked'); 6534 return (jCheckedElement.length !== 0 && jCheckedElement.val() === yesValue); 6535 }, 6536 getYesNoDefaultRadio: function () 6537 { 6538 var jCheckedElement; 6539 if ($(this).is('[type=hidden]')) 6540 { 6541 return FBUtilities.GetBoolOrNull($(this).val()); 6542 } 6543 jCheckedElement = $(this).filter(':checked'); 6544 if (jCheckedElement.length !== 0) 6545 { 6546 return FBUtilities.GetBoolOrNull(jCheckedElement.val()); 6547 } 6548 return null; 6549 }, 6550 getSelectBoxValue: function () 6551 { 6552 var selectedValue, selectedOption; 6553 selectedValue = ""; 6554 selectedOption = $(this).find("option:selected"); 6555 if (selectedOption.length !== 0) 6556 { 6557 selectedValue = selectedOption.val(); 6558 } 6559 return selectedValue; 6560 }, 6561 getMultipleCheckedValues: function () 6562 { 6563 return $(this).filter(":checked").map(function () 6564 { 6565 return $(this).val(); 6566 }).get(); 6567 } 6568 }); 6569}(jQuery)); 6570 6571/////////////////////////////////////////////////////////////////////////////// 6572// Masonry 6573/////////////////////////////////////////////////////////////////////////////// 6574/* 6575$( window ).on( 'load', function () 6576{ 6577 $('.fbcms_contentbody.masonry').each(function() 6578 { 6579 var self = $(this); 6580 self.isotope( 6581 { 6582 itemSelector: '.fbcms_contentitem', 6583 masonry: 6584 { 6585 columnWidth: 1 6586 } 6587 } 6588 ); 6589 }); 6590} ); 6591*/ 6592 6593/* 6594 RotatorManager - Foxbright Rotator Manager 6595 TODO: update docs 6596 Javascript controller for managing simple drop logic and incorporating keyboard focus 6597 into the drop behavior as well. 6598 6599 The element selected by the widget (container element) will have a class added to it 6600 to indicate that it is opened (HoverFocusClass). Selecting or focusing on the element 6601 6602 6603 Options: 6604 6605 PermaLinkUrl default: null - must be set when called. 6606 Required. The uri location of a permalink for this photo gallery. Since this 6607 is required and has no default, it must be set when initializing the manager. 6608 GalleryTitle default: null 6609 Optional. A title for the gallery. 6610 RotatorContainerSelector default: '.fbcms_imagerotator' 6611 Required. Selector indicating the element that is to be used as the rotator 6612 container. 6613 ShowButtons default: false 6614 Optional. True to show buttons, false otherwise. 6615 ButtonPositionsPlayPauseModifer default: 'upperright' [upperleft|upperright|lowerleft|lowerright] 6616 Optional; Required if ShowButtons is true. Play/Pause button position. 6617 ButtonPositionsPermaLinkModifer default: 'upperright' [upperleft|upperright|lowerleft|lowerright] 6618 Optional; Required if ShowButtons is true. Permalink button position. 6619 ButtonPositionsNextPrevModifer default: 'middle' [upperleft|upperright|middle|lowerleft|lowerright] 6620 Optional; Required if ShowButtons is true. Next/Previous buttons position. 6621 ButtonPositionsPagerModifer default: 'upperright' [upperleft|upperright|lowerleft|lowerright] 6622 Optional; Required if ShowButtons is true. Pager button postion. 6623 ButtonClass default: 'fbpgro_button' 6624 Optional; Required if ShowButtons is true. Class to be put on all buttons. 6625 PrevButtonClass default: 'fbpgro_prev' 6626 Optional; Required if ShowButtons is true. Previous button class. 6627 PrevButtonIcon default: '<span class="fas fa-angle-left" aria-hidden="true"></span>' 6628 Optional; Required if ShowButtons is true. Previous button icon. 6629 PrevButtonContent default: '<span class="screen-reader-text">Previous</span>' 6630 Optional; Required if ShowButtons is true. Previous button content.
6631 NextButtonClass default: 'fbpgro_next' 6632 Optional; Required if ShowButtons is true. Next button class. 6633 NextButtonIcon default: '<span class="fas fa-angle-right" aria-hidden="true"></span>' 6634 Optional; Required if ShowButtons is true. Next button icon. 6635 NextButtonContent default: '<span class="screen-reader-text">Next</span>' 6636 Optional; Required if ShowButtons is true. Next button content. 6637 PlayPauseButtonClass default: 'fbpgro_playpause' 6638 Optional; Required if ShowButtons is true. Play Pause button class. 6639 PlayPauseButtonIconPause default: '<span class="fas fa-pause" aria-hidden="true"></span>' 6640 Optional; Required if ShowButtons is true. Play Pause button icon when playing. 6641 PlayPauseButtonContentPause default: '<span class="screen-reader-text">Pause</span>' 6642 Optional; Required if ShowButtons is true. Play Pause button content when playing. 6643 PlayPauseButtonIconPlay default: '<span class="fas fa-play" aria-hidden="true"></span>' 6644 Optional; Required if ShowButtons is true. Play Pause button icon when paused. 6645 PlayPauseButtonContentPlay default: '<span class="screen-reader-text">Play</span>' 6646 Optional; Required if ShowButtons is true. Play Pause button content when paused. 6647 PermaLinkButtonClass default: 'fbpgro_permalink' 6648 Optional; Required if ShowButtons is true. Permalink button class. 6649 PermaLinkButtonIcon default: '<span class="fas fa-link" aria-hidden="true"></span>' 6650 Optional; Required if ShowButtons is true. Permalink button icon. 6651 PermaLinkButtonContent default: '<span class="screen-reader-text">Gallery Permalink</span>' 6652 Optional; Required if ShowButtons is true. Permalink button content. 6653 ShowPager default: false 6654 Optional. True to show pager, false otherwise. 6655 PagerClass default: 'fbpgro_pager' 6656 Optional; Required if ShowPager is true. Pager class. 6657 ShowOverlay default: false 6658 Optional. True to show overlay, false otherwise. 6659 OverlayClass default: 'fbpgro_overlay' 6660 Optional; Required if ShowOverlay is true. Overlay class. 6661 OverlayTextWrapperClass default: 'fbpgro_textwrapper' 6662 Optional; Required if ShowOverlay is true. Class for wrapper around title and 6663 description text elements. 6664 OverlayTitleClass default: 'fbpgro_title' 6665 Optional; Required if ShowOverlay is true. Text element class. 6666 OverlayDescClass default: 'fbpgro_desc' 6667 Optional; Required if ShowOverlay is true. Description element class. 6668 OverlayLinkWrapperClass default: 'fbpgro_linkwrapper' 6669 Optional; Required if ShowOverlay is true. Overlay link wrapper class. 6670 OverlayLinkClass default: 'fbpgro_link' 6671 Optional; Required if ShowOverlay is true. Overlay link class. 6672 OverlayUpdateFunction default: null 6673 Optional. An override for the overlay update function. This will be called each 6674 time a slide is changed. 6675 The signature is: function(aContentBlock, aTitle, aDesc, aUrl, aUrlTarget, aUrlText) 6676 OnPreInitFunctions default: null 6677 Optional. Functions that may be called upon before initialization of the rotator, 6678 but after the markup has been updated by the widget. 6679 The signature is: function(aCycleEvent, aCycleOptions) 6680 6681 Methods: 6682 6683 The widget is fully functional on its own, but can be remotely activated with the following 6684 methods. 6685 6686 OverlayUpdateFunction(aTitle, aDesc, aUrl, aUrlTarget, aUrlText) 6687 Called to toggle the widget open or closed. 6688 6689 Examples: 6690 6691 Since the function is built as a jQuery Widget, simply call the functions on the 6692 container element directly. 6693 6694 $('#content_1337').RotatorManager( 6695 { 6696 PermaLinkUrl: '/Core/Gallery/Index/1701/' 6697 } 6698 ); 6699*/ 6700(function ($) 6701{ 6702 $.widget("ui.RotatorManager", 6703 { 6704 options: 6705 { 6706 PermaLinkUrl: null 6707 , GalleryTitle: null 6708 , RotatorContainerSelector: '.fbcms_imagerotator'
6709 , ShowButtons: false 6710 , ButtonPositionsPlayPauseModifer: 'upperright' 6711 , ButtonPositionsPermaLinkModifer: 'upperright' 6712 , ButtonPositionsNextPrevModifer: 'middle' 6713 , ButtonPositionsPagerModifer: 'upperright' 6714 , ButtonClass: 'fbpgro_button' 6715 , PrevButtonClass: 'fbpgro_prev' 6716 , NextButtonClass: 'fbpgro_next' 6717 , PlayPauseButtonClass: 'fbpgro_playpause' 6718 , PlayPauseButtonPlayClass: 'fbpgro_play' 6719 , PermaLinkButtonClass: 'fbpgro_permalink' 6720 , ShowPager: false 6721 , PagerClass: 'fbpgro_pager' 6722 , ShowOverlay: false 6723 , OverlayClass: 'fbpgro_overlay' 6724 , OverlayTextWrapperClass: 'fbpgro_textwrapper' 6725 , OverlayTitleClass: 'fbpgro_title' 6726 , OverlayDescClass: 'fbpgro_desc' 6727 , OverlayLinkWrapperClass: 'fbpgro_linkwrapper' 6728 , OverlayLinkClass: 'fbpgro_link' 6729 , OverlayUpdateFunction: null 6730 , OnPreInitFunctions: null 6731 }, 6732 6733 _AddButtons: false, 6734 _AddPager: false, 6735 _AddOverlay: false, 6736 6737 _destroy: function () 6738 { 6739 $(this.element).find(this.options.RotatorContainerSelector).cycle('destroy'); 6740 }, 6741 6742 _init: function () 6743 { 6744 var self = this; 6745 var jElement = $(self.element); 6746 var lElementId = $(jElement).attr('id'); 6747 6748 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 6749 6750 if (lRotatorContainer.length !== 1) 6751 { 6752 FBUtilities.LogMessage('RotatorManager._init - incorrect number of rotators found.'); 6753 return; 6754 } 6755 6756 jElement.addClass('fbcmsrotator'); 6757 lRotatorContainer.cycle(); 6758 self._updatePlayPauseButton(); 6759 }, 6760 6761 _create: function () 6762 { 6763 var self = this; 6764 var jElement = $(self.element); 6765 var lElementId = $(jElement).attr('id'); 6766 6767 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 6768 6769 if (lRotatorContainer.length !== 1) 6770 { 6771 FBUtilities.LogMessage('RotatorManager._create - incorrect number of rotators found.'); 6772 return; 6773 } 6774 6775 if (self._initOptions() === false) 6776 { 6777 FBUtilities.LogMessage('RotatorManager._create - options not initialized.'); 6778 return; 6779 } 6780 6781 /*if (FBUtilities.IsStringEmptyOrWhitespace(self.options.PermaLinkUrl)) 6782 { 6783 FBUtilities.LogMessage('RotatorManager - required settings null or empty.'); 6784 return; 6785 }*/ 6786 6787 self._createButtons(true); 6788 self._createPager(); 6789 self._createOverlay(); 6790 self._createGeneralEvents(true); 6791 }, 6792 6793 ReInit: function () 6794 { 6795 var self = this; 6796 var jElement = $(self.element); 6797 var lElementId = $(jElement).attr('id'); 6798 6799 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 6800 6801 if (lRotatorContainer.length !== 1) 6802 { 6803 FBUtilities.LogMessage('RotatorManager.ReInit - incorrect number of rotators found.'); 6804 return; 6805 } 6806 6807 if (self._initOptions() === false) 6808 { 6809 FBUtilities.LogMessage('RotatorManager.ReInit - options not initialized.'); 6810 return; 6811 } 6812 6813 /*if (FBUtilities.IsStringEmptyOrWhitespace(self.options.PermaLinkUrl)) 6814 { 6815 FBUtilities.LogMessage('RotatorManager.ReInit - required settings null or empty.'); 6816 return; 6817 }*/ 6818 6819 self._createButtons(false); 6820 self._createPager(); 6821 self._createOverlay(); 6822 self._createGeneralEvents(false); 6823 }, 6824 6825 _initOptions: function () 6826 { 6827 var self = this; 6828 var jElement = $(self.element); 6829 var lElementId = $(jElement).attr('id'); 6830 6831 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 6832 6833 if (lRotatorContainer.length !== 1) 6834 { 6835 FBUtilities.LogMessage('RotatorManager - incorrect number of rotators found.'); 6836 return false; 6837 } 6838 6839 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-permalink'))) 6840 { 6841 self.options.PermaLinkUrl = lRotatorContainer.data('fbpgr-permalink'); 6842 } 6843 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-title'))) 6844 { 6845 self.options.GalleryTitle = lRotatorContainer.data('fbpgr-title'); 6846 } 6847 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-showbuttons'))) 6848 { 6849 self.options.ShowButtons = lRotatorContainer.data('fbpgr-showbuttons'); 6850 } 6851 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-playpausemod'))) 6852 { 6853 self.options.ButtonPositionsPlayPauseModifer = lRotatorContainer.data('fbpgr-playpausemod'); 6854 } 6855 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-nextprevmod'))) 6856 { 6857 self.options.ButtonPositionsNextPrevModifer = lRotatorContainer.data('fbpgr-nextprevmod'); 6858 } 6859 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-permalinkmod'))) 6860 { 6861 self.options.ButtonPositionsPermaLinkModifer = lRotatorContainer.data('fbpgr-permalinkmod'); 6862 } 6863 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-showpager'))) 6864 { 6865 self.options.ShowPager = lRotatorContainer.data('fbpgr-showpager'); 6866 } 6867 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-pagermod'))) 6868 { 6869 self.options.ButtonPositionsPagerModifer = lRotatorContainer.data('fbpgr-pagermod'); 6870 } 6871 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-showoverlay'))) 6872 { 6873 self.options.ShowOverlay = lRotatorContainer.data('fbpgr-showoverlay'); 6874 } 6875 if (!FBUtilities.IsStringEmptyOrWhitespace(lRotatorContainer.data('fbpgr-overlayfunc'))) 6876 { 6877 self.options.OverlayUpdateFunction = lRotatorContainer.data('fbpgr-overlayfunc'); 6878 } 6879 6880 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.ButtonPositionsPlayPauseModifer) 6881 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.ButtonPositionsPermaLinkModifer) 6882 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.ButtonPositionsNextPrevModifer) 6883 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.ButtonPositionsPagerModifer) 6884 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.ButtonClass) 6885 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.PrevButtonClass) 6886 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.NextButtonClass) 6887 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.PlayPauseButtonClass) 6888 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.PlayPauseButtonPlayClass) 6889 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.PermaLinkButtonClass)) 6890 { 6891 self._AddButtons = self.options.ShowButtons; 6892 } 6893 6894 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.PagerClass)) 6895 { 6896 self._AddPager = self.options.ShowPager; 6897 } 6898 6899 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.OverlayClass) 6900 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.OverlayTextWrapperClass) 6901 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.OverlayTitleClass) 6902 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.OverlayDescClass) 6903 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.OverlayLinkWrapperClass) 6904 && !FBUtilities.IsStringEmptyOrWhitespace(self.options.OverlayLinkClass)) 6905 { 6906 self._AddOverlay = self.options.ShowOverlay; 6907 } 6908 6909 //initialize the pre-init callbacks list. 6910 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.OnPreInitFunctions)) 6911 { 6912 //it's null or empty, create it. 6913 self.options.OnPreInitFunctions = []; 6914 } 6915 else if ( 6916 self.options.OnPreInitFunctions !== undefined 6917 && self.options.OnPreInitFunctions.constructor !== undefined 6918 && self.options.OnPreInitFunctions.call !== undefined 6919 && self.options.OnPreInitFunctions.apply !== undefined 6920 ) 6921 { 6922 //it's a function, add it to the array. 6923 var lFunction = self.options.OnPreInitFunctions; 6924 self.options.OnPreInitFunctions = []; 6925 self.options.OnPreInitFunctions.push(lFunction); 6926 } 6927 else if ($.isArray(self.options.OnPreInitFunctions)) 6928 { 6929 //it's an array, we can add to it. 6930 } 6931 else 6932 { 6933 //dunno what it is. nuke it and create it anew. 6934 self.options.OnPreInitFunctions = []; 6935 } 6936 }, 6937 6938 _createButtons: function (aIsInitialCreation) 6939 { 6940 var self = this; 6941 var jElement = $(self.element); 6942 var lElementId = $(jElement).attr('id'); 6943 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 6944 6945 if (self._AddButtons !== true) 6946 { 6947 FBUtilities.LogMessage('RotatorManager - not adding buttons.'); 6948 return; 6949 } 6950 6951 //TODO: cleanup 6952 /* 6953 var lPermalinkLabel = ''; 6954 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.GalleryTitle)) 6955 { 6956 lPermalinkLabel = ' aria-label="' + self.options.GalleryTitle + '"'; 6957 } 6958 6959 jElement.append('<a class="' + self.options.ButtonClass + ' ' + self.options.PrevButtonClass + '" href="#">
6959' + self.options.PrevButtonIcon + self.options.PrevButtonContent + '</a>'); 6960 jElement.append('<a class="' + self.options.ButtonClass + ' ' + self.options.NextButtonClass + '" href="#">' + self.options.NextButtonIcon + self.options.NextButtonContent + '</a>'); 6961 jElement.append('<a class="' + self.options.ButtonClass + ' ' + self.options.PlayPauseButtonClass + '" href="#">' + self.options.PlayPauseButtonIconPause + self.options.PlayPauseButtonContentPause + '</a>'); 6962 if (!FBUtilities.IsStringEmptyOrWhitespace(self.options.PermaLinkUrl)) 6963 { 6964 jElement.append('<a class="' + self.options.ButtonClass + ' ' + self.options.PermaLinkButtonClass + '" href="' + self.options.PermaLinkUrl + '" ' + lPermalinkLabel + '>' + self.options.PermaLinkButtonIcon + self.options.PermaLinkButtonContent + '</a>'); 6965 } 6966 */ 6967 6968 if (FBCommon_1_2.isInEditor() === false 6969 && aIsInitialCreation === true) 6970 { 6971 self.options.OnPreInitFunctions.push( 6972 function (aCycleEvent, aCycleOptions) 6973 { 6974 jElement.on( 6975 "click", 6976 '.' + self.options.PrevButtonClass, 6977 function (aEvent) 6978 { 6979 aEvent.preventDefault(); 6980 lRotatorContainer.cycle('prev'); 6981 return false; 6982 } 6983 ); 6984 jElement.on( 6985 "click", 6986 '.' + self.options.NextButtonClass, 6987 function (aEvent) 6988 { 6989 aEvent.preventDefault(); 6990 lRotatorContainer.cycle('next'); 6991 return false; 6992 } 6993 ); 6994 jElement.on( 6995 "click", 6996 '.' + self.options.PlayPauseButtonClass, 6997 function (aEvent) 6998 { 6999 aEvent.preventDefault(); 7000 var lMyButton = $(aEvent.target).closest('.' + self.options.PlayPauseButtonClass); 7001 if (aCycleOptions.paused === true) 7002 { 7003 lRotatorContainer.cycle('resume'); 7004 } 7005 else 7006 { 7007 lRotatorContainer.cycle('pause'); 7008 } 7009 self._updatePlayPauseButton(); 7010 return false; 7011 } 7012 ); 7013 } 7014 ); 7015 } 7016 7017 var lPrevButton = jElement.find('.' + self.options.PrevButtonClass); 7018 var lNextButton = jElement.find('.' + self.options.NextButtonClass); 7019 var lPlayPauseButton = jElement.find('.' + self.options.PlayPauseButtonClass); 7020 var lPermaLinkButton = jElement.find('.' + self.options.PermaLinkButtonClass); 7021 7022 var lNextPrevHPosition = (self.options.ButtonPositionsNextPrevModifer.indexOf('left') !== -1) === true ? 'left' : 'right'; 7023 var lPlayPauseHPosition = (self.options.ButtonPositionsPlayPauseModifer.indexOf('left') !== -1) === true ? 'left' : 'right'; 7024 var lPermaLinkHPosition = (self.options.ButtonPositionsPermaLinkModifer.indexOf('left') !== -1) === true ? 'left' : 'right'; 7025 7026 var lNextPrevVPosition = (self.options.ButtonPositionsNextPrevModifer.indexOf('upper') !== -1) === true ? 'top' : 7027 ((self.options.ButtonPositionsNextPrevModifer.indexOf('lower') !== -1) === true ? 'bottom' : 'middle'); 7028 var lPlayPauseVPosition = (self.options.ButtonPositionsPlayPauseModifer.indexOf('upper') !== -1) === true ? 'top' : 'bottom'; 7029 var lPermaLinkVPosition = (self.options.ButtonPositionsPermaLinkModifer.indexOf('upper') !== -1) === true ? 'top' : 'bottom'; 7030 7031 lPermaLinkButton.css(lPermaLinkVPosition, 0); 7032 lPlayPauseButton.css(lPlayPauseVPosition, 0); 7033 7034 if (lNextPrevVPosition === "top" 7035 || lNextPrevVPosition === "bottom") 7036 { 7037 lPrevButton.css(lNextPrevVPosition, 0); 7038 lNextButton.css(lNextPrevVPosition, 0); 7039 } 7040 else 7041 { 7042 lPrevButton.addClass('fbcpgro_over fbcpgro_large'); 7043 lNextButton.addClass('fbcpgro_over fbcpgro_large'); 7044 } 7045 7046 // permalink button position. 7047 var lPLHPosition = 0; 7048 var lPLBWidth = 0; 7049 if (lPermaLinkButton.length > 0) 7050 { 7051 lPermaLinkButton.css(lPermaLinkHPosition, lPLHPosition + (lPLHPosition > 0 ? 'px' : '')); 7052 lPLBWidth = lPermaLinkButton.width(); 7053 } 7054 7055 // play/pause button position. 7056 var lPPHPosition = 0; 7057 if (lPermaLinkHPosition === lPlayPauseHPosition 7058 && lPermaLinkVPosition === lPlayPauseVPosition) 7059 { 7060 lPPHPosition += lPLBWidth; 7061 } 7062 lPlayPauseButton.css(lPlayPauseHPosition, lPPHPosition + (lPPHPosition > 0 ? 'px' : '')); 7063 7064 // next/prev button position. 7065 if (lNextPrevVPosition.indexOf('top') >= 0 7066 || lNextPrevVPosition.indexOf('bottom') >= 0) 7067 { 7068 var lNPHPosition = 0; 7069 if (lPermaLinkHPosition === lNextPrevHPosition 7070 && lPermaLinkVPosition === lNextPrevVPosition) 7071 { 7072 lNPHPosition += lPLBWidth; 7073 } 7074 if (lPlayPauseHPosition === lNextPrevHPosition 7075 && lPlayPauseVPosition === lNextPrevVPosition) 7076 { 7077 lNPHPosition += lPlayPauseButton.width(); 7078 } 7079 if (lNextPrevHPosition.indexOf('right') >= 0) 7080 { 7081 lNextButton.css(lNextPrevHPosition, lNPHPosition + (lNPHPosition > 0 ? 'px' : '')); 7082 lNPHPosition += lNextButton.width(); 7083 lPrevButton.css(lNextPrevHPosition, lNPHPosition + (lNPHPosition > 0 ? 'px' : '')); 7084 } 7085 else 7086 { 7087 lPrevButton.css(lNextPrevHPosition, lNPHPosition + (lNPHPosition > 0 ? 'px' : '')); 7088 lNPHPosition += lPrevButton.width(); 7089 lNextButton.css(lNextPrevHPosition, lNPHPosition + (lNPHPosition > 0 ? 'px' : '')); 7090 } 7091 } 7092 }, 7093 7094 _createPager: function () 7095 { 7096 var self = this; 7097 var jElement = $(self.element); 7098 var lElementId = $(jElement).attr('id'); 7099 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 7100 7101 if (self._AddPager !== true) 7102 { 7103 FBUtilities.LogMessage('RotatorManager - not adding pager.'); 7104 return; 7105 } 7106 7107 jElement.append('<div class="' + self.options.PagerClass + '"></div>'); 7108 7109 var lPrevButton = jElement.find('.' + self.options.PrevButtonClass); 7110 var lNextButton = jElement.find('.' + self.options.NextButtonClass); 7111 var lPlayPauseButton = jElement.find('.' + self.options.PlayPauseButtonClass); 7112 var lPermaLinkButton = jElement.find('.' + self.options.PermaLinkButtonClass); 7113 var lPager = jElement.find('.' + self.options.PagerClass); 7114 7115 var lPLBWidth = 0; 7116 if (lPermaLinkButton.length > 0) 7117 { 7118 lPLBWidth = lPermaLinkButton.width(); 7119 } 7120 7121 var lNextPrevHPosition = (self.options.ButtonPositionsNextPrevModifer.indexOf('left') !== -1) === true ? 'left' : 'right'; 7122 var lPlayPauseHPosition = (self.options.ButtonPositionsPlayPauseModifer.indexOf('left') !== -1) === true ? 'left' : 'right'; 7123 var lPermaLinkHPosition = (self.options.ButtonPositionsPermaLinkModifer.indexOf('left') !== -1) === true ? 'left' : 'right'; 7124 var lPagerHPosition = (self.options.ButtonPositionsPagerModifer.indexOf('left') !== -1) === true ? 'left' : 7125 ((self.options.ButtonPositionsPagerModifer.indexOf('right') !== -1) === true ? 'right' : 'center'); 7126 7127 var lNextPrevVPosition = (self.options.ButtonPositionsNextPrevModifer.indexOf('upper') !== -1) === true ? 'top' : 7128 ((self.options.ButtonPositionsNextPrevModifer.indexOf('lower') !== -1) === true ? 'bottom' : 'middle'); 7129 var lPlayPauseVPosition = (self.options.ButtonPositionsPlayPauseModifer.indexOf('upper') !== -1) === true ? 'top' : 'bottom'; 7130 var lPermaLinkVPosition = (self.options.ButtonPositionsPermaLinkModifer.indexOf('upper') !== -1) === true ? 'top' : 'bottom'; 7131 var lPagerVPosition = (self.options.ButtonPositionsPagerModifer.indexOf('upper') !== -1) === true ? 'top' : 'bottom'; 7132 7133 lPager.css(lPagerVPosition, 0); 7134 7135 //pager position. 7136 var lPHPosition = 0; 7137 if (lPermaLinkHPosition === lPagerHPosition 7138 && lPermaLinkVPosition === lPagerVPosition) 7139 { 7140 lPHPosition += lPLBWidth; 7141 } 7142 if (lPlayPauseHPosition === lPagerHPosition 7143 && lPlayPauseVPosition === lPagerVPosition) 7144 { 7145 lPHPosition += lPlayPauseButton.width(); 7146 } 7147 if (lNextPrevHPosition === lPagerHPosition 7148 && lNextPrevVPosition === lPagerVPosition) 7149 { 7150 lPHPosition += lNextButton.width(); 7151 lPHPosition += lPrevButton.width(); 7152 } 7153 7154 if (lPagerHPosition.indexOf('center') >= 0) 7155 { 7156 lPager.css('left', '50%'); 7157 lPager.css({ 'transform': 'translate(-50%, 0)' }); 7158 } 7159 else 7160 { 7161 lPager.css(lPagerHPosition, lPHPosition + (lPHPosition > 0 ? 'px' : '')); 7162 } 7163 }, 7164 7165 _createOverlay: function () 7166 { 7167 var self = this; 7168 var jElement = $(self.element); 7169 var lElementId = $(jElement).attr('id'); 7170 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 7171 7172 if (self._AddOverlay !== true) 7173 { 7174 FBUtilities.LogMessage('RotatorManager - not adding overlay.'); 7175 return; 7176 } 7177 7178 jElement.append('<div class="' + self.options.OverlayClass + '"></div>'); 7179 7180 var lOverlay = jElement.find('.' + self.options.OverlayClass); 7181 7182 lOverlay.append('<div class="' + self.options.OverlayTextWrapperClass + '"></div>'); 7183 var lTextWrapper = lOverlay.find('.' + self.options.OverlayTextWrapperClass); 7184 7185 lTextWrapper.append('<div class="' + self.options.OverlayTitleClass + '"></div>'); 7186 lTextWrapper.append('<div class="' + self.options.OverlayDescClass + '"></div>'); 7187 }, 7188 7189 _createGeneralEvents: function (aIsInitialCreation) 7190 { 7191 var self = this; 7192 var jElement = $(self.element); 7193 var lElementId = $(jElement).attr('id'); 7194 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 7195 7196 if (FBCommon_1_2.isInEditor() === false 7197 && aIsInitialCreation === true) 7198 { 7199 self.options.OnPreInitFunctions.push( 7200 function (aCycleEvent, aCycleOptions) 7201 { 7202 jElement.on( 7203 "click", 7204 '[data-fbpg-url]', 7205 function (aEvent) 7206 { 7207 aEvent.preventDefault(); 7208 var lUrl = $(aEvent.target).data('fbpg-url'); 7209 var lTarget = $(aEvent.target).data('fbpg-urltarget'); 7210 if (FBUtilities.IsParameterUndefinedOrEmpty(lTarget) 7211 && !FBUtilities.IsParameterUndefinedOrEmpty(lUrl)) 7212 { 7213 document.location = lUrl; 7214 } 7215 else if (!FBUtilities.IsParameterUndefinedOrEmpty(lUrl)) 7216 { 7217 window.open( 7218 $(aEvent.target).data('fbpg-url'), 7219 $(aEvent.target).data('fbpg-urltarget') 7220 ); 7221 } 7222 return false; 7223 } 7224 ); 7225 } 7226 ); 7227 } 7228 7229 lRotatorContainer.on( 7230 'cycle-pre-initialize', 7231 function (aCycleEvent, aCycleOptions) 7232 { 7233 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.OnPreInitFunctions)) 7234 { 7235 return; 7236 } 7237 for (var lIndex = 0, lLength = self.options.OnPreInitFunctions.length; lIndex < lLength; lIndex++) 7238 { 7239 self.options.OnPreInitFunctions[lIndex](aCycleEvent, aCycleOptions); 7240 }//endfor 7241 } 7242 ); 7243 7244 lRotatorContainer.on( 7245 'cycle-update-view', 7246 function (_event, _options, _slideOptions, aCurrentSlideElement) 7247 { 7248 let slide = $(aCurrentSlideElement); 7249 let img = slide.find('img'); 7250 let title = img.data('fbpg-title'); 7251 let desc = img.data('fbpg-desc'); 7252 let url = img.data('fbpg-url'); 7253 let urlTarget = img.data('fbpg-urltarget'); 7254 let linkText = img.data('fbpg-linktext'); 7255 let linkAriaLabel = img.data('fbpg-linkarialabel'); 7256 7257 if (!FBUtilities.IsParameterUndefinedOrEmpty(self.options.OverlayUpdateFunction)) 7258 { 7259 self.options.OverlayUpdateFunction(jElement, title, desc, url, urlTarget, linkText, linkAriaLabel); 7260 } 7261 else 7262 { 7263 self.UpdateRotatorOverlay(title, desc, url, urlTarget, linkText, linkAriaLabel); 7264 } 7265 } 7266 ); 7267 }, 7268 7269 _addOverlayLink: functio
7269n (aLinkText, aUrl, aUrlTarget, aLinkAriaLabel) 7270 { 7271 var self = this; 7272 var jElement = $(self.element); 7273 7274 var lShowLink = !FBUtilities.IsStringEmptyOrWhitespace(aUrl) 7275 && !FBUtilities.IsStringEmptyOrWhitespace(aLinkText); 7276 if (lShowLink === false) 7277 { 7278 return; 7279 } 7280 7281 var lOverlay = jElement.find('.' + self.options.OverlayClass); 7282 var lTextWrapper = lOverlay.find('.' + self.options.OverlayTextWrapperClass); 7283 lTextWrapper.append('<div class="' + self.options.OverlayLinkWrapperClass + '"></div>'); 7284 var lLinkWrapper = lOverlay.find('.' + self.options.OverlayLinkWrapperClass); 7285 lLinkWrapper.append('<a class="' + self.options.OverlayLinkClass + '" href="#"></a>'); 7286 var lLinkElement = lLinkWrapper.find('.' + self.options.OverlayLinkClass); 7287 7288 lLinkElement.html(aLinkText); 7289 lLinkElement.attr('href', aUrl); 7290 7291 if (!FBUtilities.IsStringEmptyOrWhitespace(aUrlTarget) && aUrlTarget !== '_self') 7292 { 7293 lLinkElement.attr('target', aUrlTarget); 7294 } 7295 7296 if (!FBUtilities.IsStringEmptyOrWhitespace(aLinkAriaLabel)) 7297 { 7298 lLinkElement.attr('aria-label', aLinkAriaLabel); 7299 } 7300 }, 7301 7302 _updatePlayPauseButton: function () 7303 { 7304 var self = this; 7305 var jElement = $(self.element); 7306 var lButton = jElement.find('.' + self.options.PlayPauseButtonClass); 7307 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 7308 var lCycleOptions = lRotatorContainer.data('cycle.opts'); 7309 if (lCycleOptions.paused === true) 7310 { 7311 lButton.removeClass(self.options.PlayPauseButtonPlayClass); 7312 } 7313 else 7314 { 7315 lButton.addClass(self.options.PlayPauseButtonPlayClass); 7316 } 7317 }, 7318 7319 UpdateRotatorOverlay: function (aTitle, aDesc, aUrl, aUrlTarget, aLinkText, aLinkAriaLabel) 7320 { 7321 var self = this; 7322 var jElement = $(self.element); 7323 7324 var lOverlay = jElement.find('.' + self.options.OverlayClass); 7325 7326 if (lOverlay.length === 0) 7327 { 7328 return; 7329 } 7330 lOverlay.hide(); 7331 7332 if (FBUtilities.IsStringEmptyOrWhitespace(aTitle) 7333 && FBUtilities.IsStringEmptyOrWhitespace(aDesc) 7334 && (FBUtilities.IsStringEmptyOrWhitespace(aUrl) || FBUtilities.IsStringEmptyOrWhitespace(aLinkText))) 7335 { 7336 return; 7337 } 7338 7339 var lTitleElement = lOverlay.find('.' + self.options.OverlayTitleClass); 7340 var lDescElement = lOverlay.find('.' + self.options.OverlayDescClass); 7341 var lLinkElement = lOverlay.find('.' + self.options.OverlayLinkClass); 7342 7343 var lTextWrapElement = lOverlay.find('.' + self.options.OverlayTextWrapperClass); 7344 var lLinkWrapElement = lOverlay.find('.' + self.options.OverlayLinkWrapperClass); 7345 lLinkWrapElement.remove(); 7346 7347 var lShowTitle = !FBUtilities.IsStringEmptyOrWhitespace(aTitle); 7348 var lShowDesc = !FBUtilities.IsStringEmptyOrWhitespace(aDesc); 7349 var lShowLink = !FBUtilities.IsStringEmptyOrWhitespace(aUrl); 7350 7351 if (lShowTitle) 7352 { 7353 lTitleElement.html(aTitle); 7354 } 7355 if (lShowDesc) 7356 { 7357 lDescElement.html(aDesc); 7358 } 7359 7360 if (lShowTitle) 7361 { 7362 lTitleElement.show(); 7363 } 7364 else 7365 { 7366 lTitleElement.hide(); 7367 } 7368 if (lShowDesc) 7369 { 7370 lDescElement.show(); 7371 } 7372 else 7373 { 7374 lDescElement.hide(); 7375 } 7376 7377 self._addOverlayLink(aLinkText, aUrl, aUrlTarget, aLinkAriaLabel); 7378 7379 if (lShowTitle 7380 || lShowDesc 7381 || lShowLink) 7382 { 7383 lOverlay.show(); 7384 } 7385 } 7386 }); 7387 7388 // load it on all instances found when the page is loaded. 7389 $(document).ready( 7390 function () 7391 { 7392 $.each( 7393 $('.fbcms_photogallery .fbcms_imagerotator'), 7394 function (aIndex, aValue) 7395 { 7396 var lSelector = '#' + $(aValue).parent('.fbcms_photogallery').attr('id'); 7397 $(lSelector).RotatorManager(); 7398 } 7399 ); 7400 /* 7401 $.each( 7402 $('.fbcms_media .fbcms_imagerotator'), 7403 function (aIndex, aValue) 7404 { 7405 var lSelector = '#' + $(aValue).parent('.fbcms_media').attr('id'); 7406 $(lSelector).RotatorManager(); 7407 } 7408 );*/ 7409 } 7410 ); 7411 7412 // to reinit: 7413 /* 7414 if ($('#ElementId').is('.fbcmsrotator')) 7415 { 7416 $('#ElementId').RotatorManager('ReInit'); 7417 } 7418 else 7419 { 7420 $('#ElementId').RotatorManager(); 7421 } 7422 */ 7423 7424})(jQuery); 7425 7426 7427 7428 7429/* 7430 SpotlightManager - Foxbright Spotlight Manager 7431 7432 Javascript controller for managing spotlights. 7433 TODO: update docs 7434 7435 Options: 7436 7437 PermaLinkUrl default: null - must be set when called. 7438 Required. The uri location of a permalink for this spotlight gallery. Since 7439 this is required and has no default, it must be set when initializing the 7440 manager.
7441 GalleryTitle default: null 7442 Optional. A title for the spotlight gallery. 7443 ContentHeaderSelector default: '.fbcms_contentheader' 7444 Required. Selector indicating the element that is to be used as the content 7445 header container. 7446 ContentFooterSelector default: '.fbcms_contentfooter' 7447 Required. Selector indicating the element that is to be used as the content 7448 footer container. 7449 RotatorContainerSelector default: '.fbcms_spotlights_list' 7450 Required. Selector indicating the element that is to be used as the rotator 7451 container. 7452 ControlsClass default: 'fbcms_spotlight_controls' 7453 Required. Class to be used for controls container in the header and/or 7454 footer. 7455 ButtonPositionsHeaderModifer default: 'left' [left|right] 7456 Optional; Required if any Show*Button* option is true. Header Controls 7457 alignment. 7458 ButtonPositionsFooterModifer default: 'left' [left|right] 7459 Optional; Required if any Show*Button* option is true. Footer Controls 7460 alignment. 7461 ButtonClass default: 'spotlight_button' 7462 Optional; Required if any Show*Button* option is true. Class to be put on 7463 all buttons. 7464 ShowNextPrevButtons default: true 7465 Optional. True to show next & previous buttons, false otherwise. 7466 ButtonPositionsNextPrevModifer default: 'bottom' [top|bottom|middle|both] 7467 Optional; Required if ShowNextPrevButtons option is true. Next & previous 7468 button position. 7469 PrevButtonClass default: 'spotlight_prev' 7470 Optional; Required if ShowNextPrevButtons is true. Previous button class. 7471 PrevButtonIcon default: '<span class="fas fa-angle-left" aria-hidden="true"></span>' 7472 Optional; Required if ShowNextPrevButtons is true. Previous button icon. 7473 PrevButtonContent default: '<span class="screen-reader-text">Previous</span>' 7474 Optional; Required if ShowNextPrevButtons is true. Previous button content. 7475 NextButtonClass default: 'spotlight_next' 7476 Optional; Required if ShowNextPrevButtons is true. Next button class. 7477 NextButtonIcon default: '<span class="fas fa-angle-right" aria-hidden="true"></span>' 7478 Optional; Required if ShowNextPrevButtons is true. Next button icon. 7479 NextButtonContent default: '<span class="screen-reader-text">Next</span>' 7480 Optional; Required if ShowNextPrevButtons is true. Next button content. 7481 ShowPlayPauseButton default: true 7482 Optional. True to show play/pause button, false otherwise. 7483 ButtonPositionsPlayPauseModifer default: 'bottom' [top|bottom|both] 7484 Optional; Required if ShowPlayPauseButton option is true. Play/Pause button 7485 position. 7486 PlayPauseButtonClass default: 'spotlight_playpause' 7487 Optional; Required if ShowPlayPauseButton is true. Play Pause button class. 7488 PlayPauseButtonIconPause default: '<span class="fas fa-pause" aria-hidden="true"></span>' 7489 Optional; Required if ShowPlayPauseButton is true. Play Pause button icon when playing. 7490 PlayPauseButtonContentPause default: '<span class="screen-reader-text">Pause</span>' 7491 Optional; Required if ShowPlayPauseButton is true. Play Pause button content when playing. 7492 PlayPauseButtonIconPlay default: '<span class="fas fa-play" aria-hidden="true"></span>' 7493 Optional; Required if ShowPlayPauseButton is true. Play Pause button icon when paused. 7494 PlayPauseButtonContentPlay default: '<span class="screen-reader-text">Play</span>' 7495 Optional; Required if ShowPlayPauseButton is true. Play Pause button content when paused. 7496 ShowPager default: true 7497 Optional. True to show the pager, false otherwise. 7498 PagerClass default: 'fbcms_spotlight_pager' 7499 Optional; Required if ShowPager or ShowNextPrevButtons is true. Class to 7500 be used for element to contain pager and next/prev classes.
7501 PagesClass default: 'spotlight_pages' 7502 Optional; Required if ShowPager is true. Class to be used for the element 7503 to contain page buttons. 7504 ButtonPositionsPagerModifer default: 'bottom' [top|bottom|both] 7505 Optional; Required if ShowPager option is true. Pager position. 7506 ShowPermalinkButton default: true 7507 Optional. True to show Permalink/View All button, false otherwise. 7508 ButtonPositionsPermaLinkModifer default: 'bottom' [top|bottom|both] 7509 Optional; Required if ShowPermalinkButton option is true. Permalink 7510 button position. 7511 PermaLinkButtonClass default: 'spotlight_viewall' 7512 Optional; Required if ShowPermalinkButton is true. Permalink button class. 7513 PermaLinkButtonIcon default: '' 7514 Optional; Required if ShowPermalinkButton is true. Permalink button icon. 7515 PermaLinkButtonContent default: 'View All' 7516 Optional; Required if ShowPermalinkButton is true. Permalink button content. 7517 OnPreInitFunctions default: null 7518 Optional. Functions that may be called upon before initialization of the rotator, 7519 but after the markup has been updated by the widget. 7520 The signature is: function(aCycleEvent, aCycleOptions) 7521 7522 Methods: 7523 7524 The widget is fully functional on its own, but can be remotely activated with the following 7525 methods. 7526 7527 Examples: 7528 7529 Since the function is built as a jQuery Widget, simply call the functions on the 7530 container element directly. 7531 7532 $('#content_1337').SpotlightManager( 7533 { 7534 PermaLinkUrl: '/Core/Gallery/Spotlights/1701/' 7535 } 7536 ); 7537*/ 7538(function ($) 7539{ 7540 $.widget("ui.SpotlightManager", 7541 { 7542 options: 7543 { 7544 PermaLinkUrl: null 7545 , GalleryTitle: null 7546 , ContentHeaderSelector: '.fbcms_contentheader' 7547 , ContentFooterSelector: '.fbcms_contentfooter' 7548 , RotatorContainerSelector: '.fbcms_spotlights_list' 7549 , ControlsClass: 'fbcms_spotlight_controls' 7550 , ButtonPositionsHeaderModifer: 'left' 7551 , ButtonPositionsFooterModifer: 'left' 7552 , ButtonClass: 'spotlight_button' 7553 , PrevButtonClass: 'spotlight_prev' 7554 , NextButtonClass: 'spotlight_next' 7555 , PlayPauseButtonClass: 'spotlight_playpause' 7556 , PlayPauseButtonPlayClass: 'spotlight_play' 7557 , PagerClass: 'fbcms_spotlight_pager' 7558 , PagesClass: 'spotlight_pages' 7559 , PermaLinkButtonClass: 'spotlight_viewall' 7560 , OnPreInitFunctions: null 7561 }, 7562 7563 _destroy: function () 7564 { 7565 }, 7566 7567 _init: function () 7568 { 7569 }, 7570 7571 _create: function () 7572 { 7573 var self = this; 7574 var jElement = $(self.element); 7575 var lElementId = $(jElement).attr('id'); 7576 var lAddButtons = false; 7577 var lAddPager = false; 7578 7579 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.PermaLinkUrl) 7580 || FBUtilities.IsStringEmptyOrWhitespace(self.options.RotatorContainerSelector)) 7581 { 7582 FBUtilities.LogMessage('SpotlightManager - required settings null or empty.'); 7583 return; 7584 } 7585 7586 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 7587 7588 if (lRotatorContainer.length !== 1) 7589 { 7590 FBUtilities.LogMessage('SpotlightManager - incorrect number of rotators found.'); 7591 return; 7592 } 7593 7594 //initialize the pre-init callbacks list. 7595 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.OnPreInitFunctions)) 7596 { 7597 //it's null or empty, create it. 7598 self.options.OnPreInitFunctions = []; 7599 } 7600 else if ( 7601 self.options.OnPreInitFunctions !== undefined 7602 && self.options.OnPreInitFunctions.constructor !== undefined 7603 && self.options.OnPreInitFunctions.call !== undefined 7604 && self.options.OnPreInitFunctions.apply !== undefined 7605 ) 7606 { 7607 //it's a function, add it to the array. 7608 var lFunction = self.options.OnPreInitFunctions; 7609 self.options.OnPreInitFunctions = []; 7610 self.options.OnPreInitFunctions.push(lFunction); 7611 } 7612 else if ($.isArray(self.options.OnPreInitFunctions)) 7613 { 7614 //it's an array, we can add to it. 7615 } 7616 else 7617 { 7618 //dunno what it is. nuke it and create it anew. 7619 self.options.OnPreInitFunctions = []; 7620 } 7621 7622 self._createControls(lAddButtons, lAddPager); 7623 7624 if (FBCommon_1_2.isInEditor() === false) 7625 { 7626 self.options.OnPreInitFunctions.push( 7627 function (aCycleEvent, aCycleOptions) 7628 { 7629 jElement.on( 7630 "click", 7631 '[data-fbpg-url]', 7632 function (aEvent) 7633 { 7634 aEvent.preventDefault(); 7635 window.open( 7636 $(aEvent.target).data('fbpg-url'), 7637 $(aEvent.target).data('fbpg-urltarget') 7638 ); 7639 return false; 7640 } 7641 ); 7642 } 7643 ); 7644 } 7645 7646 lRotatorContainer.on( 7647 'cycle-pre-initialize', 7648 function (aCycleEvent, aCycleOptions) 7649 { 7650 if (FBUtilities.IsParameterUndefinedOrEmpty(self.options.OnPreInitFunctions)) 7651 { 7652 return; 7653 } 7654 for (var lIndex = 0, lLength = self.options.OnPreInitFunctions.length; lIndex < lLength; lIndex++) 7655 { 7656 self.options.OnPreInitFunctions[lIndex](aCycleEvent, aCycleOptions); 7657 }//endfor 7658 } 7659 ); 7660 7661 lRotatorContainer.cycle(); 7662 self._updatePlayPauseButton(); 7663 }, 7664 7665 _createControls: function (aAddButtons, aAddPager) 7666 { 7667 var self = this; 7668 var jElement = $(self.element); 7669 var lElementId = $(jElement).attr('id'); 7670 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 7671 7672 if (FBCommon_1_2.isInEditor() === false) 7673 { 7674 self.options.OnPreInitFunctions.push( 7675 function (aCycleEvent, aCycleOptions) 7676 { 7677 jElement.on( 7678 "click", 7679 '.' + self.options.PrevButtonClass, 7680 function (aEvent) 7681 { 7682 aEvent.preventDefault(); 7683 lRotatorContainer.cycle('prev'); 7684 return false; 7685 } 7686 ); 7687 jElement.on( 7688 "click", 7689 '.' + self.options.NextButtonClass, 7690 function (aEvent) 7691 { 7692 aEvent.preventDefault(); 7693 lRotatorContainer.cycle('next'); 7694 return false; 7695 } 7696 ); 7697 jElement.on( 7698 "click", 7699 '.' + self.options.PlayPauseButtonClass, 7700 function (aEvent) 7701 { 7702 aEvent.preventDefault(); 7703 if (aCycleOptions.paused === true) 7704 { 7705 lRotatorContainer.cycle('resume'); 7706 } 7707 else 7708 { 7709 lRotatorContainer.cycle('pause'); 7710 } 7711 self._updatePlayPauseButton(); 7712 return false; 7713 } 7714 ); 7715 } 7716 ); 7717 } 7718 }, 7719 7720 _updatePlayPauseButton: function () 7721 { 7722 var self = this; 7723 var jElement = $(self.element); 7724 var lButton = jElement.find('.' + self.options.PlayPauseButtonClass); 7725 var lRotatorContainer = jElement.find(self.options.RotatorContainerSelector); 7726 var lCycleOptions = lRotatorContainer.data('cycle.opts'); 7727 if (lCycleOptions.paused === true) 7728 { 7729 lButton.removeClass(self.options.PlayPauseButtonPlayClass); 7730 } 7731 else 7732 { 7733 lButton.addClass(self.options.PlayPauseButtonPlayClass); 7734 } 7735 } 7736 }); 7737})(jQuery); 7738 7739 7740var waitForFinalEvent = ( 7741 function () 7742 { 7743 var timers = {}; 7744 return function (callback, ms, uniqueId) 7745 { 7746 if (!uniqueId) 7747 { 7748 uniqueId = "Don't call this twice without a uniqueId"; 7749 } 7750 if (timers[uniqueId]) 7751 { 7752 clearTimeout(timers[uniqueId]); 7753 } 7754 timers[uniqueId] = setTimeout(callback, ms); 7755 }; 7756 } 7757)(); 7758 7759/* 7760 SpotlistNavManager - Foxbright Spotlist Navigation Manager 7761 7762 Javascript controller for managing spotlights. 7763 7764 Options: 7765 7766 SliderNavClass default: 'fb_audnav' 7767 Required. Class added to slider content area once the javascript is successfully 7768 in place. 7769 SlideListSelector default: '.fbcms_spotlist_items' 7770 Required. Selector for the list of items. 7771 SlideSelector default: '.fbcms_spotlist_item' 7772 Required. Selector for the items. 7773 PositionUnits default: 'px' 7774 Required. Units to use for CSS positioning. 7775 ActiveSlideClass default: 'audnav_active' 7776 Required. Class to indicate currently selected item. 7777 SmallTabHeight default: 50 7778 Required. Tab height (width when turned sideways) for small display. 7779 SmallSlideWidth default: 300 7780 Required. Slide width for small display. 7781 SmallSizeCutoff default: 767 7782 Required. Size at which the small display ends (inclusive). 7783 MediumSizeClass default: 'audnavmd' 7784 Required. Class to indicate medium display size. 7785 MediumTabHeight default: 75 7786 Required. Tab height (width when turned sideways) for medium display. 7787 MediumSlideWidth default: 400 7788 Required. Slide width for medium display. 7789 MediumSizeCutoff default: 1023 7790 Required. Size at which the medium display ends (inclusive). 7791 LargeSizeClass default: 'audnavlg' 7792 Required. Class to indicate large display size. 7793 LargeTabHeight default: 100 7794 Required. Tab height (width when turned sideways) for large display. 7795 LargeSlideWidth default: 500 7796 Required. Slide width for large display. 7797 SlideTitleSelector default: '.desc_short' 7798 Required. Selector for item titles to be rotated on medium and large display. 7799 7800 Methods: 7801 7802 The widget is fully functional on its own, but can be remotely activated
7802with the following 7803 methods. 7804 7805 Examples: 7806 7807 Since the function is built as a jQuery Widget, simply call the functions on the 7808 container element directly. 7809 7810 $('#content_1337').SpotlistNavManager(); 7811*/ 7812(function ($) 7813{ 7814 $.widget("ui.SpotlistNavManager", 7815 { 7816 options: 7817 { 7818 SliderNavClass: 'fb_audnav' 7819 , SlideListSelector: '.fbcms_spotlist_items' 7820 , SlideSelector: '.fbcms_spotlist_item' 7821 , PositionUnits: 'px' 7822 , ActiveSlideClass: 'audnav_active' 7823 , SmallTabHeight: 50 7824 , SmallSlideWidth: 300 7825 , SmallSizeCutoff: 767 7826 , MediumSizeClass: 'audnavmd' 7827 , MediumTabHeight: 75 7828 , MediumSlideWidth: 400 7829 , MediumSizeCutoff: 1023 7830 , LargeSizeClass: 'audnavlg' 7831 , LargeTabHeight: 100 7832 , LargeSlideWidth: 500 7833 , SlideTitleSelector: '.desc_short' 7834 }, 7835 7836 _slideWidth: null, 7837 _slideHeight: null, 7838 7839 _slideTabWidth: null, 7840 7841 7842 _destroy: function () 7843 { 7844 }, 7845 7846 _init: function () 7847 { 7848 }, 7849 7850 _create: function () 7851 { 7852 var self = this; 7853 var jElement = $(self.element); 7854 var lElementId = $(jElement).attr('id'); 7855 7856 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.SliderNavClass) 7857 || FBUtilities.IsStringEmptyOrWhitespace(self.options.SlideListSelector) 7858 || FBUtilities.IsStringEmptyOrWhitespace(self.options.SlideSelector) 7859 || FBUtilities.IsStringEmptyOrWhitespace(self.options.PositionUnits) 7860 || FBUtilities.IsStringEmptyOrWhitespace(self.options.ActiveSlideClass) 7861 || FBUtilities.IsStringEmptyOrWhitespace(self.options.MediumSizeClass) 7862 || FBUtilities.IsStringEmptyOrWhitespace(self.options.LargeSizeClass) 7863 || FBUtilities.IsStringEmptyOrWhitespace(self.options.SlideTitleSelector)) 7864 { 7865 FBUtilities.LogMessage('SpotlistNavManager - required settings null or empty.'); 7866 return; 7867 } 7868 7869 var lNumSpots = jElement.find(self.options.SlideSelector).length; 7870 if (lNumSpots < 3) 7871 { 7872 FBUtilities.LogMessage('SpotlistNavManager - too few slides found.'); 7873 return; 7874 } 7875 7876 self._sizeSlideNav(); 7877 7878 jElement.find(self.options.SlideListSelector).on( 7879 "mouseover", 7880 self.options.SlideSelector, 7881 function (aEvent) 7882 { 7883 self._setSlideNavPositions($(aEvent.target).closest(self.options.SlideSelector).index()); 7884 } 7885 ); 7886 7887 jElement.find(self.options.SlideListSelector).on( 7888 "click", 7889 self.options.SlideSelector, 7890 function (aEvent) 7891 { 7892 var lSlide = $(aEvent.target).closest(self.options.SlideSelector); 7893 if (lSlide.hasClass(self.options.ActiveSlideClass) === false) 7894 { 7895 aEvent.preventDefault(); 7896 self._setSlideNavPositions(lSlide.index()); 7897 return false; 7898 } 7899 else 7900 { 7901 return true; 7902 } 7903 } 7904 ); 7905 7906 self._setSlideNavPositions(0); 7907 jElement.addClass(self.options.SliderNavClass); 7908 7909 $(window).resize( 7910 function () 7911 { 7912 waitForFinalEvent( 7913 function () 7914 { 7915 self._sizeSlideNav(); 7916 }, 7917 500, 7918 "resizer" 7919 ); 7920 } 7921 ); 7922 }, 7923 7924 _sizeSlideNav: function () 7925 { 7926 var self = this; 7927 var jElement = $(self.element); 7928 var lElementId = $(jElement).attr('id'); 7929 7930 var lNumSpots = jElement.find(self.options.SlideSelector).length; 7931 if (lNumSpots < 3) 7932 { 7933 return; 7934 } 7935 7936 jElement.removeClass(self.options.MediumSizeClass); 7937 jElement.removeClass(self.options.LargeSizeClass); 7938 self._slideHeight = self.options.SmallSlideWidth; 7939 self._slideTabWidth = self.options.SmallTabHeight; 7940 7941 var lListWidth = jElement.find(self.options.SlideListSelector).width(); 7942 7943 if ($(window).width() <= self.options.SmallSizeCutoff) 7944 { 7945 jElement.find(self.options.SlideSelector).removeAttr("style"); 7946 jElement.find(self.options.SlideSelector).find('.desc_short').removeAttr("style"); 7947 jElement.find(self.options.SlideListSelector).removeAttr("style"); 7948 return; 7949 } 7950 else if ($(window).width() <= self.options.MediumSizeCutoff) 7951 { 7952 self._slideHeight = self.options.MediumSlideWidth; 7953 // self._slideTabWidth = self.options.MediumTabHeight; 7954 self._slideTabWidth = lListWidth / (lNumSpots + 1); 7955 jElement.addClass(self.options.MediumSizeClass); 7956 } 7957 else 7958 { 7959 self._slideHeight = self.options.LargeSlideWidth; 7960 // self._slideTabWidth = self.options.LargeTabHeight; 7961 self._slideTabWidth = lListWidth / (lNumSpots + 1); 7962 jElement.addClass(self.options.LargeSizeClass); 7963 } 7964 7965 self._slideWidth = jElement.find(self.options.SlideSelector).width(); 7966 7967 $.each( 7968 jElement.find(self.options.SlideSelector), 7969 function (aIndex, aValue) 7970 { 7971 var lValue = $(aValue); 7972 lValue.css('background-image', 'url("' + $(aValue).data('spotimgsrc') + '")'); 7973 } 7974 ); 7975 7976 self._slideWidth = self._slideTabWidth * 2; 7977 // self._slideWidth = lListWidth - (lNumSpots - 1) * self._slideTabWidth; 7978 jElement.find(self.options.SlideSelector).css('width', self._slideWidth + self.options.PositionUnits); 7979 jElement.find(self.options.SlideSelector).find(self.options.SlideTitleSelector).css('width', self._slideHeight + self.options.PositionUnits); 7980 jElement.find(self.options.SlideSelector).find(self.options.SlideTitleSelector).css('transform-origin',
7980(self._slideHeight / 2) + self.options.PositionUnits + ' ' + (self._slideHeight / 2) + self.options.PositionUnits); 7981 jElement.find(self.options.SlideListSelector).css('height', self._slideHeight + self.options.PositionUnits); 7982 7983 self._setSlideNavPositions(jElement.find(self.options.SlideSelector + '.' + self.options.ActiveSlideClass).index()); 7984 }, 7985 7986 _setSlideNavPositions: function (aActiveIndex) 7987 { 7988 var self = this; 7989 var jElement = $(self.element); 7990 var lElementId = $(jElement).attr('id'); 7991 7992 $.each( 7993 jElement.find(self.options.SlideSelector), 7994 function (aIndex, aValue) 7995 { 7996 var lValue = $(aValue); 7997 var lLeftPositionVal = (aIndex * self._slideTabWidth); 7998 if (aActiveIndex === aIndex) 7999 { 8000 lValue.addClass(self.options.ActiveSlideClass); 8001 lValue.find(self.options.SlideTitleSelector).css('width', 'auto'); 8002 } 8003 else 8004 { 8005 lValue.removeClass(self.options.ActiveSlideClass); 8006 lValue.find(self.options.SlideTitleSelector).css('width', self._slideHeight + self.options.PositionUnits); 8007 } 8008 if (aIndex > aActiveIndex) 8009 { 8010 lLeftPositionVal += (self._slideWidth - self._slideTabWidth); 8011 } 8012 lValue.css('left', (lLeftPositionVal + self.options.PositionUnits)); 8013 } 8014 ); 8015 } 8016 }); 8017})(jQuery); 8018 8019 8020/////////////////////////////////////////////////////////////////////////////// 8021// IFrame Video Resizer 8022/////////////////////////////////////////////////////////////////////////////// 8023 8024(function ($) 8025{ 8026 VideoUtilities.SetupVideoResizer = function (aSelector) 8027 { 8028 if (FBUtilities.IsStringEmptyOrWhitespace(aSelector)) 8029 { 8030 return; 8031 } 8032 8033 var lAllContainerElements = $(aSelector); 8034 if (lAllContainerElements.length === 0) 8035 { 8036 return; 8037 } 8038 8039 // Find all Videos (YouTube/Vimeo) 8040 var lAllVideos = lAllContainerElements.find("iframe[src^='//www.youtube.com'], iframe[src^='//player.vimeo.com']"); 8041 8042 if (lAllVideos.length === 0) 8043 { 8044 return; 8045 } 8046 8047 // Figure out and save aspect ratio for each video 8048 lAllVideos.each( 8049 function () 8050 { 8051 $(this) 8052 .data('aspectRatio', this.height / this.width) 8053 // and remove the hard coded width/height 8054 .removeAttr('height') 8055 .removeAttr('width'); 8056 } 8057 ); 8058 8059 // When the window is resized 8060 $(window).resize( 8061 function () 8062 { 8063 // Resize all videos according to their own aspect ratio 8064 lAllVideos.each( 8065 function () 8066 { 8067 var $el = $(this); 8068 var lNewWidth = $el.parent().width(); 8069 $el 8070 .width(lNewWidth) 8071 .height(lNewWidth * $el.data('aspectRatio')); 8072 8073 } 8074 ); 8075 // Kick off one resize to fix all videos on page load 8076 } 8077 ).resize(); 8078 }; //end SetupVideoResizer 8079 8080}(jQuery)); 8081 8082/////////////////////////////////////////////////////////////////////////////// 8083// Email Icon Hover/Focus Event 8084/////////////////////////////////////////////////////////////////////////////// 8085 8086(function ($) 8087{ 8088 8089 $( 8090 function () 8091 { 8092 var _EmailLinkClass = 'contact_button'; 8093 var _EmailIconClass = 'fb_emailicon'; 8094 //at rest: far fa-envelope 8095 //active: fas fa-envelope 8096 var _EmailAtRestClass = 'far'; 8097 var _EmailActiveClass = 'fas'; 8098 8099 function _ResetEmailIcons() 8100 { 8101 $('.' + _EmailIconClass).removeClass(_EmailActiveClass); 8102 $('.' + _EmailIconClass).addClass(_EmailAtRestClass); 8103 } 8104 8105 function _ActivateEmailIcon(aElement) 8106 { 8107 if (FBUtilities.IsParameterUndefinedOrEmpty(aElement)) 8108 { 8109 return; 8110 } 8111 aElement.removeClass(_EmailAtRestClass); 8112 aElement.addClass(_EmailActiveClass); 8113 } 8114 8115 $('body').on(
8116 'focusin mouseover', 8117 '.' + _EmailLinkClass, 8118 function (aEvent) 8119 { 8120 _ResetEmailIcons(); 8121 _ActivateEmailIcon($(aEvent.target).closest('.' + _EmailLinkClass).find('.' + _EmailIconClass)); 8122 } 8123 ); 8124 8125 $('body').on( 8126 'focusout mouseout', 8127 '.' + _EmailLinkClass, 8128 function (aEvent) 8129 { 8130 if (!$(aEvent.target).hasClass(_EmailLinkClass)) 8131 { 8132 //return false; 8133 } 8134 _ResetEmailIcons(); 8135 } 8136 ); 8137 } 8138 ); 8139 8140}(jQuery)); 8141 8142/////////////////////////////////////////////////////////////////////////////// 8143// Foxbright Lightbox Manager 8144/////////////////////////////////////////////////////////////////////////////// 8145/* 8146(function ($) 8147{ 8148 FBLightbox._Initialized = false; 8149 8150 FBLightbox.Init = function () 8151 { 8152 if (FBUtilities.IsParameterUndefinedOrEmpty(window.lightbox)) 8153 { 8154 return; 8155 } 8156 if (FBLightbox._Initialized === false) 8157 { 8158 window.lightbox.init(); 8159 FBLightbox._Initialized = true; 8160 } 8161 }; //end Init 8162 8163}(jQuery)); 8164*/ 8165 8166(function ($) 8167{ 8168 var quickAjaxTemplate = "<div id=\"QuickAjaxDialog\" class=\"modal fade\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"staticBackdrop\" aria-hidden=\"true\"> \ 8169 <div class=\"modal-dialog modal-dialog-centered\" role=\"document\"> \ 8170 <div class=\"modal-content\"> \ 8171 <div class=\"modal-header\" \> \ 8172 <h5 class=\"modal-title\" id=\"QuickAjaxDialogTitle\">Checking the building name.</h5> \ 8173 </div> \ 8174 <div class=\"modal-body\"> \ 8175 <div class=\"progress\" > \ 8176 <div class=\"progress-bar progress-bar-striped progress-bar-animated bg-danger\" role=\"progressbar\" style=\"width: 100%\" aria-valuenow=\"100\" aria-valuemin=\"0\" aria-valuemax=\"100\"></div> \ 8177 </div> \ 8178 </div> \ 8179 </div> \ 8180 </div> \ 8181 </div>"; 8182 8183 /** 8184 * FBQuickAjax.Async 8185 * Creates a promise object that will post a simple ajax request to a remote ajax service. 8186 * @param { 8187 * url: [the posting url of the ajax service], 8188 * timeout: [milliseconds to wait before giving up on the ajax request], 8189 * title: [a short title for progress dialog], 8190 * data: [some data to post to the posting url] 8191 * } options 8192 * @returns Promise object. 8193 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 8194 */ 8195 FBQuickAjax.Async = function (options) 8196 { 8197 return new Promise(function (resolutionFunc, rejectionFunc) 8198 { 8199 $("#QuickAjaxDialog").remove(); 8200 8201 var $dialog = $(quickAjaxTemplate); 8202 8203 $dialog.find(".modal-title").html(options.title); 8204 $("body").prepend($dialog); 8205 8206 $("#QuickAjaxDialog").off('shown.bs.modal').on('shown.bs.modal', function () 8207 { 8208 $.ajax({
8209 type: options.method || "post", 8210 url: options.url, 8211 timeout: options.timeout, 8212 dataType: "json", 8213 async: true, 8214 data: options.data, 8215 error: function (_jqXHR, textStatus, errorThrown) 8216 { 8217 console.debug(`${textStatus}: ${errorThrown}`); 8218 rejectionFunc(textStatus); 8219 }, 8220 success: function (data, _textStatus, _jqXHR) 8221 { 8222 resolutionFunc(data); 8223 }, 8224 complete: function () 8225 { 8226 $("#QuickAjaxDialog").modal("hide"); 8227 } 8228 }); 8229 }); 8230 $("#QuickAjaxDialog").modal('show'); 8231 }); 8232 } 8233 8234}(jQuery)); 8235 8236 8237// Manages any in-page changes of the url in the address bar. 8238var FBUrlManager = 8239{ 8240 CURRENTSTATEIDENTIFIER: 'CurrentUrlManagerState', 8241 _CallbackSets: {}, 8242 _SpecifiedDefaults: {}, 8243 8244 // initialize. Sets up a listener to run the callbacks upon a 'back' press in the browser. 8245 init: function () 8246 { 8247 window.addEventListener( 8248 'popstate', 8249 (event) => 8250 { 8251 FBUrlManager._runCallbacks('OnAddressBarUpdate', document.location); 8252 } 8253 ); 8254 }, 8255 // sets a default for a parameter. Setting a value matching this default for the parameter will remove the parameter from the url. 8256 setParameterDefault: function (aParamName, aDefault) 8257 { 8258 if (FBUtilities.IsStringEmptyOrWhitespace(aParamName)) 8259 { 8260 return; 8261 } 8262 if (FBUtilities.IsParameterUndefinedOrEmpty(FBUrlManager._SpecifiedDefaults)) 8263 { 8264 return; 8265 } 8266 8267 let lParamName = FBUrlManager._getNormalizedParamName(aParamName); 8268 8269 // create or overwrite. 8270 FBUrlManager._SpecifiedDefaults[lParamName] = aDefault; 8271 }, 8272 // removes a parameter default. 8273 removeParameterDefault: function (aParamName) 8274 { 8275 if (FBUtilities.IsStringEmptyOrWhitespace(aParamName)) 8276 { 8277 return; 8278 } 8279 if (FBUtilities.IsParameterUndefinedOrEmpty(FBUrlManager._SpecifiedDefaults)) 8280 { 8281 return; 8282 } 8283 8284 let lParamName = FBUrlManager._getNormalizedParamName(aParamName); 8285 8286 if (FBUtilities.IsParameterUndefinedOrNull(FBUrlManager._SpecifiedDefaults[lParamName])) 8287 { 8288 return; 8289 } 8290 delete FBUrlManager._SpecifiedDefaults[lParamName]; 8291 }, 8292 // update the address bar with the given parameter name and value. 8293 updateAddressBar: function (aParamName, aValue) 8294 { 8295 if (FBUtilities.IsStringEmptyOrWhitespace(aParamName)) 8296 { 8297 return; 8298 } 8299 let lNewAddress = FBUrlManager._getUpdatedUrl(aParamName, aValue); 8300 8301 window.history.replaceState(FBUrlManager.CURRENTSTATEIDENTIFIER, "", lNewAddress); 8302 8303 FBUrlManager._runCallbacks('OnAddressBarUpdate', lNewAddress); 8304 }, 8305 // add a set of callbacks by an arbitrary name (for use if you wish to remove them at any point) 8306 // available callbacks: 8307 // 'OnAddressBarUpdate' this will be run after an update and also if 'back' is used to navigate. 8308 // it will have one parameter: the new url as set in the address bar. 8309 addCallbackSet: function (aName, aCallbackSet) 8310 { 8311 if (FBUtilities.IsStringEmptyOrWhitespace(aName)) 8312 { 8313 return; 8314 } 8315 if (FBUtilities.IsParameterUndefinedOrEmpty(FBUrlManager._CallbackSets)) 8316 { 8317 return; 8318 } 8319 8320 let lName = FBUrlManager._getNormalizedParamName(aName); 8321 8322 // create or overwrite. 8323 FBUrlManager._CallbackSets[lName] = aCallbackSet; 8324 }, 8325 // remove a set of callbacks by name. 8326 removeCallbackSet: function (aName) 8327 { 8328 if (FBUtilities.IsStringEmptyOrWhitespace(aName)) 8329 { 8330 return; 8331 } 8332 if (FBUtilities.IsParameterUndefinedOrEmpty(FBUrlManager._CallbackSets)) 8333 { 8334 return; 8335 } 8336 8337 let lName = FBUrlManager._getNormalizedParamName(aName); 8338 8339 if (FBUtilities.IsParameterUndefinedOrNull(FBUrlManager._CallbackSets[lName])) 8340 { 8341 return; 8342 } 8343 delete FBUrlManager._CallbackSets[lName]; 8344 }, 8345 // worker method: runs the callback specified in each set of callbacks. 8346 _runCallbacks: function (aCallbackName, aNewAddress) 8347 { 8348 for(var lKey in FBUrlManager._CallbackSets) 8349 { 8350 FBUtilities.RunCallback(FBUrlManager._CallbackSets[lKey], aCallbackName, aNewAddress); 8351 }//endfor 8352 }, 8353 // worker method: performs an desired normalization on the parameter name. 8354 _getNormalizedParamName: function(aParamName) 8355 { 8356 return aParamName; 8357 }, 8358 // worker method: given a parameter name and value, returns the current address bar url updated with the new parameters.
8359 _getUpdatedUrl: function(aParamName, aValue) 8360 { 8361 let lProtocol = window.location.protocol; 8362 let lHost = window.location.host; 8363 let lPathName = window.location.pathname; 8364 let lSearch = FBUrlManager._getUpdatedSearch(window.location.search, aParamName, aValue); 8365 let lHash = window.location.hash; 8366 let lNewUrl = new URL(`${lProtocol}${lHost}${lPathName}${lSearch}${lHash}`); 8367 return lNewUrl.toString(); 8368 }, 8369 // worker method: given an address query component and parameter name and value, builds a new search query (with leading '?') for use. 8370 _getUpdatedSearch: function(aExistingQuery, aParamName, aValue) 8371 { 8372 let searchParams = new URLSearchParams(aExistingQuery); 8373 8374 if (searchParams.has(aParamName)) 8375 { 8376 if (FBUtilities.IsParameterUndefinedOrEmpty(FBUrlManager._SpecifiedDefaults[aParamName]) 8377 || FBUrlManager._SpecifiedDefaults[aParamName] !== aValue) 8378 { 8379 searchParams.set(aParamName, aValue); 8380 } 8381 else if (FBUrlManager._SpecifiedDefaults[aParamName] === aValue) 8382 { 8383 searchParams.delete(aParamName); 8384 } 8385 } 8386 else 8387 { 8388 if (FBUtilities.IsParameterUndefinedOrEmpty(FBUrlManager._SpecifiedDefaults[aParamName]) 8389 || FBUrlManager._SpecifiedDefaults[aParamName] !== aValue) 8390 { 8391 searchParams.append(aParamName, aValue); 8392 } 8393 } 8394 let newSearch = searchParams.toString(); 8395 if (FBUtilities.IsParameterUndefinedOrEmpty(newSearch) === false) 8396 { 8397 newSearch = '?' + newSearch; 8398 } 8399 return newSearch; 8400 } 8401 8402}//end FBUrlManager 8403// initialize it! It's OK if it's up before the page, needs to be ready for any default or callback submissions. 8404FBUrlManager.init(); 8405 8406 8407/////////////////////////////////////////////////////////////////////////////// 8408// Foxbright Translate Menu 8409(function ($) 8410{ 8411 $( 8412 function() 8413 { 8414 // if a translate menu exists... 8415 if ($('.menu_translate').length > 0) 8416 { 8417 // add a named callback set... 8418 // 'OnAddressBarUpdate' - update any links in the menu that have a valid url with the google translate parameters with the new url. 8419 FBUrlManager.addCallbackSet( 8420 'FoxbrightTranslateMenu', 8421 { 8422 'OnAddressBarUpdate': function (aNewUrl) 8423 { 8424 $.each($('.menu_translate a'), function (aIndex, aValue) 8425 { 8426 let lAnchor = $(aValue); 8427 let lAnchorHref = lAnchor.attr('href'); 8428 let lAnchorUrl = null; 8429 try 8430 { 8431 lAnchorUrl = new URL(lAnchorHref); 8432 } 8433 catch (_) 8434 { 8435 return; 8436 } 8437 if (lAnchorUrl.searchParams.has('u') === false 8438 || lAnchorUrl.searchParams.has('tl') === false) 8439 { 8440 return; 8441 } 8442 lAnchorUrl.searchParams.set('u', aNewUrl); 8443 lAnchor.attr('href', lAnchorUrl.toString()); 8444 }); 8445 } 8446 } 8447 ); 8448 } 8449 } 8450 ); 8451}(jQuery)); // END JQUERY WRAPPER (Foxbright Translate Menu) 8452/////////////////////////////////////////////////////////////////////////////// 8453 8454/////////////////////////////////////////////////////////////////////////////// 8455// Foxbright Drop Widget 8456(function ($) 8457{ 8458 8459 /* 8460 FBDropWidget - (Generic Drop derived from FBRListNav) 8461 - Foxbright Drop 8462 8463 Javascript controller for the responsive simple drop that pops up upon command. 8464 Derived from FBRListNav to avoid reinventing the drop. 8465 8466 Options: 8467 8468 DropClass default: 'fbcms_drop' 8469 Required. A class to be added to the drop once the widget has successfully 8470 completed. Change this at your peril. 8471 DropOpenClass default: 'dropopen' 8472 Required. A class to indicate when the drop is open, to be added or removed 8473 by the widget as appropriate. 8474 DropTitleClass default: null 8475 Required. A class selector for finding the title element of the drop in the 8476 drop element. If the drop title is empty, the widget will do nothing. 8477 DropTitleAuxClass default: 'drop_title' 8478 Required. A class to be added to the title once the widget has successfully 8479 complete. Change this at your peril. 8480 AddOpenButton default: false 8481 If true, add a button to the drop title with events to open and close the 8482 drop. If true, OpenButtonClass, OpenDropContent, and CloseDropContent are 8483 all required. 8484 OpenButtonClass default: 'drop_opener' 8485 Required if AddOpenButton is true. A class used to identify the button added 8486 to the drop title. 8487 OpenDropContent default: '<span class="fas fa-chevron-down"></span>' 8488 Required if AddOpenButton is true. Content to appear in the drop button when 8489 the drop is closed and may be opened. 8490 Whatever content is put into place, the following content is added afterward.
8491 <span class="screen-reader-text">Open {Drop Title} Drop</span> 8492 CloseDropContent default: '<span class="fas fa-chevron-up"></span>' 8493 Required if AddOpenButton is true. Content to appear in the drop button when 8494 the drop is open and may be closed. 8495 Whatever content is put into place, the following content is added afterward. 8496 <span class="screen-reader-text">Close {Drop Title} Drop</span> 8497 DropContainerClass default: null 8498 Required. A class that should be found in the markup on the element wrapping 8499 the drop. 8500 DropContainerClass default: 'drop_container' 8501 Required. A class to be added to the container once the widget has successfully 8502 complete. Change this at your peril. 8503 InitOpen default: false 8504 If true, the drop will initialize open. 8505 DropClickActive default: true 8506 If true, the drop button will be activated on mouse click events. 8507 DropHoverActive default: false 8508 If true, the drop button will be activated on mouse hover events, closing on 8509 hover out after a delay (DropHoverDelay) if not hovered over in that time. 8510 DropHoverDelay default: 300 8511 A hover delay for use if the DropHoverActive is true. 8512 8513 Methods: 8514 8515 The widget is fully functional on its own, but can be remotely activated with the following 8516 methods. 8517 8518 ToggleDrop 8519 Called to toggle the drop open or closed. 8520 OpenDrop 8521 Called to open the drop (or do nothing if the drop is already open). 8522 CloseDrop 8523 Called to close the drop (or do nothing if the drop is already closed). 8524 8525 Examples: 8526 8527 Since the function is built as a jQuery Widget, simply call the functions on the 8528 container element directly. 8529 8530 $('.fbcms_translate').FBDropWidget( 8531 { 8532 DropTitleClass: 'translatedrop_title' 8533 , DropContainerClass: 'translatedrop_container' 8534 } 8535 ); 8536 */ 8537 $.widget("ui.FBDropWidget", 8538 { 8539 options: 8540 { 8541 DropClass: 'fbcms_drop' 8542 , DropOpenClass: 'dropopen' 8543 , DropTitleClass: null 8544 , DropTitleAuxClass: 'drop_title' 8545 , AddOpenButton: false 8546 , OpenButtonClass: 'drop_opener' 8547 , DropButtonOpenContent: '<span class="drop_icon fas fa-chevron-down"></span>' 8548 , DropButtonCloseContent: '<span class="drop_icon fas fa-chevron-up"></span>' 8549 , DropContainerClass: null 8550 , DropContainerAuxClass: 'drop_container' 8551 , InitOpen: false 8552 , DropClickActive: true 8553 , DropHoverActive: false 8554 , DropHoverDelay: 300 8555 }, 8556 8557 _hoverTimer: null, 8558 8559 _destroy: function () 8560 { 8561 return undefined; 8562 }, 8563 8564 _init: function () 8565 { 8566 return undefined; 8567 }, 8568 8569 _create: function () 8570 { 8571 var self = this; 8572 var jElement = $(self.element); 8573 8574 if (FBUtilities.IsStringEmptyOrWhitespace(self.options.DropClass) 8575 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropOpenClass) 8576 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropTitleClass) 8577 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropTitleAuxClass) 8578 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropContainerClass) 8579 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropContainerAuxClass)) 8580 { 8581 FBUtilities.LogMessage('FBDropWidget - required settings null or empty.'); 8582 return; 8583 } 8584 8585 if (self.options.AddOpenButton === true 8586 && (FBUtilities.IsStringEmptyOrWhitespace(self.options.OpenButtonClass) 8587 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropButtonOpenContent) 8588 || FBUtilities.IsStringEmptyOrWhitespace(self.options.DropButtonCloseContent))) 8589 { 8590 FBUtilities.LogMessage('FBDropWidget - open button settings not set as requested.'); 8591 return; 8592 } 8593 8594 let lTitleElement = jElement.find(`.${self.options.DropTitleClass}`); 8595 let lContainerElement = jElement.find(`.${self.options.DropContainerClass}`); 8596 8597 if (lTitleElement.length === 0) 8598 { 8599 FBUtilities.LogMessage('FBDropWidget - drop title not found.'); 8600 return; 8601 } 8602 if (lContainerElement.length === 0) 8603 { 8604 FBUtilities.LogMessage('FBDropWidget - drop container not found.'); 8605 return; 8606 } 8607 lTitleElement.attr("aria-expanded", false); 8608 8609 self._DropTitle = lTitleElement.text(); 8610 8611 if (self.options.AddOpenButton === true) 8612 { 8613 lTitleElement.append('<span class="' + self.options.OpenButtonClass + '"></span>'); 8614 self._setOpenButtonContent(); 8615 } 8616 8617 let lButtonEventSelector = '.' + self.options.DropTitleClass; 8618 if (self.options.AddOpenButton === true) 8619 { 8620 lButtonEventSelector = lButtonEventSelector + ',.' + self.options.OpenButtonClass; 8621 } 8622 8623 if (self.options.DropClickActive === true) 8624 { 8625 jElement.on( 8626 'click', 8627 lButtonEventSelector, 8628 function (aEvent) 8629 { 8630 aEvent.preventDefault(); 8631 self.ToggleDrop(); 8632 return false; 8633 } 8634 ); 8635 jElement.on( 8636 'keyup', 8637 lButtonEventSelector, 8638 function (aEvent) 8639 { 8640 if(aEvent.which == 13) 8641 { 8642 aEvent.preventDefault(); 8643 self.ToggleDrop(); 8644 return false; 8645 } 8646 return true; 8647 } 8648 ); 8649 } 8650 8651 if (self.options.DropHoverActive === true) 8652 { 8653 jElement.hover( 8654 function () 8655 { 8656 self.OpenDrop(); 8657 8658 if (self._hoverTimer !== null) 8659 { 8660 $.clearTimer(self._hoverTimer); 8661 } 8662 } 8663 , function () 8664 { 8665 self._hoverTimer = $.timer( 8666 self.options.DropHoverDelay, 8667 function () 8668 { 8669 self.CloseDrop(); 8670 } 8671 ); 8672 } 8673 ); 8674 } 8675 8676 if (self.options.InitOpen) 8677 { 8678 self.OpenDrop(); 8679 } 8680 8681 jElement.DropFocusManager( 8682 { 8683 HoverFocusClass: self.options.DropOpenClass 8684 , OpenOnHoverFocus: false 8685 , TitleOpenerSelector: '.' + self.options.DropTitleClass 8686 , DropLinksSelector: '.' + self.options.DropContainerClass + ' :focusable' 8687 } 8688 ); 8689 8690 jElement.addClass(self.options.DropClass); 8691 lTitleElement.addClass(self.options.DropTitleAuxClass); 8692 lContainerElement.addClass(self.options.DropContainerAuxClass); 8693 }, 8694 8695 _DropTitle: null, 8696 8697 ToggleDrop: function () 8698 { 8699 var self = this, 8700 jElement = $(self.element); 8701 8702 jElement.toggleClass(self.options.DropOpenClass); 8703 jElement.find(`.${self.options.DropTitleClass}`).attr("aria-expanded", jElement.hasClass(self.options.DropOpenClass)); 8704 8705 self._setOpenButtonContent(); 8706 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBDropWidget:ToggleDrop' } })); 8707 }, 8708 8709 OpenDrop: function () 8710 { 8711 var self = this, 8712 jElement = $(self.element); 8713 8714 jElement.addClass(self.options.DropOpenClass); 8715 jElement.find(`.${self.options.DropTitleClass}`).attr("aria-expanded", true); 8716 8717 self._setOpenButtonContent(); 8718 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBDropWidget:OpenDrop' } })); 8719 }, 8720 8721 CloseDrop: function () 8722 { 8723 var self = this, 8724 jElement = $(self.element); 8725 8726 jElement.removeClass(self.options.DropOpenClass); 8727 jElement.find(`.${self.options.DropTitleClass}`).attr("aria-expanded", false); 8728 8729 self._setOpenButtonContent(); 8730 self.element[0].dispatchEvent(new CustomEvent('fb:changevisibility', { bubbles: true, detail: { item: jElement, name: 'FBDropWidget:CloseDrop' } })); 8731 }, 8732 8733 _setOpenButtonContent: function () 8734 { 8735 var self = this, 8736 jElement = $(self.element), 8737 lOpenButton; 8738 8739 if (self.options.AddOpenButton === true) 8740 { 8741 lOpenButton = jElement.find('.' + self.options.OpenButtonClass); 8742 8743 if (jElement.is('.' + self.options.DropOpenClass)) 8744 { 8745 lOpenButton.html(self.options.DropButtonCloseContent + '<span class="screen-reader-text">Close ' + self._DropTitle + ' Drop</span>'); 8746 } 8747 else 8748 { 8749 lOpenButton.html(self.options.DropButtonOpenContent + '<span class="screen-reader-text">Open ' + self._DropTitle + ' Drop</span>'); 8750 } 8751 } 8752 } 8753 8754 } 8755 ); 8756 8757 8758 FBUtilities.initTranslateWidget = function (aElement, aOnInitializedCallback) 8759 { 8760 if ($(aElement).FBDropWidget("instance") !== undefined) 8761 { 8762 $(aElement).FBDropWidget("destroy"); 8763 } 8764 8765 $(aElement).FBDropWidget( 8766 { 8767 DropTitleClass: 'translatedrop_title' 8768 , DropContainerClass: 'translatedrop_container' 8769 } 8770 ); 8771 8772 aOnInitializedCallback(aElement); 8773 }; 8774}(jQuery)); // END JQUERY WRAPPER (Foxbright Drop Widget) 8775/////////////////////////////////////////////////////////////////////////////// 8776 8777 8778(function ($) 8779{ 8780 $(window).on('load', function () 8781 {
8782 FBUtilities.initializeLoadables(document); 8783 }); 8784 8785 FBUtilities.initializeLoadables = function (containerElement) 8786 { 8787 if (containerElement === null) 8788 { 8789 return; 8790 } 8791 containerElement.querySelectorAll("[data-fbonload]").forEach( 8792 function (element) 8793 { 8794 FBUtilities.initializeLoadable(element); 8795 } 8796 ); 8797 } 8798 8799 FBUtilities.initializeLoadable = function (aLoadableElement) 8800 { 8801 if (!aLoadableElement.dataset.hasOwnProperty('fbonload')) 8802 { 8803 return; 8804 } 8805 8806 if (aLoadableElement.dataset.hasOwnProperty('fbInitState') 8807 && aLoadableElement.dataset.fbInitState !== "new") 8808 { 8809 return; 8810 } 8811 8812 var func = aLoadableElement.dataset.fbonload; 8813 if (typeof FBUtilities[func] !== 'undefined' 8814 && typeof FBUtilities[func] === 'function') 8815 { 8816 FBUtilities[func](aLoadableElement, FBUtilities.onLoadableInitialized); 8817 } 8818 else 8819 { 8820 console.log(`Function '${func}' not found!`); 8821 } 8822 } 8823 8824 FBUtilities.onLoadableInitialized = function (aElement) 8825 { 8826 // must set to initialized once complete. 8827 aElement.dataset.fbInitState = "complete"; 8828 } 8829}(jQuery)); // END JQUERY WRAPPER (Initialize Loadables) 8830 8831 8832/////////////////////////////////////////////////////////////////////////////// 8833// Metronic Integrated "Fancy" Labels 8834(function ($) 8835{ 8836 function updateFancyInputField(aField, aHasFocus) 8837 { 8838 let parent = $(aField).parent(); 8839 let hasWrapper = parent.hasClass('selectfolder') && parent.hasClass('input-group'); 8840 let wrapper = hasWrapper ? $(aField).parent() : aField; 8841 if (aHasFocus === true || FBUtilities.IsParameterUndefinedOrEmpty(aField.val()) === false) 8842 { 8843 wrapper.addClass('notempty'); 8844 } 8845 else 8846 { 8847 wrapper.removeClass('notempty'); 8848 } 8849 }//end updateFancyInputField 8850 8851 FBUtilities.initFancyInputField = function (aElement, aOnInitializedCallback) 8852 { 8853 let element = $(aElement); 8854 let normalInput = element.find('.form-control,.vp-input'); 8855 normalInput.on('focus blur change', 8856 function(e) 8857 { 8858 updateFancyInputField($(e.target), e.type === 'focus'); 8859 } 8860 ); 8861 8862 updateFancyInputField(normalInput, false); 8863 8864 aOnInitializedCallback(aElement); 8865 }; 8866}(jQuery)); // END JQUERY WRAPPER (Metronic Integrated "Fancy" Labels) 8867/////////////////////////////////////////////////////////////////////////////// 8868 8869 8870// 8871// BEGIN LATINIZE 8872// Thanks to https://stackoverflow.com/questions/286921/efficiently-replace-all-accented-characters-in-a-string 8873// 8874 8875var Latinise = {}; Latinise.latin_map = { 8876 "Ã": "A", 8877 "Ä": "A",
8878 "Ắ": "A", 8879 "Ặ": "A", 8880 "Ằ": "A", 8881 "Ẳ": "A", 8882 "Ẵ": "A", 8883 "Ç": "A", 8884 "Ã": "A", 8885 "Ấ": "A", 8886 "Ậ": "A", 8887 "Ầ": "A", 8888 "Ẩ": "A", 8889 "Ẫ": "A", 8890 "Ã": "A", 8891 "Ç": "A", 8892 "Ȧ": "A", 8893 "Ç ": "A", 8894 "Ạ": "A", 8895 "È": "A", 8896 "Ã": "A", 8897 "Ả": "A", 8898 "È": "A", 8899 "Ä": "A", 8900 "Ä": "A", 8901 "à ": "A", 8902 "Ǻ": "A", 8903 "á¸": "A", 8904 "Ⱥ": "A", 8905 "Ã": "A", 8906 "ê²": "AA", 8907 "Ã": "AE", 8908 "Ǽ": "AE", 8909 "Ç¢": "AE", 8910 "ê´": "AO", 8911 "ê¶": "AU", 8912 "ê¸": "AV", 8913 "êº": "AV", 8914 "ê¼": "AY", 8915 "á¸": "B", 8916 "á¸": "B", 8917 "Æ": "B", 8918 "á¸": "B", 8919 "É": "B", 8920 "Æ": "B", 8921 "Ä": "C", 8922 "Ä": "C", 8923 "Ã": "C", 8924 "á¸": "C", 8925 "Ä": "C", 8926 "Ä": "C", 8927 "Æ": "C", 8928 "È»": "C", 8929 "Ä": "D", 8930 "á¸": "D", 8931 "á¸": "D", 8932 "á¸": "D", 8933 "á¸": "D", 8934 "Æ": "D", 8935 "á¸": "D", 8936 "Dz": "D", 8937 "Ç ": "D", 8938 "Ä": "D", 8939 "Æ": "D", 8940 "DZ": "DZ", 8941 "Ç": "DZ", 8942 "Ã": "E", 8943 "Ä": "E", 8944 "Ä": "E", 8945 "Ȩ": "E", 8946 "á¸": "E", 8947 "Ã": "E", 8948 "Ế": "E", 8949 "á»": "E",
8950 "á»": "E", 8951 "á»": "E", 8952 "á»": "E", 8953 "á¸": "E", 8954 "Ã": "E", 8955 "Ä": "E", 8956 "Ẹ": "E", 8957 "È": "E", 8958 "Ã": "E", 8959 "Ẻ": "E", 8960 "È": "E", 8961 "Ä": "E", 8962 "á¸": "E", 8963 "á¸": "E", 8964 "Ä": "E", 8965 "É": "E", 8966 "Ẽ": "E", 8967 "á¸": "E", 8968 "êª": "ET", 8969 "á¸": "F", 8970 "Æ": "F", 8971 "Ç´": "G", 8972 "Ä": "G", 8973 "Ǧ": "G", 8974 "Ä¢": "G", 8975 "Ä": "G", 8976 "Ä ": "G", 8977 "Æ": "G", 8978 "Ḡ": "G", 8979 "Ǥ": "G", 8980 "Ḫ": "H", 8981 "È": "H", 8982 "Ḩ": "H", 8983 "Ĥ": "H", 8984 "â±§": "H", 8985 "Ḧ": "H", 8986 "Ḣ": "H", 8987 "Ḥ": "H", 8988 "Ħ": "H", 8989 "Ã": "I", 8990 "Ĭ": "I", 8991 "Ç": "I", 8992 "Ã": "I", 8993 "Ã": "I", 8994 "Ḯ": "I", 8995 "İ": "I", 8996 "á»": "I", 8997 "È": "I", 8998 "Ã": "I", 8999 "á»": "I", 9000 "È": "I", 9001 "Ī": "I", 9002 "Ä®": "I", 9003 "Æ": "I", 9004 "Ĩ": "I", 9005 "Ḭ": "I", 9006 "ê¹": "D", 9007 "ê»": "F", 9008 "ê½": "G", 9009 "ê": "R", 9010 "ê": "S", 9011 "ê": "T", 9012 "ê¬": "IS", 9013 "Ä´": "J", 9014 "É": "J", 9015 "Ḱ": "K", 9016 "Ǩ": "K", 9017 "Ķ": "K", 9018 "Ⱪ": "K", 9019 "ê": "K", 9020 "Ḳ": "K", 9021 "Æ": "K", 9022 "Ḵ": "K", 9023 "ê": "K", 9024 "ê": "K", 9025 "Ĺ": "L", 9026 "Ƚ": "L", 9027 "Ľ": "L", 9028 "Ä»": "L", 9029 "Ḽ": "L", 9030 "Ḷ": "L", 9031 "Ḹ": "L", 9032 "â± ": "L", 9033 "ê": "L", 9034 "Ḻ": "L", 9035 "Ä¿": "L", 9036 "â±¢": "L", 9037 "Ç": "L", 9038 "Å": "L", 9039 "Ç": "LJ", 9040 "Ḿ": "M", 9041 "á¹": "M", 9042 "á¹": "M", 9043 "â±®": "M", 9044 "Å": "N", 9045 "Å": "N", 9046 "Å ": "N", 9047 "á¹": "N", 9048 "á¹": "N", 9049 "á¹": "N", 9050 "Ǹ": "N", 9051 "Æ": "N", 9052 "á¹": "N", 9053 "È ": "N", 9054 "Ç": "N", 9055 "Ã": "N", 9056 "Ç": "NJ", 9057 "Ã": "O", 9058 "Å": "O", 9059 "Ç": "O", 9060 "Ã": "O", 9061 "á»": "O", 9062 "á»": "O", 9063 "á»": "O", 9064 "á»": "O", 9065 "á»": "O", 9066 "Ã": "O", 9067 "Ȫ": "O", 9068 "È®": "O", 9069 "Ȱ": "O", 9070 "á»": "O", 9071 "Å": "O", 9072 "È": "O", 9073 "Ã": "O", 9074 "á»": "O", 9075 "Æ ": "O", 9076 "á»": "O", 9077 "Ợ": "O", 9078 "á»": "O", 9079 "á»": "O", 9080 "á» ": "O", 9081 "È": "O", 9082 "ê": "O", 9083 "ê": "O", 9084 "Å": "O", 9085 "á¹": "O", 9086 "á¹": "O", 9087 "Æ": "O", 9088 "Ǫ": "O", 9089 "Ǭ": "O", 9090 "Ã": "O", 9091 "Ǿ": "O", 9092 "Ã": "O", 9093 "á¹": "O", 9094 "á¹": "O", 9095 "Ȭ": "O", 9096 "Æ¢": "OI", 9097 "ê": "OO", 9098 "Æ": "E", 9099 "Æ": "O", 9100 "È¢": "OU", 9101 "á¹": "P", 9102 "á¹": "P", 9103 "ê": "P", 9104 "Ƥ": "P", 9105 "ê": "P", 9106 "â±£": "P", 9107 "ê": "P", 9108 "ê": "Q", 9109 "ê": "Q", 9110 "Å": "R", 9111 "Å": "R", 9112 "Å": "R", 9113 "á¹": "R", 9114 "á¹": "R", 9115 "á¹": "R", 9116 "È": "R", 9117 "È": "R", 9118 "á¹": "R", 9119 "É": "R", 9120 "Ɽ": "R", 9121 "ê¾": "C", 9122 "Æ": "E", 9123 "Å": "S", 9124 "Ṥ": "S", 9125 "Å ": "S", 9126 "Ṧ": "S", 9127 "Å": "S", 9128 "Å": "S", 9129 "È": "S", 9130 "á¹ ": "S", 9131 "á¹¢": "S", 9132 "Ṩ": "S", 9133 "Ť": "T", 9134 "Å¢": "T", 9135 "á¹°": "T", 9136 "È": "T", 9137 "Ⱦ": "T", 9138 "Ṫ": "T", 9139 "Ṭ": "T", 9140 "Ƭ": "T", 9141 "á¹®": "T", 9142 "Æ®": "T", 9143 "Ŧ": "T", 9144 "Ɐ": "A", 9145 "ê": "L", 9146 "Æ": "M", 9147 "É ": "V", 9148 "ê¨": "TZ", 9149 "Ã": "U", 9150 "Ŭ": "U", 9151 "Ç": "U", 9152 "Ã": "U", 9153 "á¹¶": "U", 9154 "Ã": "U", 9155 "Ç": "U", 9156 "Ç": "U", 9157 "Ç": "U", 9158 "Ç": "U", 9159 "á¹²": "U", 9160 "Ụ": "U", 9161 "Ű": "U", 9162 "È": "U", 9163 "Ã": "U", 9164 "Ủ": "U", 9165 "Ư": "U", 9166 "Ứ": "U", 9167 "á»°": "U", 9168 "Ừ": "U", 9169 "Ử": "U", 9170 "á»®": "U", 9171 "È": "U", 9172 "Ū": "U", 9173 "Ṻ": "U", 9174 "Ų": "U", 9175 "Å®": "U", 9176 "Ũ": "U", 9177 "Ṹ": "U", 9178 "á¹´": "U", 9179 "ê": "V", 9180 "á¹¾": "V", 9181 "Ʋ": "V", 9182 "á¹¼": "V", 9183 "ê ": "VY", 9184 "áº": "W", 9185 "Å´": "W", 9186 "áº": "W", 9187 "áº": "W", 9188 "áº": "W", 9189 "áº": "W", 9190 "â±²": "W", 9191 "áº": "X", 9192 "áº": "X", 9193 "Ã": "Y", 9194 "Ŷ": "Y", 9195 "Ÿ": "Y", 9196 "áº": "Y", 9197 "á»´": "Y", 9198 "Ỳ": "Y", 9199 "Ƴ": "Y", 9200 "á»¶": "Y", 9201 "Ỿ": "Y", 9202 "Ȳ": "Y", 9203 "É": "Y", 9204 "Ỹ": "Y", 9205 "Ź": "Z", 9206 "Ž": "Z", 9207 "áº": "Z", 9208 "Ⱬ": "Z", 9209 "Å»": "Z", 9210 "áº": "Z", 9211 "Ȥ": "Z", 9212 "áº": "Z", 9213 "Ƶ": "Z", 9214 "IJ": "IJ", 9215 "Å": "OE", 9216 "á´": "A", 9217 "á´": "AE", 9218 "Ê": "B", 9219 "á´": "B", 9220 "á´": "C", 9221 "á´ ": "D", 9222 "á´": "E", 9223 "ê°": "F", 9224 "É¢": "G", 9225 "Ê": "G", 9226 "Ê": "H", 9227 "ɪ": "I", 9228 "Ê": "R", 9229 "á´": "J", 9230 "á´": "K", 9231 "Ê": "L", 9232 "á´": "L", 9233 "á´": "M", 9234 "É´": "N", 9235 "á´": "O", 9236 "ɶ": "OE", 9237 "á´": "O", 9238 "á´": "OU", 9239 "á´": "P", 9240 "Ê": "R", 9241 "á´": "N", 9242 "á´": "R", 9243 "ê±": "S", 9244 "á´": "T", 9245 "â±»": "E", 9246 "á´": "R", 9247 "á´": "U", 9248 "á´ ": "V", 9249 "á´¡": "W", 9250 "Ê": "Y", 9251 "á´¢": "Z", 9252 "á": "a", 9253 "Ä": "a", 9254 "ắ": "a", 9255 "ặ": "a", 9256 "ằ": "a", 9257 "ẳ": "a", 9258 "ẵ": "a", 9259 "Ç": "a", 9260 "â": "a", 9261 "ấ": "a", 9262 "áº": "a", 9263 "ầ": "a", 9264 "ẩ": "a", 9265 "ẫ": "a", 9266 "ä": "a", 9267 "Ç": "a", 9268 "ȧ": "a", 9269 "Ç¡": "a", 9270 "ạ": "a", 9271 "È": "a", 9272 "à ": "a", 9273 "ả": "a", 9274 "È": "a", 9275 "Ä": "a", 9276 "Ä ": "a", 9277 "á¶": "a", 9278 "áº": "a", 9279 "Ã¥": "a", 9280 "Ç»": "a", 9281 "á¸": "a", 9282 "â±¥": "a", 9283 "ã": "a", 9284 "ê³": "aa", 9285 "æ": "ae", 9286 "ǽ": "ae", 9287 "Ç£": "ae", 9288 "êµ": "ao", 9289 "ê·": "au", 9290 "ê¹": "av", 9291 "ê»": "av", 9292 "ê½": "ay", 9293 "á¸": "b", 9294 "Ḡ": "b", 9295 "É": "b",
9296 "á¸": "b", 9297 "ᵬ": "b", 9298 "á¶": "b", 9299 "Æ": "b", 9300 "Æ": "b", 9301 "ɵ": "o", 9302 "Ä": "c", 9303 "Ä": "c", 9304 "ç": "c", 9305 "á¸": "c", 9306 "Ä": "c", 9307 "É": "c", 9308 "Ä": "c", 9309 "Æ": "c", 9310 "ȼ": "c", 9311 "Ä": "d", 9312 "á¸": "d", 9313 "á¸": "d", 9314 "È¡": "d", 9315 "á¸": "d", 9316 "á¸": "d", 9317 "É": "d", 9318 "á¶": "d", 9319 "á¸": "d", 9320 "áµ": "d", 9321 "á¶": "d", 9322 "Ä": "d", 9323 "É": "d", 9324 "Æ": "d", 9325 "ı": "i", 9326 "È·": "j", 9327 "É": "j", 9328 "Ê": "j", 9329 "dz": "dz", 9330 "Ç": "dz", 9331 "é": "e", 9332 "Ä": "e", 9333 "Ä": "e", 9334 "È©": "e", 9335 "á¸": "e", 9336 "ê": "e", 9337 "ế": "e", 9338 "á»": "e", 9339 "á»": "e", 9340 "á»": "e", 9341 "á» ": "e", 9342 "á¸": "e", 9343 "ë": "e", 9344 "Ä": "e", 9345 "ẹ": "e", 9346 "È ": "e", 9347 "è": "e", 9348 "ẻ": "e", 9349 "È": "e", 9350 "Ä": "e", 9351 "á¸": "e", 9352 "á¸": "e", 9353 "ⱸ": "e", 9354 "Ä": "e", 9355 "á¶": "e", 9356 "É": "e", 9357 "ẽ": "e", 9358 "á¸": "e", 9359 "ê«": "et", 9360 "á¸": "f", 9361 "Æ": "f", 9362 "áµ®": "f", 9363 "á¶": "f", 9364 "ǵ": "g", 9365 "Ä": "g", 9366 "ǧ": "g", 9367 "Ä£": "g", 9368 "Ä": "g", 9369 "Ä¡": "g", 9370 "É ": "g", 9371 "ḡ": "g", 9372 "á¶": "g", 9373 "Ç¥": "g", 9374 "ḫ": "h", 9375 "È": "h", 9376 "ḩ": "h", 9377 "Ä¥": "h", 9378 "ⱨ": "h", 9379 "ḧ": "h", 9380 "ḣ": "h", 9381 "ḥ": "h", 9382 "ɦ": "h", 9383 "áº": "h", 9384 "ħ": "h", 9385 "Æ": "hv", 9386 "Ã": "i", 9387 "Ä": "i", 9388 "Ç": "i", 9389 "î": "i", 9390 "ï": "i", 9391 "ḯ": "i", 9392 "á»": "i", 9393 "È": "i", 9394 "ì": "i", 9395 "á»": "i", 9396 "È": "i", 9397 "Ä«": "i", 9398 "į": "i", 9399 "á¶": "i", 9400 "ɨ": "i", 9401 "Ä©": "i", 9402 "á¸": "i", 9403 "êº": "d", 9404 "ê¼": "f", 9405 "áµ¹": "g", 9406 "ê": "r", 9407 "ê ": "s", 9408 "ê": "t", 9409 "ê": "is", 9410 "ǰ": "j", 9411 "ĵ": "j", 9412 "Ê": "j", 9413 "É": "j", 9414 "ḱ": "k", 9415 "Ç©": "k", 9416 "Ä·": "k", 9417 "ⱪ": "k", 9418 "ê": "k", 9419 "ḳ": "k", 9420 "Æ": "k", 9421 "ḵ": "k", 9422 "á¶": "k", 9423 "ê": "k", 9424 "ê ": "k", 9425 "ĺ": "l", 9426 "Æ": "l", 9427 "ɬ": "l", 9428 "ľ": "l", 9429 "ļ": "l", 9430 "ḽ": "l", 9431 "È´": "l", 9432 "ḷ": "l", 9433 "ḹ": "l", 9434 "ⱡ": "l", 9435 "ê": "l", 9436 "ḻ": "l", 9437 "Å": "l", 9438 "É«": "l", 9439 "á¶ ": "l", 9440 "É": "l", 9441 "Å": "l", 9442 "Ç": "lj", 9443 "Å¿": "s", 9444 "áº": "s", 9445 "áº": "s", 9446 "áº": "s", 9447 "ḿ": "m", 9448 "á¹": "m", 9449 "á¹": "m", 9450 "ɱ": "m", 9451 "ᵯ": "m", 9452 "á¶": "m", 9453 "Å": "n", 9454 "Å": "n", 9455 "Å": "n", 9456 "á¹": "n", 9457 "ȵ": "n", 9458 "á¹ ": "n", 9459 "á¹": "n", 9460 "ǹ": "n", 9461 "ɲ": "n", 9462 "á¹": "n", 9463 "Æ": "n", 9464 "áµ°": "n", 9465 "á¶": "n", 9466 "ɳ": "n", 9467 "ñ": "n", 9468 "Ç": "nj", 9469 "ó": "o", 9470 "Å": "o", 9471 "Ç": "o", 9472 "ô": "o", 9473 "á»": "o", 9474 "á»": "o", 9475 "á»": "o", 9476 "á»": "o", 9477 "á»": "o", 9478 "ö": "o", 9479 "È«": "o", 9480 "ȯ": "o", 9481 "ȱ": "o", 9482 "á»": "o", 9483 "Å": "o", 9484 "È": "o", 9485 "ò": "o", 9486 "á»": "o", 9487 "Æ¡": "o", 9488 "á»": "o", 9489 "ợ": "o", 9490 "á»": "o", 9491 "á»": "o", 9492 "ỡ": "o", 9493 "È": "o", 9494 "ê": "o", 9495 "ê": "o", 9496 "ⱺ": "o", 9497 "Å": "o", 9498 "á¹": "o", 9499 "á¹": "o", 9500 "Ç«": "o", 9501 "Ç": "o", 9502 "ø": "o", 9503 "Ç¿": "o", 9504 "õ": "o", 9505 "á¹": "o", 9506 "á¹": "o", 9507 "È": "o", 9508 "Æ£": "oi", 9509 "ê": "oo", 9510 "É": "e", 9511 "á¶": "e", 9512 "É": "o", 9513 "á¶": "o", 9514 "È£": "ou", 9515 "á¹": "p", 9516 "á¹": "p", 9517 "ê": "p", 9518 "Æ¥": "p", 9519 "áµ±": "p", 9520 "á¶": "p", 9521 "ê": "p", 9522 "áµ½": "p", 9523 "ê": "p", 9524 "ê": "q", 9525 "Ê ": "q", 9526 "É": "q", 9527 "ê": "q", 9528 "Å": "r", 9529 "Å": "r", 9530 "Å": "r", 9531 "á¹": "r", 9532 "á¹": "r", 9533 "á¹": "r", 9534 "È": "r", 9535 "ɾ": "r", 9536 "áµ³": "r", 9537 "È": "r", 9538 "á¹": "r", 9539 "ɼ": "r", 9540 "áµ²": "r", 9541 "á¶": "r", 9542 "É": "r", 9543 "ɽ": "r", 9544 "â": "c", 9545 "ê¿": "c", 9546 "É": "e", 9547 "É¿": "r", 9548 "Å": "s", 9549 "á¹¥": "s", 9550 "Å¡": "s", 9551 "á¹§": "s", 9552 "Å": "s", 9553 "Å": "s", 9554 "È": "s", 9555 "ṡ": "s", 9556 "á¹£": "s", 9557 "ṩ": "s", 9558 "Ê": "s", 9559 "áµ´": "s", 9560 "á¶": "s", 9561 "È¿": "s", 9562 "É¡": "g", 9563 "á´": "o", 9564 "á´": "o", 9565 "á´": "u",
9566 "Å¥": "t", 9567 "Å£": "t", 9568 "á¹±": "t", 9569 "È": "t", 9570 "ȶ": "t", 9571 "áº": "t", 9572 "ⱦ": "t", 9573 "ṫ": "t", 9574 "á¹": "t", 9575 "Æ": "t", 9576 "ṯ": "t", 9577 "áµµ": "t", 9578 "Æ«": "t", 9579 "Ê": "t", 9580 "ŧ": "t", 9581 "ᵺ": "th", 9582 "É": "a", 9583 "á´": "ae", 9584 "Ç": "e", 9585 "áµ·": "g", 9586 "É¥": "h", 9587 "Ê®": "h", 9588 "ʯ": "h", 9589 "á´": "i", 9590 "Ê": "k", 9591 "ê": "l", 9592 "ɯ": "m", 9593 "ɰ": "m", 9594 "á´": "oe", 9595 "ɹ": "r", 9596 "É»": "r", 9597 "ɺ": "r", 9598 "â±¹": "r", 9599 "Ê": "t", 9600 "Ê": "v", 9601 "Ê": "w", 9602 "Ê": "y", 9603 "ê©": "tz", 9604 "ú": "u", 9605 "Å": "u", 9606 "Ç": "u", 9607 "û": "u", 9608 "á¹·": "u", 9609 "ü": "u", 9610 "Ç": "u", 9611 "Ç": "u", 9612 "Ç": "u", 9613 "Ç": "u", 9614 "á¹³": "u", 9615 "ụ": "u", 9616 "ű": "u", 9617 "È": "u", 9618 "ù": "u", 9619 "á»§": "u", 9620 "ư": "u", 9621 "ứ": "u", 9622 "á»±": "u", 9623 "ừ": "u", 9624 "á»": "u", 9625 "ữ": "u", 9626 "È": "u", 9627 "Å«": "u", 9628 "á¹»": "u", 9629 "ų": "u", 9630 "á¶": "u", 9631 "ů": "u", 9632 "Å©": "u", 9633 "á¹¹": "u", 9634 "á¹µ": "u", 9635 "ᵫ": "ue", 9636 "ê¸": "um", 9637 "â±´": "v", 9638 "ê": "v", 9639 "ṿ": "v", 9640 "Ê": "v", 9641 "á¶": "v", 9642 "â±±": "v", 9643 "á¹½": "v", 9644 "ê¡": "vy", 9645 "áº": "w", 9646 "ŵ": "w", 9647 "Ạ": "w", 9648 "áº": "w", 9649 "áº": "w", 9650 "áº": "w", 9651 "â±³": "w", 9652 "áº": "w", 9653 "áº": "x", 9654 "áº": "x", 9655 "á¶": "x", 9656 "ý": "y", 9657 "Å·": "y", 9658 "ÿ": "y", 9659 "áº": "y", 9660 "ỵ": "y", 9661 "ỳ": "y", 9662 "Æ´": "y", 9663 "á»·": "y", 9664 "ỿ": "y", 9665 "ȳ": "y", 9666 "áº": "y", 9667 "É": "y", 9668 "ỹ": "y", 9669 "ź": "z", 9670 "ž": "z", 9671 "áº": "z", 9672 "Ê": "z", 9673 "ⱬ": "z", 9674 "ż": "z", 9675 "áº": "z", 9676 "È¥": "z", 9677 "áº": "z", 9678 "áµ¶": "z", 9679 "á¶": "z", 9680 "Ê": "z", 9681 "ƶ": "z", 9682 "É": "z", 9683 "ï¬": "ff", 9684 "ï¬": "ffi", 9685 "ï¬": "ffl", 9686 "ï¬": "fi", 9687 "ï¬": "fl", 9688 "ij": "ij", 9689 "Å": "oe", 9690 "ï¬": "st", 9691 "â": "a", 9692 "â": "e", 9693 "áµ¢": "i", 9694 "â±¼": "j", 9695 "â": "o", 9696 "áµ£": "r", 9697 "ᵤ": "u", 9698 "áµ¥": "v", 9699 "â": "x" 9700}; 9701String.prototype.latinise = function () { return this.replace(/[^A-Za-z0-9\[\] ]/g, function (a) { return Latinise.latin_map[a] || a }) }; 9702String.prototype.latinize = String.prototype.latinise; 9703String.prototype.isLatin = function () { return this == this.latinise() } 9704 9705// END LATINIZE 9706 9707// BEGIN PROPOSE URL SEGMENT 9708String.prototype.proposePathSegment = function () 9709{ 9710 return this 9711 .toLowerCase() 9712 .latinize() 9713 .replace(/[^a-zA-Z0-9\-_~]/g, "-") 9714 .replace(/[\-~_]{2,}/g, "-"); 9715}; 9716// END PROPOSE URL SEGMENT 9717 9718// BEGIN SIMPLE DEBOUNCE 9719const debounceFunc = (func, delay) => { 9720 let timer; 9721 return function(...args) { 9722 const context = this; 9723 window.clearTimeout(timer); 9724 timer = window.setTimeout(() => { 9725 func.apply(context, args); 9726 }, delay) 9727 } 9728} 9729// END SIMPLE DEBOUNCE
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.