Skip to content

Commit 654e0ce

Browse files
committed
fix(Mobile): Allow either touch and mouse events
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
1 parent 2dc0275 commit 654e0ce

File tree

4 files changed

+94
-27
lines changed

4 files changed

+94
-27
lines changed

src/features/edit/js/gridEdit.js

+39-4
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,10 @@
369369
*
370370
*/
371371
module.directive('uiGridCell',
372-
['$compile', '$injector', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
373-
function ($compile, $injector, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
372+
['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService',
373+
function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService) {
374+
var touchstartTimeout = 500;
375+
374376
return {
375377
priority: -100, // run after default uiGridCell directive
376378
restrict: 'A',
@@ -386,6 +388,7 @@
386388
var inEdit = false;
387389
var isFocusedBeforeEdit = false;
388390
var cellModel;
391+
var cancelTouchstartTimeout;
389392

390393
registerBeginEditEvents();
391394

@@ -395,6 +398,37 @@
395398
if ($scope.col.colDef.enableCellEditOnFocus) {
396399
$elm.find('div').on('focus', beginEditFocus);
397400
}
401+
402+
// Add touchstart handling. If the users starts a touch and it doesn't end after X milliseconds, then start the edit
403+
$elm.on('touchstart', touchStart);
404+
}
405+
406+
function touchStart(event) {
407+
// jQuery masks events
408+
if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
409+
event = event.originalEvent;
410+
}
411+
412+
// Bind touchend handler
413+
$elm.on('touchend', touchEnd);
414+
415+
// Start a timeout
416+
cancelTouchstartTimeout = $timeout(function() { }, touchstartTimeout);
417+
418+
// Timeout's done! Start the edit
419+
cancelTouchstartTimeout.then(function () {
420+
// Use setTimeout to start the edit because beginEdit expects to be outside of $digest
421+
setTimeout(beginEdit, 0);
422+
423+
// Undbind the touchend handler, we don't need it anymore
424+
$elm.off('touchend', touchEnd);
425+
});
426+
}
427+
428+
// Cancel any touchstart timeout
429+
function touchEnd(event) {
430+
$timeout.cancel(cancelTouchstartTimeout);
431+
$elm.off('touchend', touchEnd);
398432
}
399433

400434
function cancelBeginEditEvents() {
@@ -403,6 +437,7 @@
403437
if ($scope.col.colDef.enableCellEditOnFocus) {
404438
$elm.find('div').off('focus', beginEditFocus);
405439
}
440+
$elm.off('touchstart', touchStart);
406441
}
407442

408443
function beginEditFocus(evt) {
@@ -634,8 +669,8 @@
634669
*
635670
*/
636671
module.directive('uiGridEditor',
637-
['uiGridConstants', 'uiGridEditConstants',
638-
function (uiGridConstants, uiGridEditConstants) {
672+
['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
673+
function (gridUtil, uiGridConstants, uiGridEditConstants) {
639674
return {
640675
scope: true,
641676
require: ['?^uiGrid', '?^uiGridRenderContainer'],

src/features/resize-columns/js/ui-grid-column-resizer.js

+26-13
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,19 @@
263263
module.directive('uiGridColumnResizer', ['$document', 'gridUtil', 'uiGridConstants', 'columnBounds', 'uiGridResizeColumnsService', function ($document, gridUtil, uiGridConstants, columnBounds, uiGridResizeColumnsService) {
264264
var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');
265265

266+
var downEvent, upEvent, moveEvent;
267+
268+
if (gridUtil.isTouchEnabled()) {
269+
downEvent = 'touchstart';
270+
upEvent = 'touchend';
271+
moveEvent = 'touchmove';
272+
}
273+
else {
274+
downEvent = 'mousedown';
275+
upEvent = 'mouseup';
276+
moveEvent = 'mousemove';
277+
}
278+
266279
var resizer = {
267280
priority: 0,
268281
scope: {
@@ -321,7 +334,7 @@
321334
if (event.originalEvent) { event = event.originalEvent; }
322335
event.preventDefault();
323336

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

326339
if (x < 0) { x = 0; }
327340
else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }
@@ -379,12 +392,12 @@
379392
resizeOverlay.remove();
380393

381394
// Resize the column
382-
x = event.clientX - gridLeft;
395+
x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
383396
var xDiff = x - startX;
384397

385398
if (xDiff === 0) {
386-
$document.off('mouseup', mouseup);
387-
$document.off('mousemove', mousemove);
399+
$document.off(upEvent, mouseup);
400+
$document.off(moveEvent, mousemove);
388401
return;
389402
}
390403

@@ -431,11 +444,11 @@
431444

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

434-
$document.off('mouseup', mouseup);
435-
$document.off('mousemove', mousemove);
447+
$document.off(upEvent, mouseup);
448+
$document.off(moveEvent, mousemove);
436449
}
437450

438-
$elm.on('mousedown', function(event, args) {
451+
$elm.on(downEvent, function(event, args) {
439452
if (event.originalEvent) { event = event.originalEvent; }
440453
event.stopPropagation();
441454

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

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

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

455468
// Add handlers for mouse move and up events
456-
$document.on('mouseup', mouseup);
457-
$document.on('mousemove', mousemove);
469+
$document.on(upEvent, mouseup);
470+
$document.on(moveEvent, mousemove);
458471
});
459472

460473
// On doubleclick, resize to fit all rendered cells
@@ -539,10 +552,10 @@
539552
});
540553

541554
$elm.on('$destroy', function() {
542-
$elm.off('mousedown');
555+
$elm.off(downEvent);
543556
$elm.off('dblclick');
544-
$document.off('mousemove', mousemove);
545-
$document.off('mouseup', mouseup);
557+
$document.off(moveEvent, mousemove);
558+
$document.off(upEvent, mouseup);
546559
});
547560
}
548561
};

src/features/resize-columns/test/resizeColumns.spec.js

+22-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
describe('ui.grid.resizeColumns', function () {
1+
ddescribe('ui.grid.resizeColumns', function () {
22
var grid, gridUtil, gridScope, $scope, $compile, recompile, uiGridConstants;
33

4+
var downEvent, upEvent, moveEvent;
5+
46
var data = [
57
{ "name": "Ethel Price", "gender": "female", "company": "Enersol" },
68
{ "name": "Claudine Neal", "gender": "female", "company": "Sealoud" },
@@ -17,6 +19,17 @@ describe('ui.grid.resizeColumns', function () {
1719
uiGridConstants = _uiGridConstants_;
1820
gridUtil = _gridUtil_;
1921

22+
if (gridUtil.isTouchEnabled()) {
23+
downEvent = 'touchstart';
24+
upEvent = 'touchend';
25+
moveEvent = 'touchmove';
26+
}
27+
else {
28+
downEvent = 'mousedown';
29+
upEvent = 'mouseup';
30+
moveEvent = 'mousemove';
31+
}
32+
2033
$scope.gridOpts = {
2134
enableColumnResizing: true,
2235
data: data
@@ -133,7 +146,7 @@ describe('ui.grid.resizeColumns', function () {
133146
it('should cause the column separator overlay to be added', function () {
134147
var firstResizer = $(grid).find('[ui-grid-column-resizer]').first();
135148

136-
firstResizer.trigger('mousedown');
149+
firstResizer.trigger(downEvent);
137150
$scope.$digest();
138151

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

157170
initialX = firstResizer.position().left;
158171

159-
$(firstResizer).simulate('mousedown', { clientX: initialX });
172+
$(firstResizer).simulate(downEvent, { clientX: initialX });
160173
$scope.$digest();
161174

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

166179
xDiff = 100;
167-
$(document).simulate('mousemove', { clientX: initialX + xDiff });
180+
$(document).simulate(moveEvent, { clientX: initialX + xDiff });
168181
$scope.$digest();
169182
});
170183

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

187200
describe('then releasing the mouse', function () {
188201
beforeEach(function () {
189-
$(document).simulate('mouseup', { clientX: initialX + xDiff });
202+
$(document).simulate(upEvent, { clientX: initialX + xDiff });
190203
$scope.$digest();
191204
});
192205

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

246-
$(firstResizer).simulate('mousedown', { clientX: initialX });
259+
$(firstResizer).simulate(downEvent, { clientX: initialX });
247260
$scope.$digest();
248261

249-
$(document).simulate('mouseup', { clientX: initialX - minWidth });
262+
$(document).simulate(upEvent, { clientX: initialX - minWidth });
250263
$scope.$digest();
251264
});
252265

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

300-
$(firstResizer).simulate('mousedown', { clientX: initialX });
313+
$(firstResizer).simulate(downEvent, { clientX: initialX });
301314
$scope.$digest();
302315

303-
$(document).simulate('mouseup', { clientX: initialX + maxWidth });
316+
$(document).simulate(upEvent, { clientX: initialX + maxWidth });
304317
$scope.$digest();
305318
});
306319

src/js/core/directives/ui-grid-header-cell.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,15 @@
136136
*
137137
*/
138138

139-
if ( $scope.sortable || $scope.colMenu ){
139+
if ($scope.sortable || $scope.colMenu) {
140140
// Long-click (for mobile)
141141
var cancelMousedownTimeout;
142142
var mousedownStartTime = 0;
143143

144144
var downEvent = gridUtil.isTouchEnabled() ? 'touchstart' : 'mousedown';
145145
$contentsElm.on(downEvent, function(event) {
146+
gridUtil.logDebug('mouse event', event.type);
147+
146148
event.stopPropagation();
147149

148150
if (typeof(event.originalEvent) !== 'undefined' && event.originalEvent !== undefined) {
@@ -203,6 +205,8 @@
203205
if ($scope.sortable) {
204206
var clickEvent = gridUtil.isTouchEnabled() ? 'touchend' : 'click';
205207
$contentsElm.on(clickEvent, function(event) {
208+
gridUtil.logDebug('mouse event 2', event.type);
209+
206210
event.stopPropagation();
207211

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

213217
if (mousedownTime > mousedownTimeout) {
218+
gridUtil.logDebug('long click');
214219
// long click, handled above with mousedown
215220
}
216221
else {
217222
// short click
223+
gridUtil.logDebug('short click');
218224
handleClick(event);
219225
}
220226
});

0 commit comments

Comments
 (0)