1$(document).ready(function () { 2 initHideLogo(); 3 initStickyLogo(); 4 5 jQuery(".preview_iframe").height(jQuery(window).height()); 6 7 // mmenu subnav indication helpers 8 var menu = $('#navigation_header'), 9 menuParent = menu.parent(), 10 menuList = menu.find('ul'), 11 subnavClass = 'sublevel-'; 12 13 // loop through main navigation, define if there are any sub-levels and wrap into container with corresponding class name 14 // the function is needed because mmenu doesn't provide this functionality, and we need it to style sub-levels differently, with their own color schemes 15 navigationSublevelWrap(menuList, subnavClass); 16 17 // init mmenu 18 menu.clone().attr('id', 'navigation--mobile').mmenu({ 19 extensions: ["multiline"] 20 }); 21 22 // move hamburger button inside nav container 23 $('#hamburger').moveElement({ 24 place: menuParent 25 }); 26 27 // init more nav - the rest of init that needs to be updated after switching from tablet/mobile to desktop is below 28 // should be called after mmenu init to eliminate MORE nav's structure inheritance by mmenu 29 // this function will be called only once, on document.ready or window.load 30 // default structure for window.moreButton = $('<li class="navigation__item has-child more"> <a href="#">More</a> <ul class="navigation__list--sub"></ul> </li>'); uncomment if you need to change it 31 // WARN: navigation shouldn't be hidden with the usage of display:none, this will break nav init when switching from tablet/mobile to desktop. Please use, e.g. top: -9999px; left: -9999px; instead 32 if ($('.navigation').not('.mm-menu').data('more-button') === 1) { 33 // custom JS for theme 34 // class is needed to add specific classes for nav with enabled/disabled more_nav option 35 var mainNav = $('.navigation').not('.mm-menu').find('.navigation__list').eq(0), 36 moreNavActiveClass = 'more_nav--active'; 37 38 if(!mainNav.hasClass(moreNavActiveClass)) { 39 mainNav.addClass(moreNavActiveClass); 40 } else { 41 mainNav.removeClass(moreNavActiveClass); 42 } 43 } 44 // create layout for dotdotdot 45 $('.slider__caption').each(function() { 46 var lines = 4, 47 holder = $(this), 48 textH = parseInt(holder.css('line-height')); 49 50 holder.css({ maxHeight: textH * lines }).dotdotdot({ 51 tolerance: 10, 52 watch: true, 53 }); 54 }); 55 56 $('.featuredblock__description').each(function() { 57 var lines = 7, 58 holder = $(this), 59 textH = parseInt(holder.css('line-height')); 60 61 holder.css({ maxHeight: textH * lines }).dotdotdot({ 62 tolerance: 10, 63 watch: true, 64 }); 65 }); 66 67 68 69 // init more nav - the rest of init that needs to be updated after switching from tablet/mobile to desktop is below 70 // should be called after mmenu init to eliminate MORE nav's structure inheritance by mmenu 71 // this function will be called only once, on document.ready or window.load 72 if ($('.navigation').not('.mm-menu').data('more-button') === 1) { 73 window.moreButton = $('<li class="navigation__item has-child more"> <a href="#">More</a> <ul class="navigation__list--sub"></ul> </li>'); 74 } 75 // moreNavResizeUpdate function will be triggered on resize 76 // Put functions inside moreNavResizeUpdate that need to be updated on resize 77 function moreNavResizeUpdate() { 78 window.currentMenuWidth = window.menuHolder.outerWidth(); 79 // this function will be needed on resize 80 addMoreButton(); 81 // moreNav helper - re-initiate content wrapper for more nav content 82 moreNav(); 83 84 $('.navigation:not(.mm-menu) .navigation__list>li>div>ul').desktopDropNav(); 85 // accordion for desktop nav 86 $('.navigation:not(.mm-menu)').slideAccordion({ 87 activeClass: 'open-close--active', 88 opener: '>a span.opener', 89 slider: '>div.slide', 90 animSpeed: 300 91 }); 92 93 $('.navigation:not(.mm-menu) > ul').dropdownFit({ 94 dropDown: '>li>div>ul' 95 }); 96 97 // init after moreNav generation 98 $('.navigation:not(.mm-menu) > ul').setClassOnHover({ 99 setOnElem: '.wrap__header' 100 }); 101 102 // main nav drop down max height calculation 103 $('.navigation:not(.mm-menu) .sublevel-1').each(function(){ 104 $(this).scrollArea({ 105 heightProp: 'maxHeight', 106 setScrollTo: '> .navigation__list--sub' 107 }); 108 }); 109 } 110 111 // move image from bx-slider LI, as we need to move image itself with transition. Because background-position + relative/absolute breaks in Chrome on resize 112 // NOTE: special conditional (!$('.wrap__slider').hasClass('text-only') && !!$('.slider__image').length && !!$('.slider__image').css('background-image').length) is required, 113 // because in the theme there's a variation of text-only slider, it doesn't require images 114 // In common situations use only this conditional (!!$('.slider__image').length && !!$('.slider__image').css('background-image').length) 115 if(!$('.wrap__slider').hasClass('text-only') && !!$('.slider__image').length && !!$('.slider__image').css('background-image').length) { 116 if(!$('.slider__image--fixed').length) { 117 $('.slider__image').each(function(){ 118 var imgHolder = $(this), 119 img = imgHolder.css('background-image').replace(/(url\(|\)|'|")/gi, ''); 120 121 $(this).css('background-image', 'none'); 122 imgHolder.append('<div class="slider__image--fixed" style="background-image: url(' + img + ')">'); 123 }); 124 } 125 126 // set class if slider text area is empty 127 $('.slider__text').each(function() { 128 if(!$(this).children().length) { 129 $(this).addClass('empty'); 130 } 131 }); 132 } 133 134 // handle layout resize 135 ResponsiveHelper.addRange({ 136 '1025..': { 137 on: function() { 138 139 if ($('.navigation').not('.mm-menu').data('more-button') === 1) { 140 menuPrepare(); 141 // init more nav 142 window.currentMenuWidth = window.menuHolder.outerWidth(); 143 // this function will be needed on resize 144 addMoreButton(); 145 // moreNav helper - re-initiate content wrapper for more nav content 146 moreNav(); 147 // update moreNav on resize 148 $(window).on('resize orientationchange', moreNavResizeUpdate); 149 } 150 151 // prepare desktop nav for accordion 152 $('.navigation:not(.mm-menu) .navigation__list>li>div>ul').desktopDropNav(); 153 // accordion for desktop nav 154 $('.navigation:not(.mm-menu)').slideAccordion({
155 activeClass: 'open-close--active', 156 opener: '>a span.opener', 157 slider: '>div.slide', 158 animSpeed: 300 159 }); 160 161 // init dropdownFit 162 $('.navigation:not(.mm-menu) > ul').dropdownFit({ 163 dropDown: '>li>div>ul' 164 }); 165 166 // init after moreNav generation 167 $('.navigation:not(.mm-menu) > ul').setClassOnHover({ 168 setOnElem: '.wrap__header' 169 }); 170 171 // init main nav drop down max height calculation 172 $('.navigation:not(.mm-menu) .sublevel-1').each(function(){ 173 $(this).scrollArea({ 174 heightProp: 'maxHeight', 175 setScrollTo: '> .navigation__list--sub' 176 }); 177 }); 178 179 // close mmenu on desktop 180 $('#navigation--mobile').data('mmenu').close(); 181 }, 182 off: function() { 183 if ($('.navigation').not('.mm-menu').data('more-button') === 1) { 184 // destroy update moreNav on resize 185 $(window).off('resize orientationchange', moreNavResizeUpdate); 186 } 187 188 // destroy main nav drop down max height calculation 189 setTimeout(function(){ 190 $('.navigation:not(.mm-menu) .sublevel-1').each(function(){ 191 if (typeof $(this).data('scrollArea') !== 'undefined') { 192 $(this).data('scrollArea').destroy(); 193 } 194 }); 195 }, 100); 196 197 // destroy dropdownFit 198 $('.navigation:not(.mm-menu) > ul').data('dropdownFit').destroy(); 199 } 200 }, 201 '768..': { 202 on: function() { 203 // check if form component exists on page 204 if($('.form').length) { 205 // set timer for layoutContactForm func (wait until form is loaded from 3rd party service) 206 contactFormTimer = setInterval(function() { 207 // init function if form is created 208 if($('.form').find('.leadForm').length) { 209 // init contact form layout 210 $('.wrap__form.contact .form').layoutContactForm(); 211 $('.wrap__form.appointment .form').layoutContactForm(); 212 213 // init set top position in contact form 214 $('.wrap__form.contact .form-input-comments .input_container').setSpacing({ 215 takeSizeFrom: '.wrap__form.contact .form-input-comments .label_container', 216 takeSize: 'height', 217 spacingProp: 'top' 218 }); 219 $('.wrap__form.appointment .form-input-comments .input_container').setSpacing({ 220 takeSizeFrom: '.wrap__form.appointment .form-input-comments .label_container', 221 takeSize: 'height', 222 spacingProp: 'top' 223 }); 224 225 // remove timer 226 clearInterval(contactFormTimer); 227 } 228 }, 500); 229 } 230 }, 231 off: function() { 232 // destroy layoutContactForm 233 if (typeof $('.wrap__form.contact .form').data('layoutContactForm') !== 'undefined') { 234 $('.wrap__form.contact .form').data('layoutContactForm').destroy(); 235 } else { 236 clearInterval(contactFormTimer); // remove timer if it has been activated, but window has been resized back to mobiles 237 } 238 if (typeof $('.wrap__form.appointment .form').data('layoutContactForm') !== 'undefined') { 239 $('.wrap__form.appointment .form').data('layoutContactForm').destroy(); 240 } else { 241 clearInterval(contactFormTimer); // remove timer if it has been activated, but window has been resized back to mobiles 242 } 243 244 // destroy setSpacing 245 if (typeof $('.wrap__form.contact .form-input-comments .input_container').data('setSpacing') !== 'undefined') { 246 $('.wrap__form.contact .form-input-comments .input_container').data('setSpacing').destroy(); 247 } else { 248 clearInterval(contactFormTimer); // remove timer if it has been activated, but window has been resized back to mobiles 249 } 250 if (typeof $('.wrap__form.appointment .form-input-comments .input_container').data('setSpacing') !== 'undefined') { 251 $('.wrap__form.appointment .form-input-comments .input_container').data('setSpacing').destroy(); 252 } else { 253 clearInterval(contactFormTimer); // remove timer if it has been activated, but window has been resized back to mobiles 254 } 255 } 256 } 257 }); 258 259 $('.wrap__layout').setSpacing({ 260 takeSizeFrom: '.wrap__header', 261 takeSize: 'height' 262 }); 263}); 264 265 266// initialize fixed logo on scroll 267function initStickyLogo() { 268 jQuery('.wrap__content').fixedScrollBlock({ 269 slideBlock: '.wrap__logoBody', 270 extraTop: 100, 271 extraBottom: -100 272 }); 273} 274 275 276function initHideLogo() { 277 var win = $(window); 278 function scrollHandler() { 279 var bo = $(window).scrollTop(); 280 if ( bo < 100 ) { 281 $('.wrap__logoHome').removeClass("sticky-logo"); 282 } 283 else { 284 $('.wrap__logoHome').addClass("sticky-logo"); 285 } 286 287 } 288 ResponsiveHelper.addRange({ 289 '1025..': { 290 on: function() { 291 win.on('scroll', scrollHandler); 292 $('.wrap__logoHome').removeClass("sticky-logo"); 293 }, 294 off: function() { 295 // destroy layoutContactForm 296 win.off('scroll', scrollHandler); 297 } 298 } 299 });
300} 301 302jQuery(window).load(function() { 303 initAnchors(); 304}); 305 306// initialize smooth anchor links 307function initAnchors() { 308 new SmoothScroll({ 309 anchorLinks: '.button-anchor', 310 easing: 'linear', 311 animMode: 'speed', 312 animSpeed: 1500 313 }); 314} 315 316/*! 317 * SmoothScroll module 318 */ 319;(function($, exports) { 320 // private variables 321 var page, 322 win = $(window), 323 activeBlock, activeWheelHandler, 324 wheelEvents = ('onwheel' in document || document.documentMode >= 9 ? 'wheel' : 'mousewheel DOMMouseScroll'); 325 326 // animation handlers 327 function scrollTo(offset, options, callback) { 328 // initialize variables 329 var scrollBlock; 330 if (document.body) { 331 if (typeof options === 'number') { 332 options = { duration: options }; 333 } else { 334 options = options || {}; 335 } 336 page = page || $('html, body'); 337 scrollBlock = options.container || page; 338 } else { 339 return; 340 } 341 342 // treat single number as scrollTop 343 if (typeof offset === 'number') { 344 offset = { top: offset }; 345 } 346 347 // handle mousewheel/trackpad while animation is active 348 if (activeBlock && activeWheelHandler) { 349 activeBlock.off(wheelEvents, activeWheelHandler); 350 } 351 if (options.wheelBehavior && options.wheelBehavior !== 'none') { 352 activeWheelHandler = function(e) { 353 if (options.wheelBehavior === 'stop') { 354 scrollBlock.off(wheelEvents, activeWheelHandler); 355 scrollBlock.stop(); 356 } else if (options.wheelBehavior === 'ignore') { 357 e.preventDefault(); 358 } 359 }; 360 activeBlock = scrollBlock.on(wheelEvents, activeWheelHandler); 361 } 362 363 // start scrolling animation 364 scrollBlock.stop().animate({ 365 scrollLeft: offset.left, 366 scrollTop: offset.top 367 }, options.duration, function() { 368 if (activeWheelHandler) { 369 scrollBlock.off(wheelEvents, activeWheelHandler); 370 } 371 if ($.isFunction(callback)) { 372 callback(); 373 } 374 }); 375 } 376 377 // smooth scroll contstructor 378 function SmoothScroll(options) { 379 this.options = $.extend({ 380 anchorLinks: 'a[href^="#"]', // selector or jQuery object 381 container: null, // specify container for scrolling (default - whole page) 382 extraOffset: null, // function or fixed number 383 activeClasses: null, // null, "link", "parent" 384 easing: 'swing', // easing of scrolling 385 animMode: 'duration', // or "speed" mode 386 animDuration: 800, // total duration for scroll (any distance) 387 animSpeed: 1500, // pixels per second 388 anchorActiveClass: 'anchor-active', 389 sectionActiveClass: 'section-active', 390 wheelBehavior: 'stop', // "stop", "ignore" or "none" 391 useNativeAnchorScrolling: false // do not handle click in devices with native smooth scrolling 392 }, options); 393 this.init(); 394 } 395 SmoothScroll.prototype = { 396 init: function() { 397 this.initStructure(); 398 this.attachEvents(); 399 }, 400 initStructure: function() { 401 var self = this; 402 403 this.container = this.options.container ? $(this.options.container) : $('html,body'); 404 this.scrollContainer = this.options.container ? this.container : win; 405 this.anchorLinks = jQuery(this.options.anchorLinks).filter(function() { 406 return document.getElementById(this.getAttribute('href').slice(1)); 407 }); 408 }, 409 getAnchorTarget: function(link) { 410 // get target block from link href 411 var targetId = $(link).attr('href'); 412 return $(targetId.length > 1 ? targetId : 'html'); 413 }, 414 getTargetOffset: function(block) { 415 // get target offset 416 var blockOffset = block.offset().top; 417 if (this.options.container) { 418 blockOffset -= this.container.offset().top - this.container.prop('scrollTop'); 419 } 420 421 // handle extra offset 422 if (typeof this.options.extraOffset === 'number') { 423 blockOffset -= this.options.extraOffset; 424 } else if (typeof this.options.extraOffset === 'function') { 425 blockOffset -= this.options.extraOffset(block); 426 } 427 return { top: blockOffset }; 428 }, 429 attachEvents: function() { 430 var self = this; 431 432 // handle active classes 433 if (this.options.activeClasses && this.anchorLinks.length) { 434 // cache structure 435 this.anchorData = []; 436 437 for (var i = 0; i < this.anchorLinks.length; i++) { 438 var link = jQuery(this.anchorLinks[i]), 439 targetBlock = self.getAnchorTarget(link), 440 anchorDataItem; 441 442 $.each(self.anchorData, function(index, item) { 443 if (item.block[0] === targetBlock[0]) { 444 anchorDataItem = item; 445 } 446 });
447 448 if (anchorDataItem) { 449 anchorDataItem.link = anchorDataItem.link.add(link); 450 } else { 451 self.anchorData.push({ 452 link: link, 453 block: targetBlock 454 }); 455 } 456 }; 457 458 // add additional event handlers 459 this.resizeHandler = function() { 460 self.recalculateOffsets(); 461 }; 462 this.scrollHandler = function() { 463 self.refreshActiveClass(); 464 }; 465 466 this.recalculateOffsets(); 467 this.scrollContainer.on('scroll', this.scrollHandler); 468 win.on('resize', this.resizeHandler); 469 } 470 471 // handle click event 472 this.clickHandler = function(e) { 473 self.onClick(e); 474 }; 475 if (!this.options.useNativeAnchorScrolling) { 476 this.anchorLinks.on('click', this.clickHandler); 477 } 478 }, 479 recalculateOffsets: function() { 480 var self = this; 481 $.each(this.anchorData, function(index, data) { 482 data.offset = self.getTargetOffset(data.block); 483 data.height = data.block.outerHeight(); 484 }); 485 this.refreshActiveClass(); 486 }, 487 refreshActiveClass: function() { 488 var self = this, 489 foundFlag = false, 490 containerHeight = this.container.prop('scrollHeight'), 491 viewPortHeight = this.scrollContainer.height(), 492 scrollTop = this.options.container ? this.container.prop('scrollTop') : win.scrollTop(); 493 494 // user function instead of default handler 495 if (this.options.customScrollHandler) { 496 this.options.customScrollHandler.call(this, scrollTop, this.anchorData); 497 return; 498 } 499 500 // sort anchor data by offsets 501 this.anchorData.sort(function(a, b) { 502 return a.offset.top - b.offset.top; 503 }); 504 function toggleActiveClass(anchor, block, state) { 505 anchor.toggleClass(self.options.anchorActiveClass, state); 506 block.toggleClass(self.options.sectionActiveClass, state); 507 } 508 509 // default active class handler 510 $.each(this.anchorData, function(index) { 511 var reverseIndex = self.anchorData.length - index - 1, 512 data = self.anchorData[reverseIndex], 513 anchorElement = (self.options.activeClasses === 'parent' ? data.link.parent() : data.link); 514 515 if (scrollTop >= containerHeight - viewPortHeight) { 516 // handle last section 517 if (reverseIndex === self.anchorData.length - 1) { 518 toggleActiveClass(anchorElement, data.block, true); 519 } else { 520 toggleActiveClass(anchorElement, data.block, false); 521 } 522 } else { 523 // handle other sections 524 if (!foundFlag && (scrollTop >= data.offset.top - 1 || reverseIndex === 0)) { 525 foundFlag = true; 526 toggleActiveClass(anchorElement, data.block, true); 527 } else { 528 toggleActiveClass(anchorElement, data.block, false); 529 } 530 } 531 }); 532 }, 533 calculateScrollDuration: function(offset) { 534 var distance; 535 if (this.options.animMode === 'speed') { 536 distance = Math.abs(this.scrollContainer.scrollTop() - offset.top); 537 return (distance / this.options.animSpeed) * 1000; 538 } else { 539 return this.options.animDuration; 540 } 541 }, 542 onClick: function(e) { 543 var targetBlock = this.getAnchorTarget(e.currentTarget), 544 targetOffset = this.getTargetOffset(targetBlock); 545 546 e.preventDefault(); 547 scrollTo(targetOffset, { 548 container: this.container, 549 wheelBehavior: this.options.wheelBehavior, 550 duration: this.calculateScrollDuration(targetOffset) 551 }); 552 }, 553 destroy: function() { 554 if (this.options.activeClasses) { 555 win.off('resize', this.resizeHandler); 556 this.scrollContainer.off('scroll', this.scrollHandler); 557 } 558 this.anchorLinks.off('click', this.clickHandler); 559 } 560 }; 561 562 // public API 563 $.extend(SmoothScroll, { 564 scrollTo: function(blockOrOffset, durationOrOptions, callback) { 565 scrollTo(blockOrOffset, durationOrOptions, callback); 566 } 567 }); 568 569 // export module 570 exports.SmoothScroll = SmoothScroll; 571}(jQuery, this));
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.