/** * ================================== * Ratchet v1.0.0 * Licensed under The MIT License * http://opensource.org/licenses/MIT * ================================== */ /* ---------------------------------- * POPOVER v1.0.0 * Licensed under The MIT License * http://opensource.org/licenses/MIT * ---------------------------------- */ !function () { var popover; var findPopovers = function (target) { var i, 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 () { document.body.removeChild(backdrop); popover.style.display = 'none'; popover.removeEventListener('webkitTransitionEnd', onPopoverHidden); } var backdrop = function () { var element = document.createElement('div'); element.classList.add('backdrop'); element.addEventListener('touchend', function () { popover.addEventListener('webkitTransitionEnd', onPopoverHidden); popover.classList.remove('visible'); }); return element; }(); var getPopover = function (e) { var anchor = findPopovers(e.target); if (!anchor || !anchor.hash) return; popover = document.querySelector(anchor.hash); if (!popover || !popover.classList.contains('popover')) return; return popover; } window.addEventListener('touchend', 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('click', function (e) { if (getPopover(e)) e.preventDefault(); }); }(); /* ---------------------------------- * PUSH v1.0.0 * Licensed under The MIT License * inspired by chris's jquery.pjax.js * http://opensource.org/licenses/MIT * ---------------------------------- */ !function () { var noop = function () {}; // Pushstate cacheing // ================== var isScrolling; var maxCacheLength = 20; var cacheMapping = sessionStorage; var domCache = {}; 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); domCache[data.id] = document.body.cloneNode(true); }; 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()]; window.history.pushState(null, '', cacheMapping[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 }); } if (transitionFromObj.transition) { activeObj = extendWithDom(activeObj, '.content', activeDom.cloneNode(true)); if (activeObj.titlebar) swapContent(activeObj.titlebar, document.querySelector('.bar-title')); if (activeObj.tabbar) swapContent(activeObj.tabbar, document.querySelector('.bar-tab')); } swapContent( (activeObj.contents || activeDom).cloneNode(true), document.querySelector('.content'), transition ); PUSH.id = id; document.body.offsetHeight; // force reflow to prevent scroll }; // Core PUSH functionality // ======================= var PUSH = function (options) { var data = {}; var xhr = PUSH.xhr; options.container = options.container || document.querySelector('.content'); options.titlebar = options.titlebar || document.querySelector('.bar-title'); options.tabbar = options.tabbar || document.querySelector('.bar-tab'); 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) xhr.status == 200 ? success(xhr, options) : failure(options.url); }; if (!PUSH.id) { cacheReplace({ id : +new Date, url : window.location.href, title : document.title, timeout : options.timeout, transition : null }); } if (options.timeout) { options._timeout = setTimeout(function () { xhr.abort('timeout'); }, options.timeout); } xhr.send(); if (xhr.readyState && !options.ignorePush) cachePush(); }; // 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; if (options.transition) { if (data.titlebar) swapContent(data.titlebar, document.querySelector('.bar-title')); if (data.tabbar) swapContent(data.tabbar, document.querySelector('.bar-tab')); } swapContent(data.contents, options.container, 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 swapContent = function (swap, container, transition, complete) { var enter; var containerDirection; var swapDirection; if (!transition) { container.innerHTML = swap.innerHTML; } else { 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(enter ? 'right' : 'left'); swap.classList.add('slide'); container.classList.add('slide'); } container.parentNode.insertBefore(swap, container); } if (!transition) complete && complete(); if (transition == 'fade') { container.offsetWidth; // force reflow container.classList.remove('in'); container.addEventListener('webkitTransitionEnd', fadeContainerEnd); function fadeContainerEnd() { container.removeEventListener('webkitTransitionEnd', fadeContainerEnd); swap.classList.add('in'); swap.addEventListener('webkitTransitionEnd', fadeSwapEnd); } function fadeSwapEnd () { swap.removeEventListener('webkitTransitionEnd', fadeSwapEnd); container.parentNode.removeChild(container); swap.classList.remove('fade'); swap.classList.remove('in'); complete && complete(); } } if (/slide/.test(transition)) { container.offsetWidth; // force reflow swapDirection = enter ? 'right' : 'left' containerDirection = enter ? 'left' : 'right' container.classList.add(containerDirection); swap.classList.remove(swapDirection); swap.addEventListener('webkitTransitionEnd', slideEnd); function slideEnd() { swap.removeEventListener('webkitTransitionEnd', slideEnd); swap.classList.remove('slide'); swap.classList.remove(swapDirection); container.parentNode.removeChild(container); complete && complete(); } } }; 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, 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 parseURL = function (url) { var a = document.createElement('a'); a.href = url; return a; }; var extendWithDom = function (obj, fragment, dom) { var result = {}; var titlebar = dom.querySelector('.bar-title') var tabbar = dom.querySelector('.bar-tab'); for (var i in obj) result[i] = obj[i]; if (titlebar) titlebar.parentNode.removeChild(titlebar); if (tabbar) tabbar.parentNode.removeChild(tabbar); result.titlebar = titlebar; result.tabbar = tabbar; result.contents = dom.querySelector(fragment); return result; }; 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'); data.title = data.title && data.title.innerText.trim(); if (options.transition) data = extendWithDom(data, '.content', body); else 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); }();/* ---------------------------------- * TABS v1.0.0 * Licensed under The MIT License * http://opensource.org/licenses/MIT * ---------------------------------- */ !function () { var getTarget = function (target) { var i, popovers = document.querySelectorAll('.segmented-controller li a'); for (; target && target !== document; target = target.parentNode) { for (i = popovers.length; i--;) { if (popovers[i] === target) return target; } } }; window.addEventListener("touchend", function (e) { var activeTab; var activeBody; var targetBody; var targetTab; var className = 'active'; var classSelector = '.' + className; var targetAnchor = getTarget(e.target); if (!targetAnchor) return; targetTab = targetAnchor.parentNode; activeTab = targetTab.parentNode.querySelector(classSelector); if (activeTab) activeTab.classList.remove(className); targetTab.classList.add(className); if (!targetAnchor.hash) return; targetBody = document.querySelector(targetAnchor.hash); if (!targetBody) return; activeBody = targetBody.parentNode.querySelector(classSelector); if (activeBody) activeBody.classList.remove(className); targetBody.classList.add(className) }); window.addEventListener('click', function (e) { if (getTarget(e.target)) e.preventDefault(); }); }();/* ---------------------------------- * SLIDER v1.0.0 * Licensed under The MIT License * Adapted from Brad Birdsall's swipe * http://opensource.org/licenses/MIT * ---------------------------------- */ !function () { 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 getSlider = function (target) { var i, sliders = document.querySelectorAll('.slider ul'); 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.webkitTransform.match(/translate3d\(([^,]*)/); return parseInt(translate3d ? translate3d[1] : 0) }; 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('li'); 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; setSlideNumber(0); slider.style['-webkit-transition-duration'] = 0; }; var onTouchMove = function (e) { if (e.touches.length > 1 || !slider) return; // Exit if a pinch || no slider 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') { 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.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)'; }; var onTouchEnd = function (e) { if (!slider || isScrolling) return; setSlideNumber( (+new Date) - startTime < 1000 && Math.abs(deltaX) > 15 ? (deltaX < 0 ? -1 : 1) : 0 ); offsetX = slideNumber * sliderWidth; slider.style['-webkit-transition-duration'] = '.2s'; slider.style.webkitTransform = '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); }(); /* ---------------------------------- * TOGGLE v1.0.0 * Licensed under The MIT License * http://opensource.org/licenses/MIT * ---------------------------------- */ !function () { var start = {}; var touchMove = false; var distanceX = false; var toggle = false; var findToggle = function (target) { var i, 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.offsetWidth; var handleWidth = handle.offsetWidth; var offset = toggle.classList.contains('active') ? toggleWidth - handleWidth : 0; start = { pageX : e.touches[0].pageX - offset, pageY : e.touches[0].pageY }; touchMove = false; // todo: probably should be moved to the css toggle.style['-webkit-transition-duration'] = 0; }); 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.offsetWidth; var handleWidth = handle.offsetWidth; 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.webkitTransform = 'translate3d(0,0,0)'; if (distanceX > offset) return handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)'; handle.style.webkitTransform = '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.offsetWidth; var handleWidth = handle.offsetWidth; var offset = toggleWidth - handleWidth; var slideOn = (!touchMove && !toggle.classList.contains('active')) || (touchMove && (distanceX > (toggleWidth/2 - handleWidth/2))); if (slideOn) handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)'; else handle.style.webkitTransform = '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; }); }();