1 2var mr = (function ($, window, document){ 3 "use strict"; 4 5 var mr = {}, 6 components = {documentReady: [],documentReadyDeferred: [], windowLoad: [], windowLoadDeferred: []}; 7 8 9 $(document).ready(documentReady); 10 $(window).on("load", windowLoad); 11 12 function documentReady(context){ 13 14 context = typeof context === typeof undefined ? $ : context; 15 components.documentReady.concat(components.documentReadyDeferred).forEach(function(component){ 16 component(context); 17 }); 18 } 19 20 function windowLoad(context){ 21 22 context = typeof context === "object" ? $ : context; 23 components.windowLoad.concat(components.windowLoadDeferred).forEach(function(component){ 24 component(context); 25 }); 26 } 27 28 mr.setContext = function (contextSelector){ 29 var context = $; 30 if(typeof contextSelector !== typeof undefined){ 31 return function(selector){ 32 return $(contextSelector).find(selector); 33 }; 34 } 35 return context; 36 }; 37 38 mr.components = components; 39 mr.documentReady = documentReady; 40 mr.windowLoad = windowLoad; 41 42 return mr; 43}(jQuery, window, document)); 44 45 46//////////////// Utility Functions 47mr = (function (mr, $, window, document){ 48 "use strict"; 49 mr.util = {}; 50 51 mr.util.requestAnimationFrame = window.requestAnimationFrame || 52 window.mozRequestAnimationFrame || 53 window.webkitRequestAnimationFrame || 54 window.msRequestAnimationFrame; 55 56 mr.util.documentReady = function($){ 57 var today = new Date(); 58 var year = today.getFullYear(); 59 $('.update-year').text(year); 60 }; 61 62 mr.util.windowLoad = function($){ 63 $('[data-delay-src]').each(function(){ 64 var $el = $(this); 65 $el.attr('src', $el.attr('data-delay-src')); 66 $el.removeAttr('data-delay-src'); 67 }); 68 }; 69 70 mr.util.getURLParameter = function(name) { 71 return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [undefined, ""])[1].replace(/\+/g, '%20')) || null; 72 }; 73 74 75 mr.util.capitaliseFirstLetter = function(string) { 76 return string.charAt(0).toUpperCase() + string.slice(1); 77 }; 78 79 mr.util.slugify = function(text, spacesOnly){ 80 if(typeof spacesOnly !== typeof undefined){ 81 return text.replace(/ +/g, ''); 82 }else{ 83 return text 84 .toLowerCase() 85 .replace(/[\~\!\@\#\$\%\^\&\*\(\)\-\_\=\+\]\[\}\{\'\"\;\\\:\?\/\>\<\.\,]+/g, '') 86 .replace(/ +/g, '-'); 87 } 88 }; 89 90 mr.util.sortChildrenByText = function(parentElement, reverse){ 91 var $parentElement = $(parentElement); 92 var items = $parentElement.children().get(); 93 var order = -1; 94 var order2 = 1; 95 if(typeof reverse !== typeof undefined){order = 1; order2 = -1;} 96 97 items.sort(function(a,b){ 98 var keyA = $(a).text(); 99 var keyB = $(b).text(); 100 101 if (keyA < keyB) return order; 102 if (keyA > keyB) return order2; 103 return 0; 104 }); 105 106 // Append back into place 107 $parentElement.empty(); 108 $(items).each(function(i, itm){ 109 $parentElement.append(itm); 110 }); 111 }; 112 113 // Set data-src attribute of element from src to be restored later 114 mr.util.idleSrc = function(context, selector){ 115 116 selector = (typeof selector !== typeof undefined) ? selector : ''; 117 var elems = context.is(selector+'[src]') ? context : context.find(selector+'[src]'); 118 119 elems.each(function(index, elem){ 120 elem = $(elem); 121 var currentSrc = elem.attr('src'), 122 dataSrc = elem.attr('data-src'); 123 124 // If there is no data-src, save current source to it 125 if(typeof dataSrc === typeof undefined){ 126 elem.attr('data-src', currentSrc); 127 } 128 129 // Clear the src attribute 130 elem.attr('src', ''); 131 132 }); 133 }; 134 135 // Set src attribute of element from its data-src where it was temporarily stored earlier 136 mr.util.activateIdleSrc = function(context, selector){ 137 138 selector = (typeof selector !== typeof undefined) ? selector : '';
139 var elems = context.is(selector+'[src]') ? context : context.find(selector+'[src]'); 140 141 elems.each(function(index, elem){ 142 elem = $(elem); 143 var dataSrc = elem.attr('data-src'); 144 145 // If there is no data-src, save current source to it 146 if(typeof dataSrc !== typeof undefined){ 147 elem.attr('src', dataSrc); 148 } 149 }); 150 }; 151 152 mr.util.pauseVideo = function(context){ 153 var elems = context.is('video') ? context : context.find('video'); 154 155 elems.each(function(index, video){ 156 var playingVideo = $(video).get(0); 157 playingVideo.pause(); 158 }); 159 }; 160 161 // Take a text value in either px (eg. 150px) or vh (eg. 65vh) and return a number in pixels. 162 mr.util.parsePixels = function(text){ 163 var windowHeight = $(window).height(), value; 164 165 // Text text against regular expression for px value. 166 if(/^[1-9]{1}[0-9]*[p][x]$/.test(text)){ 167 return parseInt(text.replace('px', ''),10); 168 } 169 // Otherwise it is vh value. 170 else if(/^[1-9]{1}[0-9]*[v][h]$/.test(text)){ 171 value = parseInt(text.replace('vh', ''),10); 172 // Return conversion to percentage of window height. 173 return windowHeight * (value/100); 174 }else{ 175 // If it is not proper text, return -1 to indicate bad value. 176 return -1; 177 } 178 }; 179 180 mr.components.documentReady.push(mr.util.documentReady); 181 mr.components.windowLoad.push(mr.util.windowLoad); 182 return mr; 183 184}(mr, jQuery, window, document)); 185 186//////////////// Window Functions 187mr = (function (mr, $, window, document){ 188 "use strict"; 189 190 mr.window = {}; 191 mr.window.height = $(window).height(); 192 mr.window.width = $(window).width(); 193 194 $(window).on('resize',function(){ 195 mr.window.height = $(window).height(); 196 mr.window.width = $(window).width(); 197 }); 198 199 return mr; 200}(mr, jQuery, window, document)); 201 202 203//////////////// Scroll Functions 204mr = (function (mr, $, window, document){ 205 "use strict"; 206 207 208 mr.scroll = {}; 209 var raf = window.requestAnimationFrame || 210 window.mozRequestAnimationFrame || 211 window.webkitRequestAnimationFrame || 212 window.msRequestAnimationFrame; 213 mr.scroll.listeners = []; 214 mr.scroll.busy = false; 215 mr.scroll.y = 0; 216 mr.scroll.x = 0; 217 218 var documentReady = function($){ 219
220 //////////////// Capture Scroll Event and fire scroll function 221 jQuery(window).off('scroll.mr'); 222 jQuery(window).on('scroll.mr', function(evt) { 223 if(mr.scroll.busy === false){ 224 225 mr.scroll.busy = true; 226 raf(function(evt){ 227 mr.scroll.update(evt); 228 }); 229 230 } 231 if(evt.stopPropagation){ 232 evt.stopPropagation(); 233 } 234 }); 235 236 }; 237 238 mr.scroll.update = function(event){ 239 240 // Loop through all mr scroll listeners 241 var parallax = typeof window.mr_parallax !== typeof undefined ? true : false; 242 mr.scroll.y = (parallax ? mr_parallax.mr_getScrollPosition() : window.pageYOffset); 243 mr.scroll.busy = false; 244 if(parallax){ 245 mr_parallax.mr_parallaxBackground(); 246 } 247 248 249 if(mr.scroll.listeners.length > 0){ 250 for (var i = 0, l = mr.scroll.listeners.length; i < l; i++) { 251 mr.scroll.listeners[i](event); 252 } 253 } 254 255 }; 256 257 mr.scroll.documentReady = documentReady; 258 259 mr.components.documentReady.push(documentReady); 260 261 return mr; 262 263}(mr, jQuery, window, document)); 264 265 266//////////////// Scroll Class Modifier 267mr = (function (mr, $, window, document){ 268 "use strict"; 269 270 mr.scroll.classModifiers = {}; 271 // Globally accessible list of elements/rules 272 mr.scroll.classModifiers.rules = []; 273 274 mr.scroll.classModifiers.parseScrollRules = function(element){ 275 var text = element.attr('data-scroll-class'), 276 rules = text.split(";"); 277
278 rules.forEach(function(rule){ 279 var ruleComponents, scrollPoint, ruleObject = {}; 280 ruleComponents = rule.replace(/\s/g, "").split(':'); 281 if(ruleComponents.length === 2){ 282 scrollPoint = mr.util.parsePixels(ruleComponents[0]); 283 if(scrollPoint > -1){ 284 ruleObject.scrollPoint = scrollPoint; 285 if(ruleComponents[1].length){ 286 var toggleClass = ruleComponents[1]; 287 ruleObject.toggleClass = toggleClass; 288 // Set variable in object to indicate that element already has class applied 289 ruleObject.hasClass = element.hasClass(toggleClass); 290 ruleObject.element = element.get(0); 291 mr.scroll.classModifiers.rules.push(ruleObject); 292 }else{ 293 // Error: toggleClass component does not exist. 294 //console.log('Error - toggle class not found.'); 295 return false; 296 } 297 }else{ 298 // Error: scrollpoint component was malformed 299 //console.log('Error - Scrollpoint not found.'); 300 return false; 301 } 302 } 303 }); 304 305 if(mr.scroll.classModifiers.rules.length){ 306 return true; 307 }else{ 308 return false; 309 } 310 }; 311 312 mr.scroll.classModifiers.update = function(event){ 313 var currentScroll = mr.scroll.y, 314 scrollRules = mr.scroll.classModifiers.rules, 315 l = scrollRules.length, 316 currentRule; 317 318 // Given the current scrollPoint, check for necessary changes 319 while(l--) { 320 321 currentRule = scrollRules[l]; 322 323 if(currentScroll > currentRule.scrollPoint && !currentRule.hasClass){ 324 // Set local copy and glogal copy at the same time; 325 currentRule.element.classList.add(currentRule.toggleClass); 326 currentRule.hasClass = mr.scroll.classModifiers.rules[l].hasClass = true; 327 } 328 if(currentScroll < currentRule.scrollPoint && currentRule.hasClass){ 329 // Set local copy and glogal copy at the same time; 330 currentRule.element.classList.remove(currentRule.toggleClass); 331 currentRule.hasClass = mr.scroll.classModifiers.rules[l].hasClass = false; 332 } 333 } 334 }; 335 336 var fixedElementSizes = function(){ 337 $('.main-container [data-scroll-class*="pos-fixed"]').each(function(){ 338 var element = $(this); 339 element.css('max-width',element.parent().outerWidth()); 340 element.parent().css('min-height',element.outerHeight()); 341 }); 342 }; 343 344 var documentReady = function($){ 345 // Collect info on all elements that require class modification at load time 346 // Each element has data-scroll-class with a formatted value to represent class to add/remove at a particular scroll point. 347 $('[data-scroll-class]').each(function(){ 348 var element = $(this); 349 350 // Test the rules to be added to an array of rules. 351 if(!mr.scroll.classModifiers.parseScrollRules(element)){ 352 console.log('Error parsing scroll rules on: '+element); 353 } 354 }); 355 356 // For 'position fixed' elements, give them a max-width for correct fixing behaviour 357 fixedElementSizes(); 358 $(window).on('resize', fixedElementSizes); 359 360 // If there are valid scroll rules add classModifiers update function to the scroll event processing queue. 361 if(mr.scroll.classModifiers.rules.length){ 362 mr.scroll.listeners.push(mr.scroll.classModifiers.update); 363 } 364 }; 365 366 mr.components.documentReady.push(documentReady); 367 mr.scroll.classModifiers.documentReady = documentReady; 368 369 370 371 return mr; 372 373}(mr, jQuery, window, document)); 374 375 376//////////////// Accordions 377mr = (function (mr, $, window, document){ 378 "use strict"; 379 380 mr.accordions = {}; 381 382 383 mr.accordions.documentReady = function($){ 384 $('.accordion__title').on('click', function(){ 385 mr.accordions.activatePanel($(this)); 386 }); 387 388 $('.accordion').each(function(){ 389 var accordion = $(this); 390 var minHeight = accordion.outerHeight(true); 391 accordion.css('min-height',minHeight); 392 }); 393 394 if(window.location.hash !== ''){ 395 mr.accordions.activatePanelById(window.location.hash, true); 396 } 397 398 $('a[href^="#"]').on('click', function(){ 399 mr.accordions.activatePanelById($(this).attr('href'), true); 400 }); 401 }; 402 403 404 405 mr.accordions.activatePanel = function(panel, forceOpen){ 406 var $panel = $(panel), 407 accordion = $panel.closest('.accordion'), 408 li = $panel.closest('li'), 409 openEvent = document.createEvent('Event'), 410 closeEvent = document.createEvent('Event'); 411 412 openEvent.initEvent('panelOpened.accordions.mr', true, true); 413 closeEvent.initEvent('panelClosed.accordions.mr', true, true); 414 415 if(li.hasClass('active')){ 416 if(forceOpen !== true){ 417 li.removeClass('active'); 418 $panel.trigger('panelClosed.accordions.mr').get(0).dispatchEvent(closeEvent); 419 } 420 }else{ 421 if(accordion.hasClass('accordion--oneopen')){ 422 var wasActive = accordion.find('li.active'); 423 wasActive.removeClass('active'); 424 wasActive.trigger('panelClosed.accordions.mr').get(0).dispatchEvent(closeEvent); 425 li.addClass('active'); 426 li.trigger('panelOpened.accordions.mr').get(0).dispatchEvent(openEvent); 427 428 }else{ 429 if(!li.is('.active')){ 430 li.trigger('panelOpened.accordions.mr').get(0).dispatchEvent(openEvent); 431 } 432 li.addClass('active'); 433 } 434 } 435 } 436 437 mr.accordions.activatePanelById = function(id, forceOpen){ 438 var panel; 439 440 if(id !== '' && id !== '#'){ 441 panel = $('.accordion > li > .accordion__title#'+id.replace('#', '')); 442 if(panel.length){ 443 $('html, body').stop(true).animate({ 444 scrollTop: (panel.offset().top - 50) 445 }, 1200); 446 mr.accordions.activatePanel(panel, forceOpen); 447 } 448 } 449 }; 450 451 mr.components.documentReady.push(mr.accordions.documentReady); 452 return mr; 453 454}(mr, jQuery, window, document)); 455 456
457//////////////// Alerts 458mr = (function (mr, $, window, document){ 459 "use strict"; 460 461 var documentReady = function($){ 462 $('.alert__close').on('click touchstart', function(){ 463 jQuery(this).closest('.alert').addClass('alert--dismissed'); 464 }); 465 }; 466 467 mr.alerts = { 468 documentReady : documentReady 469 }; 470 471 mr.components.documentReady.push(documentReady); 472 return mr; 473 474}(mr, jQuery, window, document)); 475 476 477//////////////// Backgrounds 478mr = (function (mr, $, window, document){ 479 "use strict"; 480 481 var documentReady = function($){ 482 483 //////////////// Append .background-image-holder <img>'s as CSS backgrounds 484 485 $('.background-image-holder').each(function() { 486 var imgSrc = $(this).children('img').attr('src'); 487 $(this).css('background', 'url("' + imgSrc + '")').css('background-position', 'initial').css('opacity','1'); 488 }); 489 }; 490 491 mr.backgrounds = { 492 documentReady : documentReady 493 }; 494 495 mr.components.documentReady.push(documentReady); 496 return mr; 497 498}(mr, jQuery, window, document)); 499 500//////////////// Bars 501mr = (function (mr, $, window, document){ 502 "use strict"; 503 504 var documentReady = function($){ 505 $('.nav-container .bar[data-scroll-class*="fixed"]:not(.bar--absolute)').each(function(){ 506 var bar = $(this), 507 barHeight = bar.outerHeight(true); 508 bar.closest('.nav-container').css('min-height',barHeight); 509 }); 510 }; 511 512 mr.bars = { 513 documentReady : documentReady 514 }; 515 516 mr.components.documentReady.push(documentReady); 517 return mr; 518 519}(mr, jQuery, window, document)); 520 521//////////////// Cookies 522mr = (function (mr, $, window, document){ 523 "use strict"; 524 525 mr.cookies = { 526 527 getItem: function (sKey) { 528 if (!sKey) { return null; } 529 return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; 530 }, 531 setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { 532 if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } 533 var sExpires = ""; 534 if (vEnd) { 535 switch (vEnd.constructor) { 536 case Number: 537 sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; 538 break; 539 case String: 540 sExpires = "; expires=" + vEnd; 541 break; 542 case Date: 543 sExpires = "; expires=" + vEnd.toUTCString(); 544 break; 545 } 546 } 547 document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); 548 return true; 549 }, 550 removeItem: function (sKey, sPath, sDomain) { 551 if (!this.hasItem(sKey)) { return false; } 552 document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); 553 return true; 554 }, 555 hasItem: function (sKey) { 556 if (!sKey) { return false; } 557 return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); 558 }, 559 keys: function () { 560 var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); 561 for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); } 562 return aKeys; 563 } 564 }; 565 566 return mr; 567 568}(mr, jQuery, window, document)); 569 570//////////////// Countdown 571mr = (function (mr, $, window, document){ 572 "use strict"; 573 574 var documentReady = function($){ 575 576 $('.countdown[data-date]').each(function(){ 577 var element = $(this), 578 date = element.attr('data-date'), 579 daysText = "days", 580 fallback; 581 582 if(typeof element.attr('data-date-fallback') !== typeof undefined){ 583 fallback = element.attr('data-date-fallback'); 584 } 585 586 if(typeof element.attr('data-days-text') !== typeof undefined){ 587 daysText = element.attr('data-days-text'); 588 } 589 590 element.countdown(date, function(event) { 591 if(event.elapsed){ 592 element.text(fallback); 593 }else{ 594 element.text( 595 event.strftime('%D '+daysText+' %H:%M:%S') 596 ); 597 } 598 }); 599 }); 600 601 }; 602 603 mr.countdown = { 604 documentReady : documentReady 605 }; 606 607 mr.components.documentReadyDeferred.push(documentReady); 608 return mr; 609 610}(mr, jQuery, window, document)); 611 612//////////////// Datepicker 613mr = (function (mr, $, window, document){ 614 "use strict"; 615 616 var documentReady = function($){ 617 if($('.datepicker').length){ 618 $('.datepicker').pickadate(); 619 } 620 }; 621 622 mr.components.documentReadyDeferred.push(documentReady); 623 return mr; 624 625}(mr, jQuery, window, document)); 626 627//////////////// Dropdowns 628mr = (function (mr, $, window, document){ 629 "use strict"; 630 mr.dropdowns = {}; 631 mr.dropdowns.done = false;
632 633 var documentReady = function($){ 634 635 var rtl = false; 636 637 if($('html[dir="rtl"]').length){ 638 rtl = true; 639 } 640 641 if(!mr.dropdowns.done){ 642 jQuery(document).on('click','body:not(.dropdowns--hover) .dropdown:not(.dropdown--hover), body.dropdowns--hover .dropdown.dropdown--click',function(event){ 643 var dropdown = jQuery(this); 644 if(jQuery(event.target).is('.dropdown--active > .dropdown__trigger')){ 645 dropdown.siblings().removeClass('dropdown--active').find('.dropdown').removeClass('dropdown--active'); 646 dropdown.toggleClass('dropdown--active'); 647 }else{ 648 $('.dropdown--active').removeClass('dropdown--active'); 649 dropdown.addClass('dropdown--active'); 650 } 651 }); 652 jQuery(document).on('click touchstart', 'body:not(.dropdowns--hover)', function(event){ 653 if(!jQuery(event.target).is('[class*="dropdown"], [class*="dropdown"] *')){ 654 $('.dropdown--active').removeClass('dropdown--active'); 655 } 656 }); 657 jQuery('body.dropdowns--hover .dropdown').on('click', function(event){ 658 event.stopPropagation(); 659 var hoverDropdown = jQuery(this); 660 hoverDropdown.toggleClass('dropdown--active'); 661 }); 662 663 // Append a container to the body for measuring purposes 664 jQuery('body').append('<div class="container containerMeasure" style="opacity:0;pointer-events:none;"></div>'); 665 666 667 668 669 // Menu dropdown positioning 670 if(rtl === false){ 671 repositionDropdowns($); 672 jQuery(window).on('resize', function(){repositionDropdowns($);}); 673 }else{ 674 repositionDropdownsRtl($); 675 jQuery(window).on('resize', function(){repositionDropdownsRtl($);}); 676 } 677 678 mr.dropdowns.done = true; 679 } 680 }; 681 682 function repositionDropdowns($){ 683 $('.dropdown__container').each(function(){ 684 var container, containerOffset, masterOffset, menuItem, content; 685 686 jQuery(this).css('left', ''); 687 688 container = jQuery(this); 689 containerOffset = container.offset().left; 690 masterOffset = jQuery('.containerMeasure').offset().left; 691 menuItem = container.closest('.dropdown').offset().left; 692 content = null; 693 694 container.css('left',((-containerOffset)+(masterOffset))); 695 696 if(container.find('.dropdown__content:not([class*="md-12"])').length){ 697 content = container.find('.dropdown__content'); 698 content.css('left', ((menuItem)-(masterOffset))); 699 } 700 701 }); 702 $('.dropdown__content').each(function(){ 703 var dropdown, offset, width, offsetRight, winWidth, leftCorrect; 704 705 dropdown = jQuery(this); 706 offset = dropdown.offset().left; 707 width = dropdown.outerWidth(true); 708 offsetRight = offset + width; 709 winWidth = jQuery(window).outerWidth(true); 710 leftCorrect = jQuery('.containerMeasure').outerWidth() - width; 711 712 if(offsetRight > winWidth){ 713 dropdown.css('left', leftCorrect); 714 } 715 716 }); 717 } 718 719 function repositionDropdownsRtl($){ 720 721 var windowWidth = jQuery(window).width(); 722 723 $('.dropdown__container').each(function(){ 724 var container, containerOffset, masterOffset, menuItem, content; 725 726 jQuery(this).css('left', ''); 727 728 container = jQuery(this); 729 containerOffset = windowWidth - (container.offset().left + container.outerWidth(true)); 730 masterOffset = jQuery('.containerMeasure').offset().left; 731 menuItem = windowWidth - (container.closest('.dropdown').offset().left + container.closest('.dropdown').outerWidth(true)); 732 content = null; 733 734 container.css('right',((-containerOffset)+(masterOffset))); 735 736 if(container.find('.dropdown__content:not([class*="md-12"])').length){ 737 content = container.find('.dropdown__content'); 738 content.css('right', ((menuItem)-(masterOffset))); 739 } 740 }); 741 $('.dropdown__content').each(function(){ 742 var dropdown, offset, width, offsetRight, winWidth, rightCorrect; 743 744 dropdown = jQuery(this); 745 offset = windowWidth - (dropdown.offset().left + dropdown.outerWidth(true)); 746 width = dropdown.outerWidth(true); 747 offsetRight = offset + width; 748 winWidth = jQuery(window).outerWidth(true); 749 rightCorrect = jQuery('.containerMeasure').outerWidth() - width; 750 751 if(offsetRight > winWidth){ 752 dropdown.css('right', rightCorrect); 753 } 754 755 }); 756 } 757 758 mr.dropdowns.documentReady = documentReady; 759 760 761 mr.components.documentReady.push(documentReady); 762 return mr; 763 764}(mr, jQuery, window, document)); 765 766//////////////// Forms 767 768mr = (function (mr, $, window, document){ 769 "use strict"; 770 771 mr.forms = {}; 772 mr.forms.captcha = {}; 773 mr.forms.captcha.widgets = []; 774 mr.forms.captcha.done = false;
775 776 var documentReady = function($){ 777 778 mr.forms.captcha.widgets = []; 779 780 /// Checkbox & Radio Inputs 781 782 $('.input-checkbox input[type="checkbox"], .input-radio input[type="radio"]').each(function(index){ 783 var input = $(this), 784 label = input.siblings('label'), 785 id = "input-assigned-"+index; 786 if(typeof input.attr('id') === typeof undefined || input.attr('id') === ""){ 787 input.attr('id',id); 788 label.attr('for',id); 789 }else{ 790 id = input.attr('id'); 791 label.attr('for',id); 792 } 793 }); 794 795 //////////////// Number Inputs 796 797 $('.input-number__controls > span').off('click.mr').on('click.mr',function(){ 798 var control = jQuery(this), 799 parent = control.closest('.input-number'), 800 input = parent.find('input[type="number"]'), 801 max = input.attr('max'), 802 min = input.attr('min'), 803 step = 1, 804 current = parseInt(input.attr('value'),10); 805 806 if(parent.is('[data-step]')){ 807 step = parseInt(parent.attr('data-step'),10); 808 } 809 810 if(control.hasClass('input-number__increase')){ 811 if((current+step) <= max){ 812 input.attr('value',current+step); 813 } 814 }else{ 815 if((current-step) >= min){ 816 input.attr('value',current-step); 817 } 818 } 819 }); 820 821
822 //////////////// File Uploads 823 824 $('.input-file .btn').off('click.mr').on('click.mr',function(){ 825 $(this).siblings('input').trigger('click'); 826 return false; 827 }); 828 829 //////////////// Handle Form Submit 830 831 $('form.form-email, form[action*="list-manage.com"], form[action*="createsend.com"]').attr('novalidate', true).off('submit').on('submit', mr.forms.submit); 832 833 //////////////// Handle Form Submit 834 $(document).on('change, input, paste, keyup', '.attempted-submit .field-error', function(){ 835 $(this).removeClass('field-error'); 836 }); 837 838 //////////////// Check forms for Google reCaptcha site keys 839 840 $('form[data-recaptcha-sitekey]:not([data-recaptcha-sitekey=""])').each(function(){ 841 var $thisForm = jQuery(this), 842 $captchaDiv = $thisForm.find('div.recaptcha'), 843 $insertBefore, $column, widgetObject, $script, scriptSrc, widgetColourTheme, widgetSize; 844 845 widgetColourTheme = $thisForm.attr('data-recaptcha-theme'); 846 widgetColourTheme = typeof widgetColourTheme !== typeof undefined ? widgetColourTheme : ''; 847 848 widgetSize = $thisForm.attr('data-recaptcha-size'); 849 widgetSize = typeof widgetSize !== typeof undefined ? widgetSize : ''; 850 851 // Store the site key for later use 852 mr.forms.captcha.sitekey = $thisForm.attr('data-recaptcha-sitekey'); 853 854 if($captchaDiv.length){ 855 // If a div.recaptcha was already present on this form, do nothing at this stage, 856 // It will be populated with a captcha widget later. 857 }else{ 858 // Create a captcha div and insert it before the submit button. 859 $insertBefore = $thisForm.find('button[type=submit]').closest('[class*="col-"]'); 860 $captchaDiv = jQuery('<div>').addClass('recaptcha'); 861 $column = jQuery('<div>').addClass('col-xs-12').append($captchaDiv); 862 $column.insertBefore($insertBefore); 863 } 864 865 866 // Add the widget div to the widgets array 867 widgetObject = { 868 element: $captchaDiv.get(0), 869 parentForm: $thisForm, 870 theme: widgetColourTheme, 871 size: widgetSize, 872 }; 873 874 875 876 mr.forms.captcha.widgets.push(widgetObject); 877 878 // mr.forms.captcha.done indicates whether the api script has been appended yet. 879 if(mr.forms.captcha.done === false){ 880 if(!jQuery('script[src*="recaptcha/api.js"]').length){ 881 $script = jQuery('<script async defer>'); 882 scriptSrc = 'https://www.google.com/recaptcha/api.js?onload=mrFormsCaptchaInit&render=explicit'; 883 $script.attr('src', scriptSrc); 884 jQuery('body').append($script); 885 mr.forms.captcha.done = true; 886 } 887 }else{ 888 if(typeof grecaptcha !== typeof undefined){ 889 mr.forms.captcha.renderWidgets(); 890 } 891 } 892 893 }); 894 895 896 }; 897 898 mr.forms.documentReady = documentReady; 899 900 901 902 903 mr.forms.submit = function(e){ 904 // return false so form submits through jQuery rather than reloading page. 905 if (e.preventDefault) e.preventDefault(); 906 else e.returnValue = false; 907 908 var body = $('body'), 909 thisForm = $(e.target).closest('form'), 910 formAction = typeof thisForm.attr('action') !== typeof undefined ? thisForm.attr('action') : "", 911 submitButton = thisForm.find('button[type="submit"], input[type="submit"]'), 912 error = 0, 913 originalError = thisForm.attr('original-error'), 914 captchaUsed = thisForm.find('div.recaptcha').length ? true:false, 915 successRedirect, formError, formSuccess, errorText, successText; 916 917 body.find('.form-error, .form-success').remove(); 918 submitButton.attr('data-text', submitButton.text()); 919 errorText = thisForm.attr('data-error') ? thisForm.attr('data-error') : "Please fill all fields correctly"; 920 successText = thisForm.attr('data-success') ? thisForm.attr('data-success') : "Thanks, we'll be in touch shortly"; 921 body.append('<div class="form-error" style="display: none;">' + errorText + '</div>'); 922 body.append('<div class="form-success" style="display: none;">
922' + successText + '</div>'); 923 formError = body.find('.form-error'); 924 formSuccess = body.find('.form-success'); 925 thisForm.addClass('attempted-submit'); 926 927 // Do this if the form is intended to be submitted to MailChimp or Campaign Monitor 928 if (formAction.indexOf('createsend.com') !== -1 || formAction.indexOf('list-manage.com') !== -1 ) { 929 930 console.log('Mail list form signup detected.'); 931 if (typeof originalError !== typeof undefined && originalError !== false) { 932 formError.html(originalError); 933 } 934 935 // validateFields returns 1 on error; 936 if (mr.forms.validateFields(thisForm) !== 1) { 937 938 thisForm.removeClass('attempted-submit'); 939 940 // Hide the error if one was shown 941 formError.fadeOut(200); 942 // Create a new loading spinner in the submit button. 943 submitButton.addClass('btn--loading'); 944 945 try{ 946 $.ajax({ 947 url: thisForm.attr('action'), 948 crossDomain: true, 949 data: thisForm.serialize(), 950 method: "GET", 951 cache: false, 952 dataType: 'json', 953 contentType: 'application/json; charset=utf-8', 954 success: function(data){ 955 // Request was a success, what was the response? 956 957 if (data.result !== "success" && data.Status !== 200) { 958 959 // Got an error from Mail Chimp or Campaign Monitor 960 961 // Keep the current error text in a data attribute on the form 962 formError.attr('original-error', formError.text()); 963 // Show the error with the returned error text. 964 formError.html(data.msg).stop(true).fadeIn(1000); 965 formSuccess.stop(true).fadeOut(1000); 966 967 submitButton.removeClass('btn--loading'); 968 } else { 969 970 // Got success from Mail Chimp or Campaign Monitor 971 972 submitButton.removeClass('btn--loading'); 973 974 successRedirect = thisForm.attr('data-success-redirect'); 975 // For some browsers, if empty `successRedirect` is undefined; for others, 976 // `successRedirect` is false. Check for both. 977 if (typeof successRedirect !== typeof undefined && successRedirect !== false && successRedirect !== "") { 978 window.location = successRedirect; 979 }else{ 980 mr.forms.resetForm(thisForm); 981 mr.forms.showFormSuccess(formSuccess, formError, 1000, 5000, 500); 982 } 983 } 984 } 985 }); 986 }catch(err){ 987 // Keep the current error text in a data attribute on the form 988 formError.attr('original-error', formError.text()); 989 // Show the error with the returned error text. 990 formError.html(err.message); 991 mr.forms.showFormError(formSuccess, formError, 1000, 5000, 500); 992 993 submitButton.removeClass('btn--loading'); 994 } 995 996 997 998 } else { 999 // There was a validation error - show the default form error message 1000 mr.forms.showFormError(formSuccess, formError, 1000, 5000, 500); 1001 } 1002 } else { 1003 // If no MailChimp or Campaign Monitor form was detected then this is treated as an email form instead. 1004 if (typeof originalError !== typeof undefined && originalError !== false) { 1005 formError.text(originalError); 1006 } 1007 1008 error = mr.forms.validateFields(thisForm); 1009 1010 if (error === 1) { 1011 mr.forms.showFormError(formSuccess, formError, 1000, 5000, 500); 1012 } else { 1013 1014 thisForm.removeClass('attempted-submit'); 1015 1016 // Hide the error if one was shown 1017 formError.fadeOut(200); 1018 1019 // Create a new loading spinner in the submit button. 1020 submitButton.addClass('btn--loading'); 1021 1022 jQuery.ajax({ 1023 type: "POST", 1024 url: "mail/mail.php", 1025 data: thisForm.serialize()+"&url="+window.location.href+"&captcha="+captchaUsed, 1026 success: function(response) { 1027 // Swiftmailer always sends back a number representing number of emails sent. 1028 // If this is numeric (not Swift Mailer error text) AND greater than 0 then show success message. 1029 1030 submitButton.removeClass('btn--loading'); 1031 1032 if ($.isNumeric(response)) { 1033 if (parseInt(response,10) > 0) { 1034 // For some browsers, if empty 'successRedirect' is undefined; for others, 1035 // 'successRedirect' is false. Check for both. 1036 successRedirect = thisForm.attr('data-success-redirect'); 1037 if (typeof successRedirect !== typeof undefined && successRedirect !== false && successRedirect !== "") { 1038 window.location = successRedirect; 1039 } 1040 1041 mr.forms.resetForm(thisForm); 1042 mr.forms.showFormSuccess(formSuccess, formError, 1000, 5000, 500); 1043 mr.forms.captcha.resetWidgets(); 1044 } 1045 } 1046 // If error text was returned, put the text in the .form-error div and show it. 1047 else { 1048 // Keep the current error text in a data attribute on the form 1049 formError.attr('original-error', formError.text()); 1050 // Show the error with the returned error text. 1051 formError.text(response).stop(true).fadeIn(1000); 1052 formSuccess.stop(true).fadeOut(1000); 1053 } 1054 }, 1055 error: function(errorObject, errorText, errorHTTP) { 1056 // Keep the current error text in a data attribute on the form 1057 formError.attr('original-error', formError.text()); 1058 // Show the error with the returned error text. 1059 formError.text(errorHTTP).stop(true).fadeIn(1000); 1060 formSuccess.stop(true).fadeOut(1000); 1061 submitButton.removeClass('btn--loading'); 1062 } 1063 }); 1064 } 1065 } 1066 return false;
1067 }; 1068 1069 mr.forms.validateFields = function(form) { 1070 var body = $(body), 1071 error = false, 1072 originalErrorMessage, 1073 name, 1074 thisElement; 1075 1076 form = $(form); 1077 1078 1079 1080 1081 form.find('.validate-required[type="checkbox"]').each(function() { 1082 var checkbox = $(this); 1083 if (!$('[name="' + $(this).attr('name') + '"]:checked').length) { 1084 error = 1; 1085 name = $(this).attr('data-name') || 'check'; 1086 checkbox.parent().addClass('field-error'); 1087 //body.find('.form-error').text('Please tick at least one ' + name + ' box.'); 1088 } 1089 }); 1090 1091 form.find('.validate-required, .required, [required]').not('input[type="checkbox"]').each(function() { 1092 if ($(this).val() === '') { 1093 $(this).addClass('field-error'); 1094 error = 1; 1095 } else { 1096 $(this).removeClass('field-error'); 1097 } 1098 }); 1099 1100 form.find('.validate-email, .email, [name*="cm-"][type="email"]').each(function() { 1101 if (!(/(.+)@(.+){2,}\.(.+){2,}/.test($(this).val()))) { 1102 $(this).addClass('field-error'); 1103 error = 1; 1104 } else { 1105 $(this).removeClass('field-error'); 1106 } 1107 }); 1108 1109 form.find('.validate-number-dash').each(function() { 1110 if (!(/^[0-9][0-9-]+[0-9]$/.test($(this).val()))) { 1111 $(this).addClass('field-error'); 1112 error = 1; 1113 } else { 1114 $(this).removeClass('field-error'); 1115 } 1116 }); 1117 1118 // Validate recaptcha 1119 if(form.find('div.recaptcha').length && typeof form.attr('data-recaptcha-sitekey') !== typeof undefined){ 1120 thisElement = $(form.find('div.recaptcha')); 1121 1122 if(grecaptcha.getResponse(form.data('recaptchaWidgetID')) !== ""){ 1123 thisElement.removeClass('field-error'); 1124 }else{ 1125 thisElement.addClass('field-error'); 1126 error = 1; 1127 } 1128 } 1129 1130 if (!form.find('.field-error').length) { 1131 body.find('.form-error').fadeOut(1000); 1132 }else{ 1133 1134 var firstError = $(form).find('.field-error:first'); 1135 1136 if(firstError.length){ 1137 $('html, body').stop(true).animate({ 1138 scrollTop: (firstError.offset().top - 100) 1139 }, 1200, function(){firstError.focus();}); 1140 } 1141 } 1142 1143 1144 1145 return error; 1146 }; 1147 1148 mr.forms.showFormSuccess = function(formSuccess, formError, fadeOutError, wait, fadeOutSuccess){ 1149 1150 formSuccess.stop(true).fadeIn(fadeOutError); 1151 1152 formError.stop(true).fadeOut(fadeOutError); 1153 setTimeout(function() { 1154 formSuccess.stop(true).fadeOut(fadeOutSuccess); 1155 }, wait); 1156 }; 1157 1158 mr.forms.showFormError = function(formSuccess, formError, fadeOutSuccess, wait, fadeOutError){ 1159 1160 formError.stop(true).fadeIn(fadeOutSuccess); 1161 1162 formSuccess.stop(true).fadeOut(fadeOutSuccess); 1163 setTimeout(function() { 1164 formError.stop(true).fadeOut(fadeOutError); 1165 }, wait); 1166 }; 1167 1168 // Reset form to empty/default state. 1169 mr.forms.resetForm = function(form){ 1170 form = $(form); 1171 form.get(0).reset(); 1172 form.find('.input-radio, .input-checkbox').removeClass('checked'); 1173 1174 }; 1175 1176 // Defined on the window scope as the recaptcha js api seems not to be able to call function in mr scope 1177 window.mrFormsCaptchaInit = function(){ 1178 mr.forms.captcha.renderWidgets(); 1179 }; 1180 1181 mr.forms.captcha.renderWidgets = function(){ 1182 mr.forms.captcha.widgets.forEach(function(widget){ 1183 if(widget.element.innerHTML === ''){ 1184 widget.id = grecaptcha.render(widget.element, { 1185 'sitekey' : mr.forms.captcha.sitekey, 1186 'theme' : widget.theme, 1187 'size' : widget.size, 1188 'callback' : mr.forms.captcha.setHuman 1189 }); 1190 widget.parentForm.data('recaptchaWidgetID', widget.id); 1191 } 1192 }); 1193 }; 1194 1195 mr.forms.captcha.resetWidgets = function(){
1196 mr.forms.captcha.widgets.forEach(function(widget){ 1197 grecaptcha.reset(widget.id); 1198 }); 1199 }; 1200 1201 mr.forms.captcha.setHuman = function(){ 1202 jQuery('div.recaptcha.field-error').removeClass('field-error'); 1203 }; 1204 1205 mr.components.documentReadyDeferred.push(documentReady); 1206 return mr; 1207 1208}(mr, jQuery, window, document)); 1209 1210//////////////// Granim 1211mr = (function (mr, $, window, document){ 1212 "use strict"; 1213 1214 var documentReady = function($){ 1215 $('[data-gradient-bg]').each(function(index,element){ 1216 var granimParent = $(this), 1217 granimID = 'granim-'+index+'', 1218 colours = granimParent.attr('data-gradient-bg'), 1219 pairs = [], 1220 tempPair = [], 1221 count, 1222 passes, 1223 i; 1224 1225 // Canvas element forms the gradient background 1226 granimParent.prepend('<canvas id="'+granimID+'"></canvas>'); 1227 1228 // Regular expression to match comma separated list of hex colour values 1229 passes = /^(#[0-9|a-f|A-F]{6}){1}([ ]*,[ ]*#[0-9|a-f|A-F]{6})*$/.test(colours); 1230 1231 if(passes === true){ 1232 colours = colours.replace(' ',''); 1233 colours = colours.split(','); 1234 count = colours.length; 1235 // If number of colours is odd - duplicate last colour to make even array 1236 if(count%2 !== 0){ 1237 colours.push(colours[count-1]); 1238 } 1239 for(i = 0; i < (count/2); i++){ 1240 tempPair = []; 1241 tempPair.push(colours.shift()); 1242 tempPair.push(colours.shift()); 1243 pairs.push(tempPair); 1244 } 1245 } 1246 1247 var granimElement = $(this); 1248 var granimInstance = new Granim({ 1249 element: '#'+granimID, 1250 name: 'basic-gradient', 1251 direction: 'left-right', 1252 opacity: [1, 1], 1253 isPausedWhenNotInView: true, 1254 states : { 1255 "default-state": { 1256 gradients: pairs 1257 } 1258 } 1259 }); 1260 }); 1261 }; 1262 1263 mr.granim = { 1264 documentReady : documentReady 1265 }; 1266 1267 mr.components.documentReadyDeferred.push(documentReady); 1268 return mr; 1269 1270}(mr, jQuery, window, document)); 1271 1272//////////////// Instagram 1273mr = (function (mr, $, window, document){ 1274 "use strict"; 1275 1276 var documentReady = function($){ 1277 1278 if($('.instafeed').length){ 1279 1280 // Replace with your own Access Token and Client ID 1281 var token = '4079540202.b9b1d8a.1d13c245c68d4a17bfbff87919aaeb14', 1282 client = 'b9b1d8ae049d4153b24a6332f0088686', 1283 elementToken, elementClient; 1284 1285 if($('.instafeed[data-access-token][data-client-id]').length){ 1286 elementToken = $('.instafeed[data-access-token][data-client-id]').first().attr('data-access-token'); 1287 elementClient = $('.instafeed[data-access-token][data-client-id]').first().attr('data-client-id'); 1288 1289 if(elementToken !== ""){token = elementToken;} 1290 if(elementClient !== ""){client = elementClient;} 1291 } 1292 1293 jQuery.fn.spectragram.accessData = { 1294 accessToken: token, 1295 clientID: client 1296 }; 1297 } 1298 1299 $('.instafeed').each(function(){ 1300 var feed = $(this), 1301 feedID = feed.attr('data-user-name'), 1302 fetchNumber = 12; 1303 if(typeof feed.attr('data-amount') !== typeof undefined){ 1304 fetchNumber = parseInt(feed.attr('data-amount'), 10); 1305 } 1306 feed.append('<ul></ul>'); 1307 feed.children('ul').spectragram('getUserFeed', { 1308 query: feedID, 1309 max: fetchNumber 1310 }); 1311 }); 1312 }; 1313 1314 mr.instagram = { 1315 documentReady : documentReady 1316 }; 1317 1318 mr.components.documentReadyDeferred.push(documentReady); 1319 return mr; 1320 1321}(mr, jQuery, window, document)); 1322 1323//////////////// Maps 1324mr = (function (mr, $, window, document){ 1325 "use strict"; 1326 1327 mr.maps = {}; 1328 1329 var documentReady = function($){ 1330 // Interact with Map once the user has clicked (to prevent scrolling the page = zooming the map 1331 1332 $('.map-holder').on('click', function() { 1333 $(this).addClass('interact'); 1334 }).removeClass('interact'); 1335 1336 var mapsOnPage = $('.map-container[data-maps-api-key]'); 1337 if(mapsOnPage.length){ 1338 mapsOnPage.addClass('gmaps-active'); 1339 mr.maps.initAPI($); 1340 mr.maps.init(); 1341 } 1342 1343 }; 1344 mr.maps.documentReady = documentReady; 1345 1346 mr.maps.initAPI = function($){ 1347 // Load Google MAP API JS with callback to initialise when fully loaded 1348 if(document.querySelector('[data-maps-api-key]') && !document.querySelector('.gMapsAPI')){ 1349 if($('[data-maps-api-key]').length){ 1350 var script = document.createElement('script'); 1351 var apiKey = $('[data-maps-api-key]:first').attr('data-maps-api-key'); 1352 apiKey = typeof apiKey !== typeof undefined ? apiKey : ''; 1353 if(apiKey !== ''){ 1354 script.type = 'text/javascript'; 1355 script.src = 'https://maps.googleapis.com/ma
1355ps/api/js?key='+apiKey+'&callback=mr.maps.init'; 1356 script.className = 'gMapsAPI'; 1357 document.body.appendChild(script); 1358 } 1359 } 1360 } 1361 }; 1362 1363 mr.maps.init = function(){ 1364 if(typeof window.google !== "undefined"){ 1365 if(typeof window.google.maps !== "undefined"){ 1366 1367 jQuery('.gmaps-active').each(function(){ 1368 var mapElement = this, 1369 mapInstance = jQuery(this), 1370 mapJSON = typeof mapInstance.attr('data-map-style') !== typeof undefined ? mapInstance.attr('data-map-style'): false, 1371 mapStyle = JSON.parse(mapJSON) || [{"featureType":"landscape","stylers":[{"saturation":-100},{"lightness":65},{"visibility":"on"}]},{"featureType":"poi","stylers":[{"saturation":-100},{"lightness":51},{"visibility":"simplified"}]},{"featureType":"road.highway","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"road.arterial","stylers":[{"saturation":-100},{"lightness":30},{"visibility":"on"}]},{"featureType":"road.local","stylers":[{"saturation":-100},{"lightness":40},{"visibility":"on"}]},{"featureType":"transit","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"administrative.province","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"labels","stylers":[{"visibility":"on"},{"lightness":-25},{"saturation":-100}]},{"featureType":"water","elementType":"geometry","stylers":[{"hue":"#ffff00"},{"lightness":-25},{"saturation":-97}]}], 1372 zoomLevel = (typeof mapInstance.attr('data-map-zoom') !== typeof undefined && mapInstance.attr('data-map-zoom') !== "") ? mapInstance.attr('data-map-zoom') * 1: 17, 1373 latlong = typeof mapInstance.attr('data-latlong') !== typeof undefined ? mapInstance.attr('data-latlong') : false, 1374 latitude = latlong ? 1 *latlong.substr(0, latlong.indexOf(',')) : false, 1375 longitude = latlong ? 1 * latlong.substr(latlong.indexOf(",") + 1) : false, 1376 geocoder = new google.maps.Geocoder(), 1377 address = typeof mapInstance.attr('data-address') !== typeof undefined ? mapInstance.attr('data-address').split(';'): [""], 1378 markerImage = typeof mapInstance.attr('data-marker-image') !== typeof undefined ? mapInstance.attr('data-marker-image'): 'img/mapmarker.png', 1379 markerTitle = "We Are Here", 1380 isDraggable = jQuery(document).width() > 766 ? true : false, 1381 map, marker, 1382 mapOptions = { 1383 draggable: isDraggable, 1384 scrollwheel: false, 1385 zoom: zoomLevel, 1386 disableDefaultUI: true, 1387 styles: mapStyle 1388 }; 1389 1390 if(typeof mapInstance.attr('data-marker-title') !== typeof undefined && mapInstance.attr('data-marker-title') !== "" ) 1391 { 1392 markerTitle = mapInstance.attr('data-marker-title'); 1393 } 1394 1395 if(address !== undefined && address[0] !== ""){ 1396 geocoder.geocode( { 'address': address[0].replace('[nomarker]','')}, function(results, status) { 1397 if (status === google.maps.GeocoderStatus.OK) { 1398 var map = new google.maps.Map(mapElement, mapOptions); 1399 map.setCenter(results[0].geometry.location); 1400 1401 address.forEach(function(address){ 1402 var markerGeoCoder; 1403 1404 markerImage = {url: typeof window.mr_variant === typeof undefined ? typeof markerImage !== "object" ? markerImage: markerImage.url : '../img/mapmarker.png', scaledSize: new google.maps.Size(50,50)}; 1405 1406 if(/(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)/.test(address) ){ 1407 var latlong = address.split(','), 1408 marker = new google.maps.Marker({ 1409 position: { lat: 1*latlong[0], lng: 1*latlong[1] }, 1410 map: map, 1411 icon: markerImage, 1412 title: markerTitle, 1413 optimised: fal
1413se 1414 }); 1415 } 1416 else if(address.indexOf('[nomarker]') < 0){ 1417 markerGeoCoder = new google.maps.Geocoder(); 1418 markerGeoCoder.geocode( { 'address': address.replace('[nomarker]','')}, function(results, status) { 1419 if (status === google.maps.GeocoderStatus.OK) { 1420 marker = new google.maps.Marker({ 1421 map: map, 1422 icon: markerImage, 1423 title: markerTitle, 1424 position: results[0].geometry.location, 1425 optimised: false 1426 }); 1427 } 1428 else{ 1429 console.log('Map marker error: '+status); 1430 } 1431 }); 1432 } 1433 1434 }); 1435 } else { 1436 console.log('There was a problem geocoding the address.'); 1437 } 1438 }); 1439 } 1440 else if(typeof latitude !== typeof undefined && latitude !== "" && latitude !== false && typeof longitude !== typeof undefined && longitude !== "" && longitude !== false ){ 1441 mapOptions.center = { lat: latitude, lng: longitude}; 1442 map = new google.maps.Map(mapInstance, mapOptions); 1443 marker = new google.maps.Marker({ 1444 position: { lat: latitude, lng: longitude }, 1445 map: map, 1446 icon: markerImage, 1447 title: markerTitle 1448 }); 1449 1450 } 1451 1452 }); 1453 } 1454 } 1455 }; 1456 1457 mr.components.documentReady.push(documentReady); 1458 return mr; 1459 1460}(mr, jQuery, window, document)); 1461 1462 1463//////////////// Masonry 1464mr = (function (mr, $, window, document){ 1465 "use strict"; 1466 1467 var documentReady = function($){ 1468 1469 mr.masonry.updateFilters(); 1470 1471 $(document).on('click touchstart', '.masonry__filters li', function(){ 1472 var masonryFilter = $(this); 1473 var masonryContainer = masonryFilter.closest('.masonry').find('.masonry__container'); 1474 var filterValue = '*'; 1475 if(masonryFilter.attr('data-masonry-filter') !== '*'){ 1476 filterValue = '.filter-'+masonryFilter.attr('data-masonry-filter'); 1477 } 1478 masonryFilter.siblings('li').removeClass('active'); 1479 masonryFilter.addClass('active'); 1480 masonryContainer.removeClass('masonry--animate'); 1481 masonryContainer.on('layoutComplete',function(){ 1482 $(this).addClass('masonry--active'); 1483 if(typeof mr_parallax !== typeof undefined){ 1484 setTimeout(function(){ mr_parallax.profileParallaxElements(); },100); 1485 } 1486 }); 1487 masonryContainer.isotope({ filter: filterValue }); 1488 1489 }); 1490 1491 }; 1492 1493 var windowLoad = function(){ 1494 1495 $('.masonry').each(function(){ 1496 var masonry = $(this).find('.masonry__container'), 1497 masonryParent = $(this), 1498 defaultFilter = '*'; 1499 1500 // Check for a default filter attribute 1501 if(masonryParent.is('[data-default-filter]')){ 1502 defaultFilter = masonryParent.attr('data-default-filter').toLowerCase(); 1503 defaultFilter = '.filter-'+defaultFilter; 1504 masonryParent.find('li[data-masonry-filter]').removeClass('active'); 1505 masonryParent.find('li[data-masonry-filter="'+masonryParent.attr("data-default-filter").toLowerCase()+'"]').addClass('active'); 1506 } 1507 1508 masonry.on('layoutComplete',function(){ 1509 masonry.addClass('masonry--active'); 1510 if(typeof mr_parallax !== typeof undefined){ 1511 setTimeout(function(){ mr_parallax.profileParallaxElements(); },100); 1512 } 1513 }); 1514 1515 masonry.isotope({ 1516 itemSelector: '.masonry__item', 1517 filter: defaultFilter, 1518 masonry: { 1519 columnWidth: '.masonry__item' 1520 } 1521 }); 1522 1523 }); 1524 }; 1525 1526 1527 mr.masonry = { 1528 documentReady : documentReady, 1529 windowLoad : windowLoad 1530 }; 1531 1532 mr.masonry.updateFilters = function(masonry){ 1533 1534 // If no argument is supplied, just apply the update to all masonry sets on the page. 1535 masonry = typeof masonry !== typeof undefined ? masonry : '.masonry'; 1536 1537 var $masonry = $(masonry); 1538 1539 $masonry.each(function(){ 1540 var $masonry = $(this), 1541 masonryContainer = $masonry.find('.masonry__container'), 1542 filters = $masonry.find('.masonry__filters'), 1543 // data-filter-all-text can be used to set the word for "all" 1544 filterAllText = typeof filters.attr('data-filter-all-text') !== typeof undefined ? filters.attr('data-filter-all-text') : "All", 1545 filtersList; 1546 1547 // Ensure we are working with a .masonry element 1548 if($masonry.is('.masonry')){ 1549 // If a filterable masonry item exists 1550 if(masonryContainer.find('.masonry__item[data-masonry-filter]').length){ 1551 1552 // Create empty ul for filters 1553 filtersList = filters.find('> ul'); 1554 1555 if(!filtersList.length){ 1556 filtersList = filters.append('<ul></ul>').find('> ul'); 1557 } 1558 1559 // To avoid cases where user leave filter attribute blank 1560 // only take items that have filter attribute 1561 masonryContainer.find('.masonry__item[data-masonry-filter]').each(function(){ 1562 var masonryItem = $(this), 1563 filterString = masonryItem.attr('data-masonry-filter'), 1564 filtersArray = []; 1565 1566 // If not undefined or empty 1567 if(typeof filterString !== typeof undefined && filterString !== ""){ 1568 // Split tags from string into array 1569 filtersArray = filterString.split(','); 1570 } 1571 jQuery(filtersArray).each(function(index, tag){ 1572 1573 // Slugify the tag 1574 1575 var slug = mr.util.slugify(tag); 1576 1577 // Add the filter class to the masonry item 1578 1579 masonryItem.addClass('filter-'+slug); 1580 1581 // If this tag does not appear in the list already, add it 1582 if(!filtersList.find('[data-masonry-filter="'+slug+'"]').length){ 1583 filtersList.append('<li data-masonry-filter="'+slug+'">'+tag+'</li>'); 1584 1585 } 1586 }); 1587 }); 1588 1589 mr.util.sortChildrenByText($(this).find('.masonry__filters ul')); 1590 // Add a filter "all" option 1591 if(!filtersList.find('[data-masonry-filter="*"]').length){ 1592 filtersList.prepend('<li class="active" data-masonry-filter="*">'+filterAllText+'</li>'); 1593 } 1594 1595 } 1596 //End of "if filterable masonry item exists" 1597 } 1598 //End of "if $masonry is .masonry" 1599 }); 1600 1601 }; 1602 1603 mr.masonry.updateLayout = function(masonry){ 1604 1605 // If no argument is supplied, just apply the update to all masonry sets on the page. 1606 masonry = typeof masonry !== typeof undefined ? masonry : '.masonry'; 1607 1608 var $masonry = $(masonry); 1609 1610 1611 $masonry.each(function(){ 1612 var collection = $(this), 1613 newItems = collection.find('.masonry__item:not([style])'), 1614 masonryContainer = collection.find('.masonry__container'); 1615 1616 if(collection.is('.masonry')){ 1617 if(newItems.length){ 1618 masonryContainer.isotope('appended', newItems).isotope( 'layout'); 1619 } 1620 1621 masonryContainer.isotope('layout'); 1622 } 1623 }); 1624 }; 1625 1626 mr.components.documentReady.push(documentReady); 1627 mr.components.windowLoad.push(windowLoad); 1628 return mr; 1629 1630}(mr, jQuery, window, document)); 1631 1632
1633//////////////// Modals 1634mr = (function (mr, $, window, document){ 1635 "use strict"; 1636 1637 mr.modals = {}; 1638 1639 var documentReady = function($){ 1640 var allPageModals = "<div class=\"all-page-modals\"></div>", 1641 mainContainer = $('div.main-container'); 1642 1643 if(mainContainer.length){ 1644 jQuery(allPageModals).insertAfter(mainContainer); 1645 mr.modals.allModalsContainer = $('div.all-page-modals'); 1646 } 1647 else{ 1648 jQuery('body').append(allPageModals); 1649 mr.modals.allModalsContainer = jQuery('body div.all-page-modals'); 1650 } 1651 1652 $('.modal-container').each(function(){ 1653 1654 // Add modal close if none exists 1655 1656 var modal = $(this), 1657 $window = $(window), 1658 modalContent = modal.find('.modal-content'); 1659 1660 1661 if(!modal.find('.modal-close').length){ 1662 modal.find('.modal-content').append('<div class="modal-close modal-close-cross"></div>'); 1663 } 1664 1665 // Set modal height 1666 1667 if(modalContent.attr('data-width') !== undefined){ 1668 var modalWidth = modalContent.attr('data-width').substr(0,modalContent.attr('data-width').indexOf('%')) * 1; 1669 modalContent.css('width',modalWidth + '%'); 1670 } 1671 if(modalContent.attr('data-height') !== undefined){ 1672 var modalHeight = modalContent.attr('data-height').substr(0,modalContent.attr('data-height').indexOf('%')) * 1; 1673 modalContent.css('height',modalHeight + '%'); 1674 } 1675 1676 // Set iframe's src to data-src to stop autoplaying iframes 1677 mr.util.idleSrc(modal, 'iframe'); 1678 1679 }); 1680 1681 1682 $('.modal-instance').each(function(index){ 1683 var modalInstance = $(this); 1684 var modal = modalInstance.find('.modal-container'); 1685 var modalContent = modalInstance.find('.modal-content'); 1686 var trigger = modalInstance.find('.modal-trigger'); 1687 1688 // Link modal with modal-id attribute 1689 1690 trigger.attr('data-modal-index',index); 1691 modal.attr('data-modal-index',index); 1692 1693 // Set unique id for multiple triggers 1694 1695 if(typeof modal.attr('data-modal-id') !== typeof undefined){ 1696 trigger.attr('data-modal-id', modal.attr('data-modal-id')); 1697 } 1698 1699 1700 // Attach the modal to the body 1701 modal = modal.detach(); 1702 mr.modals.allModalsContainer.append(modal); 1703 }); 1704 1705 1706 $('.modal-trigger').on('click', function(){ 1707 1708 var modalTrigger = $(this); 1709 var uniqueID, targetModal; 1710 // Determine if the modal id is set by user or is set programatically 1711 1712 if(typeof modalTrigger.attr('data-modal-id') !== typeof undefined){ 1713 uniqueID = modalTrigger.attr('data-modal-id'); 1714 targetModal = mr.modals.allModalsContainer.find('.modal-container[data-modal-id="'+uniqueID+'"]'); 1715 }else{ 1716 uniqueID = $(this).attr('data-modal-index'); 1717 targetModal = mr.modals.allModalsContainer.find('.modal-container[data-modal-index="'+uniqueID+'"]'); 1718 } 1719 1720 mr.util.activateIdleSrc(targetModal, 'iframe'); 1721 mr.modals.autoplayVideo(targetModal); 1722 1723 mr.modals.showModal(targetModal); 1724 1725 return false; 1726 }); 1727 1728 jQuery(document).on('click', '.modal-close', mr.modals.closeActiveModal); 1729 1730 jQuery(document).keyup(function(e) { 1731 if (e.keyCode === 27) { // escape key maps to keycode `27` 1732 mr.modals.closeActiveModal(); 1733 } 1734 }); 1735 1736 $('.modal-container').on('click', function(e) { 1737 if( e.target !== this ) return; 1738 mr.modals.closeActiveModal(); 1739 }); 1740 1741 // Trigger autoshow modals 1742 $('.modal-container[data-autoshow]').each(function(){ 1743 var modal = $(this); 1744 var millisecondsDelay = modal.attr('data-autoshow')*1; 1745 1746 mr.util.activateIdleSrc(modal); 1747 mr.modals.autoplayVideo(modal); 1748 1749 // If this modal has a cookie attribute, check to see if a cookie is set, and if so, don't show it. 1750 if(typeof modal.attr('data-cookie') !== typeof undefined){ 1751 if(!mr.cookies.hasItem(modal.attr('data-cookie'))){ 1752 mr.modals.showModal(modal, millisecondsDelay); 1753 } 1754 }else{ 1755 mr.modals.showModal(modal, millisecondsDelay); 1756 } 1757 }); 1758 1759 // Exit modals 1760 $('.modal-container[data-show-on-exit]').each(function(){ 1761 var modal = jQuery(this), 1762 exitSelector = modal.attr('data-show-on-exit'),
1763 delay = 0; 1764 1765 if(modal.attr('data-delay')){ 1766 delay = parseInt(modal.attr('data-delay'), 10) || 0; 1767 } 1768 1769 // If a valid selector is found, attach leave event to show modal. 1770 if($(exitSelector).length){ 1771 modal.prepend($('<i class="ti-close close-modal">')); 1772 jQuery(document).on('mouseleave', exitSelector, function(){ 1773 if(!$('.modal-active').length){ 1774 if(typeof modal.attr('data-cookie') !== typeof undefined){ 1775 if(!mr.cookies.hasItem(modal.attr('data-cookie'))){ 1776 mr.modals.showModal(modal, delay); 1777 } 1778 }else{ 1779 mr.modals.showModal(modal, delay); 1780 } 1781 } 1782 }); 1783 } 1784 }); 1785 1786 1787 // Autoshow modal by ID from location href 1788 if(window.location.href.split('#').length === 2){ 1789 var modalID = window.location.href.split('#').pop(); 1790 if($('[data-modal-id="'+modalID+'"]').length){ 1791 mr.modals.closeActiveModal(); 1792 mr.modals.showModal($('[data-modal-id="'+modalID+'"]')); 1793 } 1794 } 1795 1796 // Make modal scrollable 1797 $(document).on('wheel mousewheel scroll','.modal-content, .modal-content .scrollable', function(evt){ 1798 if(evt.preventDefault){evt.preventDefault();} 1799 if(evt.stopPropagation){evt.stopPropagation();} 1800 this.scrollTop += (evt.originalEvent.deltaY); 1801 }); 1802 }; 1803 //////////////// 1804 //////////////// End documentReady 1805 //////////////// 1806 1807 mr.modals.documentReady = documentReady; 1808 1809 mr.modals.showModal = function(modal, millisecondsDelay){ 1810 1811 var delay = (typeof millisecondsDelay !== typeof undefined) ? (1*millisecondsDelay) : 0; 1812 1813 setTimeout(function(){ 1814 $(modal).addClass('modal-active'); 1815 },delay); 1816 }; 1817 1818 mr.modals.closeActiveModal = function(){ 1819 var modal = jQuery('body div.modal-active'); 1820 mr.util.idleSrc(modal, 'iframe'); 1821 mr.util.pauseVideo(modal); 1822 1823 // If this modal requires to be closed permanently using a cookie, set the cookie now. 1824 if(typeof modal.attr('data-cookie') !== typeof undefined){ 1825 mr.cookies.setItem(modal.attr('data-cookie'), "true", Infinity, '/'); 1826 } 1827 1828 modal.removeClass('modal-active'); 1829 }; 1830 1831 mr.modals.autoplayVideo = function(modal){ 1832 // If modal contains HTML5 video with autoplay, play the video 1833 if(modal.find('video[autoplay]').length){ 1834 var video = modal.find('video').get(0); 1835 video.play(); 1836 } 1837 }; 1838 1839 mr.components.documentReady.push(documentReady); 1840 return mr; 1841 1842}(mr, jQuery, window, document)); 1843 1844//////////////// Newsletter Providers 1845mr = (function (mr, $, window, document){ 1846 "use strict"; 1847 1848 mr.newsletters = {}; 1849 1850 var documentReady = function($){ 1851 1852 var form,checkbox,label,id,parent,radio; 1853 1854 // Treat Campaign Monitor forms 1855 $('form[action*="createsend.com"]').each(function(){ 1856 form = $(this); 1857 1858 // Override browser validation and allow us to use our own 1859 form.attr('novalidate', 'novalidate'); 1860 1861 // Give each text input a placeholder value 1862 1863 if(!form.is('.form--no-placeholders')){ 1864 form.find('input:not([checkbox]):not([radio])').each(function(){ 1865 var $input = $(this); 1866 if(typeof $input.attr('placeholder') !== typeof undefined){ 1867 if($input.attr('placeholder') === ""){ 1868 if($input.siblings('label').length){ 1869 $input.attr('placeholder', $input.siblings('label').first().text()); 1870 if(form.is('.form--no-labels')){ 1871 $input.siblings('label').first().remove(); 1872 } 1873 } 1874 } 1875 }else if($input.siblings('label').length){ 1876 $input.attr('placeholder', $input.siblings('label').first().text()); 1877 if(form.is('.form--no-labels')){ 1878 $input.siblings('label').first().remove(); 1879 } 1880 } 1881 if($input.parent().is('p')){ 1882 $input.unwrap(); 1883 } 1884 }); 1885 }else{ 1886 form.find('input[placeholder]').removeAttr('placeholder'); 1887 } 1888 1889 1890 // Wrap select elements in template code 1891 1892 form.find('select').wrap('<div class="input-select"></div>'); 1893 1894 // Wrap radios elements in template code 1895 1896 form.find('input[type="radio"]').wrap('<div class="input-radio"></div>'); 1897 1898 // Wrap checkbox elements in template code 1899 1900 form.find('input[type="checkbox"]').each(function(){ 1901 checkbox = $(this); 1902 id = checkbox.attr('id'); 1903 label = form.find('label[for='+id+']'); 1904 if(!label.length){ 1905 label = $('<label for="'+id+'"></label>'); 1906 } 1907 1908 checkbox.before('<div class="input-checkbox" data-id="'+id+'"></div>'); 1909 $('.input-checkbox[data-id="'+id+'"]').prepend(checkbox); 1910 $('.input-checkbox[data-id="'+id+'"]').prepend(label); 1911 }); 1912 1913 form.find('button[type="submit"]').each(function(){ 1914 var button = $(this); 1915 button.addClass('btn'); 1916 if(button.parent().is('p')){ 1917 button.unwrap(); 1918 } 1919 }); 1920 1921 form.find('[required]').attr('required', 'required').addClass('validate-required'); 1922 1923 form.addClass('form--active'); 1924 1925 mr.newsletters.prepareAjaxAction(form); 1926 1927 1928 }); 1929 1930 // Treat MailChimp forms 1931 $('form[action*="list-manage.com"]').each(function(){ 1932 form = $(this); 1933 1934 // Override browser validation and allow us to use our own 1935 form.attr('novalidate', 'novalidate'); 1936 1937 // Give each text input a placeholder value 1938 if(!form.is('.form--no-placeholders')){
1939 form.find('input:not([checkbox]):not([radio])').each(function(){ 1940 var $input = $(this); 1941 if(typeof $input.attr('placeholder') !== typeof undefined){ 1942 if($input.attr('placeholder') === ""){ 1943 if($input.siblings('label').length){ 1944 $input.attr('placeholder', $input.siblings('label').first().text()); 1945 if(form.is('.form--no-labels')){ 1946 $input.siblings('label').first().remove(); 1947 } 1948 } 1949 } 1950 }else if($input.siblings('label').length){ 1951 $input.attr('placeholder', $input.siblings('label').first().text()); 1952 if(form.is('.form--no-labels')){ 1953 $input.siblings('label').first().remove(); 1954 } 1955 } 1956 }); 1957 }else{ 1958 form.find('input[placeholder]').removeAttr('placeholder'); 1959 } 1960 1961 if(form.is('.form--no-labels')){ 1962 form.find('input:not([checkbox]):not([radio])').each(function(){ 1963 var $input = $(this); 1964 if($input.siblings('label').length){ 1965 $input.siblings('label').first().remove(); 1966 } 1967 }); 1968 } 1969 1970 // Wrap select elements in template code 1971 1972 form.find('select').wrap('<div class="input-select"></div>'); 1973 1974 // Wrap checboxes elements in template code 1975 1976 form.find('input[type="checkbox"]').each(function(){ 1977 checkbox = $(this); 1978 parent = checkbox.parent(); 1979 label = parent.find('label'); 1980 if(!label.length){ 1981 label = $('<label></label>'); 1982 } 1983 checkbox.before('<div class="input-checkbox"></div>'); 1984 parent.find('.input-checkbox').append(checkbox); 1985 parent.find('.input-checkbox').append(label); 1986 }); 1987 1988 // Wrap radio elements in template code 1989 1990 form.find('input[type="radio"]').each(function(){ 1991 radio = $(this); 1992 parent = radio.closest('li'); 1993 label = parent.find('label'); 1994 if(!label.length){ 1995 label = $('<label></label>'); 1996 } 1997 radio.before('<div class="input-radio"></div>'); 1998 parent.find('.input-radio').prepend(radio); 1999 parent.find('.input-radio').prepend(label); 2000 }); 2001 2002 // Convert MailChimp input[type="submit"] to div.button 2003 2004 form.find('input[type="submit"]').each(function(){ 2005 var submit = $(this); 2006 2007 var newButton = jQuery('<button/>').attr('type','submit').attr('class', submit.attr('class')).addClass('btn').text(submit.attr('value')); 2008 2009 if(submit.parent().is('div.clear')){ 2010 submit.unwrap(); 2011 } 2012 2013 newButton.insertBefore(submit); 2014 submit.remove(); 2015 }); 2016 2017 form.find('input').each(function(){ 2018 var input = $(this); 2019 if(input.hasClass('required')){ 2020 input.removeClass('required').addClass('validate-required'); 2021 } 2022 }); 2023 2024 form.find('input[type="email"]').removeClass('email').addClass('validate-email'); 2025 2026 form.find('#mce-responses').remove(); 2027 2028 form.find('.mc-field-group').each(function(){ 2029 $(this).children().first().unwrap(); 2030 }); 2031 2032 form.find('[required]').attr('required', 'required').addClass('validate-required'); 2033 2034 form.addClass('form--active'); 2035 2036 mr.newsletters.prepareAjaxAction(form); 2037 2038 2039 2040 2041 }); 2042 2043 // Reinitialize the forms so interactions work as they should 2044 2045 mr.forms.documentReady(mr.setContext('form.form--active')); 2046 2047 }; 2048 2049 mr.newsletters.documentReady = documentReady; 2050 2051 mr.newsletters.prepareAjaxAction = function(form){ 2052 var action = $(form).attr('action'); 2053 2054 // Alter action for a Mail Chimp-compatible ajax request url. 2055 if(/list-manage\.com/.test(action)){ 2056 action = action.replace('/post?', '/post-json?') + "&c=?"; 2057 if(action.substr(0,2) === "//"){ 2058 action = 'http:' + action; 2059 } 2060 } 2061 2062 // Alter action for a Campaign Monitor-compatible ajax request url. 2063 if(/createsend\.com/.test(action)){ 2064 action = action + '?callback=?'; 2065 } 2066 2067 // Set action on the form 2068 $(form).attr('action', action); 2069 2070 }; 2071 2072 2073 2074 mr.components.documentReady.push(documentReady); 2075 return mr; 2076 2077}(mr, jQuery, window, document)); 2078 2079//////////////// Notifications 2080mr = (function (mr, $, window, document){ 2081 "use strict"; 2082 2083 mr.notifications = {}; 2084 2085 var documentReady = function($){ 2086 2087 $('.notification').each(function(){ 2088 var notification = $(this); 2089 if(!notification.find('.notification-close').length){ 2090 notification.append('<div class="notification-close-cross notification-close"></div>'); 2091 } 2092 }); 2093 2094 2095 $('.notification[data-autoshow]').each(function(){ 2096 var notification = $(this); 2097 var millisecondsDelay = parseInt(notification.attr('data-autoshow'),10); 2098 2099 // If this notification has a cookie attribute, check to see if a cookie is set, and if so, don't show it. 2100 if(typeof notification.attr('data-cookie') !== typeof undefined){ 2101 if(!mr.cookies.hasItem(notification.attr('data-cookie'))){ 2102 mr.notifications.showNotification(notification, millisecondsDelay); 2103 } 2104 }else{ 2105 mr.notifications.showNotification(notification, millisecondsDelay); 2106 } 2107 }); 2108 2109 $('[data-notification-link]:not(.notification)').on('click', function(){ 2110 var notificationID = jQuery(this).attr('data-notification-link'); 2111 var notification = $('.notification[data-notification-link="'+notificationID+'"]'); 2112 jQuery('.notification--reveal').addClass('notification--dismissed'); 2113 notification.removeClass('notification--dismissed'); 2114 mr.notifications.showNotification(notification, 0); 2115 return false;
2116 }); 2117 2118 $('.notification-close').on('click', function(){ 2119 var closeButton = jQuery(this); 2120 // Pass the closeNotification function a reference to the close button 2121 mr.notifications.closeNotification(closeButton); 2122 2123 if(closeButton.attr('href') === '#'){ 2124 return false; 2125 } 2126 }); 2127 2128 $('.notification .inner-link').on('click', function(){ 2129 var notificationLink = jQuery(this).closest('.notification').attr('data-notification-link'); 2130 mr.notifications.closeNotification(notificationLink); 2131 }); 2132 2133 }; 2134 2135 mr.notifications.documentReady = documentReady; 2136 2137 mr.notifications.showNotification = function(notification, millisecondsDelay){ 2138 var delay = (typeof millisecondsDelay !== typeof undefined) ? (1*millisecondsDelay) : 0; 2139 setTimeout(function(){ 2140 notification.addClass('notification--reveal'); 2141 notification.closest('nav').addClass('notification--reveal'); 2142 if(notification.find('input').length){ 2143 notification.find('input').first().focus(); 2144 } 2145 },delay); 2146 // If notification has autohide attribute, set a timeout 2147 // for the autohide time plus the original delay time in case notification was called 2148 // on page load 2149 if(notification.is('[data-autohide]')){ 2150 var hideDelay = parseInt(notification.attr('data-autohide'),10); 2151 setTimeout(function(){ 2152 mr.notifications.closeNotification(notification); 2153 },hideDelay+delay); 2154 } 2155 }; 2156 2157 mr.notifications.closeNotification = function(notification){ 2158 var $notification = jQuery(notification); 2159 2160 notification = $notification.is('.notification') ? 2161 $notification : 2162 $notification.is('.notification-close') ? 2163 $notification.closest('.notification') : 2164 $('.notification[data-notification-link="'+notification+'"]'); 2165 2166 notification.addClass('notification--dismissed'); 2167 notification.closest('nav').removeClass('notification--reveal'); 2168 2169 // If this notification requires to be closed permanently using a cookie, set the cookie now. 2170 if(typeof notification.attr('data-cookie') !== typeof undefined){ 2171 mr.cookies.setItem(notification.attr('data-cookie'), "true", Infinity, '/'); 2172 } 2173 }; 2174 2175 mr.components.documentReady.push(documentReady); 2176 return mr; 2177 2178}(mr, jQuery, window, document)); 2179 2180//////////////// Parallax 2181mr = (function (mr, $, window, document){ 2182 "use strict"; 2183 2184 var documentReady = function($){ 2185 2186 var $window = $(window); 2187 var windowWidth = $window.width(); 2188 var windowHeight = $window.height(); 2189 var navHeight = $('nav').outerHeight(true); 2190 2191 // Disable parallax on mobile 2192 2193 if ((/Android|iPhone|iPad|iPod|BlackBerry|Windows Phone/i).test(navigator.userAgent || navigator.vendor || window.opera)) { 2194 $('section').removeClass('parallax'); 2195 } 2196 2197 if (windowWidth > 768) { 2198 var parallaxHero = $('.parallax:nth-of-type(1)'), 2199 parallaxHeroImage = $('.parallax:nth-of-type(1) .background-image-holder'); 2200 2201 parallaxHeroImage.css('top', -(navHeight)); 2202 if(parallaxHero.outerHeight(true) === windowHeight){ 2203 parallaxHeroImage.css('height', windowHeight + navHeight); 2204 } 2205 } 2206 }; 2207 2208 mr.parallax = { 2209 documentReady : documentReady 2210 }; 2211 2212 mr.components.documentReady.push(documentReady); 2213 return mr; 2214 2215}(mr, jQuery, window, document)); 2216 2217//////////////// EasyPiecharts 2218mr = (function (mr, $, window, document){ 2219 "use strict"; 2220 2221 mr.easypiecharts = {}; 2222 mr.easypiecharts.pies = []; 2223 2224 var documentReady = function($){ 2225 2226 mr.easypiecharts.init = function(){ 2227 2228 mr.easypiecharts.pies = []; 2229 2230 $('.radial').each(function(){ 2231 var pieObject = {}, 2232 currentPie = jQuery(this); 2233 2234 pieObject.element = currentPie; 2235 pieObject.value = parseInt(currentPie.attr('data-value'),10); 2236 pieObject.top = currentPie.offset().top; 2237 pieObject.height = currentPie.height()/2; 2238 pieObject.active = false;
2239 mr.easypiecharts.pies.push(pieObject); 2240 }); 2241 }; 2242 2243 mr.easypiecharts.activate = function(){ 2244 mr.easypiecharts.pies.forEach(function(pie){ 2245 if(Math.round((mr.scroll.y + mr.window.height)) >= Math.round(pie.top+pie.height)){ 2246 if(pie.active === false){ 2247 2248 pie.element.data('easyPieChart').enableAnimation(); 2249 pie.element.data('easyPieChart').update(pie.value); 2250 pie.element.addClass('radial--active'); 2251 pie.active = true; 2252 } 2253 } 2254 }); 2255 }; 2256 2257 $('.radial').each(function(){ 2258 var chart = jQuery(this), 2259 value = 0, 2260 color = '#000000', 2261 time = 2000, 2262 pieSize = 110, 2263 barWidth = 3; 2264 2265 if(typeof chart.attr('data-timing') !== typeof undefined){ 2266 time = chart.attr('data-timing')*1; 2267 } 2268 if(typeof chart.attr('data-color') !== typeof undefined){ 2269 color = chart.attr('data-color'); 2270 } 2271 if(typeof chart.attr('data-size') !== typeof undefined){ 2272 pieSize = chart.attr('data-size'); 2273 } 2274 if(typeof chart.attr('data-bar-width') !== typeof undefined){ 2275 barWidth = chart.attr('data-bar-width'); 2276 } 2277 chart.css('height',pieSize).css('width',pieSize); 2278 2279 chart.easyPieChart({ 2280 animate: ({duration: time, enabled: true}), 2281 barColor: color, 2282 scaleColor: false, 2283 size: pieSize, 2284 lineWidth: barWidth 2285 }); 2286 chart.data('easyPieChart').update(0); 2287 }); 2288 2289 if($('.radial').length){ 2290 mr.easypiecharts.init(); 2291 mr.easypiecharts.activate(); 2292 mr.scroll.listeners.push(mr.easypiecharts.activate); 2293 } 2294 2295 }; 2296 2297 mr.easypiecharts.documentReady = documentReady; 2298 2299 mr.components.documentReadyDeferred.push(documentReady); 2300 return mr; 2301 2302}(mr, jQuery, window, document)); 2303 2304//////////////// Flickity 2305mr = (function (mr, $, window, document){ 2306 "use strict"; 2307 2308 mr.sliders = {}; 2309 mr.sliders.draggable = true; 2310 2311 var documentReady = function($){ 2312 2313 $('.slider').each(function(index){ 2314 2315 var slider = $(this); 2316 var sliderInitializer = slider.find('ul.slides'); 2317 sliderInitializer.find('>li').addClass('slide'); 2318 var childnum = sliderInitializer.find('li').length; 2319 var arrows = false; 2320 var paging = false; 2321 var timing = 7000; 2322 var autoplay = true; 2323 var draggable = mr.sliders.draggable; 2324 if(slider.attr('data-arrows') === 'true'){ 2325 arrows = true; 2326 }else{ 2327 arrows = false; 2328 } 2329 if(slider.attr('data-autoplay') === 'false'){ 2330 autoplay = false; 2331 }else{ 2332 autoplay = true; 2333 } 2334 if(slider.attr('data-paging') === 'true' && sliderInitializer.find('li').length > 1){ 2335 paging = true; 2336 }else{ 2337 paging = false; 2338 } 2339 if(slider.attr('data-timing')){ 2340 timing = slider.attr('data-timing')*1; 2341 } 2342 // Set data attribute to inidicate the number of children in the slider 2343 slider.attr('data-children',childnum); 2344 2345 if(childnum < 2){ 2346 draggable = false; 2347 } 2348 2349 $(sliderInitializer).flickity({ 2350 cellSelector: '.slide', 2351 cellAlign: 'left', 2352 wrapAround: true, 2353 pageDots: paging, 2354 prevNextButtons: arrows, 2355 autoPlay: timing, 2356 draggable: draggable, 2357 imagesLoaded: true 2358 }); 2359 2360 $(sliderInitializer).on( 'scroll.flickity', function( event, progress ) { 2361 if(slider.find('.is-selected').hasClass('controls--dark')){ 2362 slider.addClass('controls--dark'); 2363 }else{ 2364 slider.removeClass('controls--dark'); 2365 } 2366 }); 2367 }); 2368 2369 }; 2370 2371 mr.sliders.documentReady = documentReady; 2372 2373 mr.components.documentReadyDeferred.push(documentReady); 2374 return mr; 2375 2376}(mr, jQuery, window, document)); 2377 2378//////////////// Smoothscroll 2379mr = (function (mr, $, window, document){ 2380 "use strict"; 2381 2382 mr.smoothscroll = {}; 2383 mr.smoothscroll.sections = []; 2384 2385 mr.smoothscroll.init = function(){ 2386 mr.smoothscroll.sections = []; 2387 2388 2389 2390 $('a.inner-link').each(function(){ 2391 var sectionObject = {}, 2392 link = $(this), 2393 href = link.attr('href'), 2394 validLink = new RegExp('^#[^\r\n\t\f\v\#\.]+$','gm'); 2395 2396 if(validLink.test(href)){ 2397 2398 if($('section'+href).length){ 2399 2400 sectionObject.id = href; 2401 sectionObject.top = Math.round($(href).offset().top); 2402 sectionObject.height = Math.round($(href).outerHeight()); 2403 sectionObject.link = link.get(0); 2404 sectionObject.active = false;
2405 2406 mr.smoothscroll.sections.push(sectionObject); 2407 } 2408 } 2409 }); 2410 2411 mr.smoothscroll.highlight(); 2412 }; 2413 2414 mr.smoothscroll.highlight = function(){ 2415 mr.smoothscroll.sections.forEach(function(section){ 2416 if(mr.scroll.y >= section.top && mr.scroll.y < (section.top + section.height)){ 2417 if(section.active === false){ 2418 section.link.classList.add("inner-link--active"); 2419 section.active = true; 2420 } 2421 }else{ 2422 section.link.classList.remove("inner-link--active"); 2423 section.active = false; 2424 } 2425 }); 2426 }; 2427 2428 mr.scroll.listeners.push(mr.smoothscroll.highlight); 2429 2430 var documentReady = function($){ 2431 // Smooth scroll to inner links 2432 var innerLinks = $('a.inner-link'); 2433 2434 if(innerLinks.length){ 2435 innerLinks.each(function(index){ 2436 var link = $(this), 2437 href = link.attr('href'); 2438 if(href.charAt(0) !== "#"){ 2439 link.removeClass('inner-link'); 2440 } 2441 }); 2442 2443 mr.smoothscroll.init(); 2444 $(window).on('resize', mr.smoothscroll.init); 2445 2446 var offset = 0; 2447 if($('body[data-smooth-scroll-offset]').length){ 2448 offset = $('body').attr('data-smooth-scroll-offset'); 2449 offset = offset*1; 2450 } 2451 2452 smoothScroll.init({ 2453 selector: '.inner-link', 2454 selectorHeader: null, 2455 speed: 750, 2456 easing: 'easeInOutCubic', 2457 offset: offset 2458 }); 2459 } 2460 }; 2461 2462 mr.smoothscroll.documentReady = documentReady; 2463 2464 mr.components.documentReady.push(documentReady); 2465 mr.components.windowLoad.push(mr.smoothscroll.init); 2466 return mr; 2467 2468}(mr, jQuery, window, document)); 2469 2470//////////////// Tabs 2471mr = (function (mr, $, window, document){ 2472 "use strict"; 2473 2474 mr.tabs = {}; 2475 2476 var documentReady = function($){ 2477 $('.tabs').each(function(){ 2478 var tabs = $(this); 2479 tabs.after('<ul class="tabs-content">'); 2480 tabs.find('li').each(function(){ 2481 var currentTab = $(this), 2482 tabContent = currentTab.find('.tab__content').wrap('<li></li>').parent(), 2483 tabContentClone = tabContent.clone(true,true); 2484 tabContent.remove(); 2485 currentTab.closest('.tabs-container').find('.tabs-content').append(tabContentClone); 2486 }); 2487 }); 2488 2489 $('.tabs > li').on('click', function(){ 2490 var clickedTab = $(this), hash; 2491 mr.tabs.activateTab(clickedTab); 2492 2493 // Update the URL bar if the currently clicked tab has an ID 2494 if(clickedTab.is('[id]')){ 2495 // Create the hash from the tab's ID 2496 hash = '#'+ clickedTab.attr('id'); 2497 // Check we are in a newish browser with the history API 2498 if(history.pushState) { 2499 history.pushState(null, null, hash); 2500 } 2501 else { 2502 location.hash = hash; 2503 } 2504 } 2505 }); 2506 2507 $('.tabs li.active').each(function(){ 2508 mr.tabs.activateTab(this); 2509 }); 2510 2511 if(window.location.hash !== ''){ 2512 mr.tabs.activateTabById(window.location.hash); 2513 } 2514 2515 $('a[href^="#"]').on('click', function(){ 2516 mr.tabs.activateTabById($(this).attr('href')); 2517 }); 2518 2519 }; 2520 2521 mr.tabs.activateTab = function(tab){ 2522 var clickedTab = $(tab), 2523 tabContainer = clickedTab.closest('.tabs-container'), 2524 activeIndex = (clickedTab.index()*1)+(1), 2525 activeContent = tabContainer.find('> .tabs-content > li:nth-of-type('+activeIndex+')'), 2526 openEvent = document.createEvent('Event'), 2527 iframe, radial; 2528 2529 openEvent.initEvent('tabOpened.tabs.mr', true, true); 2530 2531 2532 tabContainer.find('> .tabs > li').removeClass('active'); 2533 tabContainer.find('> .tabs-content > li').removeClass('active'); 2534 2535 clickedTab.addClass('active').trigger('tabOpened.tabs.mr').get(0).dispatchEvent(openEvent); 2536 activeContent.addClass('active'); 2537 2538 2539 2540 // If there is an <iframe> element in the tab, reload its content when the tab is made active. 2541 iframe = activeContent.find('iframe'); 2542 if(iframe.length){ 2543 iframe.attr('src', iframe.attr('src')); 2544 } 2545 }; 2546 2547 2548 2549 mr.tabs.activateTabById = function(id){ 2550 if(id !== '' && id !== '#'){ 2551 $('.tabs > li#'+id.replace('#', '')).click(); 2552 } 2553 }; 2554 2555 mr.tabs.documentReady = documentReady; 2556 mr.components.documentReady.push(documentReady); 2557 return mr; 2558 2559}(mr, jQuery, window, document)); 2560 2561//////////////// Toggle Class 2562mr = (function (mr, $, window, document){ 2563 "use strict"; 2564 2565 var documentReady = function($){ 2566 $('[data-toggle-class]').each(function(){ 2567 var element = $(this), 2568 data = element.attr('data-toggle-class').split("|"); 2569 2570 2571 $(data).each(function(){ 2572 var candidate = element, 2573 dataArray = [], 2574 toggleClass = '', 2575 toggleElement = '', 2576 dataArray = this.split(";"); 2577 2578 if(dataArray.length === 2){ 2579 toggleElement = dataArray[0]; 2580 toggleClass = dataArray[1]; 2581 $(candidate).on('click',function(){ 2582 if(!candidate.hasClass('toggled-class')){ 2583 candidate.toggleClass('toggled-class'); 2584 }else{ 2585 candidate.removeClass('toggled-class'); 2586 } 2587 $(toggleElement).toggleClass(toggleClass); 2588 return false;
2589 }); 2590 }else{ 2591 console.log('Error in [data-toggle-class] attribute. This attribute accepts an element, or comma separated elements terminated witha ";" followed by a class name to toggle'); 2592 } 2593 }); 2594 }); 2595 }; 2596 2597 mr.toggleClass = { 2598 documentReady : documentReady 2599 }; 2600 2601 mr.components.documentReady.push(documentReady); 2602 return mr; 2603 2604}(mr, jQuery, window, document)); 2605 2606//////////////// Typed Headline Effect 2607mr = (function (mr, $, window, document){ 2608 "use strict"; 2609 2610 var documentReady = function($){ 2611 $('.typed-text').each(function(){ 2612 var text = $(this); 2613 var strings = text.attr("data-typed-strings") ? text.attr("data-typed-strings").split(",") : []; 2614 $(text).typed({ 2615 strings: strings, 2616 typeSpeed: 100, 2617 loop: true, 2618 showCursor: false 2619 }); 2620 }); 2621 }; 2622 2623 mr.typed = { 2624 documentReady : documentReady 2625 }; 2626 2627 mr.components.documentReady.push(documentReady); 2628 return mr; 2629 2630}(mr, jQuery, window, document)); 2631 2632//////////////// Twitter Feeds 2633mr = (function (mr, $, window, document){ 2634 "use strict"; 2635 2636 var documentReady = function($){ 2637 $('.tweets-feed').each(function(index) { 2638 $(this).attr('id', 'tweets-' + index); 2639 }).each(function(index) { 2640 var element = $('#tweets-' + index); 2641 var TweetConfig = { 2642 "domId": '', 2643 "maxTweets": element.attr('data-amount'), 2644 "enableLinks": true, 2645 "showUser": true, 2646 "showTime": true, 2647 "dateFunction": '', 2648 "showRetweet": false, 2649 "customCallback": handleTweets 2650 }; 2651 2652 if(typeof element.attr('data-widget-id') !== typeof undefined){ 2653 TweetConfig.id = element.attr('data-widget-id'); 2654 }else if(typeof element.attr('data-feed-name') !== typeof undefined && element.attr('data-feed-name') !== ""){ 2655 TweetConfig.profile = {"screenName": element.attr('data-feed-name').replace('@', '')}; 2656 }else{ 2657 TweetConfig.profile = {"screenName": 'twitter'}; 2658 } 2659 2660 if(element.closest('.twitter-feed--slider').length){ 2661 element.addClass('slider'); 2662 } 2663 2664 function handleTweets(tweets) { 2665 var x = tweets.length; 2666 var n = 0; 2667 var html = '<ul class="slides">'; 2668 while (n < x) { 2669 html += '<li>' + tweets[n] + '</li>'; 2670 n++; 2671 } 2672 html += '</ul>'; 2673 element.html(html); 2674 2675 // Initialize twitter feed slider 2676 if(element.closest('.slider').length){ 2677 mr.sliders.documentReady(mr.setContext()); 2678 2679 return html; 2680 } 2681 } 2682 twitterFetcher.fetch(TweetConfig); 2683 }); 2684 }; 2685 2686 mr.twitter = { 2687 documentReady : documentReady 2688 }; 2689 2690 mr.components.documentReady.push(documentReady); 2691 2692 return mr; 2693 2694}(mr, jQuery, window, document)); 2695 2696//////////////// Video 2697mr = (function (mr, $, window, document){ 2698 "use strict"; 2699 2700 var documentReady = function($){ 2701
2702 //////////////// Youtube Background 2703 2704 if($('.youtube-background').length){ 2705 $('.youtube-background').each(function(){ 2706 var player = $(this); 2707 var vidURL = $(this).attr('data-video-url'); 2708 var startAt = $(this).attr('data-start-at'); 2709 player.attr('data-property','{videoURL:"'+vidURL+'",containment:"self",autoPlay:true, mute:true, startAt:'+startAt+', opacity:1}'); 2710 player.closest('.videobg').append('<div class="loading-indicator"></div>'); 2711 player.YTPlayer(); 2712 player.on("YTPStart",function(){ 2713 player.closest('.videobg').addClass('video-active'); 2714 }); 2715 }); 2716 } 2717 2718 if($('.videobg').find('video').length){ 2719 $('.videobg').find('video').closest('.videobg').addClass('video-active'); 2720 } 2721 2722 //////////////// Video Cover Play Icons 2723 2724 $('.video-cover').each(function(){ 2725 var videoCover = $(this); 2726 if(videoCover.find('iframe').length){ 2727 videoCover.find('iframe').attr('data-src', videoCover.find('iframe').attr('src')); 2728 videoCover.find('iframe').attr('src',''); 2729 } 2730 }); 2731 2732 $('.video-cover .video-play-icon').on("click", function(){ 2733 var playIcon = $(this); 2734 var videoCover = playIcon.closest('.video-cover'); 2735 if(videoCover.find('video').length){ 2736 var video = videoCover.find('video').get(0); 2737 videoCover.addClass('reveal-video'); 2738 video.play(); 2739 return false; 2740 }else if(videoCover.find('iframe').length){ 2741 var iframe = videoCover.find('iframe'); 2742 iframe.attr('src',iframe.attr('data-src')); 2743 videoCover.addClass('reveal-video'); 2744 return false; 2745 } 2746 }); 2747 }; 2748 2749 mr.video = { 2750 documentReady : documentReady 2751 }; 2752 2753 mr.components.documentReady.push(documentReady); 2754 return mr; 2755 2756}(mr, jQuery, window, document)); 2757 2758//////////////// Wizard 2759mr = (function (mr, $, window, document){ 2760 "use strict"; 2761 2762 var documentReady = function($){ 2763 2764 $('.wizard').each(function(){ 2765 var wizard = jQuery(this); 2766 wizard.steps({ 2767 headerTag: "h5", 2768 bodyTag: "section", 2769 transitionEffect: "slideLeft", 2770 autoFocus: true 2771 }); 2772 wizard.addClass('active'); 2773 }); 2774 2775 }; 2776 2777 mr.wizard = { 2778 documentReady : documentReady 2779 }; 2780 2781 mr.components.documentReady.push(documentReady); 2782 return mr; 2783 2784}(mr, jQuery, window, document)); 2785 2786 2787$(function() { 2788 $('#meals-menu .row .feature__body').matchHeight(); 2789});
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.