mirror of https://github.com/twbs/ratchet.git
Connor Sears
12 years ago
7 changed files with 2068 additions and 1 deletions
@ -0,0 +1,720 @@
|
||||
/** |
||||
* ================================== |
||||
* 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 (/<html/i.test(responseText)) { |
||||
head = document.createElement('div'); |
||||
body = document.createElement('div'); |
||||
head.innerHTML = responseText.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0] |
||||
body.innerHTML = responseText.match(/<body[^>]*>([\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; |
||||
}); |
||||
|
||||
}(); |
@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<title>Ratchet template page</title> |
||||
|
||||
<!-- Sets initial viewport load and disables zooming --> |
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no"> |
||||
|
||||
<!-- Makes your prototype chrome-less once bookmarked to your phone's home screen --> |
||||
<meta name="apple-mobile-web-app-capable" content="yes"> |
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black"> |
||||
|
||||
<!-- Set Apple icons for when prototype is saved to home screen --> |
||||
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="touch-icons/apple-touch-icon-114x114.png"> |
||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="touch-icons/apple-touch-icon-72x72.png"> |
||||
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="touch-icons/apple-touch-icon-57x57.png"> |
||||
|
||||
<!-- Include the compiled Ratchet CSS --> |
||||
<link rel="stylesheet" href="ratchet.css"> |
||||
|
||||
<!-- Include the compiled Ratchet JS --> |
||||
<script src="ratchet.js"></script> |
||||
|
||||
<!-- Intro paragraph styles. Delete once you start using this page --> |
||||
<style type="text/css"> |
||||
.welcome { |
||||
line-height: 1.5; |
||||
color: #555; |
||||
} |
||||
</style> |
||||
|
||||
</head> |
||||
<body> |
||||
|
||||
<!-- Make sure all your bars are the first things in your <body> --> |
||||
<header class="bar-title"> |
||||
<h1 class="title">Ratchet</h1> |
||||
</header> |
||||
|
||||
<!-- Wrap all non-bar HTML in the .content div (this is actually what scrolls) --> |
||||
<div class="content"> |
||||
<div class="content-padded"> |
||||
<p class="welcome">Thanks for downloading Ratchet. This is an example HTML page that's linked up to compiled Ratchet CSS and JS, has the proper meta tags and the HTML structure. Need some more help before you start filling this with your own content? Check out some Ratchet resorces:</p> |
||||
</div> |
||||
|
||||
<ul class="list inset"> |
||||
<li> |
||||
<a href="http://maker.github.com/ratchet/"> |
||||
<strong>Ratchet documentation</strong> |
||||
<span class="chevron"></span> |
||||
</a> |
||||
</li> |
||||
<li> |
||||
<a href="http://www.github.com/maker/ratchet/"> |
||||
<strong>Ratchet on Github</strong> |
||||
<span class="chevron"></span> |
||||
</a> |
||||
</li> |
||||
<li> |
||||
<a href="https://groups.google.com/forum/#!forum/goratchet"> |
||||
<strong>Ratchet Google group</strong> |
||||
<span class="chevron"></span> |
||||
</a> |
||||
</li> |
||||
<li> |
||||
<a href="http://www.twitter.com/GoRatchet"> |
||||
<strong>Ratchet on Twitter</strong> |
||||
<span class="chevron"></span> |
||||
</a> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
|
||||
</body> |
||||
</html> |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 7.2 KiB |
Loading…
Reference in new issue