diff --git a/example/adams/events.html b/example/adams/events.html
new file mode 100644
index 0000000000..1d989cc53c
--- /dev/null
+++ b/example/adams/events.html
@@ -0,0 +1,22 @@
+
+
+
+ Example
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/events.html b/example/events.html
index b6f2538731..4764f9411b 100644
--- a/example/events.html
+++ b/example/events.html
@@ -13,8 +13,10 @@
+
diff --git a/example/events.js b/example/events.js
index 151b500fc2..9b3e7739ef 100644
--- a/example/events.js
+++ b/example/events.js
@@ -12,3 +12,10 @@ window.FM.on('tap', function(e) {
event: e
});
});
+window.FM.on('touch', function(e) {
+ console.log('GOT TOUCH', e);
+ logEvent({
+ type: 'touch',
+ event: e
+ });
+});
diff --git a/js/framework/framework-events.js b/js/framework/framework-events.js
index 2c907208be..be72221fa6 100644
--- a/js/framework/framework-events.js
+++ b/js/framework/framework-events.js
@@ -11,150 +11,124 @@
*/
(function(window, document, framework) {
- framework.EventController = function (){};
-
- // A map of event types that we virtually detect and emit
- framework.EventController.prototype.VIRTUAL_EVENT_TYPES = ['tap', 'swipeleft', 'swiperight'];
+ framework.EventController = {
+ // A map of event types that we virtually detect and emit
+ VIRTUAL_EVENT_TYPES: ['tap', 'swipeleft', 'swiperight'],
- /**
- * Trigger a new event.
- */
- framework.EventController.prototype.trigger = function(eventType, data) {
- // TODO: Do we need to use the old-school createEvent stuff?
+ /**
+ * Trigger a new event.
+ */
+ trigger: function(eventType, data) {
+ // TODO: Do we need to use the old-school createEvent stuff?
- window.dispatchEvent(new CustomEvent(eventType, data));
- };
+ window.dispatchEvent(new CustomEvent(eventType, data));
+ },
- /**
- * Shorthand for binding a new event listener to the given
- * event type.
- */
- framework.EventController.prototype.on = function(type, callback, element) {
- var i;
- var e = element || window;
- /*
- var virtualTypes = framework.EventController.VIRTUAL_EVENT_TYPES;
+ /**
+ * Shorthand for binding a new event listener to the given
+ * event type.
+ */
+ on: function(type, callback, element) {
+ var i;
+ var e = element || window;
+ /*
+ var virtualTypes = framework.EventController.VIRTUAL_EVENT_TYPES;
- for(i = 0; i < virtualTypes.length; i++) {
- if(type.toLowerCase() == virtualTypes[i]) {
- // TODO: listen for virtual event
+ for(i = 0; i < virtualTypes.length; i++) {
+ if(type.toLowerCase() == virtualTypes[i]) {
+ // TODO: listen for virtual event
+ return;
+ }
+ }
+ */
+
+ // Native listener
+ e.addEventListener(type, callback);
+ },
+
+
+ /**
+ * Process a touchstart event.
+ */
+ handleTouchStart: function(e) {
+ console.log("EVENT: touchstart", e);
+ framework.GestureController.detectGesture(e);
+ },
+
+ /**
+ * Process a touchmove event.
+ */
+ handleTouchMove: function(e) {
+ console.log("EVENT: touchmove", e);
+ framework.GestureController.detectGesture(e);
+
+ },
+
+ /**
+ * Process a touchend event.
+ */
+ handleTouchEnd: function(e) {
+ console.log("EVENT: touchend", e);
+ framework.GestureController.detectGesture(e);
+ },
+
+
+ /**
+ * Process a touchcancel event.
+ */
+ handleTouchCancel: function(e) {
+ this._hasMoved = false;
+ this._touchStartX = null;
+ this._touchStartY = null;
+ },
+
+ // With a click event, we need to check the target
+ // and if it's an internal target that doesn't want
+ // a click, cancel it
+ handleClick: function(e) {
+ var target = e.target;
+
+ if (
+ ! target
+ || e.which > 1
+ || e.metaKey
+ || e.ctrlKey
+ //|| isScrolling
+ || location.protocol !== target.protocol
+ || location.host !== target.host
+ // Not sure abotu this one
+ //|| !target.hash && /#/.test(target.href)
+ || target.hash && target.href.replace(target.hash, '') === location.href.replace(location.hash, '')
+ //|| target.getAttribute('data-ignore') == 'push'
+ ) {
+ // Allow it
+ console.log("EVENT: click", e);
return;
}
- }
- */
+ // We need to cancel this one
+ e.preventDefault();
- // Native listener
- e.addEventListener(type, callback);
- };
-
-
- /**
- * Process a touchstart event.
- */
- framework.EventController.prototype.handleTouchStart = function(e) {
- console.log("EVENT: touchstart", e);
- if(e.type === 'touchstart') {
- // We are now touching
- this._isTouching = true;
- }
+ // TODO: should we do this?
+ // e.stopPropagation();
+ },
- // Reset the movement indicator
- this._hasMoved = false;
-
- // Store touch coords
- this._touchStartX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
- this._touchStartY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY;
+ handlePopState: function(event) {
+ console.log("EVENT: popstate", event);
+ },
};
-
- /**
- * Process a touchmove event.
- */
- framework.EventController.prototype.handleTouchMove = function(e) {
- console.log("EVENT: touchmove", e);
-
- var x = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX,
- y = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
-
- // Check if the finger moved more than 10px, and then indicate we should cancel the tap
- if (Math.abs(x - this._touchStartX) > 10 || Math.abs(y - this._touchStartY) > 10) {
- this._hasMoved = true;
- console.log('DID MOVE');
- }
- };
-
- /**
- * Process a touchend event.
- */
- framework.EventController.prototype.handleTouchEnd = function(e) {
- console.log("EVENT: touchend", e);
-
- if(this._isTouching && !this._hasMoved) {
- console.log("EVENT: (virtual) tap", event);
- framework.trigger('tap', {
- bubbles: true,
- cancelable: true
- });
- }
- framework.EventController._isTouching = false;
- };
-
-
- /**
- * Process a touchcancel event.
- */
- framework.EventController.prototype.handleTouchCancel = function(e) {
- this._hasMoved = false;
- this._touchStartX = null;
- this._touchStartY = null;
- };
-
- // With a click event, we need to check the target
- // and if it's an internal target that doesn't want
- // a click, cancel it
- framework.EventController.prototype.handleClick = function(e) {
- var target = e.target;
-
- if (
- ! target
- || e.which > 1
- || e.metaKey
- || e.ctrlKey
- //|| isScrolling
- || location.protocol !== target.protocol
- || location.host !== target.host
- // Not sure abotu this one
- //|| !target.hash && /#/.test(target.href)
- || target.hash && target.href.replace(target.hash, '') === location.href.replace(location.hash, '')
- //|| target.getAttribute('data-ignore') == 'push'
- ) {
- // Allow it
- console.log("EVENT: click", e);
- return;
- }
- // We need to cancel this one
- e.preventDefault();
-
- // TODO: should we do this?
- // e.stopPropagation();
- }
-
- framework.EventController.prototype.handlePopState = function(event) {
- console.log("EVENT: popstate", event);
- }
// Map some convenient top-level functions for event handling
- framework.on = framework.EventController.prototype.on;
- framework.trigger = framework.EventController.prototype.trigger;
-
+ framework.on = framework.EventController.on;
+ framework.trigger = framework.EventController.trigger;
// Set up various listeners
- window.addEventListener('touchstart', framework.EventController.prototype.handleTouchStart);
- window.addEventListener('touchmove', framework.EventController.prototype.handleTouchMove);
- window.addEventListener('touchcancel', framework.EventController.prototype.handleTouchCancel);
- window.addEventListener('touchend', framework.EventController.prototype.handleTouchEnd);
- window.addEventListener('click', framework.EventController.prototype.handleClick);
- window.addEventListener('popstate', framework.EventController.prototype.handlePopState);
+ window.addEventListener('touchstart', framework.EventController.handleTouchStart);
+ window.addEventListener('touchmove', framework.EventController.handleTouchMove);
+ window.addEventListener('touchcancel', framework.EventController.handleTouchCancel);
+ window.addEventListener('touchend', framework.EventController.handleTouchEnd);
+ window.addEventListener('click', framework.EventController.handleClick);
+ window.addEventListener('popstate', framework.EventController.handlePopState);
})(this, document, FM = this.FM || {});
diff --git a/js/framework/framework-gestures.js b/js/framework/framework-gestures.js
new file mode 100644
index 0000000000..f65f0406ea
--- /dev/null
+++ b/js/framework/framework-gestures.js
@@ -0,0 +1,267 @@
+/**
+ * Simple gesture controllers with some common gestures that emit
+ * gesture events.
+ *
+ * Much adapted from github.com/EightMedia/Hammer.js
+ */
+(function(window, document, framework) {
+ // Gesture support
+ framework.Gesture = {}
+
+ // Simple touch gesture that triggers an event when an element is touched
+ framework.Gesture.Touch = {
+ handle: function(e) {
+ framework.EventController.trigger('touch', {
+ cancelable: true,
+ bubbles: true
+ });
+ }
+ };
+
+ // Simple tap gesture
+ framework.Gesture.Tap = {
+ handle: function(e) {
+ switch(e.type) {
+ case 'touchstart':
+ // We are now touching
+ this._isTouching = true;
+ // Reset the movement indicator
+ this._hasMoved = false;
+ break;
+ case 'touchmove':
+ this._touchStartX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
+ this._touchStartY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY;
+
+ var x = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX,
+ y = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
+
+ // Check if the finger moved more than 10px, and then indicate we should cancel the tap
+ if (Math.abs(x - this._touchStartX) > 10 || Math.abs(y - this._touchStartY) > 10) {
+ this._hasMoved = true;
+ }
+ break;
+ case 'touchend':
+ if(this._hasMoved == false) {
+ framework.EventController.trigger('tap', {
+ cancelable: true,
+ bubbles: true
+ });
+ }
+ break;
+ }
+ }
+ };
+
+ // A swipe-left gesture that emits the 'swipeleft' event when a left swipe
+ // is performed
+ framework.Gesture.SwipeLeft = {
+ handle: function(e) {
+ }
+ };
+
+ framework.GestureController = {
+ gestures: [
+ framework.Gesture.Touch,
+ framework.Gesture.Tap
+ ],
+ detectGesture: function(e) {
+ var i;
+
+ for(i = 0; i < this.gestures.length; i++) {
+ if(this.gestures[i].handle(e)) {
+ console.log('GESTURECONTROLLER: Gesture handled');
+ return;
+ }
+ }
+ },
+
+ /**
+ * find if a node is in the given parent
+ * used for event delegation tricks
+ * @param {HTMLElement} node
+ * @param {HTMLElement} parent
+ * @returns {boolean} has_parent
+ */
+ hasParent: function(node, parent) {
+ while(node){
+ if(node == parent) {
+ return true;
+ }
+ node = node.parentNode;
+ }
+ return false;
+ },
+
+
+ /**
+ * get the center of all the touches
+ * @param {Array} touches
+ * @returns {Object} center
+ */
+ getCenter: function getCenter(touches) {
+ var valuesX = [], valuesY = [];
+
+ for(var t= 0,len=touches.length; t= y) {
+ return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;
+ }
+ else {
+ return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;
+ }
+ },
+
+
+ /**
+ * calculate the distance between two touches
+ * @param {Touch} touch1
+ * @param {Touch} touch2
+ * @returns {Number} distance
+ */
+ getDistance: function getDistance(touch1, touch2) {
+ var x = touch2.pageX - touch1.pageX,
+ y = touch2.pageY - touch1.pageY;
+ return Math.sqrt((x*x) + (y*y));
+ },
+
+
+ /**
+ * calculate the scale factor between two touchLists (fingers)
+ * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
+ * @param {Array} start
+ * @param {Array} end
+ * @returns {Number} scale
+ */
+ getScale: function getScale(start, end) {
+ // need two fingers...
+ if(start.length >= 2 && end.length >= 2) {
+ return this.getDistance(end[0], end[1]) /
+ this.getDistance(start[0], start[1]);
+ }
+ return 1;
+ },
+
+
+ /**
+ * calculate the rotation degrees between two touchLists (fingers)
+ * @param {Array} start
+ * @param {Array} end
+ * @returns {Number} rotation
+ */
+ getRotation: function getRotation(start, end) {
+ // need two fingers
+ if(start.length >= 2 && end.length >= 2) {
+ return this.getAngle(end[1], end[0]) -
+ this.getAngle(start[1], start[0]);
+ }
+ return 0;
+ },
+
+
+ /**
+ * boolean if the direction is vertical
+ * @param {String} direction
+ * @returns {Boolean} is_vertical
+ */
+ isVertical: function isVertical(direction) {
+ return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN);
+ },
+
+
+ /**
+ * stop browser default behavior with css props
+ * @param {HtmlElement} element
+ * @param {Object} css_props
+ */
+ stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) {
+ var prop,
+ vendors = ['webkit','khtml','moz','Moz','ms','o',''];
+
+ if(!css_props || !element.style) {
+ return;
+ }
+
+ // with css properties for modern browsers
+ for(var i = 0; i < vendors.length; i++) {
+ for(var p in css_props) {
+ if(css_props.hasOwnProperty(p)) {
+ prop = p;
+
+ // vender prefix at the property
+ if(vendors[i]) {
+ prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1);
+ }
+
+ // set the style
+ element.style[prop] = css_props[p];
+ }
+ }
+ }
+
+ // also the disable onselectstart
+ if(css_props.userSelect == 'none') {
+ element.onselectstart = function() {
+ return false;
+ };
+ }
+
+ // and disable ondragstart
+ if(css_props.userDrag == 'none') {
+ element.ondragstart = function() {
+ return false;
+ };
+ }
+ }
+
+ }
+
+
+})(this, document, FM = this.FM || {});