Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various Code Improvements for Added Stability #12

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
e438457
Converting all tabs to spaces
alexsomeoddpilot May 26, 2014
a5ba6ab
Adding 'use strict'
alexsomeoddpilot May 26, 2014
596d9af
Reformatting comments
alexsomeoddpilot May 26, 2014
9ca7e4e
Consistent quote usage
alexsomeoddpilot May 28, 2014
604496e
Fixing comment length
alexsomeoddpilot May 28, 2014
aed77db
Simplifying handler
alexsomeoddpilot May 28, 2014
bee119b
Avoiding inline control structures
alexsomeoddpilot May 28, 2014
d795d99
Fixing undeclared variables
alexsomeoddpilot May 28, 2014
2e6e835
Changing ternary to proper conditional
alexsomeoddpilot May 28, 2014
54c9dc0
Fixing line length
alexsomeoddpilot May 28, 2014
eeaf5ff
Using strict equality for string comparison
alexsomeoddpilot May 28, 2014
ecb7196
Refactor click buster to be a proper object but scoped to closure
alexsomeoddpilot May 28, 2014
2abb0c6
Using conditional instead of ternary
alexsomeoddpilot May 28, 2014
da0bce4
Fixing case statement
alexsomeoddpilot May 28, 2014
fea29bb
Line length
alexsomeoddpilot May 28, 2014
8cc90b5
Attaching fast click to window
alexsomeoddpilot May 28, 2014
ef2210f
Fixing indentation on jQuery implementation
alexsomeoddpilot May 28, 2014
cc41e93
Adding "use strict" to jQuery implementation
alexsomeoddpilot May 28, 2014
0045a46
Fixing line length
alexsomeoddpilot May 28, 2014
1fd9db1
Consistent quotes in jQuery implementation
alexsomeoddpilot May 28, 2014
017c9bc
Adding "use strict" to xui implementation
alexsomeoddpilot May 28, 2014
049b3b2
Various lint improvements for xui implementation
alexsomeoddpilot May 28, 2014
9393dd6
JSHint Testing
alexsomeoddpilot May 28, 2014
0b35d7b
Updated travis
alexsomeoddpilot May 28, 2014
3bfa4f2
Improved Gruntfile
alexsomeoddpilot May 28, 2014
3862315
Still attempting travis
alexsomeoddpilot May 28, 2014
26aef35
Still attempting travis
alexsomeoddpilot May 28, 2014
e2f4dfe
Merge branch 'master' of https://github.com/alexsomeoddpilot/google-f…
alexsomeoddpilot May 28, 2014
564225d
Update README.md
alexsomeoddpilot May 28, 2014
2254873
Bower config
alexsomeoddpilot May 31, 2014
8c8018a
Bower
alexsomeoddpilot May 31, 2014
324539c
qunit testing
alexsomeoddpilot May 31, 2014
b0ce0a5
real qunit
alexsomeoddpilot May 31, 2014
9d9842a
Merge branch 'master' of https://github.com/alexsomeoddpilot/google-f…
alexsomeoddpilot May 31, 2014
d9676b7
Add UMD boilerplate
tjgq Dec 22, 2014
9827d70
Merge pull request #1 from digisfera/master
alexsomeoddpilot Dec 23, 2014
fef6f8d
Updating dependencies
alexsomeoddpilot Feb 4, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules/

/bower_components/
7 changes: 7 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
language: node_js
node_js:
- "0.11"
before_script:
- npm install -g grunt-cli
- npm install -g bower
- bower install
28 changes: 28 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = function(grunt) {
grunt.initConfig({
jshint: {
with_overrides: {
files: {
src: [
'google.fastbutton.js',
'jquery.google.fastbutton.js',
'xui.google.fastbutton.js'
]
}
}
},

qunit: {
all: ['tests/*.html']
}
});

grunt.loadNpmTasks('grunt-contrib-qunit');

grunt.loadNpmTasks('grunt-contrib-jshint');

grunt.registerTask('travis', [
'jshint',
'qunit'
]);
};
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Google FastButton

[![Build Status](https://travis-ci.org/alexsomeoddpilot/google-fastbutton.svg?branch=master)](https://travis-ci.org/alexsomeoddpilot/google-fastbutton)

An implementation of [Google's FastButton javascript](http://code.google.com/mobile/articles/fast_buttons.html), to avoid the 300ms touch delay on Android and iOS devices. Code forked from: http://stackoverflow.com/questions/6300136/trying-to-implement-googles-fast-button

- Doesn't break in IE6-8, Chrome 17, Firefox 11, or Windows Phone 7.5
Expand Down
20 changes: 20 additions & 0 deletions bower.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "fast-button",
"version": "0.0.0",
"homepage": "https://github.com/alexsomeoddpilot/google-fastbutton",
"authors": [
"Alex Robertson <[email protected]>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"devDependencies": {
"qunit": "~1.14.0",
"blanket": "~1.1.5"
}
}
247 changes: 160 additions & 87 deletions google.fastbutton.js
Original file line number Diff line number Diff line change
@@ -1,124 +1,197 @@
(function() {
/**
* From: http://code.this.com/mobile/articles/fast_buttons.html
* Also see: http://stackoverflow.com/questions/6300136/trying-to-implement-googles-fast-button
*/

/** For IE8 and earlier compatibility: https://developer.mozilla.org/en/DOM/element.addEventListener */
/* jshint
quotmark: single
*/

(function (root, factory) {
if (typeof exports === 'object') {
// CommonJS
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
// AMD
define(function() {
return (root.FastButton = factory());
});
} else {
// Global variable
root.FastButton = factory();
}
}(this, function() {
'use strict';

// From:
// http://code.this.com/mobile/articles/fast_buttons.html
//
// Also see:
// http://stackoverflow.com/questions/6300136/trying-to-implement-googles-fast-button

// For IE8 and earlier compatibility:
// https://developer.mozilla.org/en/DOM/element.addEventListener
function addListener(el, type, listener, useCapture) {
if (el.addEventListener) {
if (el.addEventListener) {
el.addEventListener(type, listener, useCapture);
return {
destroy: function() { el.removeEventListener(type, listener, useCapture); }
return {
destroy: function() {
el.removeEventListener(type, listener, useCapture);
}
};
} else {
// see: http://stackoverflow.com/questions/5198845/javascript-this-losing-context-in-ie
var handler = function(e) { listener.handleEvent(window.event, listener); }
} else {
// see:
// http://stackoverflow.com/questions/5198845/javascript-this-losing-context-in-ie
var handler = function() {
listener.handleEvent(window.event, listener);
};

el.attachEvent('on' + type, handler);
return {

return {
destroy: function() { el.detachEvent('on' + type, handler); }
};
}
}
}

var isTouch = "ontouchstart" in window;

/* Construct the FastButton with a reference to the element and click handler. */
this.FastButton = function(element, handler, useCapture) {
// collect functions to call to cleanup events
var isTouch = 'ontouchstart' in window;

// Construct the FastButton with a reference to the element and click handler.
function FastButton(element, handler, useCapture) {
// collect functions to call to cleanup events
this.events = [];
this.touchEvents = [];
this.element = element;
this.handler = handler;
this.useCapture = useCapture;
if (isTouch)
this.events.push(addListener(element, 'touchstart', this, this.useCapture));
if (isTouch) {
this.events.push(
addListener(element, 'touchstart', this, this.useCapture)
);
}
this.events.push(addListener(element, 'click', this, this.useCapture));
}

// Remove event handling when no longer needed for this button
FastButton.prototype.destroy = function() {
for (var i = this.events.length - 1; i >= 0; i -= 1) {
this.events[i].destroy();
}
this.events =
this.touchEvents =
this.element =
this.handler = null;
};

/* Remove event handling when no longer needed for this button */
this.FastButton.prototype.destroy = function() {
for (i = this.events.length - 1; i >= 0; i -= 1)
this.events[i].destroy();
this.events = this.touchEvents = this.element = this.handler = this.fastButton = null;
};

/* acts as an event dispatcher */
this.FastButton.prototype.handleEvent = function(event) {

// acts as an event dispatcher
FastButton.prototype.handleEvent = function(event) {
switch (event.type) {
case 'touchstart': this.onTouchStart(event); break;
case 'touchmove': this.onTouchMove(event); break;
case 'touchend': this.onClick(event); break;
case 'click': this.onClick(event); break;
case 'touchstart':
this.onTouchStart(event);
break;
case 'touchmove':
this.onTouchMove(event);
break;
case 'touchend':
this.onClick(event);
break;
case 'click':
this.onClick(event);
break;
}
};

/* Save a reference to the touchstart coordinate and start listening to touchmove and
touchend events. Calling stopPropagation guarantees that other behaviors don’t get a
chance to handle the same click event. This is executed at the beginning of touch. */
this.FastButton.prototype.onTouchStart = function(event) {
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);
this.touchEvents.push(addListener(this.element, 'touchend', this, this.useCapture));
this.touchEvents.push(addListener(document.body, 'touchmove', this, this.useCapture));

// Save a reference to the touchstart coordinate and start listening
// to touchmove and touchend events. Calling stopPropagation guarantees
// that other behaviors don’t get a chance to handle the same click event.
// This is executed at the beginning of touch.
FastButton.prototype.onTouchStart = function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
this.touchEvents.push(
addListener(this.element, 'touchend', this, this.useCapture)
);
this.touchEvents.push(
addListener(document.body, 'touchmove', this, this.useCapture)
);
this.startX = event.touches[0].clientX;
this.startY = event.touches[0].clientY;
};

/* When /if touchmove event is invoked, check if the user has dragged past the threshold of 10px. */
this.FastButton.prototype.onTouchMove = function(event) {
if (Math.abs(event.touches[0].clientX - this.startX) > 10 || Math.abs(event.touches[0].clientY - this.startY) > 10) {

// When/if touchmove event is invoked, check if the user has dragged past
// the threshold of 10px.
FastButton.prototype.onTouchMove = function(event) {
if (Math.abs(event.touches[0].clientX - this.startX) > 10 ||
Math.abs(event.touches[0].clientY - this.startY) > 10) {
this.reset(); //if he did, then cancel the touch event
}
};

/* Invoke the actual click handler and prevent ghost clicks if this was a touchend event. */
this.FastButton.prototype.onClick = function(event) {
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);

// Invoke the actual click handler and prevent ghost clicks if
// this was a touchend event.
FastButton.prototype.onClick = function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
this.reset();
// Use .call to call the method so that we have the correct "this": https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
// Use .call to call the method so that we have the correct "this":
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
var result = this.handler.call(this.element, event);
if (event.type == 'touchend')
clickbuster.preventGhostClick(this.startX, this.startY);
if (event.type === 'touchend') {
clickbuster.preventGhostClick(this.startX, this.startY);
}
return result;
};

this.FastButton.prototype.reset = function() {
for (i = this.touchEvents.length - 1; i >= 0; i -= 1)
this.touchEvents[i].destroy();

FastButton.prototype.reset = function() {
for (var i = this.touchEvents.length - 1; i >= 0; i -= 1) {
this.touchEvents[i].destroy();
}
this.touchEvents = [];
};

this.clickbuster = function() {}

/* Call preventGhostClick to bust all click events that happen within 25px of
the provided x, y coordinates in the next 2.5s. */
this.clickbuster.preventGhostClick = function(x, y) {
clickbuster.coordinates.push(x, y);
window.setTimeout(clickbuster.pop, 2500);
};

this.clickbuster.pop = function() {
clickbuster.coordinates.splice(0, 2);
};

/* If we catch a click event inside the given radius and time threshold then we call
stopPropagation and preventDefault. Calling preventDefault will stop links
from being activated. */
this.clickbuster.onClick = function(event) {
for (var i = 0; i < clickbuster.coordinates.length; i += 2) {
var x = clickbuster.coordinates[i];
var y = clickbuster.coordinates[i + 1];
if (Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);
event.preventDefault ? event.preventDefault() : (event.returnValue=false);

var clickbuster = {
// Call preventGhostClick to bust all click events that happen within
// 25px of the provided x, y coordinates in the next 2.5s.
preventGhostClick: function (x, y) {
clickbuster.coordinates.push(x, y);
window.setTimeout(clickbuster.pop, 2500);
},

pop: function () {
clickbuster.coordinates.splice(0, 2);
},

// If we catch a click event inside the given radius and time threshold
// then we call stopPropagation and preventDefault. Calling preventDefault
// will stop links from being activated.
onClick: function (event) {
for (var i = 0; i < clickbuster.coordinates.length; i += 2) {
var x = clickbuster.coordinates[i];
var y = clickbuster.coordinates[i + 1];
if (Math.abs(event.clientX - x) < 25 &&
Math.abs(event.clientY - y) < 25) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
}
}
};

if (isTouch) {
// Don't need to use our custom addListener function since we only bust clicks on touch devices
// Don't need to use our custom addListener function
// since we only bust clicks on touch devices
document.addEventListener('click', clickbuster.onClick, true);
clickbuster.coordinates = [];
}
})(this);

return FastButton;
}));
Loading