/*! * ===================================================== * Ratchet v2.0.2 (http://goratchet.com) * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * * v2.0.2 designed by @connors. * ===================================================== */ /* ======================================================================== * Ratchet: common.js v2.0.2 * http://goratchet.com/ * ======================================================================== * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * ======================================================================== */ !(function () { 'use strict'; // Compatible With CustomEvent if (!window.CustomEvent) { window.CustomEvent = function (type, config) { var e = document.createEvent('CustomEvent'); e.initCustomEvent(type, config.bubbles, config.cancelable, config.detail); return e; }; } // Create Ratchet namespace if (typeof window.RATCHET === 'undefined') { window.RATCHET = {}; } // Original script from http://davidwalsh.name/vendor-prefix window.RATCHET.getBrowserCapabilities = (function () { var styles = window.getComputedStyle(document.documentElement, ''); var pre = (Array.prototype.slice .call(styles) .join('') .match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o']) )[1]; return { prefix: '-' + pre + '-', transform: pre[0].toUpperCase() + pre.substr(1) + 'Transform' }; })(); window.RATCHET.getTransitionEnd = (function () { var el = document.createElement('ratchet'); var transEndEventNames = { WebkitTransition : 'webkitTransitionEnd', MozTransition : 'transitionend', OTransition : 'oTransitionEnd otransitionend', transition : 'transitionend' }; for (var name in transEndEventNames) { if (el.style[name] !== undefined) { return transEndEventNames[name]; } } return transEndEventNames.transition; })(); }()); /* ======================================================================== * Ratchet: modals.js v2.0.2 * http://goratchet.com/components#modals * ======================================================================== * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * ======================================================================== */ !(function () { 'use strict'; var eventModalOpen = new CustomEvent('modalOpen', { bubbles: true, cancelable: true }); var eventModalClose = new CustomEvent('modalClose', { bubbles: true, cancelable: true }); var findModals = function (target) { var i; var modals = document.querySelectorAll('a'); for (; target && target !== document; target = target.parentNode) { for (i = modals.length; i--;) { if (modals[i] === target) { return target; } } } }; var getModal = function (event) { var modalToggle = findModals(event.target); if (modalToggle && modalToggle.hash) { return document.querySelector(modalToggle.hash); } }; window.addEventListener('touchend', function (event) { var modal = getModal(event); if (modal && modal.classList.contains('modal')) { var eventToDispatch = eventModalOpen; if (modal.classList.contains('active')) { eventToDispatch = eventModalClose; } modal.dispatchEvent(eventToDispatch); modal.classList.toggle('active'); } event.preventDefault(); // prevents rewriting url (apps can still use hash values in url) }); }()); /* ======================================================================== * Ratchet: popovers.js v2.0.2 * http://goratchet.com/components#popovers * ======================================================================== * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * ======================================================================== */ !(function () { 'use strict'; var popover; var findPopovers = function (target) { var i; var popovers = document.querySelectorAll('a'); for (; target && target !== document; target = target.parentNode) { for (i = popovers.length; i--;) { if (popovers[i] === target) { return target; } } } }; var onPopoverHidden = function () { popover.style.display = 'none'; popover.removeEventListener(window.RATCHET.getTransitionEnd, onPopoverHidden); }; var backdrop = (function () { var element = document.createElement('div'); element.classList.add('backdrop'); element.addEventListener('touchend', function () { popover.addEventListener(window.RATCHET.getTransitionEnd, onPopoverHidden); popover.classList.remove('visible'); popover.parentNode.removeChild(backdrop); }); return element; }()); var getPopover = function (e) { var anchor = findPopovers(e.target); if (!anchor || !anchor.hash || (anchor.hash.indexOf('/') > 0)) { return; } try { popover = document.querySelector(anchor.hash); } catch (error) { popover = null; } if (popover === null) { return; } if (!popover || !popover.classList.contains('popover')) { return; } return popover; }; var showHidePopover = function (e) { var popover = getPopover(e); if (!popover) { return; } popover.style.display = 'block'; popover.offsetHeight; popover.classList.add('visible'); popover.parentNode.appendChild(backdrop); }; window.addEventListener('touchend', showHidePopover); }()); !(function () { 'use strict'; // Ratchet's layout includes fixed position headers & footers that should always // appear before the main .content div within // // These fixed bars will have new content swapped in, ignoring any // transitions (slide-in, slide-out & fade). // // These following selectors define which elements are transitioned with // simple DOM replacement and are always immediate children of var barSelectors = [ '.bar-tab', '.bar-nav', '.bar-footer', '.bar-header-secondary' ]; // Other than any fixed bars, '.content' should be the only other child of body var contentSelector = '.content'; // For any bar elements in `newMarkup`, either: // * replace an existing bar elements with new content // * add new bar elements when an existing one isn't present // * remove any bar elements not found in `newMarkup` var updateBars = function (newMarkup) { for (var i = 0; i < barSelectors.length; i++) { var selector = barSelectors[i]; var newBar = newMarkup.querySelector(selector); var existingBar = document.querySelector(selector); if (newBar) { displayBar(newBar, existingBar); } else if (existingBar) { existingBar.parentNode.removeChild(existingBar); } } }; var displayBar = function (bar, container) { if (container) { container.innerHTML = ''; container.appendChild(bar); } else { // per Ratchet's CSS, bar elements must be the first thing in // here we assume `.content` is an immediate child of document.body.insertBefore(bar, document.querySelector(contentSelector)); } }; var transitionContent = function (swap, container, transition, complete) { var enter; var containerDirection; var swapDirection; enter = /in$/.test(transition); if (transition === 'fade') { container.classList.add('in'); container.classList.add('fade'); swap.classList.add('fade'); } if (/slide/.test(transition)) { swap.classList.add('sliding-in', enter ? 'right' : 'left'); swap.classList.add('sliding'); container.classList.add('sliding'); } container.parentNode.insertBefore(swap, container); if (transition === 'fade') { container.offsetWidth; // force reflow container.classList.remove('in'); var fadeContainerEnd = function () { container.removeEventListener(window.RATCHET.getTransitionEnd, fadeContainerEnd); swap.classList.add('in'); swap.addEventListener(window.RATCHET.getTransitionEnd, fadeSwapEnd); }; var fadeSwapEnd = function () { swap.removeEventListener(window.RATCHET.getTransitionEnd, fadeSwapEnd); container.parentNode.removeChild(container); swap.classList.remove('fade'); swap.classList.remove('in'); complete && complete(); }; container.addEventListener(window.RATCHET.getTransitionEnd, fadeContainerEnd); } if (/slide/.test(transition)) { var slideEnd = function () { swap.removeEventListener(window.RATCHET.getTransitionEnd, slideEnd); swap.classList.remove('sliding', 'sliding-in'); swap.classList.remove(swapDirection); container.parentNode.removeChild(container); complete && complete(); }; container.offsetWidth; // force reflow swapDirection = enter ? 'right' : 'left'; containerDirection = enter ? 'left' : 'right'; container.classList.add(containerDirection); swap.classList.remove(swapDirection); swap.addEventListener('webkitTransitionEnd', slideEnd); } }; // `contents` can either be a string of HTML or a DOM object. // Either way, `contents` must include: // * bar elements (optional -- see `barSelectors`) // * a single content element // All as children of a single parent. // // For example: //
//
//
//
//
var TRANSITION = function (contents, transition, complete) { if(typeof(contents) === 'string' || contents instanceof String) { var div = document.createElement('div'); div.innerHTML = contents; contents = div.childNodes[0]; } else { contents = contents.cloneNode(true) } if (transition) { updateBars(contents); var existingContentDiv = document.querySelector(contentSelector); var newContentDiv = contents.querySelector(contentSelector); transitionContent(newContentDiv, existingContentDiv, transition, complete); } else { document.body.innerHTML = ''; document.body.appendChild(contents); complete && complete(); } }; window.TRANSITION = TRANSITION; }()); /* ======================================================================== * Ratchet: push.js v2.0.2 * http://goratchet.com/components#push * ======================================================================== * inspired by @defunkt's jquery.pjax.js * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * ======================================================================== */ /* global _gaq, TRANSITION */ !(function () { 'use strict'; var noop = function () {}; // Pushstate caching // ================== var isScrolling; var maxCacheLength = 20; var cacheMapping = sessionStorage; var domCache = {}; // Change these to unquoted camelcase in the next major version bump var transitionMap = { 'slide-in' : 'slide-out', 'slide-out' : 'slide-in', fade : 'fade' }; var cacheReplace = function (data, updates) { PUSH.id = data.id; if (updates) { data = getCached(data.id); } cacheMapping[data.id] = JSON.stringify(data); window.history.replaceState(data.id, data.title, data.url); }; var cachePush = function () { var id = PUSH.id; var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]'); var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]'); cacheBackStack.push(id); while (cacheForwardStack.length) { delete cacheMapping[cacheForwardStack.shift()]; } while (cacheBackStack.length > maxCacheLength) { delete cacheMapping[cacheBackStack.shift()]; } if (getCached(PUSH.id).url) { window.history.pushState(null, '', getCached(PUSH.id).url); } cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack); cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack); }; var cachePop = function (id, direction) { var forward = direction === 'forward'; var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]'); var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]'); var pushStack = forward ? cacheBackStack : cacheForwardStack; var popStack = forward ? cacheForwardStack : cacheBackStack; if (PUSH.id) { pushStack.push(PUSH.id); } popStack.pop(); cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack); cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack); }; var getCached = function (id) { return JSON.parse(cacheMapping[id] || null) || {}; }; var getTarget = function (e) { var target = findTarget(e.target); if (!target || e.which > 1 || e.metaKey || e.ctrlKey || isScrolling || location.protocol !== target.protocol || location.host !== target.host || !target.hash && /#/.test(target.href) || target.hash && target.href.replace(target.hash, '') === location.href.replace(location.hash, '') || target.getAttribute('data-ignore') === 'push') { return; } return target; }; // Main event handlers (touchend, popstate) // ========================================== var touchend = function (e) { var target = getTarget(e); if (!target) { return; } e.preventDefault(); PUSH({ url : target.href, hash : target.hash, timeout : target.getAttribute('data-timeout'), transition : target.getAttribute('data-transition') }); }; var popstate = function (e) { var activeObj; var activeDom; var direction; var transition; var transitionFrom; var transitionFromObj; var id = e.state; if (!id || !cacheMapping[id]) { return; } direction = PUSH.id < id ? 'forward' : 'back'; cachePop(id, direction); activeObj = getCached(id); activeDom = domCache[id]; if (activeObj.title) { document.title = activeObj.title; } if (direction === 'back') { transitionFrom = JSON.parse(direction === 'back' ? cacheMapping.cacheForwardStack : cacheMapping.cacheBackStack); transitionFromObj = getCached(transitionFrom[transitionFrom.length - 1]); } else { transitionFromObj = activeObj; } if (direction === 'back' && !transitionFromObj.id) { return (PUSH.id = id); } transition = direction === 'back' ? transitionMap[transitionFromObj.transition] : transitionFromObj.transition; if (!activeDom) { return PUSH({ id : activeObj.id, url : activeObj.url, title : activeObj.title, timeout : activeObj.timeout, transition : transition, ignorePush : true }); } TRANSITION(activeDom.cloneNode(true), transitionFromObj.transition, function() { triggerStateChange(); }); PUSH.id = id; document.body.offsetHeight; // force reflow to prevent scroll }; // Core PUSH functionality // ======================= var PUSH = function (options) { var xhr = PUSH.xhr; if (xhr && xhr.readyState < 4) { xhr.onreadystatechange = noop; xhr.abort(); } xhr = new XMLHttpRequest(); xhr.open('GET', options.url, true); xhr.setRequestHeader('X-PUSH', 'true'); xhr.onreadystatechange = function () { if (options._timeout) { clearTimeout(options._timeout); } if (xhr.readyState === 4) { if (xhr.status === 200) { success(xhr, options); } else { failure(options.url); } } }; if (!PUSH.id) { cacheReplace({ id : +new Date(), url : window.location.href, title : document.title, timeout : options.timeout, transition : options.transition }); } cacheCurrentContent(); if (options.timeout) { options._timeout = setTimeout(function () { xhr.abort('timeout'); }, options.timeout); } xhr.send(); if (xhr.readyState && !options.ignorePush) { cachePush(); } }; function cacheCurrentContent () { domCache[PUSH.id] = document.body.cloneNode(true); } // Main XHR handlers // ================= var success = function (xhr, options) { var data = parseXHR(xhr, options); if (!data.contents) { return locationReplace(options.url); } if (data.title) { document.title = data.title; } TRANSITION(data.contents, options.transition, function () { cacheReplace({ id : options.id || +new Date(), url : data.url, title : data.title, timeout : options.timeout, transition : options.transition }, options.id); triggerStateChange(); }); if (!options.ignorePush && window._gaq) { _gaq.push(['_trackPageview']); // google analytics } if (!options.hash) { return; } }; var failure = function (url) { throw new Error('Could not get: ' + url); }; // PUSH helpers // ============ var triggerStateChange = function () { var e = new CustomEvent('push', { detail: { state: getCached(PUSH.id) }, bubbles: true, cancelable: true }); window.dispatchEvent(e); }; var findTarget = function (target) { var i; var toggles = document.querySelectorAll('a'); for (; target && target !== document; target = target.parentNode) { for (i = toggles.length; i--;) { if (toggles[i] === target) { return target; } } } }; var locationReplace = function (url) { window.history.replaceState(null, '', '#'); window.location.replace(url); }; var parseXHR = function (xhr, options) { var head; var body; var data = {}; var responseText = xhr.responseText; data.url = options.url; if (!responseText) { return data; } if (/]*>([\s\S.]*)<\/head>/i)[0]; body.innerHTML = responseText.match(/]*>([\s\S.]*)<\/body>/i)[0]; } else { head = body = document.createElement('div'); head.innerHTML = responseText; } data.title = head.querySelector('title') || document.querySelector('title'); var text = 'innerText' in data.title ? 'innerText' : 'textContent'; data.title = data.title && data.title[text].trim(); data.contents = body; return data; }; // Attach PUSH event handlers // ========================== window.addEventListener('touchstart', function () { isScrolling = false; }); window.addEventListener('touchmove', function () { isScrolling = true; }); window.addEventListener('touchend', touchend); window.addEventListener('click', function (e) { if (getTarget(e)) { e.preventDefault(); } }); window.addEventListener('popstate', popstate); // TODO : Remove this line in the next major version window.PUSH = PUSH; window.RATCHET.push = PUSH; }()); /* ======================================================================== * Ratchet: segmented-controllers.js v2.0.2 * http://goratchet.com/components#segmentedControls * ======================================================================== * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * ======================================================================== */ !(function () { 'use strict'; var getTarget = function (target) { var i; var segmentedControls = document.querySelectorAll('.segmented-control .control-item'); for (; target && target !== document; target = target.parentNode) { for (i = segmentedControls.length; i--;) { if (segmentedControls[i] === target) { return target; } } } }; window.addEventListener('touchend', function (e) { var activeTab; var activeBodies; var targetBody; var targetTab = getTarget(e.target); var className = 'active'; var classSelector = '.' + className; if (!targetTab) { return; } activeTab = targetTab.parentNode.querySelector(classSelector); if (activeTab) { activeTab.classList.remove(className); } targetTab.classList.add(className); if (!targetTab.hash) { return; } targetBody = document.querySelector(targetTab.hash); if (!targetBody) { return; } activeBodies = targetBody.parentNode.querySelectorAll(classSelector); for (var i = 0; i < activeBodies.length; i++) { activeBodies[i].classList.remove(className); } targetBody.classList.add(className); }); window.addEventListener('click', function (e) { if (getTarget(e.target)) { e.preventDefault(); } }); }()); /* ======================================================================== * Ratchet: sliders.js v2.0.2 * http://goratchet.com/components#sliders * ======================================================================== Adapted from Brad Birdsall's swipe * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * ======================================================================== */ !(function () { 'use strict'; var pageX; var pageY; var slider; var deltaX; var deltaY; var offsetX; var lastSlide; var startTime; var resistance; var sliderWidth; var slideNumber; var isScrolling; var scrollableArea; var startedMoving; var transformPrefix = window.RATCHET.getBrowserCapabilities.prefix; var transformProperty = window.RATCHET.getBrowserCapabilities.transform; var getSlider = function (target) { var i; var sliders = document.querySelectorAll('.slider > .slide-group'); for (; target && target !== document; target = target.parentNode) { for (i = sliders.length; i--;) { if (sliders[i] === target) { return target; } } } }; var getScroll = function () { var translate3d = slider.style[transformProperty].match(/translate3d\(([^,]*)/); var ret = translate3d ? translate3d[1] : 0; return parseInt(ret, 10); }; var setSlideNumber = function (offset) { var round = offset ? (deltaX < 0 ? 'ceil' : 'floor') : 'round'; slideNumber = Math[round](getScroll() / (scrollableArea / slider.children.length)); slideNumber += offset; slideNumber = Math.min(slideNumber, 0); slideNumber = Math.max(-(slider.children.length - 1), slideNumber); }; var onTouchStart = function (e) { slider = getSlider(e.target); if (!slider) { return; } var firstItem = slider.querySelector('.slide'); scrollableArea = firstItem.offsetWidth * slider.children.length; isScrolling = undefined; sliderWidth = slider.offsetWidth; resistance = 1; lastSlide = -(slider.children.length - 1); startTime = +new Date(); pageX = e.touches[0].pageX; pageY = e.touches[0].pageY; deltaX = 0; deltaY = 0; setSlideNumber(0); slider.style[transformPrefix + 'transition-duration'] = 0; }; var onTouchMove = function (e) { if (e.touches.length > 1 || !slider) { return; // Exit if a pinch || no slider } // adjust the starting position if we just started to avoid jumpage if (!startedMoving) { pageX += (e.touches[0].pageX - pageX) - 1; } deltaX = e.touches[0].pageX - pageX; deltaY = e.touches[0].pageY - pageY; pageX = e.touches[0].pageX; pageY = e.touches[0].pageY; if (typeof isScrolling === 'undefined' && startedMoving) { isScrolling = Math.abs(deltaY) > Math.abs(deltaX); } if (isScrolling) { return; } offsetX = (deltaX / resistance) + getScroll(); e.preventDefault(); resistance = slideNumber === 0 && deltaX > 0 ? (pageX / sliderWidth) + 1.25 : slideNumber === lastSlide && deltaX < 0 ? (Math.abs(pageX) / sliderWidth) + 1.25 : 1; slider.style[transformProperty] = 'translate3d(' + offsetX + 'px,0,0)'; // started moving startedMoving = true; }; var onTouchEnd = function (e) { if (!slider || isScrolling) { return; } // we're done moving startedMoving = false; setSlideNumber((+new Date()) - startTime < 1000 && Math.abs(deltaX) > 15 ? (deltaX < 0 ? -1 : 1) : 0); offsetX = slideNumber * sliderWidth; slider.style[transformPrefix + 'transition-duration'] = '.2s'; slider.style[transformProperty] = 'translate3d(' + offsetX + 'px,0,0)'; e = new CustomEvent('slide', { detail: { slideNumber: Math.abs(slideNumber) }, bubbles: true, cancelable: true }); slider.parentNode.dispatchEvent(e); }; window.addEventListener('touchstart', onTouchStart); window.addEventListener('touchmove', onTouchMove); window.addEventListener('touchend', onTouchEnd); }()); /* ======================================================================== * Ratchet: toggles.js v2.0.2 * http://goratchet.com/components#toggles * ======================================================================== Adapted from Brad Birdsall's swipe * Copyright 2015 Connor Sears * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) * ======================================================================== */ !(function () { 'use strict'; var start = {}; var touchMove = false; var distanceX = false; var toggle = false; var transformProperty = window.RATCHET.getBrowserCapabilities.transform; var findToggle = function (target) { var i; var toggles = document.querySelectorAll('.toggle'); for (; target && target !== document; target = target.parentNode) { for (i = toggles.length; i--;) { if (toggles[i] === target) { return target; } } } }; window.addEventListener('touchstart', function (e) { e = e.originalEvent || e; toggle = findToggle(e.target); if (!toggle) { return; } var handle = toggle.querySelector('.toggle-handle'); var toggleWidth = toggle.clientWidth; var handleWidth = handle.clientWidth; var offset = toggle.classList.contains('active') ? (toggleWidth - handleWidth) : 0; start = { pageX : e.touches[0].pageX - offset, pageY : e.touches[0].pageY }; touchMove = false; }); window.addEventListener('touchmove', function (e) { e = e.originalEvent || e; if (e.touches.length > 1) { return; // Exit if a pinch } if (!toggle) { return; } var handle = toggle.querySelector('.toggle-handle'); var current = e.touches[0]; var toggleWidth = toggle.clientWidth; var handleWidth = handle.clientWidth; var offset = toggleWidth - handleWidth; touchMove = true; distanceX = current.pageX - start.pageX; if (Math.abs(distanceX) < Math.abs(current.pageY - start.pageY)) { return; } e.preventDefault(); if (distanceX < 0) { return (handle.style[transformProperty] = 'translate3d(0,0,0)'); } if (distanceX > offset) { return (handle.style[transformProperty] = 'translate3d(' + offset + 'px,0,0)'); } handle.style[transformProperty] = 'translate3d(' + distanceX + 'px,0,0)'; toggle.classList[(distanceX > (toggleWidth / 2 - handleWidth / 2)) ? 'add' : 'remove']('active'); }); window.addEventListener('touchend', function (e) { if (!toggle) { return; } var handle = toggle.querySelector('.toggle-handle'); var toggleWidth = toggle.clientWidth; var handleWidth = handle.clientWidth; var offset = (toggleWidth - handleWidth); var slideOn = (!touchMove && !toggle.classList.contains('active')) || (touchMove && (distanceX > (toggleWidth / 2 - handleWidth / 2))); if (slideOn) { handle.style[transformProperty] = 'translate3d(' + offset + 'px,0,0)'; } else { handle.style[transformProperty] = 'translate3d(0,0,0)'; } toggle.classList[slideOn ? 'add' : 'remove']('active'); e = new CustomEvent('toggle', { detail: { isActive: slideOn }, bubbles: true, cancelable: true }); toggle.dispatchEvent(e); touchMove = false; toggle = false; }); }());