/** * v1.0 - Copyright 2014 Madden Media - All rights reserved. * * Advanced Google Analytics tracking script that tracks starting reading, 25%, * 50%, 75% and completion. This is otherwise a duplicate of: * * madden-ga-track-start-end-v1.0.js * * This duplication is in place to reduce configuration work for callers. * * Requires Google Analytics and jQuery. This script will determine which analytics * object (universal, legacy, etc.) seems to be present and will adjust tracking * calls based on this. */ // safe console log if (typeof console == "undefined"){console={};console.log = function(){return;}} jQuery(function($) { // Debug flags var debugMode = false; var logOutput = false; // Default time delay before checking location var callBackTime = 100; // percent of the page where reader events fire // at (use decimals < 1 - i.e. .25) - use .0001 for "start of page" var readerLocationPercents = [.0001, .25, .5, .75]; // # px before tracking a reader (will be assigned based on readerLocationPercents) var readerLocations = [ ]; // how far have they made it (this will be managed by the script) var readerLastPassed = 0; // Set some flags for tracking & execution var timer = 0; var isScrolling = false; var endContent = false; var didComplete = false; // Set some time variables to calculate reading time var startTime = new Date(); var beginning = startTime.getTime(); var totalTime = 0; // Check the location and track user function trackLocation () { // positions var curWinBottom = ($(window).height() + $(window).scrollTop()); var height = $(document).height(); // figure out scroll time var currentTime = new Date(); var timeToScroll = Math.round((currentTime.getTime() - beginning) / 1000); // If user starts to scroll send an event (if it's at a tracking point) for (i=readerLastPassed; i < readerLocations.length; i++) { // run location test if ( (curWinBottom >= readerLocations[i]) && (timeToScroll > 0) ) { // set label var label = makeReadingEventLabel(readerLocationPercents[i]); // send the event sendEvent('Reading', label, timeToScroll, location.pathname); // log it log('READING: ' + readerLocations[i] + " / " + label + " / " + timeToScroll); // note what they've tracked readerLastPassed = (i + 1); } } // if user has hit the bottom of page send an event if ( (curWinBottom >= height) && (! didComplete) ) { currentTime = new Date(); // figure out scroll time var currentTime = new Date(); var timeToScroll = Math.round((currentTime.getTime() - beginning) / 1000); // set label var label = makeReadingEventLabel(1); // send the event sendEvent('Reading', label, timeToScroll, location.pathname); // log it log('READING: ' + label + " / " + timeToScroll); didComplete = true; } } // figure out how tall our page is and adjust reader location to be a percent of that function adjustReaderLocation (percent) { var docHeight = $(document).height(); var adjHeight = Math.floor(docHeight * percent); return adjHeight; } // util function to make a pretty reading label string function makeReadingEventLabel (raw) { var lbl = ""; if (raw < .001) { lbl = "StartReading"; } else if (raw == 1) { lbl = "ContentBottom"; } else { lbl = ("Reading " + (raw * 100) + "%"); } return lbl; } // a log wrapper to check if we want it logged first function log (msg) { if (logOutput) { console.log(msg); } } // sends the event to whichever object we seem to have found function sendEvent (eventCategory, eventAction, eventValue, page) { if (debugMode) { // MAY EXIT THIS BLOCK return; } // test for any given analytics type if (typeof _gaq != "undefined") { // legacy analytics if (typeof pageTracker != "undefined") { // "traditional syntax" pageTracker._trackEvent(eventCategory, eventAction, page, eventValue); } else { // "asynchronous syntax" _gaq.push(['_trackEvent', eventCategory, eventAction, page, eventValue]); _gaq.push(['pageTracker._trackEvent', eventCategory, eventAction, page, eventValue]); } } else if (typeof ga != "undefined") { // universal analytics ga('send', { 'hitType': 'event', 'eventCategory': eventCategory, 'eventAction': eventAction, 'eventLabel': page, 'eventValue': eventValue }); } } // determine reader % locations function determineReaderLocations () { for (i=0; i < readerLocationPercents.length; i++) { readerLocations[i] = adjustReaderLocation(readerLocationPercents[i]); // log it log('LOCATION: ' + readerLocationPercents[i] + ' (' + readerLocations[i] + ' / ' + $(document).height() + ')'); } } // assign all percent sizes based on height of page $(window).load(function() { determineReaderLocations(); }); // reassign all percent sizes based on height of page $(window).resize(function() { determineReaderLocations(); }); // Track the scrolling and track location $(window).scroll(function() { if (timer) { clearTimeout(timer); } // Use a buffer so we don't call trackLocation too often. timer = setTimeout(trackLocation, callBackTime); }); }); /* * v1.2 * * Automatically track outbound links in Google Analytics. Any link that you do not want tracked * can be assigned a "noGA" class and it will not be skipped here. Includes support for GA and GAQ * * CREDIT: http://www.sitepoint.com/track-outbound-links-google-analytics/ * * Modified to support ability for links to open in new window w/o triggering a popup warning */ (function($) { "use strict"; // default no tracking class var defaultNoTrackClass = "noGA"; // current page host var baseURI = window.location.host; // click event on body $("body").on("click", function(e) { // abandon if link already aborted or analytics is not available if ( (e.isDefaultPrevented()) || ( (typeof _gaq === "undefined") && (typeof ga === "undefined") ) ) { return; } // abandon if no active link or link within domain var link = $(e.target).closest("a"); // if (link.length != 1 || baseURI == link[0].host) return; if (link.length != 1) return; // check the link to see if it should not be tracked if ( (link.attr("class") !== undefined) && (link.attr("class").indexOf(defaultNoTrackClass) != -1) ) { return; } // cancel event and record outbound link e.preventDefault(); var href = link[0].href; var target = link[0].target; if (target != "") { // gets us around popup blocking $(link[0]).on("click", function(){ var w = window.open(href, target); trackEvent(href, false); return false; }); $(link[0]).click(); } else { trackEvent(href, true); // in case hit callback bogs down setTimeout(function() { self.location.href = href; }, 1000); } // track the event function trackEvent (href, runHitCallback) { // test for any given analytics type if (typeof _gaq != "undefined") { // legacy analytics if (typeof pageTracker != "undefined") { // "traditional syntax" pageTracker._trackEvent('Presentation Layer', 'Outbound Click', href); } else { // "asynchronous syntax" var redirect = function (runHitCallback) { if (runHitCallback) { self.location.href = href; } else { return false; } }; _gaq.push(['_set','hitCallback', redirect(runHitCallback)]); _gaq.push(['_trackEvent', 'Presentation Layer', 'Outbound Click', href]); _gaq.push(['pageTracker._trackEvent', 'Presentation Layer', 'Outbound Click', href]); } } else if (typeof ga != "undefined") { // universal analytics ga('send', { 'hitType': 'event', 'eventCategory': 'Presentation Layer', 'eventAction': 'Outbound Click', 'eventLabel': href, 'hitCallback': (runHitCallback) ? function() { self.location.href = href; } : function() { return false; } }); } } }); })(jQuery); /** * v1.2 - Copyright 2015 Madden Media - All rights reserved. * * A set of parallax design functionality. */ !function(a){"use strict";a.fn.parallaxBG=function(b){var c=a(window).height(),d=0,e=a(window).scrollTop(),f=0,g=0,h=a.extend({adjustX:0,adjustY:0,bgXOffset:0,bgYOffset:0,bgXPosition:"100%",bgYPosition:"100%"},b);return this.each(function(){var b=a(this);a(window).scroll(function(){var i=h.bgXAdjust,j=b.css("backgroundPosition").split(" ");parseInt(j[0]);if(e=a(window).scrollTop(),f=b.offset().top,g=b.outerHeight(),e=e+c)){var l=0==h.adjustX?h.bgXPosition:Math.round((f-e)*h.adjustX)+0+h.bgXOffset+"px",m=0==h.adjustY?h.bgYPosition:Math.round((f-e)*h.adjustY)+0+h.bgYOffset+"px";b.css("background-position",l+" "+m)}})})},a.fn.parallaxLockElement=function(b){var c=!1,d=a.extend({parentEl:"",offsetTop:0,additionalCSS:void 0,onLock:void 0,onRelease:void 0},b);return this.each(function(){var b=a(this),e=a(d.parentEl);a(window).scroll(function(){var f=parseInt(e.offset().top-a(window).scrollTop()-d.offsetTop),g=e.offset().top+e.outerHeight(),i=(parseInt(b.outerHeight()),e.offset().top+e.outerHeight()-(b.offset().top+b.outerHeight()));f<=0?g+i<=a(window).scrollTop()+a(window).innerHeight()?c&&(c=!1,b.css({position:"absolute",top:"inherit",bottom:i+"px"}),"function"==typeof d.onRelease&&d.onRelease(this)):(b.css({position:"fixed",top:d.offsetTop+"px",bottom:"auto"}),"function"==typeof d.onLock&&d.onLock(this),c=!0):(b.css({position:"relative",top:"auto"}),"function"==typeof d.onRelease&&d.onRelease(this),c=!1),void 0!=d.additionalCSS&&b.css(d.additionalCSS)})})},a.fn.parallaxAnimateElement=function(b){var c=new Array,d=0,e=0,f=!1,g=a.extend({frames:1,elementClass:"floatingElement",elementFrameClassRoot:"frame",startOffset:null,endOffset:null,showWhenCentered:!1,centerOffsetAnimationRange:null,lock:!1,parentEl:"",offsetTop:0,additionalCSS:void 0,onLock:void 0,onRelease:void 0},b);g.lock?a(this).parallaxLockElement({parentEl:g.parentEl,offsetTop:g.offsetTop,additionalCSS:g.additionalCSS,onLock:g.onLock,onRelease:g.onRelease}):f=!0;var h=parseInt(a(this).parent().height());if(g.showWhenCentered)null==g.centerOffsetAnimationRange?g.centerOffsetAnimationRange=1:g.centerOffsetAnimationRange.indexOf("%")!=-1?g.centerOffsetAnimationRange=parseInt(g.centerOffsetAnimationRange)/100:g.centerOffsetAnimationRange=1;else{if(null!=g.startOffset)if(g.startOffset.indexOf("%")!=-1){var i=parseInt(g.startOffset)/100;d=Math.floor(h*i)}else{var i=parseInt(g.startOffset);d=i}if(null!=g.endOffset)if(g.endOffset.indexOf("%")!=-1){var i=parseInt(g.endOffset)/100;e=Math.floor(h-h*i)}else{var i=parseInt(g.endOffset);e=i}0==d&&0==e||(h=h-e-d);for(var j=h/g.frames,k=1;k<=g.frames;k++)c.push(Math.floor(d+j*k));f&&void 0!=g.additionalCSS&&a(this).css(g.additionalCSS)}return this.each(function(){var b=a(this),d=c.length,e=g.showWhenCentered?a(this).height()*g.centerOffsetAnimationRange:a(this).height();a(window).scroll(function(){var f=b.offset().top,h=!(f+b.outerHeight()<=a(window).scrollTop()||f>=a(window).scrollTop()+a(window).height());if(h){if(g.showWhenCentered){var i=parseInt(b.offset().top-a(window).scrollTop()),j=parseInt(i+e/2),k=parseInt(a(window).innerHeight()/2),l=parseInt(j-e),m=parseInt(j+e);if(k=l&&k<=m){var n=Math.max(0,Math.min(1,1-(l+(j-k))/j));d=Math.ceil(g.frames*n)}else d=g.frames}else for(var o=parseInt(b.parent().offset().top-a(window).scrollTop()),p=o*-1+e/2,q=0;q";t.append(o)}},unFixBGImagesForIPads=function(e){e=void 0===e?".chapterImage":e,getDoParallax()&&getIsIPad()&&$(e).css("background-attachment","scroll")},getCurrentChapter=function(){return _onChapter},getVisibleViewport=function(e){return e?window.innerHeight-_stickyTopBarHeight+"px":parseInt(window.innerHeight-_stickyTopBarHeight)},getViewportOffset=function(e,t){return t?jQuery(e).offset().top-jQuery(window).scrollTop()-_stickyTopBarHeight+"px":parseInt(jQuery(e).offset().top-jQuery(window).scrollTop()-_stickyTopBarHeight)},getItemInViewport=function(e){var t=jQuery(e).offset().top;return!(t+jQuery(e).outerHeight()<=jQuery(window).scrollTop()||t>=jQuery(window).scrollTop()+jQuery(window).height())},getItemInViewportCenter=function(e,t){var r=jQuery(e).offset().top,a=jQuery(window).height()/2;return t=t||0,!(r>=jQuery(window).scrollTop()+a+t||r<=jQuery(window).scrollTop()+a-t)},getStickyTopBarHeight=function(){return _stickyTopBarHeight},getIsMobile=function(){return _isMobile},getIsTablet=function(){return _isTablet},getDoParallax=function(){return _doParallax},getIsDesktop=function(){return!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},getIsIPad=function(){return navigator.userAgent.match(/iPad;.*CPU.*OS/i)},getIsNewerIPad=function(){return!!getIsIPad()&&1!=window.devicePixelRatio},getIsNewerIpad=function(){return getIsNewerIPad()},getIsResponsive=function(){return IS_RESPONSIVE},adjustLayoutAfterResize=function(){initChapterTops(!0),adjustMultiSizedImages()},adjustChapterLinksArtHeight=function(e,t){jQuery(e).css("height",jQuery(t).outerHeight())},adjustSizeToParentAndViewport=function(e,t){jQuery(e).css("height",getVisibleViewport(!0)),jQuery(e).css("width",jQuery(t).width())},adjustSizeHeightToParent=function(e,t){var r=jQuery(t).height();jQuery(e).css("height",r+"px")},equalizeElementHeightsToTallest=function(e){for(var t=0,r=0;rt?a:t)}for(r=0;r=0;a--)if(jQuery(document).scrollTop()>=_chapterTops[a]){t=a+1;break}return-1!=t&&adjustChapterLinks(t),t}},adjustChapterLinks=function(e){jQuery(_chapterLinkEl).each(function(){jQuery(this).attr("href")!="#"+e?"function"==typeof _setChapterLinkCallback&&_setChapterLinkCallback(this,!1):("function"==typeof _setChapterLinkCallback&&_setChapterLinkCallback(this,!0),_onChapter=e)})},adjustMultiSizedImages=function(){var e=jQuery(_multiSizeImageEl);e.length&&e.each(function(){getIsResponsive()||void 0==jQuery(this).data("src-legacy")?getIsMobile()&&void 0!=jQuery(this).data("src-small")?jQuery(this).attr("src",jQuery(this).data("src-small")):getIsTablet()&&void 0!=jQuery(this).data("src-medium")?jQuery(this).attr("src",jQuery(this).data("src-medium")):void 0!=jQuery(this).data("src")&&jQuery(this).attr("src",jQuery(this).data("src")):jQuery(this).attr("src",jQuery(this).data("src-legacy"))})},toTop=function(){jQuery("html, body").animate({scrollTop:0},600)},runTopMenuControl=function(){getIsMobile()?toggleMobileMenu(_mobileMenuEl,_topAndMobileMenuControl):toTop()},toggleMobileMenu=function(e,t){getIsMobile()&&(jQuery(e).toggle("fast"),jQuery(t).toggle("fast"))},goToChapter=function(e){var t=jQuery(_chapterElPrefix+e).offset().top-_stickyTopBarHeight+1,r=_onChapter>e?_onChapter-e:e-_onChapter,a=Math.floor(1e3/(_chapterTops.length-(_chapterTops.length-r)));jQuery("html, body").animate({scrollTop:t},a,function(){adjustChapterLinks(e),"function"==typeof _chapterSetCompleteCallback&&_chapterSetCompleteCallback(e)}),_onChapter=e},animateOverflowContent=function(e,t,r,a,o){if(o==_onChapter){var i=jQuery(e).css("background-position").split(" "),n=isNaN(t)?t:t+parseInt(i[0])+"px",l=isNaN(r)?r:r+parseInt(i[1])+"px";jQuery(e).css({"background-position":n+" "+l})}window.setTimeout(function(){animateOverflowContent(e,t,r,a,o)},a)},cycleImages=function(e,t){var r=jQuery(e+" .active"),a=r.next().length>0?r.next():jQuery(e+" img:first");a.css("z-index",2),r.fadeOut(t,function(){r.css("z-index",1).show().removeClass("active"),a.css("z-index",3).addClass("active")})}; /** * v1.0 - Copyright 2015 Madden Media - All rights reserved. * * Content-specific layout functionality. These functions * make many assumptions about content contained in the page. * * NOTE: Assumes that madden-content-frameworks-v1.0.js has been loaded and * that the initial view types (mobile, tablet, etc.) have been defined. */ // mobile can call resize during scroll - we can cache width // and check if an actual resize happens var _winWidth = 0; ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// // STOCK EVENT FUNCTIONS ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// // // Called on document ready // contentOnReady = function () { // set the window width _winWidth = $(window).width(); // parallax effects if (getDoParallax()) { // parallax bgs $("#ci0").parallaxBG({ adjustY: .12, bgXPosition: 'center' }); $("#ci2").parallaxBG({ adjustY: .12, bgXPosition: 'center' }); $("#ci3").parallaxBG({ adjustY: .12, bgXPosition: 'center' }); //locked items $("#c2Float").parallaxLockElement({ parentEl: "#c2Text", additionalCSS: { "right": "1%", "margin-top": "120px" } }); $("#c3Float").parallaxLockElement({ parentEl: "#c3Text", additionalCSS: { "right": "1%", "margin-top": "120px" } }); } customAdjustLayout(true); // add the complete class to the loader $('#loading').addClass('complete'); // Recommended Reads links var RELATED = {}; RELATED["1"] = { "id" : "1", "link": "https://outwickenburgway.com/things-to-do/a-wickenburg-weekend/", "title": "A Wickenburg Weekend" }; RELATED["2"] = { "id" : "2", "link": "https://outwickenburgway.com/food-lodging/restaurants/", "title": "Food & Lodging" }; RELATED["3"] = { "id" : "3", "link": "https://outwickenburgway.com/things-to-do/activities/ ", "title": "Activities" }; // Populate the links on the Hub var links = document.getElementById('alsoLikeLinkWrap'); // find the div to build in var i = 0; for (var i in RELATED) { if (!document.getElementById('links'+i)) { // build the links var newLink = document.createElement("div"); newLink.setAttribute("id","links" + RELATED[i].id); newLink.setAttribute("class","linkWrapper"); newLink.innerHTML = "" + "" links.appendChild(newLink); } i++; } } // // Called on document scroll // contentOnScroll = function () { } // // Called on a touch move on mobile // contentOnTouchMove = function () { } // // Called on document resize // contentOnResize = function () { customAdjustLayout(); } ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// // CUSTOM FUNCTIONS ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// // // The frameworks was given this function to handle setting chapter buttons // when the chapter is set // // chapterEl: The chapter link DOM element // on: Is it being turned on? (true|false) // customChapterLinkAdjust = function (chapterEl, on) { $(chapterEl).attr("class", ((on) ? "navLink chapterLink noGA on" : "navLink chapterLink noGA")); } // // Adjust this specific layout after a load or resize event // // isLoad: Is this being called by a load or resize event? // customAdjustLayout = function (isLoad) { var localNotJustTouchScroll = isLoad; // is it really a resize? if ($(window).width() != _winWidth) { // yes localNotJustTouchScroll = true; _winWidth = $(window).width(); } if (localNotJustTouchScroll) { } }