1 2 3;/* Start: js/shared.js*/ 4 5// ============================================================ 6// Common Scripts and Functions that are shared between templates 7// ============================================================ 8 9// http://blog.stevenlevithan.com/archives/es3-regexes-broken 10// http://ianconery.com/2015/08/regexp-test-bug-in-javascript/ 11RegExp.prototype.test = function(str) { 12 if(str === undefined || str === null) { 13 str = ''; 14 } 15 return str.toString().match(this) !== null; 16}; 17 18// Owl Carousel Options 19var owlOptions = { 20 center: true, 21 margin: 0, 22 dots: true, 23 dotsEach: 4, 24 nav: true, 25 loop: true, 26 autoplay: false, 27 autoplayTimeout: 2000, 28 autoplayHoverPause: false, 29 responsive: { 30 0: { 31 center: true, 32 items: 1, 33 slideBy: 1 34 }, 35 480: { 36 center: false, 37 items: 2, 38 slideBy: 2 39 }, 40 720: { 41 center: false, 42 items: 3, 43 slideBy: 3 44 }, 45 920: { 46 center: false, 47 items: 4, 48 slideBy: 4 49 }, 50 1140: { 51 center: false, 52 items: 4, 53 slideBy: 4 54 } 55 } 56} 57 58// Execute when DOM ready 59jQuery(function ($) { 60 61 //Hide the mobile menu if the UL inside is empty. 62 // This is currently targeting the retail menu so it doesn't inadvertently hide the wrong elements. 63 // It can be expanded to cover other use cases as needed. 64 $($('.missing-linkset').parents('ul.topbar__left__menu.linkset')[0]).hide(); 65 66 // Throw compatibility warnings for IE 11 and under 67 if (getInternetExplorerVersion() < 11 && getInternetExplorerVersion() > 0) { 68 Command: toastr["error"]("This browser is no longer supported and many features may not work correctly or will be broken entirely. Please update to a newer browser.", "Browser Compatibility Error", 69 { 70 "closeButton": true, 71 "debug": false, 72 "newestOnTop": false, 73 "progressBar": false, 74 "positionClass": "toast-top-right", 75 "preventDuplicates": false, 76 "onclick": null, 77 "showDuration": "300", 78 "hideDuration": "1000", 79 "timeOut": "0", 80 "extendedTimeOut": "0", 81 "showEasing": "swing", 82 "hideEasing": "linear", 83 "showMethod": "fadeIn", 84 "hideMethod": "fadeOut" 85 }); 86 } else if (getInternetExplorerVersion() <= 11 && getInternetExplorerVersion() > 0 && $('body').hasClass('app_settings')) { 87 Command: toastr["warning"]("Design Previews are not supported by this browser. Please update to a newer browser to take full advantage of the application.", "Browser Compatibility Warning", 88 { 89 "closeButton": true, 90 "debug": false, 91 "newestOnTop": false, 92 "progressBar": false, 93 "positionClass": "toast-bottom-right", 94 "preventDuplicates": false, 95 "onclick": null, 96 "showDuration": "300", 97 "hideDuration": "1000", 98 "timeOut": "0", 99 "extendedTimeOut": "0", 100 "showEasing": "swing", 101 "hideEasing": "linear", 102 "showMethod": "fadeIn", 103 "hideMethod": "fadeOut" 104 }); 105 106 $('.c-app-preview').hide(); 107 $('input[type=color]').hide(); 108 109 // Add ie class 110 } else if (getInternetExplorerVersion() <= 11 && getInternetExplorerVersion() > 0) { 111 $('body').addClass(' internet-explorer-'+getInternetExplorerVersion()); 112 } 113 114 // Add autopage to link URL 115 $('.linkset a[data-autopage="1"]').each(function(){ 116 var href = $(this).attr("href"); 117 var url = window.location.href 118 if (url.indexOf('autopage=') == -1) { 119 // There is no autopage in the URL so add it to the link 120 href += (href.match(/\?/) ? '&' : '?') + 'autopage=' + encodeURIComponent(url); 121 } else { 122 // There is already an autopage in the URL so use the current URL 123 href = url 124 } 125 $(this).attr('href', href); 126 }); 127 128 // Toggle off-canvas sidebar 129 $('[data-toggle="off-canvas"]').on('click', function(e){ 130 var $target = $($(this).data('target')); 131 $('body').toggleClass('side-rail-open'); 132 $target.toggleClass('off-canvas-visible'); 133 }); 134 135 // Initialize plugins 136 // ------------------------------------------------------------ 137 $('[rel="tooltip"], .tooltip-trigger, [data-toggle="tooltip"]').tooltip(); 138 $('[rel="popover"], [data-toggle="popover"]').popover(); 139 $('input, textarea').placeholder(); 140 $('.carousel').carousel(); 141 142 // Responsive lightbox 143 $('.venobox').venobox();
144 145 // Tooltips for DDT table headers 146 $('tr.headrow > th').attr('title', function(){ 147 return $.trim($(this).text()); 148 }); 149 150 // Elements that trigger loading spinner on click 151 $('body').on('click', '[data-toggle="loading"], .loading-toggle', function(){ 152 toggleLoadingWidget(); 153 }); 154 155 // Global toast notification config (toastr) 156 // http://codeseven.github.io/toastr/demo.html 157 try { 158 toastr.options = { 159 'closeButton' : false, 160 'debug' : false, 161 'newestOnTop' : false, 162 'progressBar' : false, 163 'positionClass' : 'toast-top-center', 164 'preventDuplicates': false, 165 'onclick' : null, 166 'showDuration' : '300', 167 'hideDuration' : '1000', 168 'timeOut' : '5000', 169 'extendedTimeOut' : '1000', 170 'showEasing' : 'swing', 171 'hideEasing' : 'linear', 172 'showMethod' : 'fadeIn', 173 'hideMethod' : 'fadeOut' 174 } 175 } catch(err) { 176 console.error(err.message + ' - from /js/shared.js'); 177 } 178 179 // Nav base 180 // ------------------------------------------------------------ 181 $('.linkset ul').parents('li:not(.noparent)').addClass('link-parent'); 182 $('.hyper .active, .breadcrumb .active').parents('li').addClass('hyperactive'); 183 $('.breadcrumb .hyperactive').addClass('link-parent'); 184 185 //Justify 186 $('.linkset.justify').each(function(){ 187 var parentWidth = $(this).parent('div').width(); 188 var thisWidth = $(this).width(); 189 var setLength = $(this).children('li').size(); 190 var linkMargin = (((parentWidth - thisWidth) / (2 * setLength)-.05)); 191 $(this).children('li').children('a').css('padding-left',linkMargin); 192 $(this).children('li').children('a').css('padding-right',linkMargin); 193 }); 194 195 //Click 196 $('.linkset.click>.link-parent>a, .linkset.click-persist .link-parent>a, .linkset.click>.link-parent>span, .linkset.click-persist .link-parent>span').click(function(event){ 197 // This link is open - Close this link 198 if ($(this).parent('li').hasClass('open')) { 199 $(this).parent('li').removeClass('open'); 200 $(this).parent('li').find('li').removeClass('open'); 201 } else { 202 // Link is child of open link - Open this link 203 if ($(this).parents('li').hasClass('open')) { 204 $(this).parents('ul').siblings('ul').children('li').removeClass('open'); 205 $(this).parent('li').siblings('li').removeClass('open'); 206 $(this).parent('li').siblings('li').find('li').removeClass('open'); 207 $(this).parent('li').addClass('open'); 208 // Link is not child of open link - Close all links and open this link. 209 } else { 210 $(this).closest('.linkset').find('li.open').removeClass('open'); 211 $(this).closest('li').removeClass('open'); 212 $(this).parent('li').siblings('li').removeClass('open'); 213 $(this).parent('li').children('li').removeClass('open'); 214 $(this).parent('li').addClass('open'); 215 } 216 } 217 event.preventDefault(); 218 }); 219 220 $(document).on('click', function (event) { 221 if ($(event.target).closest('.linkset.click, .linkset.click-persist').length === 0) { 222 $('.linkset.click li, linkset.click-persist li').removeClass('open'); 223 } 224 }); 225 226 227 accordion(); 228 229 230 //Tabs 231 $('.linkset.tabs > li > a, .linkset.tabs > li > span').click(function(e){ 232 if (!$(this).hasClass('open')) { 233 $(this).parent('li').siblings('li').removeClass('open'); 234 $(this).parent('li').addClass('open'); 235 } 236 }); 237 238 // Add dropdown class 239 $('.linkset li:has(ul):not(.noparent)').each(function(){ 240 $(this).addClass('drop'); 241 }); 242 243 // Click outside to close (for dropdowns, etc.) 244 // uses http://benalman.com/projects/jquery-outside-events-plugin/ 245 $('.js-click-outside-to-close').bind('clickoutside', function(e){ 246 $(this).find('.link-parent').removeClass('open'); 247 }); 248 249 // Owl Carousel 250 $('.owl-carousel').owlCarousel(owlOptions); 251 252 // ============================================================ 253 // Responsive DDT search / filters 254 // ============================================================ 255 256 // DDT filter toggle button event handler 257 $(document).on('click', '[data-toggle="DDT-filters"]', function(){ 258 $(this).next('.DDT-form-search').addClass('show'); 259 $(this).closest('.DDT-form-search').removeClass('show'); 260 }); 261
262 // Add table search filter input element 263 //injectTablesawFilter(); 264 265 // Add indexing for table filter searches 266 // $('.tablesaw tbody tr:not(.tablesaw-filter):has(td)') 267 // .each(function(){ 268 // var t = $(this).text().toLowerCase(); 269 // $('<td class="indexColumn"></td>').hide().text(t).appendTo(this); 270 // }); 271 272 // Event handlers for table filter 273 // ------------------------------------------------------------ 274 275 // Do the filtering 276 $(document) 277 .on('keyup', '.tablesaw-filter-input', function(e){ 278 279 // Show the clear button if there is a filter value 280 if ($(this).val()) { 281 $(this).next('.tablesaw-filter-clear').removeClass('hide'); 282 } else { 283 $(this).next('.tablesaw-filter-clear').addClass('hide'); 284 } 285 286 // Table to filter 287 var $filterTable = $(this).closest('table.tablesaw'); 288 289 if (e.keyCode === 27 || $(this).val() === '') { 290 291 // clear search on ESC keypress when search is focused 292 if (e.keyCode === 27){ 293 $(this) 294 .val('').blur() 295 // hide the clear "X" 296 .next('.tablesaw-filter-clear').addClass('hide'); 297 } 298 299 // Reset previous filters 300 clearTablesawFilter($filterTable); 301 302 } else { 303 304 // Get filter values 305 var s = $(this).val().toLowerCase().split(' '); 306 307 // Reset previous filters 308 clearTablesawFilter($filterTable); 309 310 $.each(s, function(){ 311 $filterTable 312 .find('.indexColumn:not(:contains("' + this + '"))') 313 .parent('tr:not(.tablesaw-filter)') 314 .addClass('hide'); 315 }); 316 317 } //-if (e.keyCode == 27) 318 319 }); 320 321 // Clear the filter input value 322 $('.tablesaw-filter .tablesaw-filter-clear') 323 .on('click', function(e){ 324 e.preventDefault(); 325 var $filterTable = $(this).closest('.tablesaw'); 326 clearTablesawFilter($filterTable); 327 $(this).addClass('hide').prev('.tablesaw-filter-input').val(''); 328 }); 329 330 331 // Bootstrap hotfixes 332 // ------------------------------------------------------------ 333 334 // Prevents drop down to be closed on click into `.dropdown-menu`. 335 // github.com/mitnal/bootstrap/commit/29df6eaa230df3e1c9e5bcb4c86c75132ef32817 336 $(document).on( 337 'click.dropdown.data-api', 338 '.dropdown-menu', 339 function(e) { 340 e.stopPropagation(); 341 }); 342 343 // UI helpers 344 // ------------------------------------------------------------ 345 346 // Remove modals from tabindex 347 // - enables close on ESC keypress for modal windows 348 // $('.modal').attr('tabindex', -1); 349 350 // Move progress bar for payment page order processing 351 $('#order_processing_modal') 352 .on('shown', function(){ 353 fncMoveProgressBar('#order_processing_bar'); 354 }); 355 356 // Move progress bar for sign in loading msg 357 $('#login_progress_modal') 358 .on('shown', function(){ 359 fncMoveProgressBar('#login_progress_bar'); 360 }); 361 362 // Kill the default behavior for cart builder qty update links 363 $('#cartform a[onclick^="submitCart"]') 364 .on('click', function(e){ 365 e.preventDefault(); 366 }); 367 368 // Assign all buttons that add to cart ... 369 var addToCartButtons = '.prod_item .actions .btn.btn-small, ' + 370 '.detail_atc_standalone .btn-primary'; 371 372 // Add to cart button processing indicators 373 $(addToCartButtons) 374 .on('click', function(e) { 375 // only left mousedown 376 if (e.which === 1) { 377 $(this).append('<i class="icon-spinner icon-spin hide"></i>').fadeIn('fast'); 378 } 379 }); 380 381 function removeSpinners(e) { 382 $(addToCartButtons).children('i.icon-spinner').remove(); 383 } 384 385 // Kill the button processing indicators once items have been 386 // successfully added to the cart (by watching the modal) 387 // $('#atc_msg.modal').add(modal.$modal).on('shown', removeSpinners); 388 389 // Don't allow qty less than 1 for product detail standalone, 390 // and search results grid view, and quick order form, and cart 391 $('.detail_atc_standalone input.qtyinput, \ 392 #gallery_layout input.qtyinput, \ 393 #order_matrix input.qtyinput, \ 394 .cart-table input.cart-input-qty') 395 .on('focusout', function(){ 396 $(this).val() <= 0 ? $(this).val(1) : false 397 }); 398 399 // Smooth scroll to 400 $('.scroll, .scroll-to') 401 .on('click', function(e) { 402 e.preventDefault(); 403 scrollToTarget($(this)); 404 }); 405 406 407 // Fix links to named anchors when base href is used (static pages) 408 if ($('base').length) { 409 $('a[href^="#"]').each(function(){ 410 var href = ''; 411 if (!$(this).parents('ul.nav.nav-tabs').length) { 412 href += window.location; 413 } 414 href += $(this).attr('href').replace('/#.*/i',''); 415 $(this).attr('href', href); 416 }); 417 } 418 // Set active state static page 419 $('#topbar').find('a[href$="' + location.pathname.substring(location.pathname.lastIndexOf('/') + 1) + '"]').addClass('active'); 420 421 // Clear the content of the shipping estimator modal on close 422 // to prevent miscalculation of height (which is used for positioning)
423 // when it is opened again 424 $('#modal_shipest').on('hidden', function(){ 425 $(this).find('.modal-body').empty(); 426 }); 427 428 // Add a tooltip on hover if the category name is overflowing 429 $('.category-window__body .linkset li a').click(function() { 430 $('.category-window__body .linkset li a').each(function(){ 431 if (isOverflowing($(this)[0])) { 432 $(this).tooltip({ 433 animation: 'show', 434 title: $(this).children('.cat-nm').text(), 435 placement: 'top', 436 delay: {show: 400, hide: 100} 437 }); 438 } 439 }); 440 }); 441 442 $('.category-window__body .linkset li a').each(function() { 443 if (isOverflowing($(this)[0])) { 444 $(this).tooltip({ 445 animation: 'show', 446 title: $(this).children('.cat-nm').text(), 447 placement: 'top', 448 delay: {show: 400, hide: 100} 449 }); 450 } 451 }); 452 453 // Set active state static page 454 $('#topbar').find('a[href$="' + location.pathname.substring(location.pathname.lastIndexOf('/') + 1) + '"]').addClass('active'); 455 456 457 458 // Check the subarState on page load 459 getSUbarState() ? revealSUBar() : hideSUBar(); 460 461 // Remove the subar display: none; after page load to prevent animations from playing on load 462 $('#appSuperUserNotify').removeAttr('style'); 463 $('.su-action-btn').removeAttr('style'); 464 465 //Fix overflow on DDT dropdown links 466 $('.ddt-table-wrapper .ddt-dropdown').on('click', function(){ 467 //do we have a dropdown or just a single impersonate link? 468 var hasDropdown = $(this).hasClass('dropdown-toggle'); 469 if(hasDropdown){ 470 //determine if the drop is open or close. 471 var isOpen = $(this).parents('.btn-group').hasClass('open'); 472 if(isOpen){ 473 //Removing the min height on close. 474 $(this).parents('.ddt-table-wrapper').css('min-height', '' ); 475 }else{ 476 //get length of UL so we can calc the minheight 477 var numberOfSites = $(this).next().children().length; 478 var adjustHeight = 35; 479 var baseHeight = $('.ddt-table-wrapper').height(); 480 var minHeight = baseHeight + (adjustHeight * numberOfSites); 481 482 //Add a min height on open 483 $(this).parents('.ddt-table-wrapper').css('min-height', minHeight +'px' ); 484 } 485 } 486 }); 487 488}); // $(function(){}) 489 490 491// On Window Resize 492// $(window).resize(function(){ 493 494// }); 495 496 497// ============================================================ 498// Functions 499// ============================================================ 500 501// Force gallery on mobile getCookie 502function getCookie(cname) { 503 var name = cname + "="; 504 var ca = document.cookie.split(';'); 505 for (var i = 0; i < ca.length; i++) { 506 var c = ca[i]; 507 while (c.charAt(0) == ' ') { 508 c = c.substring(1); 509 } 510 if (c.indexOf(name) == 0) { 511 return c.substring(name.length, c.length); 512 } 513 } 514 return ""; 515} 516 517function injectTablesawFilter() { 518 // Inject the HTML 519 $('.tablesaw:not(.cart-table):not(.tablesaw-no-filter)').each(function () { 520 var $table = $(this); 521 var placeholder = $table.attr('data-tablesaw-filter-placeholder'); 522 523 if (placeholder === undefined) { 524 placeholder = 'Type here to filter this page of results'; 525 } 526 527 // Build HTML for table filter input element 528 var html = '<caption class="tablesaw-filter">' + 529 '<input type="text" class="tablesaw-filter-input" name="tablesaw_filter_text" placeholder="' + placeholder + '" autocomplete="off" autocapitalize="off" autocorrect="off">' + 530 '<button type="button" class="close tablesaw-filter-clear hide">×</button>' + 531 '</caption>'; 532 533 $table.prepend(html); 534 }); 535} 536 537function clearTablesawFilter($table) { 538 // Simply remove the hide class from all table rows 539 $table.find('tr').removeClass('hide'); 540} 541 542 543function toggleLoadingWidget(bShow) { 544 var src = 'templates/gfx/loading/loading.gif'; 545 var widget = $('#appLoadingWidget'); 546 547 if (bShow !== undefined) { 548 widget.toggleClass('hide', !bShow); 549 } else { 550 widget.toggleClass('hide'); 551 } 552 553 // Test browser support for SVG via Modernizr 554 // Fall back to animated gif if no support 555 if (!Modernizr.svg && !Modernizr.cssanimations) { 556 widget.find('.app-loading-spinner-img').attr('src', src); 557 } 558} 559 560 561/** 562 * Use this function to test for JS dependencies and notify if they are not found 563 * http://i2admintest.webstorepackage.com/johnmarkdev/virtualweb/index.php?title=Javascript_Dependency_Checking 564 * Example: 565 * checkJavascriptDependency('jQuery', 'jQuery()', 'You need jQuery yo!', 'http://jquery.com'); 566 */ 567function checkJavascriptDependency(name, cmd, msg, url) { 568 try { 569 eval(cmd); 570 } catch(err) { 571 alert(name + ' is required! Check console for info'); 572 console.error(err.message); 573 console.info(msg + ' ' + url); 574 } 575} 576 577 578// Use this as a generic way to simulate progressbar progress 579var fncMoveProgressBar = function(target) { 580 var progress = setInterval(function() { 581 var $bar = $(target);
582 if ($bar.width()==400) { 583 clearInterval(progress); 584 //$('.progress').removeClass('active'); 585 } else { 586 $bar.width($bar.width()+30); 587 } 588 }, 100); 589} 590 591// Test to see if current page is secure 592function isSecure() { 593 return window.location.protocol == 'https:'; 594} 595 596/** 597 * Check user agent for common mobile/tablet devices 598 * 599 * @returns boolean 600 */ 601function isMobileDevice() { 602 var userAgent = navigator.userAgent || navigator.vendor || window.opera; 603 // iPhone is implied by testing for "Phone" 604 return /iPad|iPod|Android|BlackBerry|Mobile|Phone|Tablet/i.test(userAgent); 605} 606 607// SVG Fallback v1.0 608// https://wiki.webstorepackage.com/index.php?title=SVG_Fallback 609$('img[data-svg-fallback-ext]').on('error', function () { 610 var $this = $(this); 611 612 // The SVG check is necessary to avoid infinitely looping if the fallback image also errors. 613 if ($this.attr('src').slice($this.attr('src').length - 3) === 'svg') { 614 $this.attr('src', $this.attr('src').slice(0, -3) + $this.attr('data-svg-fallback-ext')); 615 } 616}); 617 618 619/** 620 * These functions are used around the site to allow the value from one lightbox question apply a filter to another lightbox 621 * @author johns 622 * @since 02/16/2018 623 */ 624function fncChangeSearchString(field, searchstring, key) { 625 var oldHref = $('#' + field + '_disp_find_link').attr('href'); 626 oldHref = removeOldFilter(oldHref); 627 var newHref = key ? setParam(oldHref, 'filter', searchstring + $('#' + key).val()) : setParam(oldHref, 'filter', ''); 628 $('#' + field + '_disp_find_link').attr('href', newHref); 629} //- function fncChangeSearchString() 630 631function removeOldFilter(href) { 632 var parts = href.split('&'); 633 parts.splice(parts.findIndex(function(parts) { 634 return parts.split('=')[0] == 'filter'; 635 }), 1); 636 return parts.join('&') 637} //- function removeOldFilter (href) 638 639function setParam(uri, key, val) { 640 if (uri) { 641 return uri 642 .replace(new RegExp("([?&]" + key + "(?=[=&#]|$)[^#&]*|(?=#|$))"), "&" + key + "=" + encodeURIComponent(val)) 643 .replace(/^([^?&]+)&/, "$1?"); 644 } else { 645 return ''; 646 } 647} //- function setParam() 648 649 650// Scrolls the page to the target specified in the href 651function scrollToTarget(el) { 652 var target = el.hash, 653 pos = $(target).offset(), 654 scrollto = pos.top - 160; 655 $('body, html').animate( 656 {scrollTop: scrollto}, 657 300, 658 function(){ 659 $('body, html').clearQueue(); 660 $(target).trigger('focus'); 661 }); 662 return false; 663} 664 665// Mark active category menu items and expand parents 666function markActiveCategory() { 667 // fall back to querystring if not a static page 668 var c_key = (jsConfig.static_pages.content_key.length > 0) 669 ? jsConfig.static_pages.content_key 670 : getUrlParameter('pc_id'); 671 $('#category-window') 672 .find('a[data-key=' + c_key + ']') 673 .closest('li').addClass('active') 674 .parents('li.link-parent').addClass('open'); 675 676 // Add Menu Tooltips 677 $('.toolbar__btn').tooltip({ 678 placement: 'right', 679 }); 680} 681 682// Return a specified querystring parameter value 683function getUrlParameter(param) { 684 var value; 685 var parameters = window.location.search.replace('?', ''); 686 if (parameters) { 687 var pattern = new RegExp('\\b' + param + '=([^;&]+)', 'gi'); 688 value = parameters.split(pattern)[1]; 689 } 690 return value || ''; 691}; 692 693function isOverflowing(element) { 694 return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth; 695} 696 697/** 698 * This accordion function accounts for a number of submenus 699 * and utilizes the accordion's height for animated opening 700 * and closing of menus 701 * @author dnelsen 702 * @since 03/22/2019 703 */ 704function accordion() { 705 706 // set accordion total height 707 var accTotalHeight = 0; 708 var accAllLinkGroups = document.querySelectorAll('.accordion > .link-parent ul'); 709 710 // firefox makes us set an initial inline height 711 Array.prototype.slice.call(accAllLinkGroups, 0).forEach(function(group) { 712 if (!group.style.height) { 713 group.style.height = '0px'; 714 } 715 }); 716 717 $('.accordion li.link-parent > a').on('click', function(e){ 718 processAccordionClick(e); 719 }); 720} 721
722function processAccordionClick(e){ 723 // initialize variables 724 var accLink = e.target; 725 var accLinkParent = accLink.closest('.link-parent'); 726 if(!accLinkParent){ 727 return true; 728 } 729 730 e.preventDefault(); 731 var accLinkGroup = accLinkParent.querySelector('ul'); 732 var accLinkChildren = accLinkGroup.children; 733 var accTopLinkGroup = accLink.closest('.accordion > .link-parent').querySelector('ul'); 734 735 // check if this is opened already 736 if (!accLinkParent.classList.contains('open')) { 737 738 var accLinkChildrenHeight = 0; 739 740 // add class 'open' 741 accLinkParent.classList.add('open'); 742 743 // get immediate children heights 744 for (var i = 0; i < accLinkChildren.length; i++) { 745 accLinkChildrenHeight += accLinkChildren[i].offsetHeight; 746 }; 747 748 accLinkGroup.style.height = accLinkChildrenHeight+'px'; 749 750 if (!accLinkGroup.isEqualNode(accTopLinkGroup)) { 751 var accTopLinkGroupHeight = parseInt(accTopLinkGroup.style.height.replace('px', '')); 752 accTopLinkGroup.style.height = (accTopLinkGroupHeight + accLinkChildrenHeight) + 'px'; 753 } 754 755 } else { 756 757 // remove class 'open' from immediate link-parent 758 accLinkParent.classList.remove('open'); 759 var accLinkChildrenHeight = 0; 760 761 // get immediate children heights 762 for (var i = 0; i < accLinkChildren.length; i++) { 763 accLinkChildrenHeight += accLinkChildren[i].offsetHeight; 764 }; 765 766 if (!accLinkGroup.isEqualNode(accTopLinkGroup)) { 767 var accTopLinkGroupHeight = parseInt(accTopLinkGroup.style.height.replace('px', '')); 768 accTopLinkGroup.style.height = (accTopLinkGroupHeight - accLinkChildrenHeight) + 'px'; 769 } 770 771 accLinkGroup.style.height = 0; 772 773 } 774} 775 776/** 777* Detect scrolling direction and append a body class 778* 779* @author dnelsen 780* @since 01/31/2020 781*/ 782setTimeout(function() { 783 var lastScrollTop = 0; 784 window.addEventListener("scroll", function() { 785 var st = window.pageYOffset || document.documentElement.scrollTop; 786 if (st > lastScrollTop){ 787 $('body').addClass('-scrolling-down'); 788 $('body').removeClass('-scrolling-up'); 789 } else { 790 $('body').addClass('-scrolling-up'); 791 $('body').removeClass('-scrolling-down'); 792 } 793 lastScrollTop = st <= 0 ? 0 : st; // For Mobile or negative scrolling 794 }, false); 795}, 300); 796 797 798/** 799* Set show/hide states for the super user bar in impersonation mode 800* 801* @author dnelsen 802* @since 04/17/2020 803*/ 804function revealSUBar(event) { 805 setSUbarState('show'); 806 event ? event.preventDefault() : null; 807 jQuery('.su-action-bar').addClass('-visible'); 808 jQuery('.su-action-btn').removeClass('-visible'); 809} 810 811function hideSUBar(event) { 812 setSUbarState('hide'); 813 event ? event.preventDefault() : null; 814 jQuery('.su-action-bar').removeClass('-visible'); 815 jQuery('.su-action-btn').addClass('-visible'); 816} 817 818function showSUbarInfo(event) { 819 event ? event.preventDefault() : null; 820 jQuery('.su-action-bar').toggleClass('-show-info'); 821} 822 823function setSUbarState(state) { 824 $.cookie('subarState', state, { expires: 7 }); 825} 826 827function getSUbarState() { 828 var state; 829 var curState = $.cookie('subarState'); 830 831 if (curState) { 832 if (curState === 'show') { 833 state = true; 834 } else { 835 state = false; 836 } 837 } else { 838 state = true; 839 } 840 return state; 841} 842 843var GLOBAL_JS_EMAIL_REGEX = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/gi; 844 845$( function(){ 846 markActiveCategory();
847}); 848 849function isEmpty(obj){ 850 if(!obj) return false; 851 852 for(var prop in obj) { 853 if(obj.hasOwnProperty(prop)) 854 return false; 855 } 856 857 return JSON.stringify(obj) === JSON.stringify({}); 858} 859 860 861 862/* End: js/shared.js*/ 863 864 865 866;/* Start: js/vendor/ResizeSensor.js*/ 867 868'use strict'; 869 870/** 871 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level 872 * directory of this distribution and at 873 * https://github.com/marcj/css-element-queries/blob/master/LICENSE. 874 */ 875(function (root, factory) { 876 if (typeof define === "function" && define.amd) { 877 define(factory); 878 } else if (typeof exports === "object") { 879 module.exports = factory(); 880 } else { 881 root.ResizeSensor = factory(); 882 } 883}(typeof window !== 'undefined' ? window : this, function () { 884 885 // Make sure it does not throw in a SSR (Server Side Rendering) situation 886 if (typeof window === "undefined") { 887 return null; 888 } 889 // https://github.com/Semantic-Org/Semantic-UI/issues/3855 890 // https://github.com/marcj/css-element-queries/issues/257 891 var globalWindow = typeof window != 'undefined' && window.Math == Math 892 ? window 893 : typeof self != 'undefined' && self.Math == Math 894 ? self 895 : Function('return this')(); 896 // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor. 897 // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and 898 // would generate too many unnecessary events. 899 var requestAnimationFrame = globalWindow.requestAnimationFrame || 900 globalWindow.mozRequestAnimationFrame || 901 globalWindow.webkitRequestAnimationFrame || 902 function (fn) { 903 return globalWindow.setTimeout(fn, 20); 904 }; 905 906 var cancelAnimationFrame = globalWindow.cancelAnimationFrame || 907 globalWindow.mozCancelAnimationFrame || 908 globalWindow.webkitCancelAnimationFrame || 909 function (timer) { 910 globalWindow.clearTimeout(timer); 911 }; 912 913 /** 914 * Iterate over each of the provided element(s). 915 * 916 * @param {HTMLElement|HTMLElement[]} elements 917 * @param {Function} callback 918 */ 919 function forEachElement(elements, callback) { 920 var elementsType = Object.prototype.toString.call(elements); 921 var isCollectionTyped = ('[object Array]' === elementsType 922 || ('[object NodeList]' === elementsType) 923 || ('[object HTMLCollection]' === elementsType) 924 || ('[object Object]' === elementsType) 925 || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery 926 || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools 927 ); 928 var i = 0, j = elements.length; 929 if (isCollectionTyped) { 930 for (; i < j; i++) { 931 callback(elements[i]); 932 } 933 } else { 934 callback(elements); 935 } 936 } 937 938 /** 939 * Get element size 940 * @param {HTMLElement} element 941 * @returns {Object} {width, height} 942 */ 943 function getElementSize(element) { 944 if (!element.getBoundingClientRect) { 945 return { 946 width: element.offsetWidth, 947 height: element.offsetHeight 948 } 949 } 950 951 var rect = element.getBoundingClientRect(); 952 return { 953 width: Math.round(rect.width), 954 height: Math.round(rect.height) 955 } 956 } 957 958 /** 959 * Apply CSS styles to element. 960 * 961 * @param {HTMLElement} element 962 * @param {Object} style 963 */ 964 function setStyle(element, style) { 965 Object.keys(style).forEach(function (key) { 966 element.style[key] = style[key]; 967 }); 968 } 969 970 /** 971 * Class for dimension change detection. 972 * 973 * @param {Element|Element[]|Elements|jQuery} element 974 * @param {Function} callback 975 * 976 * @constructor 977 */ 978 var ResizeSensor = function (element, callback) { 979 //Is used when checking in reset() only for invisible elements 980 var lastAnimationFrameForInvisibleCheck = 0; 981 982 /** 983 * 984 * @constructor 985 */ 986 function EventQueue() { 987 var q = []; 988 this.add = function (ev) { 989 q.push(ev); 990 }; 991 992 var i, j; 993 this.call = function (sizeInfo) { 994 for (i = 0, j = q.length; i < j; i++) { 995 q[i].call(this, sizeInfo); 996 } 997 }; 998 999 this.remove = function (ev) { 1000 var newQueue = []; 1001 for (i = 0, j = q.length; i < j; i++) { 1002 if (q[i] !== ev) newQueue.push(q[i]); 1003 } 1004 q = newQueue; 1005 }; 1006 1007 this.length = function () { 1008 return q.length; 1009 } 1010 } 1011 1012 /** 1013 * 1014 * @param {HTMLElement} element 1015 * @param {Function} resized 1016 */ 1017 function attachResizeEvent(element, resized) { 1018 if (!element) return; 1019 if (element.resizedAttached) { 1020 element.resizedAttached.add(resized); 1021 return; 1022 } 1023 1024 element.resizedAttached = new EventQueue(); 1025 element.resizedAttached.add(resized); 1026 1027 element.resizeSensor = document.createElement('div'); 1028 element.resizeSensor.dir = 'ltr'; 1029 element.resizeSensor.className = 'resize-sensor'; 1030 1031 var style = { 1032 pointerEvents: 'none', 1033 position: 'absolute', 1034 left: '0px', 1035 top: '0px', 1036 right: '0px', 1037 bottom: '0px', 1038 overflow: 'hidden', 1039 zIndex: '-1', 1040 visibility: 'hidden', 1041 maxWidth: '100%' 1042 }; 1043 var styleChild = { 1044 position: 'absolute', 1045 left: '0px', 1046 top: '0px', 1047 transition: '0s', 1048 }; 1049 1050 setStyle(element.resizeSensor, style); 1051 1052 var expand = document.createElement('div'); 1053 expand.className = 'resize-sensor-expand'; 1054 setStyle(expand, style); 1055 1056 var expandChild = document.createElement('div'); 1057 setStyle(expandChild, styleChild); 1058 expand.appendChild(expandChild); 1059 1060 var shrink = document.createElement('div'); 1061 shrink.className = 'resize-sensor-shrink'; 1062 setStyle(shrink, style); 1063 1064 var shrinkChild = document.createElement('div'); 1065 setStyle(shrinkChild, styleChild); 1066 setStyle(shrinkChild, { width: '200%', height: '200%' }); 1067 shrink.appendChild(shrinkChild); 1068 1069 element.resizeSensor.appendChild(expand); 1070 element.resizeSensor.appendChild(shrink); 1071 element.appendChild(element.resizeSensor); 1072 1073 var computedStyle = window.getComputedStyle(element); 1074 var position = computedStyle ? computedStyle.getPropertyValue('position') : null; 1075 if ('absolute' !== position && 'relative' !== position && 'fixed' !== position && 'sticky' !== position) { 1076 element.style.position = 'relative'; 1077 } 1078 1079 var dirty = false; 1080 1081 //last request animation frame id used in onscroll event 1082 var rafId = 0; 1083 var size = getElementSize(element); 1084 var lastWidth = 0; 1085 var lastHeight = 0; 1086 var initialHiddenCheck = true; 1087 lastAnimationFrameForInvisibleCheck = 0; 1088 1089 var resetExpandShrink = function () { 1090 var width = element.offsetWidth; 1091 var height = element.offsetHeight; 1092 1093 expandChild.style.width = (width + 10) + 'px'; 1094 expandChild.style.height = (height + 10) + 'px'; 1095 1096 expand.scrollLeft = width + 10; 1097 expand.scrollTop = height + 10; 1098 1099 shrink.scrollLeft = width + 10; 1100 shrink.scrollTop = height + 10; 1101 }; 1102 1103 var reset = function () { 1104 // Check if element is hidden 1105 if (initialHiddenCheck) { 1106 var invisible = element.offsetWidth === 0 && element.offsetHeight === 0; 1107 if (invisible) { 1108 // Check in next frame 1109 if (!lastAnimationFrameForInvisibleCheck) { 1110 lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function () { 1111 lastAnimationFrameForInvisibleCheck = 0; 1112 reset(); 1113 }); 1114 } 1115 1116 return; 1117 } else { 1118 // Stop checking 1119 initialHiddenCheck = false; 1120 } 1121 } 1122 1123 resetExpandShrink(); 1124 }; 1125 element.resizeSensor.resetSensor = reset; 1126 1127 var onResized = function () { 1128 rafId = 0; 1129 1130 if (!dirty) return; 1131 1132 lastWidth = size.width; 1133 lastHeight = size.height; 1134 1135 if (element.resizedAttached) { 1136 element.resizedAttached.call(size); 1137 } 1138 }; 1139 1140 var onScroll = function () { 1141 size = getElementSize(element); 1142 dirty = size.width !== lastWidth || size.height !== lastHeight; 1143
1144 if (dirty && !rafId) { 1145 rafId = requestAnimationFrame(onResized); 1146 } 1147 1148 reset(); 1149 }; 1150 1151 var addEvent = function (el, name, cb) { 1152 if (el.attachEvent) { 1153 el.attachEvent('on' + name, cb); 1154 } else { 1155 el.addEventListener(name, cb); 1156 } 1157 }; 1158 1159 addEvent(expand, 'scroll', onScroll); 1160 addEvent(shrink, 'scroll', onScroll); 1161 1162 // Fix for custom Elements and invisible elements 1163 lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function () { 1164 lastAnimationFrameForInvisibleCheck = 0; 1165 reset(); 1166 }); 1167 } 1168 1169 forEachElement(element, function (elem) { 1170 attachResizeEvent(elem, callback); 1171 }); 1172 1173 this.detach = function (ev) { 1174 // clean up the unfinished animation frame to prevent a potential endless requestAnimationFrame of reset 1175 if (lastAnimationFrameForInvisibleCheck) { 1176 cancelAnimationFrame(lastAnimationFrameForInvisibleCheck); 1177 lastAnimationFrameForInvisibleCheck = 0; 1178 } 1179 ResizeSensor.detach(element, ev); 1180 }; 1181 1182 this.reset = function () { 1183 //To prevent invoking element.resizeSensor.resetSensor if it's undefined 1184 if (element.resizeSensor.resetSensor) { 1185 element.resizeSensor.resetSensor(); 1186 } 1187 }; 1188 }; 1189 1190 ResizeSensor.reset = function (element) { 1191 forEachElement(element, function (elem) { 1192 //To prevent invoking element.resizeSensor.resetSensor if it's undefined 1193 if (element.resizeSensor.resetSensor) { 1194 elem.resizeSensor.resetSensor(); 1195 } 1196 }); 1197 }; 1198 1199 ResizeSensor.detach = function (element, ev) { 1200 forEachElement(element, function (elem) { 1201 if (!elem) return; 1202 if (elem.resizedAttached && typeof ev === "function") { 1203 elem.resizedAttached.remove(ev); 1204 if (elem.resizedAttached.length()) return; 1205 } 1206 if (elem.resizeSensor) { 1207 if (elem.contains(elem.resizeSensor)) { 1208 elem.removeChild(elem.resizeSensor); 1209 } 1210 delete elem.resizeSensor; 1211 delete elem.resizedAttached; 1212 } 1213 }); 1214 }; 1215 1216 if (typeof MutationObserver !== "undefined") { 1217 var observer = new MutationObserver(function (mutations) { 1218 for (var i in mutations) { 1219 if (mutations.hasOwnProperty(i)) { 1220 var items = mutations[i].addedNodes; 1221 for (var j = 0; j < items.length; j++) { 1222 if (items[j].resizeSensor) { 1223 ResizeSensor.reset(items[j]); 1224 } 1225 } 1226 } 1227 } 1228 }); 1229 1230 document.addEventListener("DOMContentLoaded", function (event) { 1231 observer.observe(document.body, { 1232 childList: true, 1233 subtree: true, 1234 }); 1235 }); 1236 } 1237 1238 return ResizeSensor; 1239 1240})); 1241 1242 1243 1244/* End: js/vendor/ResizeSensor.js*/ 1245 1246 1247 1248;/* Start: js/form builder/help_tip.js*/ 1249 1250 /* This notice must be untouched at all times. 1251 1252 wz_tooltip.js v. 4.12 1253 1254 The latest version is available at 1255 http://www.walterzorn.com 1256 or http://www.devira.com 1257 or http://www.walterzorn.de 1258 1259 Copyright (c) 2002-2007 Walter Zorn. All rights reserved. 1260 Created 1.12.2002 by Walter Zorn (Web: http://www.walterzorn.com ) 1261 Last modified: 13.7.2007 1262 1263 Easy-to-use cross-browser tooltips. 1264 Just include the script at the beginning of the <body> section, and invoke 1265 Tip('Tooltip text') from within the desired HTML onmouseover eventhandlers. 1266 No container DIV, no onmouseouts required. 1267 By default, width of tooltips is automatically adapted to content.
1268 Is even capable of dynamically converting arbitrary HTML elements to tooltips 1269 by calling TagToTip('ID_of_HTML_element_to_be_converted') instead of Tip(), 1270 which means you can put important, search-engine-relevant stuff into tooltips. 1271 Appearance of tooltips can be individually configured 1272 via commands passed to Tip() or TagToTip(). 1273 1274 Tab Width: 4 1275 LICENSE: LGPL 1276 1277 This library is free software; you can redistribute it and/or 1278 modify it under the terms of the GNU Lesser General Public 1279 License (LGPL) as published by the Free Software Foundation; either 1280 version 2.1 of the License, or (at your option) any later version. 1281 1282 This library is distributed in the hope that it will be useful, 1283 but WITHOUT ANY WARRANTY; without even the implied warranty of 1284 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 1285 1286 For more details on the GNU Lesser General Public License, 1287 see http://www.gnu.org/copyleft/lesser.html 1288 */ 1289 1290 var config = new Object(); 1291 1292 1293 //=================== GLOBAL TOOPTIP CONFIGURATION =========================// 1294 var tt_Debug = true // false or true - recommended: false once you release your page to the public 1295 var tt_Enabled = true // Allows to (temporarily) suppress tooltips, e.g. by providing the user with a button that sets this global variable to false 1296 var TagsToTip = true // false or true - if true, the script is capable of converting HTML elements to tooltips 1297 var tt_Current = '' 1298 1299 // For each of the following config variables there exists a command, which is 1300 // just the variablename in uppercase, to be passed to Tip() or TagToTip() to 1301 // configure tooltips individually. Individual commands override global 1302 // configuration. Order of commands is arbitrary. 1303 // Example: onmouseover="Tip('Tooltip text', LEFT, true, BGCOLOR, '#FF9900', FADEIN, 400)" 1304 1305 config. Above = false // false or true - tooltip above mousepointer? 1306 config. BgColor = '#E4E7FF' // Background color 1307 config. BgImg = '' // Path to background image, none if empty string '' 1308 config. BorderColor = '#002299' 1309 config. BorderStyle = 'solid' // Any permitted CSS value, but I recommend 'solid', 'dotted' or 'dashed' 1310 config. BorderWidth = 1 1311 config. CenterMouse = false // false or true - center the tip horizontally below (or above) the mousepointer 1312 config. ClickClose = false // false or true - close tooltip if the user clicks somewhere 1313 config. CloseBtn = false // false or true - closebutton in titlebar 1314 config. CloseBtnColors = ['#990000', '#FFFFFF', '#DD3333', '#FFFFFF'] // [Background, text, hovered background, hovered text] - use empty strings '' to inherit title colors 1315 config. CloseBtnText = ' X ' // Close button text (may also be an image tag) 1316 config. CopyContent = true // When converting a HTML element to a tooltip, copy only the element's content, rather than converting the element by its own 1317 config. Delay = 200 // Time span in ms until tooltip shows up 1318 config. Duration = 0 // Time span in ms after which the tooltip disappears; 0 for infinite duration 1319 config. FadeIn = 0 // Fade-in duration in ms, e.g. 400; 0 for no animation 1320 config. FadeOut = 0 1321 config. FadeInterval = 30 // Duration of each fade step in ms (recommended: 30) - shorter is smoother but causes more CPU-load 1322 config. Fix = null // Fixated position - x- an y-oordinates in brackets, e.g. [210, 480], or null for no fixation 1323 config. FollowMouse = false // false or true - tooltip follows the mouse 1324 config. FontColor = '#000044' 1325 config. FontFace = 'Verdana,Geneva,sans-serif' 1326 config. FontSize = '8pt' // E.g. '9pt' or '12px' - unit is mandatory 1327 config. FontWeight = 'normal' // 'normal' or 'bold'; 1328 config. Left = false // false or true - tooltip on the left of the mouse 1329 config. OffsetX = 14 // Horizontal offset of left-top corner from mousepointer 1330 config. OffsetY = 8 // Vertical offset 1331 config. Opacity = 100 // Integer between 0 and 100 - opacity of tooltip in percent 1332 config. Padding = 3 // Spacing between border and content 1333 config. Shadow = false // false or true 1334 config. ShadowColor = '#C0C0C0' 1335 config. ShadowWidth = 5 1336 config. Sticky = false // Do NOT hide tooltip on mouseout? false or true 1337 config. TextAlign = 'left' // 'left', 'right' or 'justify' 1338 config. Title = '' // Default title text applied to all tips (no default title: empty string '') 1339 config. TitleAlign = 'left' // 'left' or 'right' - text alignment inside the title bar 1340 config. TitleBgColor = '' // If empty string '', BorderColor will be used 1341 config. TitleFontColor = '#ffffff' // Color of title text - if '', BgColor (of tooltip body) will be used 1342 config. TitleFontFace = '' // If '' use FontFace (boldified) 1343 config. TitleFontSize = '' // If '' use FontSize 1344 config. Width = 0 // Tooltip width; 0 for automatic adaption to tooltip content 1345 config. CssClass = '' 1346 config. TitleCssClass = '' 1347 1348 config. Balloon = false // true or false - set to true if you want this to be the default behaviour 1349 config. BalloonImgPath = "common_images/" // Path to images (border, corners, stem), in quotes. Path must be relative to your HTML file. 1350 // Sizes of balloon images 1351 config. BalloonEdgeSize = 5 // Integer - sidelength of quadratic corner images 1352 config. BalloonStemWidth = 15 // Integer 1353 config. BalloonStemHeight = 19 // Integer 1354 1355 //======= END OF TOOLTIP CONFIG, DO NOT CHANGE ANYTHING BELOW ==============// 1356 1357 1358 1359 1360 //====================== PUBLIC ============================================// 1361 function Tip() 1362 { 1363 tt_Tip(arguments, null); 1364 } 1365 function TagToTip() 1366 { 1367 if(TagsToTip) 1368 { 1369 var t2t = tt_GetElt(arguments[0]); 1370 if(t2t) 1371 tt_Tip(arguments, t2t); 1372 } 1373 } 1374 1375 //================== PUBLIC EXTENSION API ==================================// 1376 // Extension eventhandlers currently supported: 1377 // OnLoadConfig, OnCreateContentString, OnSubDivsCreated, OnShow, OnMoveBefore, 1378 // OnMoveAfter, OnHideInit, OnHide, OnKill 1379 1380 var tt_aElt = new Array(10), // Container DIV, outer title & body DIVs, inner title & body TDs, closebutton SPAN, shadow DIVs, and IFRAME to cover windowed elements in IE 1381 tt_aV = new Array(), // Caches and enumerates config data for currently active tooltip 1382 tt_sContent, // Inner tooltip text or HTML 1383 tt_scrlX = 0, tt_scrlY = 0, 1384 tt_musX, tt_musY, 1385 tt_over, 1386 tt_x, tt_y, tt_w, tt_h; // Position, width and height of currently displayed tooltip 1387 1388 function tt_Extension() 1389 { 1390 tt_ExtCmdEnum(); 1391 tt_aExt[tt_aExt.length] = this; 1392 return this; 1393 } 1394 function tt_SetTipPos(x, y) 1395 { 1396 var css = tt_aElt[0].style; 1397 1398 tt_x = x; 1399 tt_y = y; 1400 css.left = x + "px"; 1401 css.top = y + "px"; 1402 if(tt_ie56) 1403 { 1404 var ifrm = tt_aElt[tt_aElt.length - 1]; 1405 if(ifrm) 1406 { 1407 ifrm.style.left = css.left; 1408 ifrm.style.top = css.top; 1409 } 1410 } 1411 } 1412 function tt_Hide() 1413 { 1414 tt_Current = ''; 1415 if(tt_db && tt_iState) 1416 { 1417 if(tt_iState & 0x2) 1418 { 1419 tt_aElt[0].style.visibility = "hidden"; 1420 tt_ExtCallFncs(0, "Hide"); 1421 } 1422 tt_tShow.EndTimer(); 1423 tt_tHide.EndTimer(); 1424 tt_tDurt.EndTimer(); 1425 tt_tFade.EndTimer(); 1426 if(!tt_op && !tt_ie) 1427 { 1428 tt_tWaitMov.EndTimer(); 1429 tt_bWait = false; 1430 } 1431 if(tt_aV[CLICKCLOSE]) 1432 tt_RemEvtFnc(document, "mouseup", tt_HideInit); 1433 tt_AddRemOutFnc(false); 1434 tt_ExtCallFncs(0, "Kill"); 1435 // In case of a TagToTip tooltip, hide converted DOM node and 1436 // re-insert it into document 1437 if(tt_t2t && !tt_aV[COPYCONTENT]) 1438 { 1439 tt_t2t.style.display = "none"; 1440 tt_MovDomNode(tt_t2t, tt_aElt[6], tt_t2tDad); 1441 } 1442 tt_iState = 0; 1443 tt_over = null; 1444 tt_ResetMainDiv(); 1445 if(tt_aElt[tt_aElt.length - 1]) 1446 tt_aElt[tt_aElt.length - 1].style.display = "none"; 1447 } 1448 } 1449 function tt_GetElt(id) 1450 { 1451 return(document.getElementById ? document.getElementById(id) 1452 : document.all ? document.all[id] 1453 : null); 1454 } 1455 function tt_GetDivW(el) 1456 { 1457 return(el ? (el.offsetWidth || el.style.pixelWidth || 0) : 0); 1458 } 1459 function tt_GetDivH(el) 1460 {
1461 return(el ? (el.offsetHeight || el.style.pixelHeight || 0) : 0); 1462 } 1463 function tt_GetScrollX() 1464 { 1465 return(window.pageXOffset || (tt_db ? (tt_db.scrollLeft || 0) : 0)); 1466 } 1467 function tt_GetScrollY() 1468 { 1469 return(window.pageYOffset || (tt_db ? (tt_db.scrollTop || 0) : 0)); 1470 } 1471 function tt_GetClientW() 1472 { 1473 return(document.body && (typeof(document.body.clientWidth) != tt_u) ? document.body.clientWidth 1474 : (typeof(window.innerWidth) != tt_u) ? window.innerWidth 1475 : tt_db ? (tt_db.clientWidth || 0) 1476 : 0); 1477 } 1478 function tt_GetClientH() 1479 { 1480 // Exactly this order seems to yield correct values in all major browsers 1481 return(document.body && (typeof(document.body.clientHeight) != tt_u) ? document.body.clientHeight 1482 : (typeof(window.innerHeight) != tt_u) ? window.innerHeight 1483 : tt_db ? (tt_db.clientHeight || 0) 1484 : 0); 1485 } 1486 function tt_GetEvtX(e) 1487 { 1488 return (e ? ((typeof(e.pageX) != tt_u) ? e.pageX : (e.clientX + tt_scrlX)) : 0); 1489 } 1490 function tt_GetEvtY(e) 1491 { 1492 return (e ? ((typeof(e.pageY) != tt_u) ? e.pageY : (e.clientY + tt_scrlY)) : 0); 1493 } 1494 function tt_AddEvtFnc(el, sEvt, PFnc) 1495 { 1496 if(el) 1497 { 1498 if(el.addEventListener) 1499 el.addEventListener(sEvt, PFnc, false); 1500 else 1501 el.attachEvent("on" + sEvt, PFnc); 1502 } 1503 } 1504 function tt_RemEvtFnc(el, sEvt, PFnc) 1505 { 1506 if(el) 1507 { 1508 if(el.removeEventListener) 1509 el.removeEventListener(sEvt, PFnc, false); 1510 else 1511 el.detachEvent("on" + sEvt, PFnc); 1512 } 1513 } 1514 1515 //====================== PRIVATE ===========================================// 1516 var tt_aExt = new Array(), // Array of extension objects 1517 1518 tt_db, tt_op, tt_ie, tt_ie56, tt_bBoxOld, // Browser flags 1519 tt_body, 1520 tt_flagOpa, // Opacity support: 1=IE, 2=Khtml, 3=KHTML, 4=Moz, 5=W3C 1521 tt_maxPosX, tt_maxPosY, 1522 tt_iState = 0, // Tooltip active |= 1, shown |= 2, move with mouse |= 4 1523 tt_opa, // Currently applied opacity 1524 tt_bJmpVert, // Tip above mouse (or ABOVE tip below mouse) 1525 tt_t2t, tt_t2tDad, // Tag converted to tip, and its parent element in the document 1526 tt_elDeHref, // The tag from which Opera has removed the href attribute 1527 // Timer 1528 tt_tShow = new Number(0), tt_tHide = new Number(0), tt_tDurt = new Number(0), 1529 tt_tFade = new Number(0), tt_tWaitMov = new Number(0), 1530 tt_bWait = false, 1531 tt_u = "undefined"; 1532 1533 1534 function tt_Init() 1535 { 1536 tt_MkCmdEnum(); 1537 // Send old browsers instantly to hell 1538 if(!tt_Browser() || !tt_MkMainDiv()) 1539 return; 1540 tt_IsW3cBox(); 1541 tt_OpaSupport(); 1542 tt_AddEvtFnc(document, "mousemove", tt_Move); 1543 // In Debug mode we search for TagToTip() calls in order to notify 1544 // the user if they've forgotten to set the TagsToTip config flag 1545 if(TagsToTip || tt_Debug) 1546 tt_SetOnloadFnc(); 1547 tt_AddEvtFnc(window, "scroll", 1548 function() 1549 { 1550 tt_scrlX = tt_GetScrollX(); 1551 tt_scrlY = tt_GetScrollY(); 1552 if(tt_iState && !(tt_aV[STICKY] && (tt_iState & 2))) 1553 tt_HideInit(); 1554 } ); 1555 // Ensure the tip be hidden when the page unloads 1556 tt_AddEvtFnc(window, "beforeunload", tt_Hide); 1557 tt_Hide(); 1558 } 1559 // Creates command names by translating config variable names to upper case 1560 function tt_MkCmdEnum() 1561 { 1562 var n = 0; 1563 for(var i in config) 1564 eval("window." + i.toString().toUpperCase() + " = " + n++); 1565 tt_aV.length = n; 1566 } 1567 function tt_Browser() 1568 { 1569 var n, nv, n6, w3c; 1570 1571 n = navigator.userAgent.toLowerCase(), 1572 nv = navigator.appVersion; 1573 tt_op = (document.defaultView && typeof(eval("w" + "indow" + "." + "o" + "p" + "er" + "a")) != tt_u); 1574 tt_ie = n.indexOf("msie") != -1 && document.all && !tt_op; 1575 if(tt_ie) 1576 { 1577 var ieOld = (!document.compatMode || document.compatMode == "BackCompat"); 1578 tt_db = !ieOld ? document.documentElement : (document.body || null); 1579 if(tt_db) 1580 tt_ie56 = parseFloat(nv.substring(nv.indexOf("MSIE") + 5)) >= 5.5 1581 && typeof document.body.style.maxHeight == tt_u; 1582 } 1583 else 1584 { 1585 tt_db = document.documentElement || document.body || 1586 (document.getElementsByTagName ? document.getElementsByTagName("body")[0] 1587 : null); 1588 if(!tt_op) 1589 { 1590 n6 = document.defaultView && typeof document.defaultView.getComputedStyle != tt_u; 1591 w3c = !n6 && document.getElementById; 1592 } 1593 } 1594 tt_body = (document.getElementsByTagName ? document.getElementsByTagName("body")[0] 1595 : (document.body || null)); 1596 if(tt_ie || n6 || tt_op || w3c){ 1597 if(tt_body && tt_db) { 1598 if(document.attachEvent || document.addEventListener) 1599 return true; 1600 } else { 1601 //tt_Err("wz_tooltip.js must be included INSIDE the body section," 1602 // + " immediately after the opening <body> tag."); 1603 } 1604 } 1605 tt_db = null; 1606 return false; 1607 } 1608 function tt_MkMainDiv() 1609 { 1610 // Create the tooltip DIV 1611 if(tt_body.insertAdjacentHTML)
1612 tt_body.insertAdjacentHTML("afterBegin", tt_MkMainDivHtm()); 1613 else if(typeof tt_body.innerHTML != tt_u && document.createElement && tt_body.appendChild) 1614 tt_body.appendChild(tt_MkMainDivDom()); 1615 // FireFox Alzheimer bug 1616 if(window.tt_GetMainDivRefs && tt_GetMainDivRefs()) 1617 return true; 1618 tt_db = null; 1619 return false; 1620 } 1621 function tt_MkMainDivHtm() 1622 { 1623 return('<div id="WzTtDiV" class="tooltip-wrapper"></div>' + 1624 (tt_ie56 ? ('<iframe id="WzTtIfRm" src="javascript:false" scrolling="no" frameborder="0" style="filter:Alpha(opacity=0);position:absolute;top:0px;left:0px;display:none;"></iframe>') 1625 : '')); 1626 } 1627 function tt_MkMainDivDom() 1628 { 1629 var el = document.createElement("div"); 1630 if(el) 1631 el.id = "WzTtDiV"; 1632 return el; 1633 } 1634 function tt_GetMainDivRefs() 1635 { 1636 tt_aElt[0] = tt_GetElt("WzTtDiV"); 1637 if(tt_ie56 && tt_aElt[0]) 1638 { 1639 tt_aElt[tt_aElt.length - 1] = tt_GetElt("WzTtIfRm"); 1640 if(!tt_aElt[tt_aElt.length - 1]) 1641 tt_aElt[0] = null; 1642 } 1643 if(tt_aElt[0]) 1644 { 1645 var css = tt_aElt[0].style; 1646 1647 css.visibility = "hidden"; 1648 css.position = "absolute"; 1649 css.overflow = "hidden"; 1650 return true; 1651 } 1652 return false; 1653 } 1654 function tt_ResetMainDiv() 1655 { 1656 var w = (window.screen && screen.width) ? screen.width : 10000; 1657 1658 tt_SetTipPos(-w, 0); 1659 tt_aElt[0].innerHTML = ""; 1660 tt_aElt[0].style.width = (w - 1) + "px"; 1661 } 1662 function tt_IsW3cBox() 1663 { 1664 var css = tt_aElt[0].style; 1665 1666 css.padding = "10px"; 1667 css.width = "40px"; 1668 tt_bBoxOld = (tt_GetDivW(tt_aElt[0]) == 40); 1669 css.padding = "0px"; 1670 tt_ResetMainDiv(); 1671 } 1672 function tt_OpaSupport() 1673 { 1674 var css = tt_body.style; 1675 1676 tt_flagOpa = (typeof(css.filter) != tt_u) ? 1 1677 : (typeof(css.KhtmlOpacity) != tt_u) ? 2 1678 : (typeof(css.KHTMLOpacity) != tt_u) ? 3 1679 : (typeof(css.MozOpacity) != tt_u) ? 4 1680 : (typeof(css.opacity) != tt_u) ? 5 1681 : 0; 1682 } 1683 // Ported from http://dean.edwards.name/weblog/2006/06/again/ 1684 // (Dean Edwards et al.) 1685 function tt_SetOnloadFnc() 1686 { 1687 tt_AddEvtFnc(document, "DOMContentLoaded", tt_HideSrcTags); 1688 tt_AddEvtFnc(window, "load", tt_HideSrcTags); 1689 if(tt_body.attachEvent) 1690 tt_body.attachEvent("onreadystatechange", 1691 function() { 1692 if(tt_body.readyState == "complete") 1693 tt_HideSrcTags(); 1694 } ); 1695 if(/WebKit|KHTML/i.test(navigator.userAgent)) 1696 { 1697 var t = setInterval(function() { 1698 if(/loaded|complete/.test(document.readyState)) 1699 { 1700 clearInterval(t); 1701 tt_HideSrcTags(); 1702 } 1703 }, 10); 1704 } 1705 } 1706 function tt_HideSrcTags() 1707 { 1708 if(!window.tt_HideSrcTags || window.tt_HideSrcTags.done) 1709 return; 1710 window.tt_HideSrcTags.done = true; 1711 if(!tt_HideSrcTagsRecurs(tt_body)) 1712 tt_Err("To enable the capability to convert HTML elements to tooltips," 1713 + " you must set TagsToTip in the global tooltip configuration" 1714 + " to true."); 1715 } 1716 function tt_HideSrcTagsRecurs(dad) 1717 { 1718 var a, ovr, asT2t; 1719 1720 // Walk the DOM tree for tags that have an onmouseover attribute 1721 // containing a TagToTip('...') call. 1722 // (.childNodes first since .children is bugous in Safari) 1723 a = dad.childNodes || dad.children || null; 1724 for(var i = a ? a.length : 0; i;) 1725 {--i; 1726 if(!tt_HideSrcTagsRecurs(a[i])) 1727 return false; 1728 ovr = a[i].getAttribute ? a[i].getAttribute("onmouseover") 1729 : (typeof a[i].onmouseover == "function") ? a[i].onmouseover 1730 : null; 1731 if(ovr) 1732 { 1733 asT2t = ovr.toString().match(/TagToTip\s*\(\s*'[^'.]+'\s*[\),]/); 1734 if(asT2t && asT2t.length) 1735 { 1736 if(!tt_HideSrcTag(asT2t[0])) 1737 return false; 1738 } 1739 } 1740 } 1741 return true; 1742 } 1743 function tt_HideSrcTag(sT2t) 1744 { 1745 var id, el; 1746 1747 // The ID passed to the found TagToTip() call identifies an HTML element 1748 // to be converted to a tooltip, so hide that element 1749 id = sT2t.replace(/.+'([^'.]+)'.+/, "$1"); 1750 el = tt_GetElt(id); 1751 if(el) 1752 { 1753 if(tt_Debug && !TagsToTip) 1754 return false; 1755 else 1756 el.style.display = "none"; 1757 } 1758 else 1759 tt_Err("Invalid ID\n'" + id + "'\npassed to TagToTip()." 1760 + " There exists no HTML element with that ID."); 1761 return true; 1762 } 1763 function tt_Tip(arg, t2t) 1764 { 1765 if (arg[0] == tt_Current) { 1766 tt_HideInit(); 1767 } else { 1768 tt_Current = arg[0]; 1769 if(!tt_db) 1770 return; 1771 if(tt_iState) 1772 tt_Hide(); 1773 if(!tt_Enabled) 1774 return; 1775 tt_t2t = t2t; 1776 if(!tt_ReadCmds(arg)) 1777 return; 1778 tt_iState = 0x1 | 0x4; 1779 tt_AdaptConfig1(); 1780 tt_MkTipContent(arg); 1781 tt_MkTipSubDivs(); 1782 tt_FormatTip(); 1783 tt_bJmpVert = false; 1784 tt_maxPosX = tt_GetClientW() + tt_scrlX - tt_w - 1; 1785 tt_maxPosY = tt_GetClientH() + tt_scrlY - tt_h - 1; 1786 tt_AdaptConfig2(); 1787 // We must fake the first mousemove in order to ensure the tip 1788 // be immediately shown and positioned 1789 tt_Move(); 1790 tt_ShowInit(); 1791 } 1792 } 1793 function tt_ReadCmds(a) 1794 { 1795 var i; 1796 1797 // First load the global config values, to initialize also values 1798 // for which no command has been passed 1799 i = 0; 1800 for(var j in config) 1801 tt_aV[i++] = config[j]; 1802 // Then replace each cached config value for which a command has been 1803 // passed (ensure the # of command args plus value args be even) 1804 1805 if(!(a.length & 1)) 1806 { 1807 for(i = a.length - 1; i > 0; i -= 2) 1808 tt_aV[a[i - 1]] = a[i]; 1809 return true; 1810 } 1811 tt_Err("Incorrect call of Tip() or TagToTip().\n"
1812 + "Each command must be followed by a value."); 1813 return false; 1814 } 1815 function tt_AdaptConfig1() 1816 { 1817 tt_ExtCallFncs(0, "LoadConfig"); 1818 // Inherit unspecified title formattings from body 1819 if(!tt_aV[TITLEBGCOLOR].length) 1820 tt_aV[TITLEBGCOLOR] = tt_aV[BORDERCOLOR]; 1821 if(!tt_aV[TITLEFONTCOLOR].length) 1822 tt_aV[TITLEFONTCOLOR] = tt_aV[BGCOLOR]; 1823 if(!tt_aV[TITLEFONTFACE].length) 1824 tt_aV[TITLEFONTFACE] = tt_aV[FONTFACE]; 1825 if(!tt_aV[TITLEFONTSIZE].length) 1826 tt_aV[TITLEFONTSIZE] = tt_aV[FONTSIZE]; 1827 if(tt_aV[CLOSEBTN]) 1828 { 1829 // Use title colors for non-specified closebutton colors 1830 if(!tt_aV[CLOSEBTNCOLORS]) 1831 tt_aV[CLOSEBTNCOLORS] = new Array("", "", "", ""); 1832 for(var i = 4; i;) 1833 {--i; 1834 if(!tt_aV[CLOSEBTNCOLORS][i].length) 1835 tt_aV[CLOSEBTNCOLORS][i] = (i & 1) ? tt_aV[TITLEFONTCOLOR] : tt_aV[TITLEBGCOLOR]; 1836 } 1837 // Enforce titlebar be shown 1838 if(!tt_aV[TITLE].length) 1839 tt_aV[TITLE] = " "; 1840 } 1841 // Circumvents broken display of images and fade-in flicker in Geckos < 1.8 1842 if(tt_aV[OPACITY] == 100 && typeof tt_aElt[0].style.MozOpacity != tt_u && !Array.every) 1843 tt_aV[OPACITY] = 99; 1844 // Smartly shorten the delay for fade-in tooltips 1845 if(tt_aV[FADEIN] && tt_flagOpa && tt_aV[DELAY] > 100) 1846 tt_aV[DELAY] = Math.max(tt_aV[DELAY] - tt_aV[FADEIN], 100); 1847 } 1848 function tt_AdaptConfig2() 1849 { 1850 if(tt_aV[CENTERMOUSE]) 1851 tt_aV[OFFSETX] -= ((tt_w - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0)) >> 1); 1852 } 1853 // Expose content globally so extensions can modify it 1854 function tt_MkTipContent(a) 1855 { 1856 if(tt_t2t) 1857 { 1858 if(tt_aV[COPYCONTENT]) 1859 tt_sContent = tt_t2t.innerHTML; 1860 else 1861 tt_sContent = ""; 1862 } 1863 else 1864 tt_sContent = a[1]; 1865 tt_ExtCallFncs(0, "CreateContentString"); 1866 } 1867 function tt_MkTipSubDivs() 1868 { 1869 var sCss = 'position: relative; margin: 0px; padding: 0px; border-width: 0px; left: 0px; top: 0px; line-height: normal; width: auto;', 1870 sTbTrTd = ' cellspacing=0 cellpadding=0 border=0 style="' + sCss + '"><tbody style="' + sCss + '"><tr><td '; 1871 1872 tt_aElt[0].innerHTML = 1873 ('' 1874 + (tt_aV[TITLE].length ? 1875 ('<div id="WzTiTl" style="position:relative;z-index:1;">' 1876 + '<table id="WzTiTlTb"' + sTbTrTd + 'id="WzTiTlI" style="' + sCss + '">' 1877 + tt_aV[TITLE] 1878 + '</td>' 1879 + (tt_aV[CLOSEBTN] ? 1880 ('<td align="right" style="' + sCss 1881 + 'text-align:right;">' 1882 + '<span id="WzClOsE" style="padding-left:2px;padding-right:2px;' 1883 + 'cursor:' + (tt_ie ? 'hand' : 'pointer') 1884 + ';" onmouseover="tt_OnCloseBtnOver(1)" onmouseout="tt_OnCloseBtnOver(0)" onclick="tt_HideInit()">' 1885 + tt_aV[CLOSEBTNTEXT] 1886 + '</span></td>') 1887 : '') 1888 + '</tr></tbody></table></div>') 1889 : '') 1890 + '<div id="WzBoDy" style="position:relative;z-index:0;">' 1891 + '<table' + sTbTrTd + 'id="WzBoDyI" style="' + sCss + '">' 1892 + tt_sContent 1893 + '</td></tr></tbody></table></div>' 1894 + (tt_aV[SHADOW] 1895 ? ('<div id="WzTtShDwR" style="position:absolute;overflow:hidden;"></div>' 1896 + '<div id="WzTtShDwB" style="position:relative;overflow:hidden;"></div>') 1897 : '') 1898 ); 1899 tt_GetSubDivRefs(); 1900 // Convert DOM node to tip 1901 if(tt_t2t && !tt_aV[COPYCONTENT]) 1902 { 1903 // Store the tag's parent element so we can restore that DOM branch 1904 // once the tooltip is hidden 1905 tt_t2tDad = tt_t2t.parentNode || tt_t2t.parentElement || tt_t2t.offsetParent || null; 1906 if(tt_t2tDad) 1907 { 1908 tt_MovDomNode(tt_t2t, tt_t2tDad, tt_aElt[6]); 1909 tt_t2t.style.display = "block"; 1910 } 1911 } 1912 tt_ExtCallFncs(0, "SubDivsCreated"); 1913 } 1914 function tt_GetSubDivRefs() 1915 { 1916 var aId = new Array("WzTiTl", "WzTiTlTb", "WzTiTlI", "WzClOsE", "WzBoDy", "WzBoDyI", "WzTtShDwB", "WzTtShDwR"); 1917 1918 for(var i = aId.length; i; --i) 1919 tt_aElt[i] = tt_GetElt(aId[i - 1]); 1920 } 1921 function tt_FormatTip() 1922 { 1923 var css, w, iOffY, iOffSh; 1924 1925 //--------- Title DIV ---------- 1926 if(tt_aV[TITLE].length) 1927 { 1928 css = tt_aElt[1].style; 1929 1930 if (tt_aV[TITLECSSCLASS]) { 1931 tt_aElt[1].className = tt_aV[TITLECSSCLASS] 1932 } else { 1933 css.background = tt_aV[TITLEBGCOLOR]; 1934 css.paddingTop = (tt_aV[CLOSEBTN] ? 2 : 0) + "px"; 1935 css.paddingBottom = "1px"; 1936 css.paddingLeft = css.paddingRight = tt_aV[PADDING] + "px"; 1937 css = tt_aElt[3].style; 1938 css.color = tt_aV[TITLEFONTCOLOR]; 1939 css.fontFamily = tt_aV[TITLEFONTFACE]; 1940 css.fontSize = tt_aV[TITLEFONTSIZE]; 1941 css.fontWeight = "bold"; 1942 css.textAlign = tt_aV[TITLEALIGN]; 1943 } 1944 // Close button DIV 1945 if(tt_aElt[4]) 1946 { 1947 css.paddingRight = (tt_aV[PADDING] << 1) + "px"; 1948 css = tt_aElt[4].style; 1949 css.background = tt_aV[CLOSEBTNCOLORS][0]; 1950 css.color = tt_aV[CLOSEBTNCOLORS][1]; 1951 css.fontFamily = tt_aV[TITLEFONTFACE]; 1952 css.fontSize = tt_aV[TITLEFONTSIZE]; 1953 css.fontWeight = "bold"; 1954 } 1955 if(tt_aV[WIDTH] > 0) 1956 tt_w = tt_aV[WIDTH] + ((tt_aV[PADDING] + tt_aV[BORDERWIDTH]) << 1); 1957 else 1958 { 1959 tt_w = tt_GetDivW(tt_aElt[3]) + tt_GetDivW(tt_aElt[4]); 1960 // Some spacing between title DIV and closebutton 1961 if(tt_aElt[4]) 1962 tt_w += tt_aV[PADDING]; 1963 } 1964 // Ensure the top border of the body DIV be covered by the title DIV 1965 iOffY = -tt_aV[BORDERWIDTH]; 1966 } 1967 else 1968 { 1969 tt_w = 0; 1970 iOffY = 0; 1971 } 1972 1973 //-------- Body DIV ------------ 1974 css = tt_aElt[5].style; 1975 css.top = "0px"; 1976 if(tt_aV[CSSCLASS]) { 1977 tt_aElt[5].className = tt_aV[CSSCLASS] 1978 } else { 1979 if(tt_aV[BORDERWIDTH]) 1980 { 1981 css.borderColor = tt_aV[BORDERCOLOR]; 1982 css.borderStyle = tt_aV[BORDERSTYLE]; 1983 css.borderWidth = tt_aV[BORDERWIDTH] + "px"; 1984 } 1985 if(tt_aV[BGCOLOR].length) 1986 css.background = tt_aV[BGCOLOR]; 1987 if(tt_aV[BGIMG].length) 1988 css.backgroundImage = "url(" + tt_aV[BGIMG] + ")"; 1989 css.padding = tt_aV[PADDING] + "px"; 1990 css.textAlign = tt_aV[TEXTALIGN]; 1991 // TD inside body DIV 1992 css = tt_aElt[6].style; 1993 css.color = tt_aV[FONTCOLOR]; 1994 css.fontFamily = tt_aV[FONTFACE]; 1995 css.fontSize = tt_aV[FONTSIZE]; 1996 css.fontWeight = tt_aV[FONTWEIGHT]; 1997 css.background = ""; 1998 css.textAlign = tt_aV[TEXTALIGN]; 1999 } 2000 2001 if(tt_aV[WIDTH] > 0) 2002 w = tt_aV[WIDTH] + ((tt_aV[PADDING] + tt_aV[BORDERWIDTH]) << 1); 2003 else 2004 // We measure the width of the body's inner TD, because some browsers 2005 // expand the width of the container and outer body DIV to 100% 2006 w = tt_GetDivW(tt_aElt[6]) + ((tt_aV[PADDING] + tt_aV[BORDERWIDTH]) << 1); 2007 if(w > tt_w) 2008 tt_w = w; 2009 2010 //--------- Shadow DIVs ------------ 2011 if(tt_aV[SHADOW]) 2012 { 2013 tt_w += tt_aV[SHADOWWIDTH]; 2014 iOffSh = Math.floor((tt_aV[SHADOWWIDTH] * 4) / 3); 2015 // Bottom shadow 2016 css = tt_aElt[7].style; 2017 css.top = iOffY + "px"; 2018 css.left = iOffSh + "px"; 2019 css.width = (tt_w - iOffSh - tt_aV[SHADOWWIDTH]) + "px"; 2020 css.height = tt_aV[SHADOWWIDTH] + "px"; 2021 css.background = tt_aV[SHADOWCOLOR]; 2022 // Right shadow 2023 css = tt_aElt[8].style; 2024 css.top = iOffSh + "px"; 2025 css.left = (tt_w - tt_aV[SHADOWWIDTH]) + "px"; 2026 css.width = tt_aV[SHADOWWIDTH] + "px"; 2027 css.background = tt_aV[SHADOWCOLOR]; 2028 } 2029 else 2030 iOffSh = 0; 2031 2032 //-------- Container DIV ------- 2033 tt_SetTipOpa(tt_aV[FADEIN] ? 0 : tt_aV[OPACITY]); 2034 tt_FixSize(iOffY, iOffSh); 2035 } 2036 // Fixate the size so it can't dynamically change while the tooltip is moving. 2037 function tt_FixSize(iOffY, iOffSh) 2038 { 2039 var wIn, wOut, i; 2040 2041 tt_aElt[0].style.width = tt_w + "px"; 2042 tt_aElt[0].style.pixelWidth = tt_w; 2043 wOut = tt_w - ((tt_aV[SHADOW]) ? tt_aV[SHADOWWIDTH] : 0); 2044 // Body 2045 wIn = wOut; 2046 if(!tt_bBoxOld) 2047 wIn = wOut - (tt_aV[PADDING] << 1); 2048 // Title 2049 if(tt_aElt[1]) 2050 { 2051 wIn = wOut - (tt_aV[PADDING] << 1); 2052 if(!tt_bBoxOld) 2053 wOut = wIn; 2054 } 2055 tt_h = tt_GetDivH(tt_aElt[0]) + iOffY; 2056 // Right shadow 2057 if(tt_aElt[8]) 2058 i = tt_aElt.length - 1; 2059 if(tt_aElt[i]) 2060 { 2061 tt_aElt[i].style.width = tt_w + "px"; 2062 tt_aElt[i].style.height = tt_h + "px"; 2063 } 2064 } 2065 function tt_DeAlt(el) 2066 { 2067 var aKid; 2068 2069 if(el.alt) 2070 el.alt = ""; 2071 if(el.title) 2072 el.title = ""; 2073 aKid = el.childNodes || el.children || null; 2074 if(aKid) 2075 { 2076 for(var i = aKid.length; i;) 2077 tt_DeAlt(aKid[--i]); 2078 } 2079 } 2080 // This hack removes the annoying native tooltips over links in Opera 2081 function tt_OpDeHref(el) 2082 { 2083 if(!tt_op) 2084 return; 2085 if(tt_elDeHref) 2086 tt_OpReHref(); 2087 while(el) 2088 { 2089 if(el.hasAttribute("href")) 2090 { 2091 el.t_href = el.getAttribute("href"); 2092 el.t_stats = window.status; 2093 el.removeAttribute("href"); 2094 el.style.cursor = "hand"; 2095 tt_AddEvtFnc(el, "mousedown", tt_OpReHref); 2096 window.status = el.t_href; 2097 tt_elDeHref = el; 2098 break; 2099 } 2100 el = el.parentElement; 2101 } 2102 } 2103 function tt_ShowInit() 2104 { 2105 tt_tShow.Timer("tt_Show()", tt_aV[DELAY], true); 2106 if(tt_aV[CLICKCLOSE]) 2107 tt_AddEvtFnc(document, "mouseup", tt_HideInit); 2108 } 2109 function tt_OverInit(e) 2110 { 2111 tt_over = e.target || e.srcElement; 2112 tt_DeAlt(tt_over); 2113 tt_OpDeHref(tt_over); 2114 tt_AddRemOutFnc(true); 2115 } 2116 function tt_Show() 2117 { 2118 var css = tt_aElt[0].style; 2119 2120 // Override the z-index of the topmost wz_dragdrop.js D&D item 2121 css.zIndex = Math.max((window.dd && dd.z) ? (dd.z + 2) : 0, 1010); 2122 if(tt_aV[STICKY] || !tt_aV[FOLLOWMOUSE]) 2123 tt_iState &= ~0x4; 2124 if(tt_aV[DURATION] > 0) 2125 tt_tDurt.Timer("tt_HideInit()", tt_aV[DURATION], true); 2126 tt_ExtCallFncs(0, "Show") 2127 css.visibility = "visible"; 2128 tt_iState |= 0x2; 2129 if(tt_aV[FADEIN]) 2130 tt_Fade(0, 0, tt_aV[OPACITY], Math.round(tt_aV[FADEIN] / tt_aV[FADEINTERVAL])); 2131 tt_ShowIfrm(); 2132 } 2133 function tt_ShowIfrm() 2134 { 2135 if(tt_ie56) 2136 { 2137 var ifrm = tt_aElt[tt_aElt.length - 1]; 2138 if(ifrm) 2139 { 2140 var css = ifrm.style; 2141 css.zIndex = tt_aElt[0].style.zIndex - 1; 2142 css.display = "block"; 2143 } 2144 } 2145 } 2146 function tt_Move(e) 2147 { 2148 e = window.event || e; 2149 if(e) 2150 { 2151 tt_musX = tt_GetEvtX(e); 2152 tt_musY = tt_GetEvtY(e); 2153 } 2154 if(tt_iState) 2155 { 2156 if(!tt_over && e) 2157 tt_OverInit(e); 2158 if(tt_iState & 0x4) 2159 { 2160 // Protect some browsers against jam of mousemove events 2161 if(!tt_op && !tt_ie) 2162 { 2163 if(tt_bWait) 2164 return; 2165 tt_bWait = true; 2166 tt_tWaitMov.Timer("tt_bWait = false;", 1, true); 2167 } 2168 if(tt_aV[FIX]) 2169 { 2170 tt_iState &= ~0x4; 2171 tt_SetTipPos(tt_aV[FIX][0], tt_aV[FIX][1]); 2172 } 2173 else if(!tt_ExtCallFncs(e, "MoveBefore")) 2174 tt_SetTipPos(tt_PosX(), tt_PosY()); 2175 tt_ExtCallFncs([tt_musX, tt_musY], "MoveAfter") 2176 } 2177 } 2178 } 2179 function tt_PosX() 2180 { 2181 var x; 2182 2183 x = tt_musX; 2184 if(tt_aV[LEFT]) 2185 x -= tt_w + tt_aV[OFFSETX] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0); 2186 else 2187 x += tt_aV[OFFSETX]; 2188 // Prevent tip from extending past right/left clientarea boundary 2189 if(x > tt_maxPosX) 2190 x = tt_maxPosX; 2191 return((x < tt_scrlX) ? tt_scrlX : x); 2192 } 2193 function tt_PosY() 2194 { 2195 var y; 2196 2197 // Apply some hysteresis after the tip has snapped to the other side of the 2198 // mouse. In case of insufficient space above and below the mouse, we place 2199 // the tip below. 2200 if(tt_aV[ABOVE] && (!tt_bJmpVert || tt_CalcPosYAbove() >= tt_scrlY + 16)) 2201 y = tt_DoPosYAbove(); 2202 else if(!tt_aV[ABOVE] && tt_bJmpVert && tt_CalcPosYBelow() > tt_maxPosY - 16) 2203 y = tt_DoPosYAbove(); 2204 else 2205 y = tt_DoPosYBelow(); 2206 // Snap to other side of mouse if tip would extend past window boundary 2207 if(y > tt_maxPosY) 2208 y = tt_DoPosYAbove(); 2209 if(y < tt_scrlY) 2210 y = tt_DoPosYBelow(); 2211 return y; 2212 } 2213 function tt_DoPosYBelow() 2214 { 2215 tt_bJmpVert = tt_aV[ABOVE]; 2216 return tt_CalcPosYBelow(); 2217 } 2218 function tt_DoPosYAbove() 2219 { 2220 tt_bJmpVert = !tt_aV[ABOVE]; 2221 return tt_CalcPosYAbove(); 2222 } 2223 function tt_CalcPosYBelow() 2224 { 2225 return(tt_musY + tt_aV[OFFSETY]); 2226 } 2227 function tt_CalcPosYAbove() 2228 { 2229 var dy = tt_aV[OFFSETY] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0); 2230 if(tt_aV[OFFSETY] > 0 && dy <= 0) 2231 dy = 1; 2232 return(tt_musY - tt_h - dy);
2233 } 2234 function tt_OnOut() 2235 { 2236 tt_AddRemOutFnc(false); 2237 if(!(tt_aV[STICKY] && (tt_iState & 0x2))) 2238 tt_HideInit(); 2239 } 2240 function tt_HideInit() 2241 { 2242 tt_ExtCallFncs(0, "HideInit"); 2243 tt_iState &= ~0x4; 2244 if(tt_flagOpa && tt_aV[FADEOUT]) 2245 { 2246 tt_tFade.EndTimer(); 2247 if(tt_opa) 2248 { 2249 var n = Math.round(tt_aV[FADEOUT] / (tt_aV[FADEINTERVAL] * (tt_aV[OPACITY] / tt_opa))); 2250 tt_Fade(tt_opa, tt_opa, 0, n); 2251 return; 2252 } 2253 } 2254 tt_tHide.Timer("tt_Hide();", 1, false); 2255 } 2256 function tt_OpReHref() 2257 { 2258 if(tt_elDeHref) 2259 { 2260 tt_elDeHref.setAttribute("href", tt_elDeHref.t_href); 2261 tt_RemEvtFnc(tt_elDeHref, "mousedown", tt_OpReHref); 2262 window.status = tt_elDeHref.t_stats; 2263 tt_elDeHref = null; 2264 } 2265 } 2266 function tt_Fade(a, now, z, n) 2267 { 2268 if(n) 2269 { 2270 now += Math.round((z - now) / n); 2271 if((z > a) ? (now >= z) : (now <= z)) 2272 now = z; 2273 else 2274 tt_tFade.Timer("tt_Fade(" 2275 + a + "," + now + "," + z + "," + (n - 1) 2276 + ")", 2277 tt_aV[FADEINTERVAL], 2278 true); 2279 } 2280 now ? tt_SetTipOpa(now) : tt_Hide(); 2281 } 2282 // To circumvent the opacity nesting flaws of IE, we set the opacity 2283 // for each sub-DIV separately, rather than for the container DIV. 2284 function tt_SetTipOpa(opa) 2285 { 2286 tt_SetOpa(tt_aElt[5].style, opa); 2287 if(tt_aElt[1]) 2288 tt_SetOpa(tt_aElt[1].style, opa); 2289 if(tt_aV[SHADOW]) 2290 { 2291 opa = Math.round(opa * 0.8); 2292 tt_SetOpa(tt_aElt[7].style, opa); 2293 tt_SetOpa(tt_aElt[8].style, opa); 2294 } 2295 } 2296 function tt_OnCloseBtnOver(iOver) 2297 { 2298 var css = tt_aElt[4].style; 2299 2300 iOver <<= 1; 2301 css.background = tt_aV[CLOSEBTNCOLORS][iOver]; 2302 css.color = tt_aV[CLOSEBTNCOLORS][iOver + 1]; 2303 } 2304 function tt_Int(x) 2305 { 2306 var y; 2307 2308 return(isNaN(y = parseInt(x)) ? 0 : y); 2309 } 2310 // Adds or removes the document.mousemove or HoveredElem.mouseout handler 2311 // conveniently. Keeps track of those handlers to prevent them from being 2312 // set or removed redundantly. 2313 function tt_AddRemOutFnc(bAdd) 2314 { 2315 var PSet = bAdd ? tt_AddEvtFnc : tt_RemEvtFnc; 2316 2317 if(bAdd != tt_AddRemOutFnc.bOn) 2318 { 2319 PSet(tt_over, "mouseout", tt_OnOut); 2320 tt_AddRemOutFnc.bOn = bAdd; 2321 if(!bAdd) 2322 tt_OpReHref(); 2323 } 2324 } 2325 tt_AddRemOutFnc.bOn = false; 2326 Number.prototype.Timer = function(s, iT, bUrge) 2327 { 2328 if(!this.value || bUrge) 2329 this.value = window.setTimeout(s, iT); 2330 } 2331 Number.prototype.EndTimer = function() 2332 { 2333 if(this.value) 2334 { 2335 window.clearTimeout(this.value); 2336 this.value = 0; 2337 } 2338 } 2339 function tt_SetOpa(css, opa) 2340 { 2341 tt_opa = opa; 2342 if(tt_flagOpa == 1) 2343 { 2344 // Hack for bugs of IE: 2345 // A DIV cannot be made visible in a single step if an opacity < 100 2346 // has been applied while the DIV was hidden. 2347 // Moreover, in IE6, applying an opacity < 100 has no effect if the 2348 // concerned element has no layout (position, size, zoom, ...). 2349 if(opa < 100) 2350 { 2351 var bVis = css.visibility != "hidden"; 2352 css.zoom = "100%"; 2353 if(!bVis) 2354 css.visibility = "visible"; 2355 css.filter = "alpha(opacity=" + opa + ")"; 2356 if(!bVis) 2357 css.visibility = "hidden"; 2358 } 2359 else 2360 css.filter = ""; 2361 } 2362 else 2363 { 2364 opa /= 100.0; 2365 switch(tt_flagOpa) 2366 { 2367 case 2: 2368 css.KhtmlOpacity = opa; break; 2369 case 3: 2370 css.KHTMLOpacity = opa; break; 2371 case 4: 2372 css.MozOpacity = opa; break; 2373 case 5: 2374 css.opacity = opa; break; 2375 } 2376 } 2377 } 2378 function tt_MovDomNode(el, dadFrom, dadTo) 2379 { 2380 if(dadFrom) 2381 dadFrom.removeChild(el); 2382 if(dadTo) 2383 dadTo.appendChild(el); 2384 } 2385 function tt_Err(sErr) 2386 { 2387 if(tt_Debug) 2388 alert("Tooltip Script Error Message:\n\n" + sErr); 2389 } 2390 2391 //=========== DEALING WITH EXTENSIONS ==============// 2392 function tt_ExtCmdEnum() 2393 { 2394 var s; 2395 2396 // Add new command(s) to the commands enum 2397 for(var i in config) 2398 { 2399 s = "window." + i.toString().toUpperCase(); 2400 if(eval("typeof(" + s + ") == tt_u")) 2401 { 2402 eval(s + " = " + tt_aV.length); 2403 tt_aV[tt_aV.length] = null; 2404 } 2405 } 2406 } 2407 function tt_ExtCallFncs(arg, sFnc) 2408 { 2409 var b = false; 2410 for(var i = tt_aExt.length; i;) 2411 {--i; 2412 var fnc = tt_aExt[i]["On" + sFnc]; 2413 // Call the method the extension has defined for this event 2414 if(fnc && fnc(arg)) 2415 b = true; 2416 } 2417 return b; 2418 } 2419 2420 tt_Init(); 2421 2422 2423 2424 2425 2426 2427/* End: js/form builder/help_tip.js*/ 2428 2429 2430 2431;/* Start: js/vendor/ElementQueries.js*/ 2432 2433'use strict'; 2434 2435/** 2436 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level 2437 * directory of this distribution and at 2438 * https://github.com/marcj/css-element-queries/blob/master/LICENSE. 2439 */ 2440(function (root, factory) { 2441 if (typeof define === "function" && define.amd) { 2442 define(['./ResizeSensor.js'], factory); 2443 } else if (typeof exports === "object") { 2444 module.exports = factory(require('./ResizeSensor.js')); 2445 } else { 2446 root.ElementQueries = factory(root.ResizeSensor); 2447 root.ElementQueries.listen(); 2448 } 2449}(typeof window !== 'undefined' ? window : this, function (ResizeSensor) { 2450 2451 /** 2452 * 2453 * @type {Function} 2454 * @constructor 2455 */ 2456 var ElementQueries = function () { 2457 //<style> element with our dynamically created styles 2458 var cssStyleElement; 2459 2460 //all rules found for element queries 2461 var allQueries = {}; 2462 2463 //association map to identify which selector belongs to a element from the animationstart event. 2464 var idToSelectorMapping = []; 2465 2466 /** 2467 * 2468 * @param element 2469 * @returns {Number} 2470 */ 2471 function getEmSize(element) { 2472 if (!element) { 2473 element = document.documentElement; 2474 } 2475 var fontSize = window.getComputedStyle(element, null).fontSize; 2476 return parseFloat(fontSize) || 16; 2477 } 2478 2479 /** 2480 * Get element size 2481 * @param {HTMLElement} element 2482 * @returns {Object} {width, height} 2483 */ 2484 function getElementSize(element) { 2485 if (!element.getBoundingClientRect) { 2486 return { 2487 width: element.offsetWidth, 2488 height: element.offsetHeight 2489 } 2490 } 2491 2492 var rect = element.getBoundingClientRect(); 2493 return { 2494 width: Math.round(rect.width), 2495 height: Math.round(rect.height) 2496 } 2497 } 2498 2499 /** 2500 * 2501 * @copyright https://github.com/Mr0grog/element-query/blob/master/LICENSE 2502 * 2503 * @param {HTMLElement} element 2504 * @param {*} value 2505 * @returns {*} 2506 */ 2507 function convertToPx(element, value) { 2508 var numbers = value.split(/\d/); 2509 var units = numbers[numbers.length - 1]; 2510 value = parseFloat(value); 2511 switch (units) { 2512 case "px": 2513 return value; 2514 case "em": 2515 return value * getEmSize(element); 2516 case "rem": 2517 return value * getEmSize(); 2518 // Viewport units! 2519 // According to http://quirksmode.org/mobile/tableViewport.html 2520 // documentElement.clientWidth/Height gets us the most reliable info 2521 case "vw": 2522 return value * document.documentElement.clientWidth / 100; 2523 case "vh": 2524 return value * document.documentElement.clientHeight / 100; 2525 case "vmin": 2526 case "vmax": 2527 var vw = document.documentElement.clientWidth / 100; 2528 var vh = document.documentElement.clientHeight / 100; 2529 var chooser = Math[units === "vmin" ? "min" : "max"]; 2530 return value * chooser(vw, vh); 2531 default: 2532 return value; 2533 // for now, not supporting physical units (since they are just a set number of px) 2534 // or ex/ch (getting accurate measurements is hard) 2535 } 2536 } 2537 2538 /** 2539 * 2540 * @param {HTMLElement} element 2541 * @param {String} id 2542 * @constructor 2543 */ 2544 function SetupInformation(element, id) { 2545 this.element = element; 2546 var key, option, elementSize, value, actualValue, attrValues, attrValue, attrName; 2547 2548 var attributes = ['min-width', 'min-height', 'max-width', 'max-height']; 2549 2550 /** 2551 * Extracts the computed width/height and sets to min/max- attribute. 2552 */ 2553 this.call = function () { 2554 // extract current dimensions 2555 elementSize = getElementSize(this.element); 2556 2557 attrValues = {}; 2558 2559 for (key in allQueries[id]) { 2560 if (!allQueries[id].hasOwnProperty(key)) { 2561 continue; 2562 } 2563 option = allQueries[id][key]; 2564 2565 value = convertToPx(this.element, option.value); 2566 2567 actualValue = option.property === 'width' ? elementSize.width : elementSize.height; 2568 attrName = option.mode + '-' + option.property; 2569 attrValue = ''; 2570 2571 if (option.mode === 'min' && actualValue >= value) { 2572 attrValue += option.value; 2573 } 2574 2575 if (option.mode === 'max' && actualValue <= value) { 2576 attrValue += option.value; 2577 } 2578 2579 if (!attrValues[attrName]) attrValues[attrName] = ''; 2580 if (attrValue && -1 === (' ' + attrValues[attrName] + ' ').indexOf(' ' + attrValue + ' ')) { 2581 attrValues[attrName] += ' ' + attrValue; 2582 } 2583 } 2584 2585 for (var k in attributes) { 2586 if (!attributes.hasOwnProperty(k)) continue; 2587 2588 if (attrValues[attributes[k]]) { 2589 this.element.setAttribute(attributes[k], attrValues[attributes[k]].substr(1)); 2590 } else { 2591 this.element.removeAttribute(attributes[k]); 2592 } 2593 } 2594 }; 2595 } 2596 2597 /** 2598 * @param {HTMLElement} element 2599 * @param {Object} id 2600 */ 2601 function setupElement(element, id) { 2602 if (!element.elementQueriesSetupInformation) { 2603 element.elementQueriesSetupInformation = new SetupInformation(element, id); 2604 } 2605 2606 if (!element.elementQueriesSensor) { 2607 element.elementQueriesSensor = new ResizeSensor(element, function () { 2608 element.elementQueriesSetupInformation.call(); 2609 }); 2610 } 2611 } 2612 2613 /** 2614 * Stores rules to the selector that should be applied once resized. 2615 * 2616 * @param {String} selector 2617 * @param {String} mode min|max 2618 * @param {String} property width|height 2619 * @param {String} value 2620 */ 2621 function queueQuery(selector, mode, property, value) { 2622 if (typeof (allQueries[selector]) === 'undefined') { 2623 allQueries[selector] = []; 2624 // add animation to trigger animationstart event, so we know exactly when a element appears in the DOM 2625 2626 var id = idToSelectorMapping.length; 2627 cssStyleElement.innerHTML += '\n' + selector + ' {animation: 0.1s element-queries;}'; 2628 cssStyleElement.innerHTML += '\n' + selector + ' > .resize-sensor {min-width: ' + id + 'px;}'; 2629 idToSelectorMapping.push(selector); 2630 } 2631 2632 allQueries[selector].push({ 2633 mode: mode, 2634 property: property, 2635 value: value 2636 }); 2637 } 2638 2639 function getQuery(container) { 2640 var query; 2641 if (document.querySelectorAll) query = (container) ? container.querySelectorAll.bind(container) : document.querySelectorAll.bind(document); 2642 if (!query && 'undefined' !== typeof $$) query = $$; 2643 if (!query && 'undefined' !== typeof jQuery) query = jQuery; 2644 2645 if (!query) { 2646 throw 'No document.querySelectorAll, jQuery or Mootools\'s $$ found.'; 2647 } 2648 2649 return query; 2650 } 2651 2652 /** 2653 * If animationStart didn't catch a new element in the DOM, we can manually search for it 2654 */ 2655 function findElementQueriesElements(container) { 2656 var query = getQuery(container); 2657 2658 for (var selector in allQueries) if (allQueries.hasOwnProperty(selector)) { 2659 // find all elements based on the extract query selector from the element query rule 2660 var elements = query(selector, container); 2661 2662 for (var i = 0, j = elements.length; i < j; i++) { 2663 setupElement(elements[i], selector); 2664 } 2665 } 2666 } 2667 2668 /** 2669 * 2670 * @param {HTMLElement} element 2671 */ 2672 function attachResponsiveImage(element) { 2673 var children = []; 2674 var rules = []; 2675 var sources = []; 2676 var defaultImageId = 0; 2677 var lastActiveImage = -1; 2678 var loadedImages = []; 2679 2680 for (var i in element.children) { 2681 if (!element.children.hasOwnProperty(i)) continue; 2682 2683 if (element.children[i].tagName && element.children[i].tagName.toLowerCase() === 'img') { 2684 children.push(element.children[i]); 2685 2686 var minWidth = element.children[i].getAttribute('min-width') || element.children[i].getAttribute('data-min-width'); 2687 //var minHeight = element.children[i].getAttribute('min-height') || element.children[i].getAttribute('data-min-height'); 2688 var src = element.children[i].getAttribute('data-src') || element.children[i].getAttribute('url'); 2689 2690 sources.push(src); 2691 2692 var rule = { 2693 minWidth: minWidth 2694 }; 2695 2696 rules.push(rule); 2697 2698 if (!minWidth) { 2699 defaultImageId = children.length - 1; 2700 element.children[i].style.display = 'block'; 2701 } else { 2702 element.children[i].style.display = 'none'; 2703 } 2704 } 2705 } 2706 2707 lastActiveImage = defaultImageId; 2708 2709 function check() { 2710 var imageToDisplay = false, i; 2711 2712 for (i in children) { 2713 if (!children.hasOwnProperty(i)) continue; 2714 2715 if (rules[i].minWidth) { 2716 if (element.offsetWidth > rules[i].minWidth) { 2717 imageToDisplay = i; 2718 } 2719 } 2720 } 2721 2722 if (!imageToDisplay) { 2723 //no rule matched, show default 2724 imageToDisplay = defaultImageId; 2725 } 2726 2727 if (lastActiveImage !== imageToDisplay) { 2728 //image change 2729 2730 if (!loadedImages[imageToDisplay]) { 2731 //image has not been loaded yet, we need to load the image first in memory to prevent flash of 2732 //no content 2733 2734 var image = new Image(); 2735 image.onload = function () { 2736 children[imageToDisplay].src = sources[imageToDisplay]; 2737 2738 children[lastActiveImage].style.display = 'none'; 2739 children[imageToDisplay].style.display = 'block'; 2740 2741 loadedImages[imageToDisplay] = true; 2742 2743 lastActiveImage = imageToDisplay; 2744 }; 2745 2746 image.src = sources[imageToDisplay]; 2747 } else { 2748 children[lastActiveImage].style.
2748display = 'none'; 2749 children[imageToDisplay].style.display = 'block'; 2750 lastActiveImage = imageToDisplay; 2751 } 2752 } else { 2753 //make sure for initial check call the .src is set correctly 2754 children[imageToDisplay].src = sources[imageToDisplay]; 2755 } 2756 } 2757 2758 element.resizeSensorInstance = new ResizeSensor(element, check); 2759 check(); 2760 } 2761 2762 function findResponsiveImages() { 2763 var query = getQuery(); 2764 2765 var elements = query('[data-responsive-image],[responsive-image]'); 2766 for (var i = 0, j = elements.length; i < j; i++) { 2767 attachResponsiveImage(elements[i]); 2768 } 2769 } 2770 2771 var regex = /,?[\s\t]*([^,\n]*?)((?:\[[\s\t]*?(?:min|max)-(?:width|height)[\s\t]*?[~$\^]?=[\s\t]*?"[^"]*?"[\s\t]*?])+)([^,\n\s\{]*)/mgi; 2772 var attrRegex = /\[[\s\t]*?(min|max)-(width|height)[\s\t]*?[~$\^]?=[\s\t]*?"([^"]*?)"[\s\t]*?]/mgi; 2773 2774 /** 2775 * @param {String} css 2776 */ 2777 function extractQuery(css) { 2778 var match, smatch, attrs, attrMatch; 2779 2780 css = css.replace(/'/g, '"'); 2781 while (null !== (match = regex.exec(css))) { 2782 smatch = match[1] + match[3]; 2783 attrs = match[2]; 2784 2785 while (null !== (attrMatch = attrRegex.exec(attrs))) { 2786 queueQuery(smatch, attrMatch[1], attrMatch[2], attrMatch[3]); 2787 } 2788 } 2789 } 2790 2791 /** 2792 * @param {CssRule[]|String} rules 2793 */ 2794 function readRules(rules) { 2795 var selector = ''; 2796 2797 if (!rules) { 2798 return; 2799 } 2800 2801 if ('string' === typeof rules) { 2802 rules = rules.toLowerCase(); 2803 if (-1 !== rules.indexOf('min-width') || -1 !== rules.indexOf('max-width')) { 2804 extractQuery(rules); 2805 } 2806 } else { 2807 for (var i = 0, j = rules.length; i < j; i++) { 2808 if (1 === rules[i].type) { 2809 selector = rules[i].selectorText || rules[i].cssText; 2810 if (-1 !== selector.indexOf('min-height') || -1 !== selector.indexOf('max-height')) { 2811 extractQuery(selector); 2812 } else if (-1 !== selector.indexOf('min-width') || -1 !== selector.indexOf('max-width')) { 2813 extractQuery(selector); 2814 } 2815 } else if (4 === rules[i].type) { 2816 readRules(rules[i].cssRules || rules[i].rules); 2817 } else if (3 === rules[i].type) { 2818 if (rules[i].styleSheet.hasOwnProperty("cssRules")) { 2819 readRules(rules[i].styleSheet.cssRules); 2820 } 2821 } 2822 } 2823 } 2824 } 2825 2826 var defaultCssInjected = false; 2827 2828 /** 2829 * Searches all css rules and setups the event listener to all elements with element query rules.. 2830 */ 2831 this.init = function () { 2832 var animationStart = 'animationstart'; 2833 if (typeof document.documentElement.style['webkitAnimationName'] !== 'undefined') { 2834 animationStart = 'webkitAnimationStart'; 2835 } else if (typeof document.documentElement.style['MozAnimationName'] !== 'undefined') { 2836 animationStart = 'mozanimationstart'; 2837 } else if (typeof document.documentElement.style['OAnimationName'] !== 'undefined') { 2838 animationStart = 'oanimationstart'; 2839 } 2840 2841 document.body.addEventListener(animationStart, function (e) { 2842 var element = e.target; 2843 var styles = element && window.getComputedStyle(element, null); 2844 var animationName = styles && styles.getPropertyValue('animation-name'); 2845 var requiresSetup = animationName && (-1 !== animationName.indexOf('element-queries')); 2846 2847 if (requiresSetup) { 2848 element.elementQueriesSensor = new ResizeSensor(element, function () { 2849 if (element.elementQueriesSetupInformation) { 2850 element.elementQueriesSetupInformation.call(); 2851 } 2852 }); 2853 2854 var sensorStyles = window.getComputedStyle(element.resizeSensor, null); 2855 var id = sensorStyles.getPropertyValue('min-width'); 2856 id = parseInt(id.replace('px', '')); 2857 setupElement(e.target, idToSelectorMapping[id]); 2858 } 2859 }); 2860 2861 if (!defaultCssInjected) { 2862 cssStyleElement = document.createElement('style'); 2863 cssStyleElement.type = 'text/css'; 2864 cssStyleElement.innerHTML = '[responsive-image] > img, [data-responsive-image] {overflow: hidden; padding: 0; } [responsive-image] > img, [data-responsive-image] > img {width: 100%;}'; 2865 2866 //safari wants at least one rule in keyframes to start working 2867 cssStyleElement.innerHTML += '\n@keyframes element-queries { 0% { visibility: inherit; } }'; 2868 document.getElementsByTagName('head')[0].appendChild(cssStyleElement); 2869 defaultCssInjected = true; 2870 } 2871 2872 for (var i = 0, j = document.styleSheets.length; i < j; i++) { 2873 try { 2874 if (document.styleSheets[i].href && 0 === document.styleSheets[i].href.indexOf('file://')) { 2875 console.warn("CssElementQueries: unable to parse local css files, " + document.styleSheets[i].href); 2876 } 2877 2878 readRules(document.styleSheets[i].cssRules || document.styleSheets[i].rules || document.styleSheets[i].cssText); 2879 } catch (e) { 2880 } 2881 } 2882 2883 findResponsiveImages(); 2884 }; 2885 2886 /** 2887 * Go through all collected rules (readRules()) and attach the resize-listener. 2888 * Not necessary to call it manually, since we detect automatically when new elements 2889 * are available in the DOM. However, sometimes handy for dirty DOM modifications. 2890 * 2891 * @param {HTMLElement} container only elements of the container are considered (document.body if not set) 2892 */ 2893 this.findElementQueriesElements = function (container) { 2894 findElementQueriesElements(container); 2895 }; 2896 2897 this.update = function () { 2898 this.init(); 2899 }; 2900 }; 2901 2902 ElementQueries.update = function () {
2903 ElementQueries.instance.update(); 2904 }; 2905 2906 /** 2907 * Removes all sensor and elementquery information from the element. 2908 * 2909 * @param {HTMLElement} element 2910 */ 2911 ElementQueries.detach = function (element) { 2912 if (element.elementQueriesSetupInformation) { 2913 //element queries 2914 element.elementQueriesSensor.detach(); 2915 delete element.elementQueriesSetupInformation; 2916 delete element.elementQueriesSensor; 2917 2918 } else if (element.resizeSensorInstance) { 2919 //responsive image 2920 2921 element.resizeSensorInstance.detach(); 2922 delete element.resizeSensorInstance; 2923 } 2924 }; 2925 2926 ElementQueries.init = function () { 2927 if (!ElementQueries.instance) { 2928 ElementQueries.instance = new ElementQueries(); 2929 } 2930 2931 ElementQueries.instance.init(); 2932 }; 2933 2934 var domLoaded = function (callback) { 2935 /* Mozilla, Chrome, Opera */ 2936 if (document.addEventListener) { 2937 document.addEventListener('DOMContentLoaded', callback, false); 2938 } 2939 /* Safari, iCab, Konqueror */ 2940 else if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) { 2941 var DOMLoadTimer = setInterval(function () { 2942 if (/loaded|complete/i.test(document.readyState)) { 2943 callback(); 2944 clearInterval(DOMLoadTimer); 2945 } 2946 }, 10); 2947 } 2948 /* Other web browsers */ 2949 else window.onload = callback; 2950 }; 2951 2952 ElementQueries.findElementQueriesElements = function (container) { 2953 ElementQueries.instance.findElementQueriesElements(container); 2954 }; 2955 2956 ElementQueries.listen = function () { 2957 domLoaded(ElementQueries.init); 2958 }; 2959 2960 return ElementQueries; 2961 2962})); 2963 2964 2965 2966/* End: js/vendor/ElementQueries.js*/ 2967
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.