|
52 | 52 | * @ngdoc object |
53 | 53 | * @name isSelected |
54 | 54 | * @propertyOf ui.grid.selection.api:GridRow |
55 | | - * @description Selected state of row. Should be readonly. Make any changes to selected state using setSelected(). |
| 55 | + * @description Selected state of row. Should be readonly. Make any changes to selected state using setSelected(). |
56 | 56 | * <br/>Defaults to false |
57 | 57 | */ |
58 | 58 |
|
| 59 | + /** |
| 60 | + * @ngdoc object |
| 61 | + * @name isFocused |
| 62 | + * @propertyOf ui.grid.selection.api:GridRow |
| 63 | + * @description Focused state of row. Should be readonly. Make any changes to focused state using setFocused(). |
| 64 | + * <br/>Defaults to false |
| 65 | + */ |
59 | 66 |
|
60 | 67 | /** |
61 | 68 | * @ngdoc function |
62 | 69 | * @name setSelected |
63 | 70 | * @methodOf ui.grid.selection.api:GridRow |
64 | 71 | * @description Sets the isSelected property and updates the selectedCount |
65 | 72 | * Changes to isSelected state should only be made via this function |
66 | | - * @param {bool} selected value to set |
| 73 | + * @param {Boolean} selected value to set |
67 | 74 | */ |
68 | 75 | $delegate.prototype.setSelected = function (selected) { |
69 | 76 | if (selected !== this.isSelected) { |
|
72 | 79 | } |
73 | 80 | }; |
74 | 81 |
|
| 82 | + /** |
| 83 | + * @ngdoc function |
| 84 | + * @name setFocused |
| 85 | + * @methodOf ui.grid.selection.api:GridRow |
| 86 | + * @description Sets the isFocused property |
| 87 | + * Changes to isFocused state should only be made via this function |
| 88 | + * @param {Boolean} val value to set |
| 89 | + */ |
| 90 | + $delegate.prototype.setFocused = function(val) { |
| 91 | + if (val !== this.isFocused) { |
| 92 | + this.grid.selection.focusedRow && (this.grid.selection.focusedRow.isFocused = false); |
| 93 | + this.grid.selection.focusedRow = val ? this : null; |
| 94 | + this.isFocused = val; |
| 95 | + } |
| 96 | + }; |
| 97 | + |
75 | 98 | return $delegate; |
76 | 99 | }]); |
77 | 100 | }]); |
|
84 | 107 | */ |
85 | 108 | module.service('uiGridSelectionService', ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil', |
86 | 109 | function ($q, $templateCache, uiGridSelectionConstants, gridUtil) { |
87 | | - |
88 | 110 | var service = { |
89 | 111 |
|
90 | 112 | initializeGrid: function (grid) { |
|
96 | 118 | * |
97 | 119 | * @description Grid properties and functions added for selection |
98 | 120 | */ |
99 | | - grid.selection = {}; |
100 | | - grid.selection.lastSelectedRow = null; |
101 | | - grid.selection.selectAll = false; |
| 121 | + grid.selection = { |
| 122 | + lastSelectedRow: null, |
| 123 | + /** |
| 124 | + * @ngdoc object |
| 125 | + * @name focusedRow |
| 126 | + * @propertyOf ui.grid.selection.grid:selection |
| 127 | + * @description Focused row. |
| 128 | + */ |
| 129 | + focusedRow: null, |
| 130 | + selectAll: false |
| 131 | + }; |
102 | 132 |
|
103 | 133 |
|
104 | 134 | /** |
|
122 | 152 | var publicApi = { |
123 | 153 | events: { |
124 | 154 | selection: { |
| 155 | + /** |
| 156 | + * @ngdoc event |
| 157 | + * @name rowFocusChanged |
| 158 | + * @eventOf ui.grid.selection.api:PublicApi |
| 159 | + * @description is raised after the row.isFocused state is changed |
| 160 | + * @param {object} scope the scope associated with the grid |
| 161 | + * @param {GridRow} row the row that was focused/unfocused |
| 162 | + * @param {Event} evt object if raised from an event |
| 163 | + */ |
| 164 | + rowFocusChanged: function (scope, row, evt) {}, |
125 | 165 | /** |
126 | 166 | * @ngdoc event |
127 | 167 | * @name rowSelectionChanged |
|
414 | 454 | * @name enableFullRowSelection |
415 | 455 | * @propertyOf ui.grid.selection.api:GridOptions |
416 | 456 | * @description Enable selection by clicking anywhere on the row. Defaults to |
417 | | - * false if `enableRowHeaderSelection` is true, otherwise defaults to false. |
| 457 | + * false if `enableRowHeaderSelection` is true, otherwise defaults to true. |
418 | 458 | */ |
419 | 459 | if (typeof (gridOptions.enableFullRowSelection) === 'undefined') { |
420 | 460 | gridOptions.enableFullRowSelection = !gridOptions.enableRowHeaderSelection; |
421 | 461 | } |
| 462 | + /** |
| 463 | + * @ngdoc object |
| 464 | + * @name enableFocusRowOnRowHeaderClick |
| 465 | + * @propertyOf ui.grid.selection.api:GridOptions |
| 466 | + * @description Enable focuse row by clicking on the row header. Defaults to |
| 467 | + * true if `enableRowHeaderSelection` is true, otherwise defaults to false. |
| 468 | + */ |
| 469 | + gridOptions.enableFocusRowOnRowHeaderClick = (gridOptions.enableFocusRowOnRowHeaderClick !== false) |
| 470 | + || !gridOptions.enableRowHeaderSelection; |
| 471 | + /** |
| 472 | + * @ngdoc object |
| 473 | + * @name enableSelectRowOnFocus |
| 474 | + * @propertyOf ui.grid.selection.api:GridOptions |
| 475 | + * @description Enable focuse row by clicking on the row anywhere. Defaults true. |
| 476 | + */ |
| 477 | + gridOptions.enableSelectRowOnFocus = (gridOptions.enableSelectRowOnFocus !== false); |
422 | 478 | /** |
423 | 479 | * @ngdoc object |
424 | 480 | * @name enableSelectAll |
|
446 | 502 | * <br/>Defaults to 30px |
447 | 503 | */ |
448 | 504 | gridOptions.selectionRowHeaderWidth = angular.isDefined(gridOptions.selectionRowHeaderWidth) ? gridOptions.selectionRowHeaderWidth : 30; |
449 | | - |
450 | 505 | /** |
451 | 506 | * @ngdoc object |
452 | 507 | * @name enableFooterTotalSelected |
|
456 | 511 | * <br/>GridOptions.showGridFooter must also be set to true. |
457 | 512 | */ |
458 | 513 | gridOptions.enableFooterTotalSelected = gridOptions.enableFooterTotalSelected !== false; |
459 | | - |
460 | 514 | /** |
461 | 515 | * @ngdoc object |
462 | 516 | * @name isRowSelectable |
463 | 517 | * @propertyOf ui.grid.selection.api:GridOptions |
464 | 518 | * @description Makes it possible to specify a method that evaluates for each row and sets its "enableSelection" property. |
465 | 519 | */ |
466 | | - |
467 | 520 | gridOptions.isRowSelectable = angular.isDefined(gridOptions.isRowSelectable) ? gridOptions.isRowSelectable : angular.noop; |
468 | 521 | }, |
469 | | - |
| 522 | + |
470 | 523 | /** |
471 | 524 | * @ngdoc function |
472 | 525 | * @name toggleRowSelection |
|
479 | 532 | * @param {bool} noUnselect if true then rows cannot be unselected |
480 | 533 | */ |
481 | 534 | toggleRowSelection: function (grid, row, evt, multiSelect, noUnselect) { |
482 | | - var selected = row.isSelected, |
483 | | - selectedRows; |
484 | | - |
485 | | - if (row.enableSelection === false) { |
| 535 | + if ( row.enableSelection === false ){ |
486 | 536 | return; |
487 | 537 | } |
488 | 538 |
|
489 | | - if (!multiSelect && !selected) { |
490 | | - service.clearSelectedRows(grid, evt); |
491 | | - } else if (!multiSelect && selected) { |
492 | | - selectedRows = service.getSelectedRows(grid); |
493 | | - if (selectedRows.length > 1) { |
494 | | - selected = false; // Enable reselect of the row |
| 539 | + var selected = row.isSelected, |
| 540 | + selectedRows; |
| 541 | + |
| 542 | + if (!multiSelect) { |
| 543 | + if (!selected) { |
495 | 544 | service.clearSelectedRows(grid, evt); |
| 545 | + } else { |
| 546 | + selectedRows = service.getSelectedRows(grid); |
| 547 | + if (selectedRows.length > 1) { |
| 548 | + selected = false; // Enable reselect of the row |
| 549 | + service.clearSelectedRows(grid, evt); |
| 550 | + } |
496 | 551 | } |
497 | 552 | } |
498 | 553 |
|
|
726 | 781 | $scope.selectButtonKeyDown = selectButtonKeyDown; |
727 | 782 |
|
728 | 783 | // On IE, prevent mousedowns on the select button from starting a selection. |
729 | | - // If this is not done and you shift+click on another row, the browser will select a big chunk of text |
| 784 | + // If this is not done and you shift+click on another row, the browser will select a big chunk of text |
730 | 785 | if (gridUtil.detectBrowser() === 'ie') { |
731 | 786 | $elm.on('mousedown', selectButtonMouseDown); |
732 | 787 | } |
|
745 | 800 | uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect); |
746 | 801 | } |
747 | 802 | else if (evt.ctrlKey || evt.metaKey) { |
748 | | - uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect); |
| 803 | + uiGridSelectionService.toggleRowSelection(self, row, evt, |
| 804 | + self.options.multiSelect, self.options.noUnselect); |
749 | 805 | } |
750 | 806 | else if (row.groupHeader) { |
751 | 807 | uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect); |
|
754 | 810 | } |
755 | 811 | } |
756 | 812 | else { |
757 | | - uiGridSelectionService.toggleRowSelection(self, row, evt, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect); |
| 813 | + uiGridSelectionService.toggleRowSelection(self, row, evt, |
| 814 | + (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect); |
758 | 815 | } |
| 816 | + self.options.enableFocusRowOnRowHeaderClick && row.setFocused(!row.isFocused) && self.api.selection.raise.rowFocusChanged(row, evt); |
759 | 817 | } |
760 | 818 |
|
761 | 819 | function selectButtonMouseDown(evt) { |
|
820 | 878 | priority: -200, // run after default directive |
821 | 879 | scope: false, |
822 | 880 | compile: function ($elm, $attrs) { |
823 | | - var rowRepeatDiv = angular.element($elm[0].querySelector('.ui-grid-canvas:not(.ui-grid-empty-base-layer-container)').children[0]); |
| 881 | + var rowRepeatDiv = angular.element($elm[0].querySelector('.ui-grid-canvas:not(.ui-grid-empty-base-layer-container)').children[0]), |
| 882 | + newNgClass = "'ui-grid-row-selected': row.isSelected, 'ui-grid-row-focused': row.isFocused}", |
| 883 | + existingNgClass = rowRepeatDiv.attr('ng-class'); |
824 | 884 |
|
825 | | - var existingNgClass = rowRepeatDiv.attr("ng-class"); |
826 | | - var newNgClass = ''; |
827 | 885 | if (existingNgClass) { |
828 | | - newNgClass = existingNgClass.slice(0, -1) + ",'ui-grid-row-selected': row.isSelected}"; |
| 886 | + newNgClass = existingNgClass.slice(0, -1) + ',' + newNgClass; |
829 | 887 | } else { |
830 | | - newNgClass = "{'ui-grid-row-selected': row.isSelected}"; |
| 888 | + newNgClass = '{' + newNgClass; |
831 | 889 | } |
832 | | - rowRepeatDiv.attr("ng-class", newNgClass); |
| 890 | + rowRepeatDiv.attr('ng-class', newNgClass); |
833 | 891 |
|
834 | 892 | return { |
835 | | - pre: function ($scope, $elm, $attrs, controllers) { |
836 | | - |
837 | | - }, |
838 | | - post: function ($scope, $elm, $attrs, controllers) { |
839 | | - } |
| 893 | + pre: function ($scope, $elm, $attrs, controllers) {}, |
| 894 | + post: function ($scope, $elm, $attrs, controllers) {} |
840 | 895 | }; |
841 | 896 | } |
842 | 897 | }; |
|
859 | 914 | require: '?^uiGrid', |
860 | 915 | scope: false, |
861 | 916 | link: function ($scope, $elm, $attrs, uiGridCtrl) { |
862 | | - |
863 | | - var touchStartTime = 0; |
864 | | - var touchTimeout = 300; |
| 917 | + var touchStartTime = 0, |
| 918 | + touchTimeout = 300; |
865 | 919 |
|
866 | 920 | // Bind to keydown events in the render container |
867 | 921 | if (uiGridCtrl.grid.api.cellNav) { |
868 | | - |
869 | 922 | uiGridCtrl.grid.api.cellNav.on.viewPortKeyDown($scope, function (evt, rowCol) { |
870 | 923 | if (rowCol === null || |
871 | 924 | rowCol.row !== $scope.row || |
872 | 925 | rowCol.col !== $scope.col) { |
873 | 926 | return; |
874 | 927 | } |
875 | 928 |
|
876 | | - if (evt.keyCode === 32 && $scope.col.colDef.name === "selectionRowHeaderCol") { |
| 929 | + if (evt.keyCode === uiGridConstants.keymap.SPACE && $scope.col.colDef.name === 'selectionRowHeaderCol') { |
877 | 930 | evt.preventDefault(); |
878 | | - uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect); |
| 931 | + uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, |
| 932 | + ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), |
| 933 | + $scope.grid.options.noUnselect); |
879 | 934 | $scope.$apply(); |
880 | 935 | } |
881 | 936 |
|
|
903 | 958 | uiGridSelectionService.shiftSelect($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect); |
904 | 959 | } |
905 | 960 | else if (evt.ctrlKey || evt.metaKey) { |
906 | | - uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, $scope.grid.options.multiSelect, $scope.grid.options.noUnselect); |
| 961 | + uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, |
| 962 | + $scope.grid.options.multiSelect, $scope.grid.options.noUnselect); |
907 | 963 | } |
908 | | - else { |
909 | | - uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, ($scope.grid.options.multiSelect && !$scope.grid.options.modifierKeysToMultiSelect), $scope.grid.options.noUnselect); |
| 964 | + else if ($scope.grid.options.enableSelectRowOnFocus) { |
| 965 | + uiGridSelectionService.toggleRowSelection($scope.grid, $scope.row, evt, |
| 966 | + false, $scope.grid.options.noUnselect); |
910 | 967 | } |
| 968 | + $scope.row.setFocused(!$scope.row.isFocused); |
| 969 | + $scope.grid.api.selection.raise.rowFocusChanged($scope.row, evt); |
911 | 970 | $scope.$apply(); |
912 | 971 |
|
913 | 972 | // don't re-enable the touchend handler for a little while - some devices generate both, and it will |
914 | 973 | // take a little while to move your hand from the mouse to the screen if you have both modes of input |
915 | | - $timeout(function () { |
| 974 | + window.setTimeout(function () { |
916 | 975 | $elm.on('touchend', touchEnd); |
917 | 976 | }, touchTimeout); |
918 | 977 | }; |
919 | 978 |
|
920 | | - var touchStart = function (evt) { |
| 979 | + var touchStart = function () { |
921 | 980 | touchStartTime = (new Date()).getTime(); |
922 | 981 |
|
923 | 982 | // if we get a touch event, then stop listening for click |
|
935 | 994 |
|
936 | 995 | // don't re-enable the click handler for a little while - some devices generate both, and it will |
937 | 996 | // take a little while to move your hand from the screen to the mouse if you have both modes of input |
938 | | - $timeout(function () { |
| 997 | + window.setTimeout(function () { |
939 | 998 | $elm.on('click', selectCells); |
940 | 999 | }, touchTimeout); |
941 | 1000 | }; |
|
951 | 1010 | } |
952 | 1011 | } |
953 | 1012 |
|
954 | | - function deregisterRowSelectionEvents() { |
| 1013 | + function unregisterRowSelectionEvents() { |
955 | 1014 | if ($scope.registered) { |
956 | 1015 | $elm.removeClass('ui-grid-disable-selection'); |
957 | | - |
958 | 1016 | $elm.off('touchstart', touchStart); |
959 | 1017 | $elm.off('touchend', touchEnd); |
960 | 1018 | $elm.off('click', selectCells); |
|
964 | 1022 | } |
965 | 1023 |
|
966 | 1024 | registerRowSelectionEvents(); |
| 1025 | + |
967 | 1026 | // register a dataChange callback so that we can change the selection configuration dynamically |
968 | 1027 | // if the user changes the options |
969 | | - var dataChangeDereg = $scope.grid.registerDataChangeCallback(function () { |
| 1028 | + var dataChangeUnreg = $scope.grid.registerDataChangeCallback(function () { |
970 | 1029 | if ($scope.grid.options.enableRowSelection && $scope.grid.options.enableFullRowSelection && |
971 | 1030 | !$scope.registered) { |
972 | 1031 | registerRowSelectionEvents(); |
973 | 1032 | } else if ((!$scope.grid.options.enableRowSelection || !$scope.grid.options.enableFullRowSelection) && |
974 | 1033 | $scope.registered) { |
975 | | - deregisterRowSelectionEvents(); |
| 1034 | + unregisterRowSelectionEvents(); |
976 | 1035 | } |
977 | 1036 | }, [uiGridConstants.dataChange.OPTIONS]); |
978 | 1037 |
|
979 | | - $elm.on('$destroy', dataChangeDereg); |
| 1038 | + $elm.on('$destroy', dataChangeUnreg); |
980 | 1039 | } |
981 | 1040 | }; |
982 | 1041 | }]); |
|
1014 | 1073 | } |
1015 | 1074 | }; |
1016 | 1075 | }]); |
1017 | | - |
1018 | 1076 | })(); |
0 commit comments