Skip to content

Commit

Permalink
fix(Mobile): Allow either touch and mouse events
Browse files Browse the repository at this point in the history
Many features were broken on mobile devices due to us only binding to
mouse-based events. Switching to touch-events, where supported, should fix
this.

BREAKING CHANGE: On mobile devices the user will have to long-click to
edit a cell instead of double-clicking
  • Loading branch information
c0bra committed Dec 10, 2014
1 parent 2dc0275 commit 654e0ce
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 27 deletions.
43 changes: 39 additions & 4 deletions src/features/edit/js/gridEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,10 @@
*
*/
module.directive('uiGridCell',
['$compile', '$injector', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
function ($compile, $injector, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
var touchstartTimeout = 500;

return {
priority: -100, // run after default uiGridCell directive
restrict: 'A',
Expand All @@ -386,6 +388,7 @@
var inEdit = false;
var isFocusedBeforeEdit = false;
var cellModel;
var cancelTouchstartTimeout;

registerBeginEditEvents();

Expand All @@ -395,6 +398,37 @@
if ($scope.col.colDef.enableCellEditOnFocus) {
$elm.find('div').on('focus', beginEditFocus);
}

// Add touchstart handling. If the users starts a touch and it doesn't end after X milliseconds, then start the edit
$elm.on('touchstart', touchStart);
}

function touchStart(event) {
// jQuery masks events
if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
event = event.originalEvent;
}

// Bind touchend handler
$elm.on('touchend', touchEnd);

// Start a timeout
cancelTouchstartTimeout = $timeout(function() { }, touchstartTimeout);

// Timeout's done! Start the edit
cancelTouchstartTimeout.then(function () {
// Use setTimeout to start the edit because beginEdit expects to be outside of $digest
setTimeout(beginEdit, 0);

// Undbind the touchend handler, we don't need it anymore
$elm.off('touchend', touchEnd);
});
}

// Cancel any touchstart timeout
function touchEnd(event) {
$timeout.cancel(cancelTouchstartTimeout);
$elm.off('touchend', touchEnd);
}

function cancelBeginEditEvents() {
Expand All @@ -403,6 +437,7 @@
if ($scope.col.colDef.enableCellEditOnFocus) {
$elm.find('div').off('focus', beginEditFocus);
}
$elm.off('touchstart', touchStart);
}

function beginEditFocus(evt) {
Expand Down Expand Up @@ -634,8 +669,8 @@
*
*/
module.directive('uiGridEditor',
['uiGridConstants', 'uiGridEditConstants',
function (uiGridConstants, uiGridEditConstants) {
['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
function (gridUtil, uiGridConstants, uiGridEditConstants) {
return {
scope: true,
require: ['?^uiGrid', '?^uiGridRenderContainer'],
Expand Down
39 changes: 26 additions & 13 deletions src/features/resize-columns/js/ui-grid-column-resizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@
module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'columnBounds', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, columnBounds, uiGridResizeColumnsService) {
var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');

var downEvent, upEvent, moveEvent;

if (gridUtil.isTouchEnabled()) {
downEvent = 'touchstart';
upEvent = 'touchend';
moveEvent = 'touchmove';
}
else {
downEvent = 'mousedown';
upEvent = 'mouseup';
moveEvent = 'mousemove';
}

var resizer = {
priority: 0,
scope: {
Expand Down Expand Up @@ -321,7 +334,7 @@
if (event.originalEvent) { event = event.originalEvent; }
event.preventDefault();

x = event.clientX - gridLeft;
x = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;

if (x < 0) { x = 0; }
else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
Expand Down Expand Up @@ -379,12 +392,12 @@
resizeOverlay.remove();

// Resize the column
x = event.clientX - gridLeft;
x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
var xDiff = x - startX;

if (xDiff === 0) {
$document.off('mouseup', mouseup);
$document.off('mousemove', mousemove);
$document.off(upEvent, mouseup);
$document.off(moveEvent, mousemove);
return;
}

Expand Down Expand Up @@ -431,11 +444,11 @@

uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);

$document.off('mouseup', mouseup);
$document.off('mousemove', mousemove);
$document.off(upEvent, mouseup);
$document.off(moveEvent, mousemove);
}

$elm.on('mousedown', function(event, args) {
$elm.on(downEvent, function(event, args) {
if (event.originalEvent) { event = event.originalEvent; }
event.stopPropagation();

Expand All @@ -444,7 +457,7 @@
gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;

// Get the starting X position, which is the X coordinate of the click minus the grid's offset
startX = event.clientX - gridLeft;
startX = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;

// Append the resizer overlay
uiGridCtrl.grid.element.append(resizeOverlay);
Expand All @@ -453,8 +466,8 @@
resizeOverlay.css({ left: startX });

// Add handlers for mouse move and up events
$document.on('mouseup', mouseup);
$document.on('mousemove', mousemove);
$document.on(upEvent, mouseup);
$document.on(moveEvent, mousemove);
});

// On doubleclick, resize to fit all rendered cells
Expand Down Expand Up @@ -539,10 +552,10 @@
});

$elm.on('$destroy', function() {
$elm.off('mousedown');
$elm.off(downEvent);
$elm.off('dblclick');
$document.off('mousemove', mousemove);
$document.off('mouseup', mouseup);
$document.off(moveEvent, mousemove);
$document.off(upEvent, mouseup);
});
}
};
Expand Down
31 changes: 22 additions & 9 deletions src/features/resize-columns/test/resizeColumns.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
describe('ui.grid.resizeColumns', function () {
ddescribe('ui.grid.resizeColumns', function () {
var grid, gridUtil, gridScope, $scope, $compile, recompile, uiGridConstants;

var downEvent, upEvent, moveEvent;

var data = [
{ "name": "Ethel Price", "gender": "female", "company": "Enersol" },
{ "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
Expand All @@ -17,6 +19,17 @@ describe('ui.grid.resizeColumns', function () {
uiGridConstants = _uiGridConstants_;
gridUtil = _gridUtil_;

if (gridUtil.isTouchEnabled()) {
downEvent = 'touchstart';
upEvent = 'touchend';
moveEvent = 'touchmove';
}
else {
downEvent = 'mousedown';
upEvent = 'mouseup';
moveEvent = 'mousemove';
}

$scope.gridOpts = {
enableColumnResizing: true,
data: data
Expand Down Expand Up @@ -133,7 +146,7 @@ describe('ui.grid.resizeColumns', function () {
it('should cause the column separator overlay to be added', function () {
var firstResizer = $(grid).find('[ui-grid-column-resizer]').first();

firstResizer.trigger('mousedown');
firstResizer.trigger(downEvent);
$scope.$digest();

var overlay = $(grid).find('.ui-grid-resize-overlay');
Expand All @@ -156,15 +169,15 @@ describe('ui.grid.resizeColumns', function () {

initialX = firstResizer.position().left;

$(firstResizer).simulate('mousedown', { clientX: initialX });
$(firstResizer).simulate(downEvent, { clientX: initialX });
$scope.$digest();

// Get the overlay
overlay = $(grid).find('.ui-grid-resize-overlay');
initialOverlayX = $(overlay).position().left;

xDiff = 100;
$(document).simulate('mousemove', { clientX: initialX + xDiff });
$(document).simulate(moveEvent, { clientX: initialX + xDiff });
$scope.$digest();
});

Expand All @@ -186,7 +199,7 @@ describe('ui.grid.resizeColumns', function () {

describe('then releasing the mouse', function () {
beforeEach(function () {
$(document).simulate('mouseup', { clientX: initialX + xDiff });
$(document).simulate(upEvent, { clientX: initialX + xDiff });
$scope.$digest();
});

Expand Down Expand Up @@ -243,10 +256,10 @@ describe('ui.grid.resizeColumns', function () {
var firstResizer = $(grid).find('[ui-grid-column-resizer]').first();
initialX = firstResizer.position().left;

$(firstResizer).simulate('mousedown', { clientX: initialX });
$(firstResizer).simulate(downEvent, { clientX: initialX });
$scope.$digest();

$(document).simulate('mouseup', { clientX: initialX - minWidth });
$(document).simulate(upEvent, { clientX: initialX - minWidth });
$scope.$digest();
});

Expand Down Expand Up @@ -297,10 +310,10 @@ describe('ui.grid.resizeColumns', function () {
var firstResizer = $(grid).find('[ui-grid-column-resizer]').first();
initialX = firstResizer.position().left;

$(firstResizer).simulate('mousedown', { clientX: initialX });
$(firstResizer).simulate(downEvent, { clientX: initialX });
$scope.$digest();

$(document).simulate('mouseup', { clientX: initialX + maxWidth });
$(document).simulate(upEvent, { clientX: initialX + maxWidth });
$scope.$digest();
});

Expand Down
8 changes: 7 additions & 1 deletion src/js/core/directives/ui-grid-header-cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,15 @@
*
*/

if ( $scope.sortable || $scope.colMenu ){
if ($scope.sortable || $scope.colMenu) {
// Long-click (for mobile)
var cancelMousedownTimeout;
var mousedownStartTime = 0;

var downEvent = gridUtil.isTouchEnabled() ? 'touchstart' : 'mousedown';
$contentsElm.on(downEvent, function(event) {
gridUtil.logDebug('mouse event', event.type);

event.stopPropagation();

if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
Expand Down Expand Up @@ -203,6 +205,8 @@
if ($scope.sortable) {
var clickEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'click';
$contentsElm.on(clickEvent, function(event) {
gridUtil.logDebug('mouse event 2', event.type);

event.stopPropagation();

$timeout.cancel(cancelMousedownTimeout);
Expand All @@ -211,10 +215,12 @@
var mousedownTime = mousedownEndTime - mousedownStartTime;

if (mousedownTime > mousedownTimeout) {
gridUtil.logDebug('long click');
// long click, handled above with mousedown
}
else {
// short click
gridUtil.logDebug('short click');
handleClick(event);
}
});
Expand Down

0 comments on commit 654e0ce

Please sign in to comment.