1/** ********************************************** ** 2 @Author Dorin Grigoras 3 @Website www.stepofweb.com 4 @Last Update 12:56 AM Friday, February 07, 2014 5 6 TABLE CONTENTS 7 ------------------------------- 8 01. Top Nav 9 02. Animate 10 03. Superslides 11 04. OWL Carousel 12 05. Popover 13 06. Lightbox 14 07. ScrollTo 15 08. Parallax 16 09. Masonry Filter 17 10. Toggle 18 11. Background Image 19 13. Scroll 20 21 GOOGLE MAP 22 AFTER RESIZE 23 COUNT TO 24 FITVIDS 25 WAIT FOR IMAGES [used by masonry] 26*************************************************** **/ 27 28// GOOGLE MAP 29var $googlemap_latitude = $('#gmap').data('lat'), 30 $googlemap_longitude = $('#gmap').data('long'), 31 $googlemap_zoom = 15; 32 33 34 /* Init */ 35 jQuery(window).ready(function () { 36 Atropos(); 37 }); 38 39 40 41/** Core 42 **************************************************************** **/ 43 function Atropos() { 44 45 _topNav(); 46 _animate(); 47 _superslide(); 48 _owl_carousel(); 49 _popover(); 50 _lightbox(); 51 _scrollTo(); 52 _parallax(); 53 _masonry(); 54 _toggle(); 55 _bgimage(); 56 57 /** Bootstrap Tooltip **/ 58 jQuery("a[data-toggle=tooltip]").tooltip(); 59 60 /** Fitvids [Youtube|Vimeo] **/ 61 if(jQuery(".fullwidthbanner iframe").length < 1 && jQuery(".fullscreenbanner iframe").length < 1 && jQuery(".fullscreenvideo").length < 1) { // disable fitvids if revolution slider video is present! 62 jQuery("body").fitVids(); 63 } 64 65 } 66 67 68 69/** 01. Top Nav 70 **************************************************************** **/ 71function _topNav() { 72 var addActiveClass = false; 73 74 jQuery("#topMain li.dropdown > a, #topMain li.dropdown-submenu > a").bind("click", function(e) { 75 e.preventDefault(); 76 77 if($(window).width() > 979) { 78 return; 79 } 80 81 82 addActiveClass = jQuery(this).parent().hasClass("resp-active"); 83 jQuery("#topMain").find(".resp-active").removeClass("resp-active"); 84 85 if(!addActiveClass) { 86 jQuery(this).parents("li").addClass("resp-active"); 87 } 88 89 return; 90 91 }); 92 93 // Mega Menu 94 jQuery(document).bind("click", ".mega-menu .dropdown-menu", function(e) { 95 e.stopPropagation() 96 }); 97 98 99 /*jQuery(window).scroll(function() { 100 topMain(); // on scroll 101 }); topMain(); // on load 102*/ 103 104 window.topNavSmall = false;
105 function topMain() { 106 var _scrollTop = jQuery(document).scrollTop(); 107 108 if(_scrollTop > 0) { 109 jQuery('header#topNav div.nav-main-collapse').addClass('topFix'); 110 //jQuery('#topNav').stop().animate({ 'height':'60px'},400); 111 jQuery('header#topNav div.nav-main-collapse').stop().animate({ 'margin-top':'0'},400); 112 jQuery('header#topNav button').stop().animate({ 'margin-top':'-6px'},100); 113 jQuery('header#topNav a.logo').stop().animate({ 'line-height':'0', 'margin-top':'-7px'},400); 114 jQuery('#header_shadow').stop().animate({ 'top':'30px'},400); //just a little visible 115 window.topNavSmall = true; 116 } 117 118 if(window.topNavSmall === true && _scrollTop < 3) { 119 jQuery('header#topNav div.nav-main-collapse').removeClass('topFix'); 120 //jQuery('#topNav').stop().animate({ 'height':'92px'},400); 121 jQuery('header#topNav div.nav-main-collapse').stop().animate({ 'margin-top':'16px'},400); 122 jQuery('header#topNav button').stop().animate({ 'margin-top':'8px'},100); 123 jQuery('header#topNav a.logo').stop().animate({ 'line-height':'50px', 'margin-top':'0'},400); 124 jQuery('#header_shadow').stop().animate({ 'top':'92px'},400); 125 window.topNavSmall = false; 126 } 127 128 if(jQuery('#topHead').length > 0) { 129 if(_scrollTop > 0) { 130 jQuery('#topHead').addClass('fixed'); 131 } else { 132 jQuery('#topHead').removeClass('fixed'); 133 } 134 } 135 136 } 137} 138 139/** 02. Animate 140 **************************************************************** **/ 141function _animate() { 142 143 // Bootstrap Progress Bar 144 jQuery("[data-appear-progress-animation]").each(function() { 145 var $_t = jQuery(this); 146 147 if(jQuery(window).width() > 767) { 148 149 $_t.appear(function() { 150 _delay = 1; 151 152 if($_t.attr("data-appear-progress-animation-delay")) { 153 _delay = $_t.attr("data-appear-progress-animation-delay"); 154 } 155 156 if(_delay > 1) { 157 $_t.css("animation-delay", _delay + "ms"); 158 } 159 160 $_t.addClass($_t.attr("data-appear-progress-animation")); 161 162 setTimeout(function() { 163 164 $_t.addClass("animation-visible"); 165 166 }, _delay); 167 168 }, {accX: 0, accY: -150}); 169 170 } else { 171 172 $_t.addClass("animation-visible"); 173 174 } 175 176 }); 177 178 179 jQuery("[data-appear-progress-animation]").each(function() { 180 var $_t = jQuery(this); 181 182 $_t.appear(function() { 183 184 var _delay = ($_t.attr("data-appear-animation-delay") ? $_t.attr("data-appear-animation-delay"): 1); 185 186 if(_delay > 1) { 187 $_t.css("animation-delay", _delay + "ms"); 188 } 189 190 $_t.addClass($_t.attr("data-appear-animation")); 191 setTimeout(function() { 192 193 $_t.animate({"width": $_t.attr("data-appear-progress-animation")}, 1000, "easeOutQuad", function() { 194 $_t.find(".progress-bar-tooltip").animate({"opacity": 1}, 500, "easeOutQuad"); 195 }); 196 197 }, _delay); 198 199 }, {accX: 0, accY: -50}); 200 201 }); 202 203 204 // Count To 205 jQuery(".countTo [data-to]").each(function() { 206 var $_t = jQuery(this); 207 208 $_t.appear(function() { 209 210 $_t.countTo(); 211 212 }, {accX:0, accY:0}); 213 214 }); 215 216 217 /* Knob Circular Bar */ 218 if(jQuery().knob) { 219 220 jQuery(".knob").knob(); 221 222 } 223 224 225 /* Animation */ 226 jQuery('.animate_from_top').each(function () { 227 jQuery(this).appear(function() { 228 jQuery(this).delay(150).animate({opacity:1,top:"0px"},1000); 229 }); 230 }); 231 232 jQuery('.animate_from_bottom').each(function () { 233 jQuery(this).appear(function() { 234 jQuery(this).delay(150).animate({opacity:1,bottom:"0px"},1000); 235 }); 236 }); 237 238 239 jQuery('.animate_from_left').each(function () { 240 jQuery(this).appear(function() { 241 jQuery(this).delay(150).animate({opacity:1,left:"0px"},1000); 242 }); 243 }); 244 245 246 jQuery('.animate_from_right').each(function () { 247 jQuery(this).appear(function() { 248 jQuery(this).delay(150).animate({opacity:1,right:"0px"},1000); 249 }); 250 }); 251 252 jQuery('.animate_fade_in').each(function () { 253 jQuery(this).appear(function() { 254 jQuery(this).delay(350).animate({opacity:1,right:"0px"},1000); 255 }); 256 }); 257} 258 259/** 03. Superslides 260 **************************************************************** **/ 261function _superslide() { 262 263 if(jQuery("#slider").length > 0) { 264 265 var data_autoplay = jQuery("#slider").attr('data-autoplay'), 266 data_mouseover_stop = jQuery("#slider").attr('data-mouseover-stop'); 267 268 if(data_autoplay) { 269 if(data_autoplay == '') { 270 var data_autoplay = false;
271 } else { 272 var data_autoplay = parseInt(data_autoplay); 273 } 274 } else { 275 var data_autoplay = false; 276 } 277 278 if(!data_autoplay) { 279 data_mouseover_stop = false; 280 } 281 282 jQuery("#slider").superslides({ 283 animation: "fade", // slide|fade 284 pagination: true, // true|false 285 play: data_autoplay, // false to disable autoplay -OR- miliseconds (eg.: 1000 = 1s) 286 animation_speed: 2000, // animation transition 287 288 elements: { 289 preserve: '.preserve', 290 nav: '.slides-navigation', 291 container: '.slides-container', 292 pagination: '.slides-pagination' 293 } 294 }); 295 296 if(data_mouseover_stop == 'true') { 297 298 // Stop on mouse over ! 299 jQuery('#slider').on('mouseenter', function() { 300 jQuery(this).superslides('stop'); 301 // console.log('Stopped') 302 }); 303 jQuery('#slider').on('mouseleave', function() { 304 jQuery(this).superslides('start'); 305 // console.log('_start') 306 }); 307 308 } 309 310 jQuery(window).load(function () { 311 jQuery("#slider").css({"background":"none"}); 312 }); 313 314 } 315} 316 317/** 04. OWL Carousel 318 **************************************************************** **/ 319function _owl_carousel() { 320 321 var total = jQuery("div.owl-carousel").length, 322 count = 0; 323 324 jQuery("div.owl-carousel").each(function() { 325 326 var slider = jQuery(this); 327 var options = slider.attr('data-plugin-options'); 328 329 var defaults = { 330 items: 5, 331 itemsCustom: false, 332 itemsDesktop: [1199,4], 333 itemsDesktopSmall: [980,3], 334 itemsTablet: [768,2], 335 itemsTabletSmall: false, 336 itemsMobile: [479,1], 337 singleItem: true, 338 itemsScaleUp: false, 339 340 slideSpeed: 200, 341 paginationSpeed: 800, 342 rewindSpeed: 1000, 343 344 autoPlay: false, 345 stopOnHover: false, 346 347 navigation: false, 348 navigationText: [ 349 '<i class="fa fa-chevron-left"></i>', 350 '<i class="fa fa-chevron-right"></i>' 351 ], 352 rewindNav: true, 353 scrollPerPage: false, 354 355 pagination: true, 356 paginationNumbers: false, 357 358 responsive: true, 359 responsiveRefreshRate: 200, 360 responsiveBaseWidth: window, 361 362 baseClass: "owl-carousel", 363 theme: "owl-theme", 364 365 lazyLoad: false, 366 lazyFollow: true, 367 lazyEffect: "fade", 368 369 autoHeight: false, 370 371 jsonPath: false, 372 jsonSuccess: false, 373 374 dragBeforeAnimFinish: true, 375 mouseDrag: true, 376 touchDrag: true, 377 378 transitionStyle: false, 379 380 addClassActive: false, 381 382 beforeUpdate: false, 383 afterUpdate: false, 384 beforeInit: false, 385 afterInit: false, 386 beforeMove: false, 387 afterMove: false, 388 afterAction: false, 389 startDragging: false, 390 afterLazyLoad: false 391 } 392 var config = jQuery.extend({}, defaults, options, slider.data("plugin-options")); 393 slider.owlCarousel(config).addClass("owl-carousel-init"); 394 }); 395} 396 397/** 05. Popover 398 **************************************************************** **/ 399function _popover() { 400 jQuery("a[data-toggle=popover]").bind("click", function(e) { 401 e.preventDefault(); 402 }); 403 404 jQuery("a[data-toggle=popover], button[data-toggle=popover]").popover(); 405} 406 407/** 06. LightBox 408 **************************************************************** **/ 409function _lightbox() { 410 411 if(typeof(jQuery.magnificPopup) == "undefined") { 412 return false; 413 } 414 415 jQuery.extend(true, jQuery.magnificPopup.defaults, { 416 tClose: 'Close', 417 tLoading: 'Loading...', 418 419 gallery: { 420 tPrev: 'Previous', 421 tNext: 'Next', 422 tCounter: '%curr% / %total%' 423 }, 424 425 image: { 426 tError: 'Image not loaded!' 427 }, 428 429 ajax: { 430 tError: 'Content not loaded!' 431 } 432 }); 433 434 jQuery(".lightbox").each(function() { 435 436 var _t = jQuery(this), 437 options = _t.attr('data-plugin-options'), 438 config = {}, 439 defaults = { 440 type: 'image', 441 fixedContentPos: false, 442 fixedBgPos: false, 443 mainClass: 'mfp-no-margins mfp-with-zoom', 444 image: { 445 verticalFit: true 446 }, 447 448 zoom: { 449 enabled: false, 450 duration: 300 451 }, 452 453 gallery: { 454 enabled: false, 455 navigateByImgClick: true, 456 preload: [0,1], 457 arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>', 458 tPrev: 'Previou', 459 tNext: 'Next', 460 tCounter: '<span class="mfp-counter">%curr% / %total%</span>' 461 }, 462 }; 463 464 if(_t.data("plugin-options")) { 465 config = jQuery.extend({}, defaults, options, _t.data("plugin-options")); 466 } 467 468 jQuery(this).magnificPopup(config); 469 470 }); 471} 472 473 474/** 07. ScrollTo 475 **************************************************************** **/ 476function _scrollTo() { 477 478 // thsi part of code is used when we just want to scroll into a defined page 479 jQuery("a.scrollTo").bind("click", function(e) { 480 481 var href = jQuery(this).attr('href'), 482 pathname = document.location.pathname; 483 var topNavHeight = $('#topNav').outerHeight(); 484 // mobile specific instructions 485 // if ($('.nav-main-collapse').length) { 486 //$('.nav-main-collapse').collapse('hide'); Commenté Debug #55377 pour eviter le bug du header qui collapse au click dans la sous nav 487 // topNavHeight += $('.tophead').outerHeight(); 488 // } 489 490 if ((pathname != '/' && href.startsWith(pathname)) || href.startsWith('#')) { 491 e.preventDefault(); 492 href = href.replace(pathname, ''); 493 if(href != '#') { 494 jQuery('html,body').animate({scrollTop: jQuery(href).offset().top - topNavHeight}, 1000, 'easeInOutExpo'); 495 } 496 } 497 }); 498 499 jQuery("a.toTop").bind("click", function(e) { 500 var href = jQuery(this).attr('href'), 501 pathname = document.location.pathname; 502 503 if (jQuery(this).hasClass('dropdown-toggle')) { 504 if (jQuery('i.fa-bars:hidden').length == 0) { 505 // the mobile menu is enabled, we prevent click on tov nav 506 // redirects to the page to allow sub nav items to be clicked 507 e.preventDefault(); 508 return; 509 } 510 } 511 512 if ((pathname != '/' && href.startsWith(pathname)) || href.startsWith('#')) { 513 e.preventDefault(); 514 jQuery('html,body').animate({scrollTop: 0}, 1000, 'easeInOutExpo'); 515 } else { 516 document.location.href = href; 517 } 518 }); 519 520 // this part of code is used when we use "deep link" from another page 521 var anchor = window.location.hash; 522 if (anchor) { 523 var topNavHeight = $('#topNav').outerHeight(); 524 if(anchor != '#') { 525 jQuery('html,body').animate({scrollTop: jQuery(anchor).offset().top - topNavHeight}, 1000, 'easeInOutExpo'); 526 } 527 } 528} 529 530 531 532/** 08. Parallax 533 **************************************************************** **/ 534function _parallax() { 535
536 if(typeof(jQuery.stellar) == "undefined") { 537 538 jQuery(".parallax").addClass("parallax-init"); 539 return false; 540 541 } 542 543 jQuery(window).load(function () { 544 545 if(jQuery(".parallax").length > 0) { 546 547 if(!Modernizr.touch) { 548 549 jQuery(window).stellar({ 550 551 responsive: true, 552 scrollProperty: 'scroll', 553 parallaxElements: false, 554 horizontalScrolling: false, 555 horizontalOffset: 0, 556 verticalOffset: 0 557 }); 558 559 } else { 560 561 jQuery(".parallax").addClass("disabled"); 562 563 } 564 } 565 566 jQuery(".parallax").addClass("parallax-init"); 567 568 // responsive 569 jQuery(window).afterResize(function() { 570 jQuery.stellar('refresh'); 571 }); 572 573 }); 574} 575 576/** 09. Masonry Filter 577 **************************************************************** **/ 578function _masonry() { 579 580 jQuery(window).load(function() { 581 582 jQuery("span.js_loader").remove(); 583 jQuery("li.masonry-item").addClass('fadeIn'); 584 585 jQuery(".masonry-list").each(function() { 586 587 var _c = jQuery(this); 588 589 _c.waitForImages(function() { // waitForImages Plugin - bottom of this file 590 591 _c.masonry({ 592 itemSelector: '.masonry-item' 593 }); 594 595 }); 596 597 }); 598 599 }); 600 601 jQuery("ul.isotope-filter").each(function() { 602 603 var _el = jQuery(this), 604 destination = jQuery("ul.sort-destination[data-sort-id=" + jQuery(this).attr("data-sort-id") + "]"); 605 606 if(destination.get(0)) { 607 608 $(document).ready(function() { 609 destination.isotope({ 610 itemSelector: "li", 611 masonry: { columnWidth: destination.width() / 12 } 612 }); 613 614 _el.find("a").click(function(e) { 615 616 e.preventDefault(); 617 618 var $_t = jQuery(this), 619 sortId = $_t.parents(".sort-source").attr("data-sort-id"), 620 filter = $_t.parent().attr("data-option-value"); 621 622 _el.find("li.active").removeClass("active"); 623 $_t.parent().addClass("active"); 624 625 destination.isotope({ 626 filter: filter 627 }); 628 629 jQuery(".sort-source-title[data-sort-id=" + sortId + "] strong").html($_t.html()); 630 return false; 631 632 }); 633 634 }); 635 636 } 637 638 }); 639 640 641 $(document).ready(function() { 642 643 jQuery("ul.isotope").addClass('fadeIn'); 644 645 }); 646} 647 648/** 10. Toggle 649 **************************************************************** **/ 650function _toggle() { 651 652 var $_t = this, 653 previewParClosedHeight = 25; 654 655 jQuery("div.toggle.active > p").addClass("preview-active"); 656 jQuery("div.toggle.active > div.toggle-content").slideDown(400); 657 jQuery("div.toggle > label").click(function(e) { 658 659 var parentSection = jQuery(this).parent(), 660 parentWrapper = jQuery(this).parents("div.toogle"), 661 previewPar = false, 662 isAccordion = parentWrapper.hasClass("toogle-accordion"); 663 664 if(isAccordion && typeof(e.originalEvent) != "undefined") { 665 parentWrapper.find("div.toggle.active > label").trigger("click"); 666 } 667 668 parentSection.toggleClass("active"); 669 670 if(parentSection.find("> p").get(0)) { 671 672 previewPar = parentSection.find("> p"); 673 var previewParCurrentHeight = previewPar.css("height"); 674 var previewParAnimateHeight = previewPar.css("height"); 675 previewPar.css("height", "auto"); 676 previewPar.css("height", previewParCurrentHeight); 677 678 } 679 680 var toggleContent = parentSection.find("> div.toggle-content"); 681 682 if(parentSection.hasClass("active")) { 683 684 jQuery(previewPar).animate({height: previewParAnimateHeight}, 350, function() {jQuery(this).addClass("preview-active");}); 685 toggleContent.slideDown(350); 686 687 } else { 688 689 jQuery(previewPar).animate({height: previewParClosedHeight}, 350, function() {jQuery(this).removeClass("preview-active");}); 690 toggleContent.slideUp(350); 691 692 } 693 694 }); 695} 696 697 698
699/** 11. Background Image 700 class="boxed" should be added to body. 701 Add to body - example: data-background="assets/images/boxed_background/1.jpg" 702 **************************************************************** **/ 703 function _bgimage() { 704 if(jQuery('body').hasClass('boxed')) { 705 backgroundImageSwitch(); 706 } 707 function backgroundImageSwitch() { 708 var data_background = jQuery('body').attr('data-background'); 709 if(data_background) { 710 jQuery.backstretch(data_background); 711 jQuery('body').addClass('transparent'); // remove backround color of boxed class 712 } 713 } 714 } 715 716 717/** 12. Scroll arrowDown Homepage 718**************************************************************** **/ 719$('.arrowDown').on('click', function(){ 720 var topNavHeight = $('#topNav').outerHeight(); 721 $('html, body').stop().animate({scrollTop: $('#scrollEdito').offset().top - topNavHeight},1000, 'easeInOutExpo'); 722 }); 723 724 725/** **************************************************************************************************************** **/ 726/** **************************************************************************************************************** **/ 727/** **************************************************************************************************************** **/ 728/** **************************************************************************************************************** **/ 729 730 731 732 733/** MEDIA ELEMENTS 734*************************************************** **/ 735 if(jQuery().mediaelementplayer && jQuery('video').length > 0 && jQuery(".fullscreenbanner video").length < 1 && jQuery(".fullwidthbanner video").length < 1) { // exclude revolution slider videos 736 jQuery('video').mediaelementplayer({ 737 // if the <video width> is not specified, this is the default 738 defaultVideoWidth: 480, 739 // if the <video height> is not specified, this is the default 740 defaultVideoHeight: 270, 741 // if set, overrides <video width> 742 videoWidth: '100%', // -1 743 // if set, overrides <video height> 744 videoHeight: '100%', // -1 745 // width of audio player 746 audioWidth: 400, 747 // height of audio player 748 audioHeight: 30, 749 // initial volume when the player starts 750 startVolume: 0.8, 751 // useful for <audio> player loops 752 loop: true, 753 // enables Flash and Silverlight to resize to content size 754 enableAutosize: true, 755 // the order of controls you want on the control bar (and other plugins below) 756 features: ['playpause','progress','current','duration','tracks','volume','fullscreen'], 757 // Hide controls when playing and mouse is not over the video 758 alwaysShowControls: false, 759 // force iPad's native controls 760 iPadUseNativeControls: false, 761 // force iPhone's native controls 762 iPhoneUseNativeControls: false, 763 // force Android's native controls 764 AndroidUseNativeControls: false, 765 // forces the hour marker (##:00:00) 766 alwaysShowHours: false, 767 // show framecount in timecode (##:00:00:00) 768 showTimecodeFrameCount: false, 769 // used when showTimecodeFrameCount is set to true 770 framesPerSecond: 25, 771 // turns keyboard support on and off for this instance 772 enableKeyboard: true, 773 // when this player starts, it will pause other players 774 pauseOtherPlayers: true, 775 // array of keyboard commands 776 keyActions: [] 777 778 }); 779 780 setTimeout('eventClickTrigger()', 1000); 781 function eventClickTrigger() { 782 jQuery('video').trigger('click'); 783 // resizeToCover(); 784 } 785 786 // VOVER STYLE 787 var min_w = 300; // minimum video width allowed 788 var vid_w_orig; // original video dimensions 789 var vid_h_orig; 790 791 jQuery(function() { // runs after DOM has loaded 792 vid_w_orig = parseInt(jQuery('video, source').attr('width')); 793 vid_h_orig = parseInt(jQuery('video, source').attr('height')); 794 jQuery(window).resize(function () { resizeToCover(); }); 795 }); 796 797 function resizeToCover() { 798 799 // set the video viewport to the window size 800 jQuery('.video-wrap').width(jQuery(window).width()); 801 jQuery('.video-wrap').height(jQuery(window).height()); 802 803 // use largest scale factor of horizontal/vertical 804 var scale_h = jQuery(window).width() / vid_w_orig; 805 var scale_v = jQuery(window).height() / vid_h_orig; 806 var scale = scale_h > scale_v ? scale_h: scale_v; 807 808 // don't allow scaled width < minimum video width
809 if (scale * vid_w_orig < min_w) {scale = min_w / vid_w_orig;}; 810 811 // now scale the video 812 jQuery('video, source').width(scale * vid_w_orig); 813 jQuery('video, source').height(scale * vid_h_orig); 814 815 // and center it by scrolling the video viewport 816 jQuery('.video-wrap').scrollLeft((jQuery('video').width() - jQuery(window).width()) / 2); 817 jQuery('.video-wrap').scrollTop((jQuery('video').height() - jQuery(window).height()) / 2); 818 } 819 820 } 821 822 823 824/** GOOGLE MAP 825*************************************************** **/ 826 function contactMap() { 827 828 var latLang = new google.maps.LatLng($googlemap_latitude,$googlemap_longitude); 829 830 var mapOptions = { 831 zoom:$googlemap_zoom, 832 center: latLang, 833 disableDefaultUI: false, 834 navigationControl: false, 835 mapTypeControl: false, 836 scrollwheel: false, 837 // styles: styles, 838 mapTypeId: google.maps.MapTypeId.ROADMAP 839 }; 840 841 var map = new google.maps.Map(document.getElementById('gmap'), mapOptions); 842 google.maps.event.trigger(map, 'resize'); 843 map.setZoom( map.getZoom() ); 844 845 var marker = new google.maps.Marker({ 846 icon: 'data:image/png;base64,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', 847 position: latLang, 848 map: map, 849 title: "" 850 }); 851 852 marker.setMap(map); 853 google.maps.event.addListener(marker, "click", function() { 854 // Add optionally an action for when the marker is clicked 855 }); 856 857 // kepp googlemap responsive - center on resize 858 google.maps.event.addDomListener(window, 'resize', function() { 859 map.setCenter(latLang); 860 }); 861 862 } 863 864 865 function showMap(initWhat) { 866 var script = document.createElement('script'); 867 script.type = 'text/javascript'; 868 script.src = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyAa-o8nATJ3xAy02WmmMRnpuoftblojEsU&v=3.exp&sensor=true&callback='+initWhat; 869 document.body.appendChild(script); 870 } 871 872 873 // INIT CONTACT, NLY IF #contactMap EXISRS 874 if(jQuery("#gmap").length > 0) { 875 showMap('contactMap'); 876 } 877 878 879 880/** @Facebook 881*************************************************** **/ 882 /* 883 https://developers.facebook.com/docs/plugins/like-button/ 884 885 ADD TO YOUR CODE (just change data-href, that's all): 886 887 <div class="fb-like" data-href="https://developers.facebook.com/docs/plugins/" data-layout="button_count" data-action="like" data-show-faces="false" data-share="false"></div> 888 */ 889 if(jQuery("div.fb-like").length > 0) { 890 891 jQuery('body').append('<div id="fb-root"></div>'); 892 893 (function(d, s, id) { 894 var js, fjs = d.getElementsByTagName(s)[0]; 895 if (d.getElementById(id)) return; 896 js = d.createElement(s); js.id = id; 897 js.src = "https://connect.facebook.net/en_US/all.js#xfbml=1"; 898 fjs.parentNode.insertBefore(js, fjs); 899 }(document, 'script', 'facebook-jssdk')); 900 901 } 902 903/** @Google Plus 904*************************************************** **/ 905 /* 906 https://developers.google.com/+/web/+1button/ 907 908 <!-- Place this tag where you want the +1 button to render. --> 909 <div class="g-plusone" data-size="medium" data-annotation="inline" data-width="300"></div> 910 */ 911 if(jQuery("div.g-plusone").length > 0) { 912 913 (function() { 914 var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; 915 po.src = 'https://apis.google.com/js/platform.js'; 916 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); 917 })(); 918 919 } 920 921/** @Twitter 922*************************************************** **/ 923 /* 924 https://dev.twitter.com/docs/tweet-button 925 926 <!-- Place this tag where you want the twitter button to render. --> 927 <a href="https://twitter.com/share" class="twitter-share-button" data-lang="en">Tweet</a> 928 */ 929 if(jQuery("a.twitter-share-button").length > 0) { 930 931 !function(d,s,id){ 932 var js,fjs=d.getElementsByTagName(s)[0]; 933 if(!d.getElementById(id)){js=d.createElement(s); 934 js.id=id;js.src="https://platform.twitter.com/widgets.js"; 935 fjs.parentNode.insertBefore(js,fjs);} 936 }(document,"script","twitter-wjs"); 937 938 } 939 940 941 942 943 944/** AFTER RESIZE 945 https://www.mcshaman.com/afterresize-js-jquery-plugin/ 946 **************************************************************** **/ 947 948( function( $ ) { 949 "use strict"; 950 951 // Define default settings 952 var defaults = { 953 action: function() {}, 954 runOnLoad: false, 955 duration: 500 956 }; 957 958 // Define global variables 959 var settings = defaults, 960 running = false, 961 start; 962 963 var methods = {}; 964 965 // Initial plugin configuration 966 methods.init = function() { 967 968 // Allocate passed arguments to settings based on type 969 for( var i = 0; i <= arguments.length; i++ ) { 970 var arg = arguments[i]; 971 switch ( typeof arg ) { 972 case "function": 973 settings.action = arg; 974 break; 975 case "boolean": 976 settings.runOnLoad = arg;
977 break; 978 case "number": 979 settings.duration = arg; 980 break; 981 } 982 } 983 984 // Process each matching jQuery object 985 return this.each(function() { 986 987 if( settings.runOnLoad ) { settings.action(); } 988 989 jQuery(this).resize( function() { 990 991 methods.timedAction.call( this ); 992 993 } ); 994 995 } ); 996 }; 997 998 methods.timedAction = function( code, millisec ) { 999 1000 var doAction = function() { 1001 var remaining = settings.duration; 1002 1003 if( running ) { 1004 var elapse = new Date() - start; 1005 remaining = settings.duration - elapse; 1006 if( remaining <= 0 ) { 1007 // Clear timeout and reset running variable 1008 clearTimeout(running); 1009 running = false; 1010 // Perform user defined function 1011 settings.action(); 1012 1013 return; 1014 } 1015 } 1016 wait( remaining ); 1017 }; 1018 1019 var wait = function( time ) { 1020 running = setTimeout( doAction, time ); 1021 }; 1022 1023 // Define new action starting time 1024 start = new Date(); 1025 1026 // Define runtime settings if function is run directly 1027 if( typeof millisec === 'number' ) { settings.duration = millisec; } 1028 if( typeof code === 'function' ) { settings.action = code; } 1029 1030 // Only run timed loop if not already running 1031 if( !running ) { doAction(); } 1032 1033 }; 1034 1035 1036 $.fn.afterResize = function( method ) { 1037 1038 if( methods[method] ) { 1039 return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) ); 1040 } else { 1041 return methods.init.apply( this, arguments ); 1042 } 1043 1044 }; 1045 1046})(jQuery); 1047 1048 1049 1050 1051/** COUNT TO 1052 https://github.com/mhuggins/jquery-countTo 1053 **************************************************************** **/ 1054 (function ($) { 1055 $.fn.countTo = function (options) { 1056 options = options || {}; 1057 1058 return jQuery(this).each(function () { 1059 // set options for current element 1060 var settings = jQuery.extend({}, $.fn.countTo.defaults, { 1061 from: jQuery(this).data('from'), 1062 to: jQuery(this).data('to'), 1063 speed: jQuery(this).data('speed'), 1064 refreshInterval: jQuery(this).data('refresh-interval'), 1065 decimals: jQuery(this).data('decimals') 1066 }, options); 1067 1068 // how many times to update the value, and how much to increment the value on each update 1069 var loops = Math.ceil(settings.speed / settings.refreshInterval), 1070 increment = (settings.to - settings.from) / loops; 1071 1072 // references & variables that will change with each update 1073 var self = this, 1074 $self = jQuery(this), 1075 loopCount = 0, 1076 value = settings.from, 1077 data = $self.data('countTo') || {}; 1078 1079 $self.data('countTo', data); 1080 1081 // if an existing interval can be found, clear it first 1082 if (data.interval) { 1083 clearInterval(data.interval); 1084 } 1085 data.interval = setInterval(updateTimer, settings.refreshInterval); 1086 1087 // __construct the element with the starting value 1088 render(value); 1089 1090 function updateTimer() { 1091 value += increment; 1092 loopCount++; 1093 1094 render(value); 1095
1096 if (typeof(settings.onUpdate) == 'function') { 1097 settings.onUpdate.call(self, value); 1098 } 1099 1100 if (loopCount >= loops) { 1101 // remove the interval 1102 $self.removeData('countTo'); 1103 clearInterval(data.interval); 1104 value = settings.to; 1105 1106 if (typeof(settings.onComplete) == 'function') { 1107 settings.onComplete.call(self, value); 1108 } 1109 } 1110 } 1111 1112 function render(value) { 1113 var formattedValue = settings.formatter.call(self, value, settings); 1114 $self.html(formattedValue); 1115 } 1116 }); 1117 }; 1118 1119 $.fn.countTo.defaults = { 1120 from: 0, // the number the element should start at 1121 to: 0, // the number the element should end at 1122 speed: 1000, // how long it should take to count between the target numbers 1123 refreshInterval: 100, // how often the element should be updated 1124 decimals: 0, // the number of decimal places to show 1125 formatter: formatter, // handler for formatting the value before rendering 1126 onUpdate: null, // callback method for every time the element is updated 1127 onComplete: null // callback method for when the element finishes updating 1128 }; 1129 1130 function formatter(value, settings) { 1131 return value.toFixed(settings.decimals); 1132 } 1133}(jQuery)); 1134 1135 1136 1137 1138 1139/** FITVIDS 1140 https://fitvidsjs.com/ 1141 **************************************************************** **/ 1142(function( $ ){ 1143 1144 "use strict"; 1145 1146 $.fn.fitVids = function( options ) { 1147 var settings = { 1148 customSelector: null 1149 }; 1150 1151 if(!document.getElementById('fit-vids-style')) { 1152 1153 var div = document.createElement('div'), 1154 ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0]; 1155 1156 div.className = 'fit-vids-style'; 1157 div.id = 'fit-vids-style'; 1158 div.style.display = 'none'; 1159 div.innerHTML = '­<style> \ 1160 .fluid-width-video-wrapper { \ 1161 width: 100%; \ 1162 position: relative; \ 1163 padding: 0; \ 1164 } \ 1165 \ 1166 .fluid-width-video-wrapper iframe, \ 1167 .fluid-width-video-wrapper object, \ 1168 .fluid-width-video-wrapper embed { \ 1169 position: absolute; \ 1170 top: 0; \ 1171 left: 0; \ 1172 width: 100%; \ 1173 height: 100%; \ 1174 } \ 1175 </style>'; 1176 1177 ref.parentNode.insertBefore(div,ref); 1178 1179 } 1180 1181 if ( options ) { 1182 jQuery.extend( settings, options ); 1183 } 1184 1185 return this.each(function(){ 1186 var selectors = [ 1187 "iframe[src*='player.vimeo.com']", 1188 "iframe[src*='youtube.com']", 1189 "iframe[src*='youtube-nocookie.com']", 1190 "iframe[src*='kickstarter.com'][src*='video.html']", 1191 "object", 1192 "embed" 1193 ]; 1194 1195 if (settings.customSelector) { 1196 selectors.push(settings.customSelector); 1197 } 1198 1199 var $allVideos = jQuery(this).find(selectors.join(',')); 1200 $allVideos = $allVideos.not("object object"); // SwfObj conflict patch 1201 1202 $allVideos.each(function(){ 1203 var $_t = jQuery(this); 1204 if (this.tagName.toLowerCase() === 'embed' && $_t.parent('object').length || $_t.parent('.fluid-width-video-wrapper').length) { return; } 1205 var height = ( this.tagName.toLowerCase() === 'object' || ($_t.attr('height') && !isNaN(parseInt($_t.attr('height'), 10))) ) ? parseInt($_t.attr('height'), 10): $_t.height(), 1206 width = !isNaN(parseInt($_t.attr('width'), 10)) ? parseInt($_t.attr('width'), 10): $_t.width(), 1207 aspectRatio = height / width; 1208 if(!$_t.attr('id')){ 1209 var videoID = 'fitvid' + Math.floor(Math.random()*999999); 1210 $_t.attr('id', videoID); 1211 } 1212 $_t.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); 1213 $_t.removeAttr('height').removeAttr('width'); 1214 }); 1215 }); 1216 }; 1217})(jQuery); 1218 1219// remove fitvids for a specific element: jQuery("#myDiv").unFitVids(); 1220jQuery.fn.unFitVids = function () { 1221 var id = jQuery(this).attr("id"); 1222 var $children = jQuery("#" + id + " .fluid-width-video-wrapper").children().clone(); 1223 jQuery("#" + id + " .fluid-width-video-wrapper").remove(); //removes the element 1224 jQuery("#" + id).append($children); //adds it to the parent 1225}; 1226 1227 1228 1229 1230 1231/** WAIT FOR IMAGES [used by masonry] 1232 https://github.com/alexanderdickson/waitForImages 1233 **************************************************************** **/ 1234;(function ($) { 1235 // Namespace all events. 1236 var eventNamespace = 'waitForImages'; 1237 1238 // CSS properties which contain references to images. 1239 $.waitForImages = { 1240 hasImageProperties: ['backgroundImage', 'listStyleImage', 'borderImage', 'borderCornerImage', 'cursor'] 1241 }; 1242 1243 // Custom selector to find `img` elements that have a valid `src` attribute and have not already loaded. 1244 $.expr[':'].uncached = function (obj) { 1245 // Ensure we are dealing with an `img` element with a valid `src` attribute. 1246 if (!$(obj).is('img[src!=""]')) { 1247 return false;
1248 } 1249 1250 // Firefox's `complete` property will always be `true` even if the image has not been downloaded. 1251 // Doing it this way works in Firefox. 1252 var img = new Image(); 1253 img.src = obj.src; 1254 return !img.complete; 1255 }; 1256 1257 $.fn.waitForImages = function (finishedCallback, eachCallback, waitForAll) { 1258 1259 var allImgsLength = 0; 1260 var allImgsLoaded = 0; 1261 1262 // Handle options object. 1263 if ($.isPlainObject(arguments[0])) { 1264 waitForAll = arguments[0].waitForAll; 1265 eachCallback = arguments[0].each; 1266 // This must be last as arguments[0] 1267 // is aliased with finishedCallback. 1268 finishedCallback = arguments[0].finished; 1269 } 1270 1271 // Handle missing callbacks. 1272 finishedCallback = finishedCallback || $.noop; 1273 eachCallback = eachCallback || $.noop; 1274 1275 // Convert waitForAll to Boolean 1276 waitForAll = !! waitForAll; 1277 1278 // Ensure callbacks are functions. 1279 if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { 1280 throw new TypeError('An invalid callback was supplied.'); 1281 } 1282 1283 return this.each(function () { 1284 // Build a list of all imgs, dependent on what images will be considered. 1285 var obj = $(this); 1286 var allImgs = []; 1287 // CSS properties which may contain an image. 1288 var hasImgProperties = $.waitForImages.hasImageProperties || []; 1289 // To match `url()` references. 1290 // Spec: https://www.w3.org/TR/CSS2/syndata.html#value-def-uri 1291 var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; 1292 1293 if (waitForAll) { 1294 1295 // Get all elements (including the original), as any one of them could have a background image. 1296 obj.find('*').addBack().each(function () { 1297 var element = $(this); 1298 1299 // If an `img` element, add it. But keep iterating in case it has a background image too. 1300 if (element.is('img:uncached')) { 1301 allImgs.push({ 1302 src: element.attr('src'), 1303 element: element[0] 1304 }); 1305 } 1306 1307 $.each(hasImgProperties, function (i, property) { 1308 var propertyValue = element.css(property); 1309 var match; 1310 1311 // If it doesn't contain this property, skip. 1312 if (!propertyValue) { 1313 return true; 1314 } 1315 1316 // Get all url() of this element. 1317 while (match = matchUrl.exec(propertyValue)) { 1318 allImgs.push({ 1319 src: match[2], 1320 element: element[0] 1321 }); 1322 } 1323 }); 1324 }); 1325 } else { 1326 // For images only, the task is simpler. 1327 obj.find('img:uncached') 1328 .each(function () { 1329 allImgs.push({ 1330 src: this.src, 1331 element: this 1332 }); 1333 }); 1334 } 1335 1336 allImgsLength = allImgs.length; 1337 allImgsLoaded = 0; 1338 1339 // If no images found, don't bother. 1340 if (allImgsLength === 0) { 1341 finishedCallback.call(obj[0]); 1342 } 1343 1344 $.each(allImgs, function (i, img) { 1345 1346 var image = new Image(); 1347 1348 // Handle the image loading and error with the same callback. 1349 $(image).on('load.' + eventNamespace + ' error.' + eventNamespace, function (event) { 1350 allImgsLoaded++; 1351 1352 // If an error occurred with loading the image, set the third argument accordingly. 1353 eachCallback.call(img.element, allImgsLoaded, allImgsLength, event.type == 'load'); 1354 1355 if (allImgsLoaded == allImgsLength) { 1356 finishedCallback.call(obj[0]); 1357 return false;
1358 } 1359 1360 }); 1361 1362 image.src = img.src; 1363 }); 1364 }); 1365 }; 1366}(jQuery));
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.