sioux-offscreen
Version:
An off screen navigation item. Similar to the menu of the Facebook and Path app
402 lines (319 loc) • 13.2 kB
JavaScript
;(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
(function(){var $ = require('sioux-global');
window.$ = $;
var Offscreen = require('../index.js');
window.onload = function () {
var offscr = new Offscreen($('.offscreen'), $('.onscreen'));
$('.menu').on('tap', function () {
offscr.toggle();
}).on('click', function () {
offscr.toggle();
});
};
})()
},{"../index.js":5,"sioux-global":2}],2:[function(require,module,exports){
require('node-touch')();
function SiouxGlobal (selector, parentElement) {
var self = this;
if (!parentElement) parentElement = document;
var elems = parentElement.querySelectorAll(selector);
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
if (!elem.classList.contains('touch')) elem.classList.add('touch');
}
self._elems = elems;
self.element = elems.length === 1 ? elems[0] : elems;
return self;
}
SiouxGlobal.prototype.on = function(eventName, handler) {
var self = this;
for (var i = 0; i < self._elems.length; i++) {
self._elems[i].addEventListener(eventName, handler, false);
}
return self;
};
SiouxGlobal.prototype.off = function(eventName, handler) {
var self = this;
for (var i = 0; i < self._elems.length; i++) {
self._elems[i].removeEventListener(eventName, handler, false);
}
return self;
};
SiouxGlobal.prototype.css = function(prop, val) {
var self = this;
if (val) {
for (var i = 0; i < self._elems.length; i++)
self._elems[i].style[prop] = val;
return self;
}
for (var ix in prop) {
for (var i = 0; i < self._elems.length; i++)
self._elems[i].style[ix] = prop[ix];
}
return self;
};
function helper (selector, parentElement) {
return (new SiouxGlobal(selector, parentElement));
}
helper.isTouchDevice = !!('ontouchstart' in window);
module.exports = helper;
},{"node-touch":3}],3:[function(require,module,exports){
require('node-inserted')('touch');
var TAP_BOUND_X = 15;
var TAP_BOUND_Y = 15;
function isInBounds (touch, element) {
var left = element.offsetLeft
, top = element.offsetTop
, right = left + element.offsetWidth
, bottom = top + element.offsetHeight
;
return (touch.pageX > left && touch.pageX < right && touch.pageY > top && touch.pageY < bottom);
}
if (!window.isTouchDevice) window.isTouchDevice = !!('ontouchstart' in window);
module.exports = function () {
document.addEventListener('inserted', function (event) {
if (event.animationName !== 'touchNodeInserted') return;
var elem = event.inserted;
var _tapStartTouch = { pageX: undefined, pageY: undefined };
if (!window.isTouchDevice) {
elem.addEventListener('mouseover', function (event) {
this.classList.add('hover');
}, false);
elem.addEventListener('mouseout', function (event) {
this.classList.remove('hover');
}, false);
return;
}
var handler = function (event) {
event.preventDefault();
};
elem.addEventListener('mouseenter', handler, false);
elem.addEventListener('mousemove', handler, false);
elem.addEventListener('mouseleave', handler, false);
elem.addEventListener('touchstart', function (event) {
this.classList.add('hover');
_tapStartTouch.pageX = event.changedTouches[0].pageX;
_tapStartTouch.pageY = event.changedTouches[0].pageY;
}, false);
elem.addEventListener('touchend', function (event) {
this.classList.remove('hover');
if (!_tapStartTouch.pageX && !_tapStartTouch.pageY) return;
var x = Math.abs(event.changedTouches[0].pageX - _tapStartTouch.pageX);
var y = Math.abs(event.changedTouches[0].pageY - _tapStartTouch.pageY);
if (x < TAP_BOUND_X && y < TAP_BOUND_Y) {
var tapEvent = new Event('tap');
tapEvent.initEvent('tap', true, true);
elem.dispatchEvent(tapEvent);
}
_tapStartTouch.pageX = undefined;
_tapStartTouch.pageY = undefined;
}, false);
// Touch leave event
var touchleaveHandler = function (event) {
var touch = event.touches[0] || event.changedTouches[0];
if (!isInBounds(touch, elem)) {
var leaveEvent = new Event('touchleave');
leaveEvent.initEvent('touchleave', true, true);
elem.dispatchEvent(leaveEvent);
elem.removeEventListener('touchmove', touchleaveHandler, false);
}
};
elem.addEventListener('touchmove', touchleaveHandler, false);
elem.addEventListener('touchend', function (event) {
elem.addEventListener('touchmove', touchleaveHandler, false);
}, false);
// Tap event
elem.addEventListener('touchleave', function (event) {
_tapStartTouch.pageX = undefined;
_tapStartTouch.pageY = undefined;
}, false);
// Swipe event
var swipeStarted = false;
var startTouch, prevTouch;
var startX = 0, startY = 0;
var direction = '';
var d = 0;
elem.addEventListener('touchstart', function (event) {
startX = event.changedTouches[0].clientX;
startY = event.changedTouches[0].clientY;
startTouch = event.changedTouches[0];
}, false);
elem.addEventListener('touchmove', function (event) {
var dx = event.changedTouches[0].clientX - startX;
var dy = event.changedTouches[0].clientY - startY;
var swipeEvent = new Event('swipe');
if (swipeStarted) {
swipeEvent.initEvent('swipemove', true, true);
swipeEvent.startTouch = startTouch;
swipeEvent.prevTouch = prevTouch;
swipeEvent.changedTouch = event.changedTouches[0];
prevTouch = event.changedTouches[0];
if (direction === 'RIGHT' || direction === 'LEFT') {
if (dx !== d) {
swipeEvent.direction = direction;
swipeEvent.delta = direction === 'RIGHT' ? dx : -dx;
d = dx;
elem.dispatchEvent(swipeEvent);
}
}
else {
if (dy !== d) {
swipeEvent.direction = direction;
swipeEvent.delta = direction === 'DOWN' ? dy : -dy;
d = dy;
elem.dispatchEvent(swipeEvent);
}
}
return;
}
swipeStarted = true;
swipeEvent.initEvent('swipestart', true, true);
swipeEvent.startTouch = startTouch;
swipeEvent.changedTouch = event.changedTouches[0];
prevTouch = event.changedTouches[0];
if (Math.abs(dx) > Math.abs(dy)) {
direction = dx > 0 ? 'RIGHT' : 'LEFT';
swipeEvent.delta = dx > 0 ? dx : -dx;
d = dx;
}
else {
direction = dy > 0 ? 'DOWN' : 'UP';
swipeEvent.delta = dy > 0 ? dy : -dy;
d = dy;
}
swipeEvent.direction = direction;
elem.dispatchEvent(swipeEvent);
}, false);
elem.addEventListener('touchend', function (event) {
if (!swipeStarted) return;
var swipeEvent = new Event('swipeend');
swipeEvent.initEvent('swipeend', true, true);
swipeEvent.startTouch = startTouch;
swipeEvent.prevTouch = prevTouch;
swipeEvent.changedTouch = event.changedTouches[0];
swipeEvent.direction = direction;
swipeEvent.delta = Math.abs(d);
elem.dispatchEvent(swipeEvent);
swipeStarted = false;
}, false);
}, false);
};
},{"node-inserted":4}],4:[function(require,module,exports){
module.exports = function (className) {
if (!className) className = 'inserted';
var css = '@keyframes ' + className + 'NodeInserted { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, to); } } @-moz-keyframes ' + className + 'NodeInserted { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, auto); } } @-webkit-keyframes ' + className + 'NodeInserted { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, auto); } } @-ms-keyframes ' + className + 'NodeInserted { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, auto); } } @-o-keyframes ' + className + 'NodeInserted { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, auto); } } .' + className + ' { animation-duration: 0.001s; -o-animation-duration: 0.001s; -ms-animation-duration: 0.001s; -moz-animation-duration: 0.001s; -webkit-animation-duration: 0.001s; animation-name: ' + className + 'NodeInserted; -o-animation-name: ' + className + 'NodeInserted; -ms-animation-name: ' + className + 'NodeInserted; -moz-animation-name: ' + className + 'NodeInserted; -webkit-animation-name: ' + className + 'NodeInserted;}';
var elem = document.createElement('style');
var text = document.createTextNode(css);
elem.appendChild(text);
if (document.head.childNodes.length)
document.head.insertBefore(elem, document.head.childNodes[0]);
else document.head.appendChild(elem);
insertListener = function (event) {
if (event.animationName !== className +'NodeInserted') return;
var insertEvent = new Event('inserted');
insertEvent.initEvent('inserted', false, true);
insertEvent.inserted = event.target;
insertEvent.animationName = event.animationName;
if (event.target.parentNode) event.target.parentNode.dispatchEvent(insertEvent);
document.dispatchEvent(insertEvent);
};
document.addEventListener("animationstart", insertListener, false);
document.addEventListener("MSAnimationStart", insertListener, false);
document.addEventListener("webkitAnimationStart", insertListener, false);
};
},{}],5:[function(require,module,exports){
var preventDefault = function (e) { e.preventDefault(); };
function Offscreen (offscreen, onscreen) {
var self = this;
if (!offscreen) self.offscreen = document.querySelector('.offscreen');
else self.offscreen = offscreen._elems ? offscreen.element : offscreen;
if (!onscreen) self.onscreen = document.querySelector('.onscreen');
else self.onscreen = onscreen._elems ? onscreen.element : onscreen;
self.hidden = true;
var onscr = self.onscreen;
var duration = '';
var translateX = 0;
var translate = function (left, right, delta) {
var d = translateX + (right ? delta : -delta);
if (d < 0) d = 0;
else if (d > self.offscreen.offsetWidth) d = self.offscreen.offsetWidth;
onscr.style.webkitTransform = 'translateX(' + d + 'px)';
};
onscr.addEventListener('swipestart', function (event) {
var left = !self.hidden && event.direction === 'LEFT';
var right = self.hidden && event.direction === 'RIGHT';
if (!(left ^ right)) return;
onscr.ontouchmove = preventDefault;
duration = getComputedStyle(onscr).webkitTransitionDuration;
onscr.style.webkitTransitionDuration = '0s';
onscr.style.webkitOverflowScrolling = 'auto';
onscr.style.overflow = 'hidden';
var s = self.onscreen.style.webkitTransform.match(/\d+/);
translateX = Number(s ? s[0] : 0);
translate(left, right, event.delta);
}, false);
onscr.addEventListener('swipemove', function (event) {
var left = !self.hidden && event.direction === 'LEFT';
var right = self.hidden && event.direction === 'RIGHT';
if (!(left ^ right)) return;
translate(left, right, event.delta);
}, false);
onscr.addEventListener('swipeend', function (event) {
var left = !self.hidden && event.direction === 'LEFT';
var right = self.hidden && event.direction === 'RIGHT';
if (!(left ^ right)) return;
onscr.style.webkitOverflowScrolling = 'touch';
onscr.style.overflow = 'auto';
onscr.style.webkitTransitionDuration = duration;
var enough = event.delta > 35;
if ((right && enough) || (left && !enough)) self.show();
if ((left && enough) || (right && !enough)) self.hide();
}, false);
}
Offscreen.prototype.show = function (cb) {
var self = this;
self.onscreen.ontouchmove = preventDefault;
var s = self.onscreen.style.webkitTransform.match(/\d+/);
var translate = Number(s ? s[0] : 0);
if (translate === this.offscreen.offsetWidth) {
self.hidden = false;
if (cb) cb();
return;
}
self.onscreen.style.webkitTransform = 'translateX(' + this.offscreen.offsetWidth + 'px)';
var handler = function (event) {
if (event.propertyName !== '-webkit-transform') return;
self.hidden = false;
if (cb) cb();
this.removeEventListener('webkitTransitionEnd', handler, false);
};
self.onscreen.addEventListener('webkitTransitionEnd', handler, false);
};
Offscreen.prototype.hide = function (cb) {
var self = this;
self.onscreen.ontouchmove = null;
var s = self.onscreen.style.webkitTransform.match(/\d+/);
var translate = Number(s ? s[0] : 0);
if (translate === 0) {
self.hidden = true;
if (cb) cb();
return;
}
self.onscreen.style.webkitTransform = 'translateX(0)';
var handler = function (event) {
if (event.propertyName !== '-webkit-transform') return;
self.hidden = true;
if (cb) cb();
this.removeEventListener('webkitTransitionEnd', handler, false);
};
self.onscreen.addEventListener('webkitTransitionEnd', handler, false);
return this;
};
Offscreen.prototype.toggle = function(cb) {
if (this.hidden) this.show(cb);
else this.hide(cb);
return this;
};
module.exports = Offscreen;
},{}]},{},[1])
;