From 941d78c698e7723fd899203c5f8b1b99c424a937 Mon Sep 17 00:00:00 2001 From: alexlukelevy Date: Tue, 1 Nov 2016 18:42:51 +0000 Subject: [PATCH 01/13] docs: correcting parameter type for row visibility methods on gridApi --- src/js/core/factories/GridApi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/core/factories/GridApi.js b/src/js/core/factories/GridApi.js index 594bae0a32..cd0049753c 100644 --- a/src/js/core/factories/GridApi.js +++ b/src/js/core/factories/GridApi.js @@ -66,7 +66,7 @@ * which will override any filtering or other visibility calculations. * If the row is currently visible then sets it to invisible and calls * both grid refresh and emits the rowsVisibleChanged event - * @param {object} rowEntity gridOptions.data[] array instance + * @param {GridRow} row the row we want to make invisible */ this.registerMethod( 'core', 'setRowInvisible', GridRow.prototype.setRowInvisible ); @@ -79,7 +79,7 @@ * If the row is currently invisible then sets it to visible and calls * both grid refresh and emits the rowsVisibleChanged event * TODO: if a filter is active then we can't just set it to visible? - * @param {object} rowEntity gridOptions.data[] array instance + * @param {GridRow} row the row we want to make visible */ this.registerMethod( 'core', 'clearRowInvisible', GridRow.prototype.clearRowInvisible ); From 2da4e12da6583553570dde164f8c2f795dc43612 Mon Sep 17 00:00:00 2001 From: Marco Bisioli Date: Fri, 28 Oct 2016 15:14:46 +0200 Subject: [PATCH 02/13] Correct priority sort. Fixes #5777 Return correct order when only one member has priority. --- src/js/core/services/rowSorter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/core/services/rowSorter.js b/src/js/core/services/rowSorter.js index e918d45735..9626a8934e 100644 --- a/src/js/core/services/rowSorter.js +++ b/src/js/core/services/rowSorter.js @@ -358,11 +358,11 @@ module.service('rowSorter', ['$parse', 'uiGridConstants', function ($parse, uiGr } } // Only A has a priority - else if (a.sort.priority || a.sort.priority === undefined) { + else if (a.sort.priority !== undefined) { return -1; } // Only B has a priority - else if (b.sort.priority || b.sort.priority === undefined) { + else if (b.sort.priority !== undefined) { return 1; } // Neither has a priority From b50c9e888c9c220bdd670e85b0bb57cdcd5d4be9 Mon Sep 17 00:00:00 2001 From: Cole Mecum Date: Tue, 8 Nov 2016 06:24:16 -0600 Subject: [PATCH 03/13] Fix#4658 (#5762) * Fixes #3832 * chore(less): Propose fix for #4658 Added icon definitions into icons.less and removed fontello from build process https://github.com/angular-ui/ui-grid/issues/4658 --- grunt/aliases.js | 7 +- grunt/watch.js | 5 - .../tutorial/116_fonts_and_installation.ngdoc | 2 +- package.json | 1 - src/js/core/factories/GridOptions.js | 11 +- src/less/icons.less | 115 ++++++++++++++++-- 6 files changed, 115 insertions(+), 26 deletions(-) diff --git a/grunt/aliases.js b/grunt/aliases.js index e927f7ce68..7e4422fea5 100644 --- a/grunt/aliases.js +++ b/grunt/aliases.js @@ -10,7 +10,7 @@ module.exports = function (grunt, options) { 'default': ['before-test', 'test:single', 'after-test'], // Build with no testing - 'build': ['ngtemplates', 'concat', 'uglify', 'fontello', 'less', 'ngdocs', 'copy:site', 'copy:less_customizer',], + 'build': ['ngtemplates', 'concat', 'uglify', 'less', 'ngdocs', 'copy:site', 'copy:less_customizer',], // Auto-test tasks for development 'autotest:unit': ['karmangular:start'], @@ -36,11 +36,6 @@ module.exports = function (grunt, options) { baseTasks['dev'].splice(baseTasks['dev'].indexOf('autotest:unit'), 1); } - if (grunt.option('fontello') === false) { - grunt.log.writeln("Skipping fontello..."); - baseTasks['build'].splice(baseTasks['build'].indexOf('fontello'), 1); - } - if (process.env.TRAVIS){ baseTasks['test:single'] = ['karma:travis']; } diff --git a/grunt/watch.js b/grunt/watch.js index 8bb6bd98f3..3f0ceeafad 100644 --- a/grunt/watch.js +++ b/grunt/watch.js @@ -30,11 +30,6 @@ module.exports = function( grunt, options ){ tasks: ['less', 'ngdocs', 'concat:customizer_less'] }, - fontello: { - files: 'src/font/config.json', - tasks: ['fontello', 'less'] - }, - docs: { files: ['misc/tutorial/**/*.ngdoc', 'misc/api/**/*.ngdoc', 'misc/doc/**'], tasks: 'ngdocs' diff --git a/misc/tutorial/116_fonts_and_installation.ngdoc b/misc/tutorial/116_fonts_and_installation.ngdoc index 83ba66d08e..bb574d5490 100644 --- a/misc/tutorial/116_fonts_and_installation.ngdoc +++ b/misc/tutorial/116_fonts_and_installation.ngdoc @@ -9,7 +9,7 @@ This tutorial addresses the basics of the configuration. Key points here are: -1. Fonts are a derivative of font-awesome via fontello, and are used for the dropdown icons and +1. Fonts are a derivative of font-awesome and are used for the dropdown icons and various menu buttons and the like. When they're not working they show a "chinese looking" character. 2. The tutorial pages generally show the fonts correctly. If a tutorial page, when served from ui-grid.info is not showing fonts correctly, then this is likely a defect with ui-grid. If it's diff --git a/package.json b/package.json index 794b2f9d93..7b312647ea 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "grunt-contrib-uglify": "~0.2", "grunt-contrib-watch": "~0.5", "grunt-conventional-changelog": "~1.0.0", - "grunt-fontello": "~0.1", "grunt-gh-pages": "~0.9.0", "grunt-jscs": "^0.7.1", "grunt-karma": "~0.8", diff --git a/src/js/core/factories/GridOptions.js b/src/js/core/factories/GridOptions.js index e3a944cb7b..512988daaa 100644 --- a/src/js/core/factories/GridOptions.js +++ b/src/js/core/factories/GridOptions.js @@ -224,10 +224,17 @@ angular.module('ui.grid') * @ngdoc property * @name rowHeight * @propertyOf ui.grid.class:GridOptions - * @description The height of the row in pixels, defaults to 30 + * @description The height of the row in pixels, Can be passed as integer or string. defaults to 30. * */ - baseOptions.rowHeight = baseOptions.rowHeight || 30; + + if (typeof baseOptions.rowHeight === "string") { + baseOptions.rowHeight = parseInt(baseOptions.rowHeight) || 30; + } + + else { + baseOptions.rowHeight = baseOptions.rowHeight || 30; + } /** * @ngdoc integer diff --git a/src/less/icons.less b/src/less/icons.less index 28a081a1f4..1519d14614 100644 --- a/src/less/icons.less +++ b/src/less/icons.less @@ -2,12 +2,13 @@ font-family: 'ui-grid'; src: url('@{font-path}ui-grid.eot'); src: url('@{font-path}ui-grid.eot#iefix') format('embedded-opentype'), - url('@{font-path}ui-grid.woff') format('woff'), - url('@{font-path}ui-grid.ttf') format('truetype'), - url('@{font-path}ui-grid.svg?#ui-grid') format('svg'); + url('@{font-path}ui-grid.woff') format('woff'), + url('@{font-path}ui-grid.ttf') format('truetype'), + url('@{font-path}ui-grid.svg?#ui-grid') format('svg'); font-weight: normal; font-style: normal; } + /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ /* @@ -18,34 +19,34 @@ } } */ - - [class^="ui-grid-icon"]:before, [class*=" ui-grid-icon"]:before { + +[class^="ui-grid-icon"]:before, [class*=" ui-grid-icon"]:before { font-family: "ui-grid"; font-style: normal; font-weight: normal; speak: none; - + display: inline-block; text-decoration: inherit; width: 1em; margin-right: .2em; text-align: center; /* opacity: .8; */ - + /* For safety - reset parent styles, that can break glyph codes*/ font-variant: normal; text-transform: none; - + /* fix buttons height, for twitter bootstrap */ line-height: 1em; - + /* Animation center compensation - margins should be symmetric */ /* remove if not needed */ margin-left: .2em; - + /* you can be more comfortable with increased icons size */ /* font-size: 120%; */ - + /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } @@ -54,3 +55,95 @@ width: 1em; content: ' '; } + +.ui-grid-icon-plus-squared:before { + content: '\c350' +} + +.ui-grid-icon-minus-squared:before { + content: '\c351' +} + +.ui-grid-icon-search:before { + content: '\c352' +} + +.ui-grid-icon-cancel:before { + content: '\c353' +} + +.ui-grid-icon-info-circled:before { + content: '\c354' +} + +.ui-grid-icon-lock:before { + content: '\c355' +} + +.ui-grid-icon-lock-open:before { + content: '\c356' +} + +.ui-grid-icon-pencil:before { + content: '\c357' +} + +.ui-grid-icon-down-dir:before { + content: '\c358' +} + +.ui-grid-icon-up-dir:before { + content: '\c359' +} + +.ui-grid-icon-left-dir:before { + content: '\c35a' +} + +.ui-grid-icon-right-dir:before { + content: '\c35b' +} + +.ui-grid-icon-left-open:before { + content: '\c35c' +} + +.ui-grid-icon-right-open:before { + content: '\c35d' +} + +.ui-grid-icon-angle-down:before { + content: '\c35e' +} + +.ui-grid-icon-filter:before { + content: '\c35f' +} + +.ui-grid-icon-sort-alt-up:before { + content: '\c360' +} + +.ui-grid-icon-sort-alt-down:before { + content: '\c361' +} + +.ui-grid-icon-ok:before { + content: '\c362' +} + +.ui-grid-icon-menu:before { + content: '\c363' +} + +.ui-grid-icon-indent-left:before { + content: '\e800' +} + +.ui-grid-icon-indent-right:before { + content: '\e801' +} + +.ui-grid-icon-spin5:before { + content: '\ea61' +} From b84fc54521960383228358f6331889524444a067 Mon Sep 17 00:00:00 2001 From: Umer Farooq Date: Wed, 26 Oct 2016 11:48:15 -0400 Subject: [PATCH 04/13] fix(edit): fix boolean edit issue on Firefox and Safari on macOS Add mousedown listener to ui.grid.edit.directive:uiGridEditor to disable blur handler if the element is a checkbox, and then re-focus the checkbox and enable the blur handler after a $timeout. This change is to deal with Safari and Firefox behavior in macOS where clicking the checkbox causes a blur event, and the value is not updated. GitHub issues: #1785, #4778, #4782 --- src/features/edit/js/gridEdit.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/features/edit/js/gridEdit.js b/src/features/edit/js/gridEdit.js index eff7c66ecc..8c7df01879 100644 --- a/src/features/edit/js/gridEdit.js +++ b/src/features/edit/js/gridEdit.js @@ -966,9 +966,20 @@ }); } - $elm.on('blur', function (evt) { - $scope.stopEdit(evt); + // macOS will blur the checkbox when clicked in Safari and Firefox, + // to get around this, we disable the blur handler on mousedown, + // and then focus the checkbox and re-enable the blur handler after $timeout + $elm.on('mousedown', function(evt) { + if ($elm[0].type === 'checkbox') { + $elm.off('blur', $scope.stopEdit); + $timeout(function() { + $elm.focus(); + $elm.on('blur', $scope.stopEdit); + }); + } }); + + $elm.on('blur', $scope.stopEdit); }); @@ -1132,9 +1143,9 @@ //set focus at start of edit $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () { $timeout(function(){ - $elm[0].focus(); + $elm[0].focus(); }); - + $elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px'; $elm.on('blur', function (evt) { $scope.stopEdit(evt); From 71a96be1a58eeebed6180b38d691c33fbdd41e33 Mon Sep 17 00:00:00 2001 From: nilad Date: Thu, 13 Oct 2016 15:50:10 +0200 Subject: [PATCH 05/13] vertical scroll length should never be 0. This will result in division by 0 errors --- src/js/core/factories/GridRenderContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/core/factories/GridRenderContainer.js b/src/js/core/factories/GridRenderContainer.js index 5a4fd67b6a..05f7edac7b 100644 --- a/src/js/core/factories/GridRenderContainer.js +++ b/src/js/core/factories/GridRenderContainer.js @@ -300,7 +300,7 @@ angular.module('ui.grid') }; GridRenderContainer.prototype.getVerticalScrollLength = function getVerticalScrollLength() { - return this.getCanvasHeight() - this.getViewportHeight() + this.grid.scrollbarHeight; + return this.getCanvasHeight() - this.getViewportHeight() + this.grid.scrollbarHeight !== 0 ? this.getCanvasHeight() - this.getViewportHeight() + this.grid.scrollbarHeight : -1; }; GridRenderContainer.prototype.getHorizontalScrollLength = function getHorizontalScrollLength() { From 1c28836bf89a3106fc854b233cb1f3d74665f377 Mon Sep 17 00:00:00 2001 From: Niels Ladekarl Date: Thu, 20 Oct 2016 16:43:13 +0200 Subject: [PATCH 06/13] Update GridRenderContainer.js --- src/js/core/factories/GridRenderContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/core/factories/GridRenderContainer.js b/src/js/core/factories/GridRenderContainer.js index 05f7edac7b..7f4bba9d4a 100644 --- a/src/js/core/factories/GridRenderContainer.js +++ b/src/js/core/factories/GridRenderContainer.js @@ -304,7 +304,7 @@ angular.module('ui.grid') }; GridRenderContainer.prototype.getHorizontalScrollLength = function getHorizontalScrollLength() { - return this.getCanvasWidth() - this.getViewportWidth() + this.grid.scrollbarWidth; + return this.getCanvasWidth() - this.getViewportWidth() + this.grid.scrollbarWidth !== 0 ? this.getCanvasWidth() - this.getViewportWidth() + this.grid.scrollbarWidth : -1; }; GridRenderContainer.prototype.getCanvasWidth = function getCanvasWidth() { From db80dc5272e2ba512794c852c2bfbaea7255acc4 Mon Sep 17 00:00:00 2001 From: Justin Sunsri Date: Tue, 8 Nov 2016 06:38:48 -0600 Subject: [PATCH 07/13] Option to adjust where the exporter showed up in the menu (#4671) * Option to adjust where the exporter showed up in the menu I added a new option exporterMenuItemOrder for the gridOptions so that I could adjust where the menu items were showing up in the grid * adding option to adjust grid menu item order adding to the tests to make sure when set to default number and when set to non default number the option still works --- src/features/exporter/js/exporter.js | 20 ++++++++++++++------ src/features/exporter/test/exporter.spec.js | 9 ++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/features/exporter/js/exporter.js b/src/features/exporter/js/exporter.js index 55845f151d..ca246a2048 100755 --- a/src/features/exporter/js/exporter.js +++ b/src/features/exporter/js/exporter.js @@ -235,6 +235,14 @@ *
Defaults to false */ gridOptions.exporterOlderExcelCompatibility = gridOptions.exporterOlderExcelCompatibility === true; + /** + * @ngdoc object + * @name exporterMenuItemOrder + * @propertyOf ui.grid.exporter.api:GridOptions + * @description An option to determine the starting point for the menu items created by the exporter + *
Defaults to 200 + */ + gridOptions.exporterMenuItemOrder = gridOptions.exporterMenuItemOrder ? gridOptions.exporterMenuItemOrder : 200; /** * @ngdoc object * @name exporterPdfDefaultStyle @@ -547,7 +555,7 @@ shown: function() { return this.grid.options.exporterMenuCsv && this.grid.options.exporterMenuAllData; }, - order: 200 + order: grid.options.exporterMenuItemOrder }, { title: i18nService.getSafeText('gridMenu.exporterVisibleAsCsv'), @@ -557,7 +565,7 @@ shown: function() { return this.grid.options.exporterMenuCsv && this.grid.options.exporterMenuVisibleData; }, - order: 201 + order: grid.options.exporterMenuItemOrder + 1 }, { title: i18nService.getSafeText('gridMenu.exporterSelectedAsCsv'), @@ -568,7 +576,7 @@ return this.grid.options.exporterMenuCsv && this.grid.options.exporterMenuSelectedData && ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); }, - order: 202 + order: grid.options.exporterMenuItemOrder + 2 }, { title: i18nService.getSafeText('gridMenu.exporterAllAsPdf'), @@ -578,7 +586,7 @@ shown: function() { return this.grid.options.exporterMenuPdf && this.grid.options.exporterMenuAllData; }, - order: 203 + order: grid.options.exporterMenuItemOrder + 3 }, { title: i18nService.getSafeText('gridMenu.exporterVisibleAsPdf'), @@ -588,7 +596,7 @@ shown: function() { return this.grid.options.exporterMenuPdf && this.grid.options.exporterMenuVisibleData; }, - order: 204 + order: grid.options.exporterMenuItemOrder + 4 }, { title: i18nService.getSafeText('gridMenu.exporterSelectedAsPdf'), @@ -599,7 +607,7 @@ return this.grid.options.exporterMenuPdf && this.grid.options.exporterMenuSelectedData && ( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 ); }, - order: 205 + order: grid.options.exporterMenuItemOrder + 5 } ]); }, diff --git a/src/features/exporter/test/exporter.spec.js b/src/features/exporter/test/exporter.spec.js index 4d6bbc5da7..9c2ed6a996 100644 --- a/src/features/exporter/test/exporter.spec.js +++ b/src/features/exporter/test/exporter.spec.js @@ -92,7 +92,8 @@ describe('ui.grid.exporter uiGridExporterService', function () { exporterMenuPdf: true, exporterFieldCallback: jasmine.any(Function), exporterAllDataFn: null, - exporterSuppressColumns: [] + exporterSuppressColumns: [], + exporterMenuItemOrder: 200 }); }); @@ -122,7 +123,8 @@ describe('ui.grid.exporter uiGridExporterService', function () { exporterMenuPdf: false, exporterFieldCallback: callback, exporterAllDataPromise: callback, - exporterSuppressColumns: [ 'buttons' ] + exporterSuppressColumns: [ 'buttons' ], + exporterMenuItemOrder: 75 }; uiGridExporterService.defaultGridOptions(options); expect( options ).toEqual({ @@ -150,7 +152,8 @@ describe('ui.grid.exporter uiGridExporterService', function () { exporterFieldCallback: callback, exporterAllDataFn: callback, exporterAllDataPromise: callback, - exporterSuppressColumns: [ 'buttons' ] + exporterSuppressColumns: [ 'buttons' ], + exporterMenuItemOrder: 75 }); }); }); From a407c6d0ec5b4bdc324c77c919dc499c345cadfa Mon Sep 17 00:00:00 2001 From: "Kondratev, Gennadii" Date: Thu, 6 Oct 2016 18:39:36 +0300 Subject: [PATCH 08/13] add the new service GridScrolling (updated return value) --- src/js/core/directives/ui-grid-viewport.js | 7 +- src/js/core/factories/GridScrolling.js | 195 +++++++++++++++++++++ 2 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 src/js/core/factories/GridScrolling.js diff --git a/src/js/core/directives/ui-grid-viewport.js b/src/js/core/directives/ui-grid-viewport.js index 712cd8c425..240f562205 100644 --- a/src/js/core/directives/ui-grid-viewport.js +++ b/src/js/core/directives/ui-grid-viewport.js @@ -1,8 +1,8 @@ (function(){ 'use strict'; - angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants', '$log', - function(gridUtil, ScrollEvent, uiGridConstants, $log) { + angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants', '$log', 'GridScrolling', + function(gridUtil, ScrollEvent, uiGridConstants, $log, gridScrolling) { return { replace: true, scope: {}, @@ -31,8 +31,7 @@ // Register this viewport with its container containerCtrl.viewport = $elm; - - $elm.on('scroll', scrollHandler); + gridScrolling($elm, scrollHandler); var ignoreScroll = false; diff --git a/src/js/core/factories/GridScrolling.js b/src/js/core/factories/GridScrolling.js new file mode 100644 index 0000000000..6482376043 --- /dev/null +++ b/src/js/core/factories/GridScrolling.js @@ -0,0 +1,195 @@ +(function() { + 'use strict'; + + angular.module('ui.grid') + .factory('GridScrolling', function($window, gridUtil) { + var isAnimating; + + myScrolling.initiated = 0; + + return myScrolling; + + function myScrolling(elm, scrollHandler) { + var wrapper = elm, pointX, pointY, startTime, startX, startY, + scroller = wrapper[0].children[0], + TOUCHABLE = 1, + MOUSE = 2, + POINTER = 3, + maxScroll, + initType = { + touchstart: TOUCHABLE, + touchmove: TOUCHABLE, + touchend: TOUCHABLE, + + mousedown: MOUSE, + mousemove: MOUSE, + mouseup: MOUSE, + + pointerdown: POINTER, + pointermove: POINTER, + pointerup: POINTER + }; + + if ('onmousedown' in $window) { + wrapper.on('scroll', scrollHandler); + } + + if (gridUtil.isTouchEnabled()) { + wrapper.on('touchstart', start); + wrapper.on('touchmove', move); + wrapper.on('touchcancel', end); + wrapper.on('touchend', end); + document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); + } + + function start(e) { + var point = e.touches ? e.touches[0] : e; + + wrapper.off('scroll', scrollHandler); + + myScrolling.initiated = initType[e.type]; + + pointX = point.pageX; + pointY = point.pageY; + + startTime = (new Date()).getTime(); + startX = wrapper[0].scrollLeft; + startY = wrapper[0].scrollTop; + isAnimating = false; + + } + + function move(e) { + if (initType[e.type] !== myScrolling.initiated) { + return; + } + + var newX, newY, timestamp = (new Date()).getTime(), + point = e.touches ? e.touches[0] : e, + deltaX = pointX - point.pageX, + deltaY = pointY - point.pageY; + + pointX = point.pageX; + pointY = point.pageY; + + newX = wrapper[0].scrollLeft + deltaX; + newY = wrapper[0].scrollTop + deltaY; + + if ( newX < 0 || newX > getMaxScroll().x ) { + newX = newX < 0 ? 0 : getMaxScroll().x; + } + + if ( newY < 0 || newY > getMaxScroll().y ) { + newY = newY < 0 ? 0 : getMaxScroll().y; + } + + if (timestamp - startTime > 300) { + startTime = (new Date()).getTime(); + startX = newX; + startY = newY; + } + + translate(newX, newY, wrapper); + + scrollHandler.call(null, e); + + } + + function end(e) { + if ( initType[e.type] !== myScrolling.initiated ) { + return; + } + + var duration = (new Date()).getTime() - startTime; + + var momentumX = momentum(wrapper[0].scrollLeft, startX, duration); + var momentumY = momentum(wrapper[0].scrollTop, startY, duration); + var newX = momentumX.destination; + var newY = momentumY.destination; + var time = Math.max(momentumX.duration, momentumY.duration); + + animate(newX, newY, time, wrapper, scrollHandler.bind(null, e)); + + myScrolling.initiated = 0; + } + + function momentum(curr, start, time) { + curr = Math.abs(curr); + start = Math.abs(start); + + var distance = curr - start, + speed = Math.abs(distance)/time, + deceleration = 0.0007; + + var destination = curr + (speed * speed)/(2 * deceleration)* (distance >= 0 ? 1 : -1); + var duration = speed / deceleration; + + return { + destination: Math.round(destination), + duration: duration + }; + } + + function getMaxScroll() { + if (!maxScroll) { + maxScroll = { + x: scroller.offsetWidth - wrapper[0].clientWidth, + y: scroller.offsetHeight - wrapper[0].clientHeight + }; + } + return maxScroll; + } + } + + function translate(x, y, wrapper) { + wrapper[0].scrollLeft = x; + wrapper[0].scrollTop = y; + } + + function easeClb(k) { + return k * ( 2 - k ); + } + + function animate(destX, destY, duration, wrapper, clbck) { + var startTime = (new Date()).getTime(), + startX = wrapper[0].scrollLeft, + startY = wrapper[0].scrollTop, + destTime = startTime + duration; + + isAnimating = true; + + next(); + + function next() { + var now = (new Date()).getTime(), + relPoint, easeRes, newX, newY; + + + + if (now >= destTime) { + isAnimating = false; + translate(destX, destY, wrapper); + wrapper.on('scroll', clbck); + return; + } + + relPoint = (now - startTime) / duration; + + easeRes = easeClb(relPoint); + + newX = ( destX - Math.abs(startX) ) * easeRes + Math.abs(startX); + newY = ( destY - Math.abs(startY) ) * easeRes + Math.abs(startY); + + translate(newX, newY, wrapper); + + clbck.call(); + + if (isAnimating) { + window.requestAnimationFrame(next); + } else { + wrapper.on('scroll', clbck); + } + } + } + }); +})(); From dd1fe1d47755c06c94e103f9b4a034a0dfbe1889 Mon Sep 17 00:00:00 2001 From: "Portugal, Marcelo" Date: Fri, 2 Dec 2016 18:09:37 -0500 Subject: [PATCH 09/13] refactor(gridScrolling): Making code review changes and documenting. Making as many of the code review changes as possible, renaming some variables and adding documentation. --- src/js/core/directives/ui-grid-viewport.js | 2 +- src/js/core/factories/GridScrolling.js | 155 +++++++++++++++------ 2 files changed, 117 insertions(+), 40 deletions(-) diff --git a/src/js/core/directives/ui-grid-viewport.js b/src/js/core/directives/ui-grid-viewport.js index 240f562205..057039d88a 100644 --- a/src/js/core/directives/ui-grid-viewport.js +++ b/src/js/core/directives/ui-grid-viewport.js @@ -1,7 +1,7 @@ (function(){ 'use strict'; - angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants', '$log', 'GridScrolling', + angular.module('ui.grid').directive('uiGridViewport', ['gridUtil','ScrollEvent','uiGridConstants', '$log', 'gridScrolling', function(gridUtil, ScrollEvent, uiGridConstants, $log, gridScrolling) { return { replace: true, diff --git a/src/js/core/factories/GridScrolling.js b/src/js/core/factories/GridScrolling.js index 6482376043..e776a3b480 100644 --- a/src/js/core/factories/GridScrolling.js +++ b/src/js/core/factories/GridScrolling.js @@ -2,15 +2,28 @@ 'use strict'; angular.module('ui.grid') - .factory('GridScrolling', function($window, gridUtil) { + .factory('gridScrolling', function($window, gridUtil) { var isAnimating; - myScrolling.initiated = 0; - - return myScrolling; - - function myScrolling(elm, scrollHandler) { - var wrapper = elm, pointX, pointY, startTime, startX, startY, + /** + * @ngdoc object + * @name initiated + * @propertyOf ui.grid.class:gridScrolling + * @description Keeps track of which type of scrolling event has been initiated + * and sets it to 0, when no event is being triggered. + */ + gridScrolling.initiated = 0; + + /** + * @ngdoc function + * @name ui.grid.class:gridScrolling + * @description gridScrolling is a wrapper service that takes over the default scrolling logic in order to + * ensure that grid scrolling works consistently in both the browser and devices, as well as slow machines. + * @param {object} element Element being scrolled + * @param {function} scrollHandler Function that needs to be called when scrolling happens. + */ + function gridScrolling(element, scrollHandler) { + var wrapper = element, pointX, pointY, startTime, startX, startY, scroller = wrapper[0].children[0], TOUCHABLE = 1, MOUSE = 2, @@ -42,12 +55,20 @@ document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); } - function start(e) { - var point = e.touches ? e.touches[0] : e; + /** + * @ngdoc function + * @name start + * @methodOf ui.grid.class:gridScrolling + * @description Gets the current coordinates and time, as well as the target coordinate + * and initializes the scrolling event + * @param {object} event The event object + */ + function start(event) { + var point = event.touches ? event.touches[0] : event; wrapper.off('scroll', scrollHandler); - myScrolling.initiated = initType[e.type]; + gridScrolling.initiated = initType[event.type]; pointX = point.pageX; pointY = point.pageY; @@ -56,16 +77,22 @@ startX = wrapper[0].scrollLeft; startY = wrapper[0].scrollTop; isAnimating = false; - } - function move(e) { - if (initType[e.type] !== myScrolling.initiated) { + /** + * @ngdoc function + * @name move + * @methodOf ui.grid.class:gridScrolling + * @description Calculates what the next move should be and starts the scrolling. + * @param {object} event The event object + */ + function move(event) { + if (initType[event.type] !== gridScrolling.initiated) { return; } var newX, newY, timestamp = (new Date()).getTime(), - point = e.touches ? e.touches[0] : e, + point = event.touches ? event.touches[0] : event, deltaX = pointX - point.pageX, deltaY = pointY - point.pageY; @@ -91,38 +118,54 @@ translate(newX, newY, wrapper); - scrollHandler.call(null, e); - + scrollHandler.call(null, event); } - function end(e) { - if ( initType[e.type] !== myScrolling.initiated ) { + /** + * @ngdoc function + * @name end + * @methodOf ui.grid.class:gridScrolling + * @description Finishes the scrolling animation. + * @param {object} event The event object + */ + function end(event) { + if ( initType[event.type] !== gridScrolling.initiated ) { return; } - var duration = (new Date()).getTime() - startTime; - - var momentumX = momentum(wrapper[0].scrollLeft, startX, duration); - var momentumY = momentum(wrapper[0].scrollTop, startY, duration); - var newX = momentumX.destination; - var newY = momentumY.destination; - var time = Math.max(momentumX.duration, momentumY.duration); + var duration = (new Date()).getTime() - startTime, + momentumX = momentum(wrapper[0].scrollLeft, startX, duration), + momentumY = momentum(wrapper[0].scrollTop, startY, duration), + newX = momentumX.destination, + newY = momentumY.destination, + time = Math.max(momentumX.duration, momentumY.duration); - animate(newX, newY, time, wrapper, scrollHandler.bind(null, e)); + animate(newX, newY, time, wrapper, scrollHandler.bind(null, event)); - myScrolling.initiated = 0; + gridScrolling.initiated = 0; } + /** + * @ngdoc function + * @name momentum + * @methodOf ui.grid.class:gridScrolling + * @description Calculates current momentum of the scrolling based on the current position of the element, + * its initial position and the duration of this movement. + * @param {number} curr The current position of the element + * @param {number} start The original position of the element + * @param {number} time The time it has taken for the element to get to its current position. + * @returns {object} An object with the next position for the element and how long + * that animation should take. + */ function momentum(curr, start, time) { curr = Math.abs(curr); start = Math.abs(start); var distance = curr - start, speed = Math.abs(distance)/time, - deceleration = 0.0007; - - var destination = curr + (speed * speed)/(2 * deceleration)* (distance >= 0 ? 1 : -1); - var duration = speed / deceleration; + deceleration = 0.0007, + destination = curr + (speed * speed)/(2 * deceleration)* (distance >= 0 ? 1 : -1), + duration = speed / deceleration; return { destination: Math.round(destination), @@ -130,6 +173,12 @@ }; } + /** + * @ngdoc function + * @name getMaxScroll + * @methodOf ui.grid.class:gridScrolling + * @description Gets the limit of the scrolling for both the x and y positions. + */ function getMaxScroll() { if (!maxScroll) { maxScroll = { @@ -141,16 +190,44 @@ } } + /** + * @ngdoc function + * @name translate + * @methodOf ui.grid.class:gridScrolling + * @description Updates the wrapper's scroll position. + * @param {number} x The horizontal position of the wrapper + * @param {number} y The vertical position of the wrapper + * @param {object} wrapper The wrapper element being updated + */ function translate(x, y, wrapper) { wrapper[0].scrollLeft = x; wrapper[0].scrollTop = y; } - function easeClb(k) { - return k * ( 2 - k ); + /** + * @ngdoc function + * @name easeClb + * @methodOf ui.grid.class:gridScrolling + * @description Calculates the ease resolution base on the current animation times. + * @param {number} relPoint The time the animation is taking between frames. + * @returns {number} The ideal ease time. + */ + function easeClb(relPoint) { + return relPoint * ( 2 - relPoint ); } - function animate(destX, destY, duration, wrapper, clbck) { + /** + * @ngdoc function + * @name animate + * @methodOf ui.grid.class:gridScrolling + * @description Calculates the ease resolution base on the current animation times. + * @param {number} destX The coordinate of the x axis that the scrolling needs to animate to. + * @param {number} destY The coordinate of the y axis that the scrolling needs to animate to. + * @param {number} duration The animation duration + * @param {object} wrapper The wrapper element being updated + * @param {function} callback Function that needs to be called when the animation is done. + */ + function animate(destX, destY, duration, wrapper, callback) { var startTime = (new Date()).getTime(), startX = wrapper[0].scrollLeft, startY = wrapper[0].scrollTop, @@ -164,12 +241,10 @@ var now = (new Date()).getTime(), relPoint, easeRes, newX, newY; - - if (now >= destTime) { isAnimating = false; translate(destX, destY, wrapper); - wrapper.on('scroll', clbck); + wrapper.on('scroll', callback); return; } @@ -182,14 +257,16 @@ translate(newX, newY, wrapper); - clbck.call(); + callback.call(); if (isAnimating) { window.requestAnimationFrame(next); } else { - wrapper.on('scroll', clbck); + wrapper.on('scroll', callback); } } } + + return gridScrolling; }); })(); From 7bac58b280f2bc549d70b15c23be57ce827eeb58 Mon Sep 17 00:00:00 2001 From: "Portugal, Marcelo" Date: Sun, 4 Dec 2016 23:05:54 -0500 Subject: [PATCH 10/13] refactor(Grid Scrolling): Moving constants to uiGridContants. Minor refactoring and moving constants to a more appropiate location. --- src/js/core/constants.js | 19 ++++++++++ src/js/core/factories/GridScrolling.js | 51 ++++++++++++++++---------- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/js/core/constants.js b/src/js/core/constants.js index ef9f0f1629..7a20489596 100644 --- a/src/js/core/constants.js +++ b/src/js/core/constants.js @@ -190,7 +190,26 @@ LEFT: 'left', RIGHT: 'right', NONE: 'none' + }, + /** + * @ngdoc object + * @name scrollEvent + * @propertyOf ui.grid.service:uiGridConstants + * @description Used in {@link ui.grid.class:gridScrolling}, + * to the type of scroll event currently in progress + * + * Available options are: + * - `uiGridConstants.scrollEvent.NONE` - set when no scroll events are being triggered + * - `uiGridConstants.scrollEvent.TOUCHABLE` - set when touchstart, touchmove or touchend are triggered + * - `uiGridConstants.scrollEvent.MOUSE` - set when mousedown, mousemove or mouseup are triggered + * - `uiGridConstants.scrollEvent.POINTER` - set when pointerdown, pointermove or pointerup are triggered + */ + scrollEvent: { + NONE: 0, + TOUCHABLE: 1, + MOUSE: 2, + POINTER: 3 }, /** diff --git a/src/js/core/factories/GridScrolling.js b/src/js/core/factories/GridScrolling.js index e776a3b480..820ef723cf 100644 --- a/src/js/core/factories/GridScrolling.js +++ b/src/js/core/factories/GridScrolling.js @@ -2,7 +2,7 @@ 'use strict'; angular.module('ui.grid') - .factory('gridScrolling', function($window, gridUtil) { + .factory('gridScrolling', function($window, uiGridConstants, gridUtil) { var isAnimating; /** @@ -10,9 +10,9 @@ * @name initiated * @propertyOf ui.grid.class:gridScrolling * @description Keeps track of which type of scrolling event has been initiated - * and sets it to 0, when no event is being triggered. + * and sets it to NONE, when no event is being triggered. */ - gridScrolling.initiated = 0; + gridScrolling.initiated = uiGridConstants.scrollEvent.NONE; /** * @ngdoc function @@ -23,24 +23,20 @@ * @param {function} scrollHandler Function that needs to be called when scrolling happens. */ function gridScrolling(element, scrollHandler) { - var wrapper = element, pointX, pointY, startTime, startX, startY, + var wrapper = element, pointX, pointY, startTime, startX, startY, maxScroll, scroller = wrapper[0].children[0], - TOUCHABLE = 1, - MOUSE = 2, - POINTER = 3, - maxScroll, initType = { - touchstart: TOUCHABLE, - touchmove: TOUCHABLE, - touchend: TOUCHABLE, + touchstart: uiGridConstants.scrollEvent.TOUCHABLE, + touchmove: uiGridConstants.scrollEvent.TOUCHABLE, + touchend: uiGridConstants.scrollEvent.TOUCHABLE, - mousedown: MOUSE, - mousemove: MOUSE, - mouseup: MOUSE, + mousedown: uiGridConstants.scrollEvent.MOUSE, + mousemove: uiGridConstants.scrollEvent.MOUSE, + mouseup: uiGridConstants.scrollEvent.MOUSE, - pointerdown: POINTER, - pointermove: POINTER, - pointerup: POINTER + pointerdown: uiGridConstants.scrollEvent.POINTER, + pointermove: uiGridConstants.scrollEvent.POINTER, + pointerup: uiGridConstants.scrollEvent.POINTER }; if ('onmousedown' in $window) { @@ -142,7 +138,7 @@ animate(newX, newY, time, wrapper, scrollHandler.bind(null, event)); - gridScrolling.initiated = 0; + gridScrolling.initiated = uiGridConstants.scrollEvent.NONE; } /** @@ -216,6 +212,21 @@ return relPoint * ( 2 - relPoint ); } + /** + * @ngdoc function + * @name calcNewPos + * @methodOf ui.grid.class:gridScrolling + * @description Calculates the new position of the element based on where it started, the animation time + * and where it is ultimately supposed to end up. + * @param {number} destPos The destination. + * @param {number} easeRes The ideal ease time. + * @param {number} startPos The original position. + * @returns {number} The next position of the element. + */ + function calcNewPos(destPos, easeRes, startPos) { + return ( destPos - Math.abs(startPos) ) * easeRes + Math.abs(startPos); + } + /** * @ngdoc function * @name animate @@ -252,8 +263,8 @@ easeRes = easeClb(relPoint); - newX = ( destX - Math.abs(startX) ) * easeRes + Math.abs(startX); - newY = ( destY - Math.abs(startY) ) * easeRes + Math.abs(startY); + newX = calcNewPos(destX, easeRes, startX); + newY = calcNewPos(destY, easeRes, startY); translate(newX, newY, wrapper); From e4d1d1ce296ab56e62619aaaf1d42dde823be6a6 Mon Sep 17 00:00:00 2001 From: "Portugal, Marcelo" Date: Sun, 4 Dec 2016 23:33:36 -0500 Subject: [PATCH 11/13] refactor(Grid Scrolling): Reducing duplicate code. Creating a new function to calculate the x and y moves in the move function. --- src/js/core/factories/GridScrolling.js | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/js/core/factories/GridScrolling.js b/src/js/core/factories/GridScrolling.js index 820ef723cf..64208bc37e 100644 --- a/src/js/core/factories/GridScrolling.js +++ b/src/js/core/factories/GridScrolling.js @@ -75,6 +75,27 @@ isAnimating = false; } + /** + * @ngdoc function + * @name calcNewMove + * @methodOf ui.grid.class:gridScrolling + * @description Calculates the next position of the element for a particular axis + * based on the delta. + * @param {number} scrollPos The original position of the element. + * @param {number} delta The amount the pointer moved. + * @param {number} axis The axis being moved. + * @returns {number} The next position of the element. + */ + function calcNewMove(scrollPos, delta, axis) { + var newMove = scrollPos + delta; + + if ( newMove < 0 || newMove > getMaxScroll()[axis] ) { + newMove = newMove < 0 ? 0 : getMaxScroll()[axis]; + } + + return newMove; + } + /** * @ngdoc function * @name move @@ -95,16 +116,8 @@ pointX = point.pageX; pointY = point.pageY; - newX = wrapper[0].scrollLeft + deltaX; - newY = wrapper[0].scrollTop + deltaY; - - if ( newX < 0 || newX > getMaxScroll().x ) { - newX = newX < 0 ? 0 : getMaxScroll().x; - } - - if ( newY < 0 || newY > getMaxScroll().y ) { - newY = newY < 0 ? 0 : getMaxScroll().y; - } + newX = calcNewMove(wrapper[0].scrollLeft, deltaX, 'x'); + newY = calcNewMove(wrapper[0].scrollTop, deltaY, 'y'); if (timestamp - startTime > 300) { startTime = (new Date()).getTime(); @@ -174,6 +187,7 @@ * @name getMaxScroll * @methodOf ui.grid.class:gridScrolling * @description Gets the limit of the scrolling for both the x and y positions. + * @returns {object} An object with the x and y scroll limits. */ function getMaxScroll() { if (!maxScroll) { From 5d4a93cbbe164ab02f0d960099b8194d708a65f3 Mon Sep 17 00:00:00 2001 From: "Portugal, Marcelo" Date: Sun, 4 Dec 2016 23:47:06 -0500 Subject: [PATCH 12/13] refactor(Grid Scrolling): Using more angular. Replacing instances of window and document with and . Also, added annotations and updated constants name. --- src/js/core/constants.js | 4 +- src/js/core/factories/GridScrolling.js | 493 +++++++++++++------------ 2 files changed, 250 insertions(+), 247 deletions(-) diff --git a/src/js/core/constants.js b/src/js/core/constants.js index 7a20489596..917f6bdf7a 100644 --- a/src/js/core/constants.js +++ b/src/js/core/constants.js @@ -194,7 +194,7 @@ /** * @ngdoc object - * @name scrollEvent + * @name scrollType * @propertyOf ui.grid.service:uiGridConstants * @description Used in {@link ui.grid.class:gridScrolling}, * to the type of scroll event currently in progress @@ -205,7 +205,7 @@ * - `uiGridConstants.scrollEvent.MOUSE` - set when mousedown, mousemove or mouseup are triggered * - `uiGridConstants.scrollEvent.POINTER` - set when pointerdown, pointermove or pointerup are triggered */ - scrollEvent: { + scrollType: { NONE: 0, TOUCHABLE: 1, MOUSE: 2, diff --git a/src/js/core/factories/GridScrolling.js b/src/js/core/factories/GridScrolling.js index 64208bc37e..e676f863e7 100644 --- a/src/js/core/factories/GridScrolling.js +++ b/src/js/core/factories/GridScrolling.js @@ -2,296 +2,299 @@ 'use strict'; angular.module('ui.grid') - .factory('gridScrolling', function($window, uiGridConstants, gridUtil) { - var isAnimating; - - /** - * @ngdoc object - * @name initiated - * @propertyOf ui.grid.class:gridScrolling - * @description Keeps track of which type of scrolling event has been initiated - * and sets it to NONE, when no event is being triggered. - */ - gridScrolling.initiated = uiGridConstants.scrollEvent.NONE; - - /** - * @ngdoc function - * @name ui.grid.class:gridScrolling - * @description gridScrolling is a wrapper service that takes over the default scrolling logic in order to - * ensure that grid scrolling works consistently in both the browser and devices, as well as slow machines. - * @param {object} element Element being scrolled - * @param {function} scrollHandler Function that needs to be called when scrolling happens. - */ - function gridScrolling(element, scrollHandler) { - var wrapper = element, pointX, pointY, startTime, startX, startY, maxScroll, - scroller = wrapper[0].children[0], - initType = { - touchstart: uiGridConstants.scrollEvent.TOUCHABLE, - touchmove: uiGridConstants.scrollEvent.TOUCHABLE, - touchend: uiGridConstants.scrollEvent.TOUCHABLE, - - mousedown: uiGridConstants.scrollEvent.MOUSE, - mousemove: uiGridConstants.scrollEvent.MOUSE, - mouseup: uiGridConstants.scrollEvent.MOUSE, - - pointerdown: uiGridConstants.scrollEvent.POINTER, - pointermove: uiGridConstants.scrollEvent.POINTER, - pointerup: uiGridConstants.scrollEvent.POINTER - }; - - if ('onmousedown' in $window) { - wrapper.on('scroll', scrollHandler); - } - - if (gridUtil.isTouchEnabled()) { - wrapper.on('touchstart', start); - wrapper.on('touchmove', move); - wrapper.on('touchcancel', end); - wrapper.on('touchend', end); - document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); - } + .factory('gridScrolling', ['$document', '$window', 'gridUtil', 'uiGridConstants', + function($document, $window, gridUtil, uiGridConstants) { + var isAnimating; /** - * @ngdoc function - * @name start - * @methodOf ui.grid.class:gridScrolling - * @description Gets the current coordinates and time, as well as the target coordinate - * and initializes the scrolling event - * @param {object} event The event object + * @ngdoc object + * @name initiated + * @propertyOf ui.grid.class:gridScrolling + * @description Keeps track of which type of scrolling event has been initiated + * and sets it to NONE, when no event is being triggered. */ - function start(event) { - var point = event.touches ? event.touches[0] : event; - - wrapper.off('scroll', scrollHandler); - - gridScrolling.initiated = initType[event.type]; - - pointX = point.pageX; - pointY = point.pageY; - - startTime = (new Date()).getTime(); - startX = wrapper[0].scrollLeft; - startY = wrapper[0].scrollTop; - isAnimating = false; - } + gridScrolling.initiated = uiGridConstants.scrollType.NONE; /** * @ngdoc function - * @name calcNewMove - * @methodOf ui.grid.class:gridScrolling - * @description Calculates the next position of the element for a particular axis - * based on the delta. - * @param {number} scrollPos The original position of the element. - * @param {number} delta The amount the pointer moved. - * @param {number} axis The axis being moved. - * @returns {number} The next position of the element. + * @name ui.grid.class:gridScrolling + * @description gridScrolling is a wrapper service that takes over the default scrolling logic in order to + * ensure that grid scrolling works consistently in both the browser and devices, as well as slow machines. + * @param {object} element Element being scrolled + * @param {function} scrollHandler Function that needs to be called when scrolling happens. */ - function calcNewMove(scrollPos, delta, axis) { - var newMove = scrollPos + delta; + function gridScrolling(element, scrollHandler) { + var wrapper = element, pointX, pointY, startTime, startX, startY, maxScroll, + scroller = wrapper[0].children[0], + initType = { + touchstart: uiGridConstants.scrollType.TOUCHABLE, + touchmove: uiGridConstants.scrollType.TOUCHABLE, + touchend: uiGridConstants.scrollType.TOUCHABLE, + + mousedown: uiGridConstants.scrollType.MOUSE, + mousemove: uiGridConstants.scrollType.MOUSE, + mouseup: uiGridConstants.scrollType.MOUSE, + + pointerdown: uiGridConstants.scrollType.POINTER, + pointermove: uiGridConstants.scrollType.POINTER, + pointerup: uiGridConstants.scrollType.POINTER + }; - if ( newMove < 0 || newMove > getMaxScroll()[axis] ) { - newMove = newMove < 0 ? 0 : getMaxScroll()[axis]; + if ('onmousedown' in $window) { + wrapper.on('scroll', scrollHandler); } - return newMove; - } - - /** - * @ngdoc function - * @name move - * @methodOf ui.grid.class:gridScrolling - * @description Calculates what the next move should be and starts the scrolling. - * @param {object} event The event object - */ - function move(event) { - if (initType[event.type] !== gridScrolling.initiated) { - return; + if (gridUtil.isTouchEnabled()) { + wrapper.on('touchstart', start); + wrapper.on('touchmove', move); + wrapper.on('touchcancel', end); + wrapper.on('touchend', end); + $document.addEventListener('touchmove', function(e) { + e.preventDefault(); + }, false); } - var newX, newY, timestamp = (new Date()).getTime(), - point = event.touches ? event.touches[0] : event, - deltaX = pointX - point.pageX, - deltaY = pointY - point.pageY; + /** + * @ngdoc function + * @name start + * @methodOf ui.grid.class:gridScrolling + * @description Gets the current coordinates and time, as well as the target coordinate + * and initializes the scrolling event + * @param {object} event The event object + */ + function start(event) { + var point = event.touches ? event.touches[0] : event; + + wrapper.off('scroll', scrollHandler); - pointX = point.pageX; - pointY = point.pageY; + gridScrolling.initiated = initType[event.type]; - newX = calcNewMove(wrapper[0].scrollLeft, deltaX, 'x'); - newY = calcNewMove(wrapper[0].scrollTop, deltaY, 'y'); + pointX = point.pageX; + pointY = point.pageY; - if (timestamp - startTime > 300) { startTime = (new Date()).getTime(); - startX = newX; - startY = newY; + startX = wrapper[0].scrollLeft; + startY = wrapper[0].scrollTop; + isAnimating = false; + } + + /** + * @ngdoc function + * @name calcNewMove + * @methodOf ui.grid.class:gridScrolling + * @description Calculates the next position of the element for a particular axis + * based on the delta. + * @param {number} scrollPos The original position of the element. + * @param {number} delta The amount the pointer moved. + * @param {number} axis The original position. + * @returns {number} The next position of the element. + */ + function calcNewMove(scrollPos, delta, axis) { + var newMove = scrollPos + delta; + + if (newMove < 0 || newMove > getMaxScroll()[axis]) { + newMove = newMove < 0 ? 0 : getMaxScroll()[axis]; + } + + return newMove; + } + + /** + * @ngdoc function + * @name move + * @methodOf ui.grid.class:gridScrolling + * @description Calculates what the next move should be and starts the scrolling. + * @param {object} event The event object + */ + function move(event) { + if (initType[event.type] !== gridScrolling.initiated) { + return; + } + + var newX, newY, timestamp = (new Date()).getTime(), + point = event.touches ? event.touches[0] : event, + deltaX = pointX - point.pageX, + deltaY = pointY - point.pageY; + + pointX = point.pageX; + pointY = point.pageY; + + newX = calcNewMove(wrapper[0].scrollLeft, deltaX, 'x'); + newY = calcNewMove(wrapper[0].scrollTop, deltaY, 'y'); + + if (timestamp - startTime > 300) { + startTime = (new Date()).getTime(); + startX = newX; + startY = newY; + } + + translate(newX, newY, wrapper); + + scrollHandler.call(null, event); + } + + /** + * @ngdoc function + * @name end + * @methodOf ui.grid.class:gridScrolling + * @description Finishes the scrolling animation. + * @param {object} event The event object + */ + function end(event) { + if (initType[event.type] !== gridScrolling.initiated) { + return; + } + + var duration = (new Date()).getTime() - startTime, + momentumX = momentum(wrapper[0].scrollLeft, startX, duration), + momentumY = momentum(wrapper[0].scrollTop, startY, duration), + newX = momentumX.destination, + newY = momentumY.destination, + time = Math.max(momentumX.duration, momentumY.duration); + + animate(newX, newY, time, wrapper, scrollHandler.bind(null, event)); + + gridScrolling.initiated = uiGridConstants.scrollType.NONE; } - translate(newX, newY, wrapper); + /** + * @ngdoc function + * @name momentum + * @methodOf ui.grid.class:gridScrolling + * @description Calculates current momentum of the scrolling based on the current position of the element, + * its initial position and the duration of this movement. + * @param {number} curr The current position of the element + * @param {number} start The original position of the element + * @param {number} time The time it has taken for the element to get to its current position. + * @returns {object} An object with the next position for the element and how long + * that animation should take. + */ + function momentum(curr, start, time) { + curr = Math.abs(curr); + start = Math.abs(start); + + var distance = curr - start, + speed = Math.abs(distance) / time, + deceleration = 0.0007, + destination = curr + (speed * speed) / (2 * deceleration) * (distance >= 0 ? 1 : -1), + duration = speed / deceleration; + + return { + destination: Math.round(destination), + duration: duration + }; + } - scrollHandler.call(null, event); + /** + * @ngdoc function + * @name getMaxScroll + * @methodOf ui.grid.class:gridScrolling + * @description Gets the limit of the scrolling for both the x and y positions. + * @returns {object} An object with the x and y scroll limits. + */ + function getMaxScroll() { + if (!maxScroll) { + maxScroll = { + x: scroller.offsetWidth - wrapper[0].clientWidth, + y: scroller.offsetHeight - wrapper[0].clientHeight + }; + } + return maxScroll; + } } /** * @ngdoc function - * @name end + * @name translate * @methodOf ui.grid.class:gridScrolling - * @description Finishes the scrolling animation. - * @param {object} event The event object + * @description Updates the wrapper's scroll position. + * @param {number} x The horizontal position of the wrapper + * @param {number} y The vertical position of the wrapper + * @param {object} wrapper The wrapper element being updated */ - function end(event) { - if ( initType[event.type] !== gridScrolling.initiated ) { - return; - } - - var duration = (new Date()).getTime() - startTime, - momentumX = momentum(wrapper[0].scrollLeft, startX, duration), - momentumY = momentum(wrapper[0].scrollTop, startY, duration), - newX = momentumX.destination, - newY = momentumY.destination, - time = Math.max(momentumX.duration, momentumY.duration); - - animate(newX, newY, time, wrapper, scrollHandler.bind(null, event)); - - gridScrolling.initiated = uiGridConstants.scrollEvent.NONE; + function translate(x, y, wrapper) { + wrapper[0].scrollLeft = x; + wrapper[0].scrollTop = y; } /** * @ngdoc function - * @name momentum + * @name easeClb * @methodOf ui.grid.class:gridScrolling - * @description Calculates current momentum of the scrolling based on the current position of the element, - * its initial position and the duration of this movement. - * @param {number} curr The current position of the element - * @param {number} start The original position of the element - * @param {number} time The time it has taken for the element to get to its current position. - * @returns {object} An object with the next position for the element and how long - * that animation should take. + * @description Calculates the ease resolution base on the current animation times. + * @param {number} relPoint The time the animation is taking between frames. + * @returns {number} The ideal ease time. */ - function momentum(curr, start, time) { - curr = Math.abs(curr); - start = Math.abs(start); - - var distance = curr - start, - speed = Math.abs(distance)/time, - deceleration = 0.0007, - destination = curr + (speed * speed)/(2 * deceleration)* (distance >= 0 ? 1 : -1), - duration = speed / deceleration; - - return { - destination: Math.round(destination), - duration: duration - }; + function easeClb(relPoint) { + return relPoint * ( 2 - relPoint ); } /** * @ngdoc function - * @name getMaxScroll + * @name calcNewPos * @methodOf ui.grid.class:gridScrolling - * @description Gets the limit of the scrolling for both the x and y positions. - * @returns {object} An object with the x and y scroll limits. + * @description Calculates the new position of the element based on where it started, the animation time + * and where it is ultimately supposed to end up. + * @param {number} destPos The destination. + * @param {number} easeRes The ideal ease time. + * @param {number} startPos The original position. + * @returns {number} The next position of the element. */ - function getMaxScroll() { - if (!maxScroll) { - maxScroll = { - x: scroller.offsetWidth - wrapper[0].clientWidth, - y: scroller.offsetHeight - wrapper[0].clientHeight - }; - } - return maxScroll; + function calcNewPos(destPos, easeRes, startPos) { + return ( destPos - Math.abs(startPos) ) * easeRes + Math.abs(startPos); } - } - - /** - * @ngdoc function - * @name translate - * @methodOf ui.grid.class:gridScrolling - * @description Updates the wrapper's scroll position. - * @param {number} x The horizontal position of the wrapper - * @param {number} y The vertical position of the wrapper - * @param {object} wrapper The wrapper element being updated - */ - function translate(x, y, wrapper) { - wrapper[0].scrollLeft = x; - wrapper[0].scrollTop = y; - } - - /** - * @ngdoc function - * @name easeClb - * @methodOf ui.grid.class:gridScrolling - * @description Calculates the ease resolution base on the current animation times. - * @param {number} relPoint The time the animation is taking between frames. - * @returns {number} The ideal ease time. - */ - function easeClb(relPoint) { - return relPoint * ( 2 - relPoint ); - } - - /** - * @ngdoc function - * @name calcNewPos - * @methodOf ui.grid.class:gridScrolling - * @description Calculates the new position of the element based on where it started, the animation time - * and where it is ultimately supposed to end up. - * @param {number} destPos The destination. - * @param {number} easeRes The ideal ease time. - * @param {number} startPos The original position. - * @returns {number} The next position of the element. - */ - function calcNewPos(destPos, easeRes, startPos) { - return ( destPos - Math.abs(startPos) ) * easeRes + Math.abs(startPos); - } - - /** - * @ngdoc function - * @name animate - * @methodOf ui.grid.class:gridScrolling - * @description Calculates the ease resolution base on the current animation times. - * @param {number} destX The coordinate of the x axis that the scrolling needs to animate to. - * @param {number} destY The coordinate of the y axis that the scrolling needs to animate to. - * @param {number} duration The animation duration - * @param {object} wrapper The wrapper element being updated - * @param {function} callback Function that needs to be called when the animation is done. - */ - function animate(destX, destY, duration, wrapper, callback) { - var startTime = (new Date()).getTime(), - startX = wrapper[0].scrollLeft, - startY = wrapper[0].scrollTop, - destTime = startTime + duration; - - isAnimating = true; - - next(); - - function next() { - var now = (new Date()).getTime(), - relPoint, easeRes, newX, newY; - - if (now >= destTime) { - isAnimating = false; - translate(destX, destY, wrapper); - wrapper.on('scroll', callback); - return; - } - relPoint = (now - startTime) / duration; + /** + * @ngdoc function + * @name animate + * @methodOf ui.grid.class:gridScrolling + * @description Calculates the ease resolution base on the current animation times. + * @param {number} destX The coordinate of the x axis that the scrolling needs to animate to. + * @param {number} destY The coordinate of the y axis that the scrolling needs to animate to. + * @param {number} duration The animation duration + * @param {object} wrapper The wrapper element being updated + * @param {function} callback Function that needs to be called when the animation is done. + */ + function animate(destX, destY, duration, wrapper, callback) { + var startTime = (new Date()).getTime(), + startX = wrapper[0].scrollLeft, + startY = wrapper[0].scrollTop, + destTime = startTime + duration; + + isAnimating = true; + + next(); + + function next() { + var now = (new Date()).getTime(), + relPoint, easeRes, newX, newY; + + if (now >= destTime) { + isAnimating = false; + translate(destX, destY, wrapper); + wrapper.on('scroll', callback); + return; + } + + relPoint = (now - startTime) / duration; - easeRes = easeClb(relPoint); + easeRes = easeClb(relPoint); - newX = calcNewPos(destX, easeRes, startX); - newY = calcNewPos(destY, easeRes, startY); + newX = calcNewPos(destX, easeRes, startX); + newY = calcNewPos(destY, easeRes, startY); - translate(newX, newY, wrapper); + translate(newX, newY, wrapper); - callback.call(); + callback.call(); - if (isAnimating) { - window.requestAnimationFrame(next); - } else { - wrapper.on('scroll', callback); + if (isAnimating) { + $window.requestAnimationFrame(next); + } else { + wrapper.on('scroll', callback); + } } } - } - return gridScrolling; - }); + return gridScrolling; + }]); })(); From 52289fbed648f32b8a444ac680cb3e0dcd38a4b6 Mon Sep 17 00:00:00 2001 From: "Portugal, Marcelo" Date: Mon, 5 Dec 2016 00:02:32 -0500 Subject: [PATCH 13/13] refactor(Grid Scrolling): Reverting earlier change to use and . --- src/js/core/factories/GridScrolling.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/core/factories/GridScrolling.js b/src/js/core/factories/GridScrolling.js index e676f863e7..705b64e02e 100644 --- a/src/js/core/factories/GridScrolling.js +++ b/src/js/core/factories/GridScrolling.js @@ -2,8 +2,8 @@ 'use strict'; angular.module('ui.grid') - .factory('gridScrolling', ['$document', '$window', 'gridUtil', 'uiGridConstants', - function($document, $window, gridUtil, uiGridConstants) { + .factory('gridScrolling', ['$window', 'gridUtil', 'uiGridConstants', + function($window, gridUtil, uiGridConstants) { var isAnimating; /** @@ -49,7 +49,7 @@ wrapper.on('touchmove', move); wrapper.on('touchcancel', end); wrapper.on('touchend', end); - $document.addEventListener('touchmove', function(e) { + document.addEventListener('touchmove', function(e) { e.preventDefault(); }, false); } @@ -288,7 +288,7 @@ callback.call(); if (isAnimating) { - $window.requestAnimationFrame(next); + window.requestAnimationFrame(next); } else { wrapper.on('scroll', callback); }