Skip to content

Commit d10464e

Browse files
author
Dana Greenberg
committed
Removed the X and Close on menu, and implemented close-on-ESC and cyclical tabbing
codacy recommended code improvements only grab menu items that are visible
1 parent 83af4a2 commit d10464e

File tree

4 files changed

+78
-43
lines changed

4 files changed

+78
-43
lines changed

src/js/core/directives/ui-grid-column-menu.js

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function ( i18nService, uiGridConstants, gridUtil ) {
4848
*
4949
*/
5050
setColMenuItemWatch: function ( $scope ){
51-
var deregFunction = $scope.$watch('col.menuItems', function (n, o) {
51+
var deregFunction = $scope.$watch('col.menuItems', function (n) {
5252
if (typeof(n) !== 'undefined' && n && angular.isArray(n)) {
5353
n.forEach(function (item) {
5454
if (typeof(item.context) === 'undefined' || !item.context) {
@@ -213,16 +213,6 @@ function ( i18nService, uiGridConstants, gridUtil ) {
213213
$event.stopPropagation();
214214
$scope.hideColumn();
215215
}
216-
},
217-
{
218-
title: i18nService.getSafeText('columnMenu.close'),
219-
screenReaderOnly: true,
220-
shown: function(){
221-
return true;
222-
},
223-
action: function($event){
224-
$event.stopPropagation();
225-
}
226216
}
227217
];
228218
},
@@ -275,8 +265,6 @@ function ( i18nService, uiGridConstants, gridUtil ) {
275265
*/
276266
repositionMenu: function( $scope, column, positionData, $elm, $columnElement ) {
277267
var menu = $elm[0].querySelectorAll('.ui-grid-menu');
278-
var containerId = column.renderContainer ? column.renderContainer : 'body';
279-
var renderContainer = column.grid.renderContainers[containerId];
280268

281269
// It's possible that the render container of the column we're attaching to is
282270
// offset from the grid (i.e. pinned containers), we need to get the difference in the offsetLeft
@@ -379,6 +367,7 @@ function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService, $documen
379367
$scope.colElement = $columnElement;
380368
$scope.colElementPosition = colElementPosition;
381369
$scope.$broadcast('show-menu', { originalEvent: event });
370+
382371
}
383372
};
384373

@@ -421,6 +410,8 @@ function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService, $documen
421410
$scope.$on('menu-shown', function() {
422411
$timeout( function() {
423412
uiGridColumnMenuService.repositionMenu( $scope, $scope.col, $scope.colElementPosition, $elm, $scope.colElement );
413+
//Focus on the first item
414+
gridUtil.focus.bySelector($document, '.ui-grid-menu-items .ui-grid-menu-item', true);
424415
delete $scope.colElementPosition;
425416
delete $scope.columnElement;
426417
}, 200);
@@ -516,7 +507,7 @@ function ($timeout, gridUtil, uiGridConstants, uiGridColumnMenuService, $documen
516507
controller: ['$scope', function ($scope) {
517508
var self = this;
518509

519-
$scope.$watch('menuItems', function (n, o) {
510+
$scope.$watch('menuItems', function (n) {
520511
self.menuItems = n;
521512
});
522513
}]

src/js/core/directives/ui-grid-menu.js

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, i18
4343
templateUrl: 'ui-grid/uiGridMenu',
4444
replace: false,
4545
link: function ($scope, $elm, $attrs, uiGridCtrl) {
46-
var menuMid;
47-
var $animate;
4846
var gridMenuMaxHeight;
4947

5048
$scope.dynamicStyles = '';
@@ -99,17 +97,22 @@ function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, i18
9997

10098
// Turn off an existing document click handler
10199
angular.element(document).off('click touchstart', applyHideMenu);
100+
$elm.off('keyup', checkKeyUp);
101+
$elm.off('keydown', checkKeyDown);
102102

103103
// Turn on the document click handler, but in a timeout so it doesn't apply to THIS click if there is one
104104
$timeout(function() {
105105
angular.element(document).on(docEventType, applyHideMenu);
106+
$elm.on('keyup', checkKeyUp);
107+
$elm.on('keydown', checkKeyDown);
108+
106109
});
107110
//automatically set the focus to the first button element in the now open menu.
108111
gridUtil.focus.bySelector($elm, 'button[type=button]', true);
109112
};
110113

111114

112-
$scope.hideMenu = function(event, args) {
115+
$scope.hideMenu = function(event) {
113116
if ( $scope.shown ){
114117
/*
115118
* In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
@@ -129,6 +132,8 @@ function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, i18
129132
}
130133

131134
angular.element(document).off('click touchstart', applyHideMenu);
135+
$elm.off('keyup', checkKeyUp);
136+
$elm.off('keydown', checkKeyDown);
132137
};
133138

134139
$scope.$on('hide-menu', function (event, args) {
@@ -149,6 +154,34 @@ function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, i18
149154
}
150155
};
151156

157+
// close menu on ESC and keep tab cyclical
158+
var checkKeyUp = function(event) {
159+
if (event.keyCode === 27) {
160+
$scope.hideMenu();
161+
}
162+
};
163+
164+
var checkKeyDown = function(event) {
165+
var setFocus = function(elm) {
166+
elm.focus();
167+
event.preventDefault();
168+
return false;
169+
};
170+
if (event.keyCode === 9) {
171+
var firstMenuItem, lastMenuItem;
172+
var menuItemButtons = $elm[0].querySelectorAll('button:not(.ng-hide)');
173+
if (menuItemButtons.length > 0) {
174+
firstMenuItem = menuItemButtons[0];
175+
lastMenuItem = menuItemButtons[menuItemButtons.length - 1];
176+
if (event.target === lastMenuItem && !event.shiftKey) {
177+
setFocus(firstMenuItem);
178+
} else if (event.target === firstMenuItem && event.shiftKey) {
179+
setFocus(lastMenuItem);
180+
}
181+
}
182+
}
183+
};
184+
152185
if (typeof($scope.autoHide) === 'undefined' || $scope.autoHide === undefined) {
153186
$scope.autoHide = true;
154187
}
@@ -171,12 +204,7 @@ function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, i18
171204
}
172205

173206
$scope.$on('$destroy', $scope.$on(uiGridConstants.events.ITEM_DRAGGING, applyHideMenu ));
174-
},
175-
176-
177-
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
178-
var self = this;
179-
}]
207+
}
180208
};
181209

182210
return uiGridMenu;
@@ -196,15 +224,12 @@ function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, i18
196224
leaveOpen: '=',
197225
screenReaderOnly: '='
198226
},
199-
require: ['?^uiGrid', '^uiGridMenu'],
227+
require: ['?^uiGrid'],
200228
templateUrl: 'ui-grid/uiGridMenuItem',
201229
replace: false,
202-
compile: function($elm, $attrs) {
230+
compile: function() {
203231
return {
204-
pre: function ($scope, $elm, $attrs, controllers) {
205-
var uiGridCtrl = controllers[0],
206-
uiGridMenuCtrl = controllers[1];
207-
232+
pre: function ($scope, $elm) {
208233
if ($scope.templateUrl) {
209234
gridUtil.getTemplate($scope.templateUrl)
210235
.then(function (contents) {
@@ -216,8 +241,7 @@ function ($compile, $timeout, $window, $document, gridUtil, uiGridConstants, i18
216241
}
217242
},
218243
post: function ($scope, $elm, $attrs, controllers) {
219-
var uiGridCtrl = controllers[0],
220-
uiGridMenuCtrl = controllers[1];
244+
var uiGridCtrl = controllers[0];
221245

222246
// TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
223247
// if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {

src/templates/ui-grid/uiGridMenu.html

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,6 @@
99
ng-show="shownMid">
1010
<div
1111
class="ui-grid-menu-inner">
12-
<button
13-
type="button"
14-
ng-focus="focus=true"
15-
ng-blur="focus=false"
16-
class="ui-grid-menu-close-button"
17-
ng-class="{'ui-grid-sr-only': (!focus)}">
18-
<i
19-
class="ui-grid-icon-cancel"
20-
ui-grid-one-bind-aria-label="i18n.close">
21-
</i>
22-
</button>
2312
<ul
2413
role="menu"
2514
class="ui-grid-menu-items">

test/unit/core/directives/ui-grid-menu.spec.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,35 @@ describe('ui-grid-menu', function() {
231231
expect(item.hasClass('ng-hide')).toBe(false);
232232
});
233233
});
234-
});
234+
235+
236+
describe('keyUp and keyDown actions', function() {
237+
var timeout, menuItemButtons;
238+
beforeEach( function() {
239+
inject(function ($timeout) {
240+
timeout = $timeout;
241+
});
242+
$scope.$broadcast('show-menu');
243+
$scope.$digest();
244+
timeout.flush();
245+
});
246+
247+
it('should focus on the first menu item after tabbing from the last menu item', function() {
248+
menuItemButtons = menu.find('button');
249+
var e = $.Event("keydown");
250+
e.keyCode = 9;
251+
spyOn(menuItemButtons[0],'focus');
252+
//mock has 4 items, last one his hidden
253+
$(menuItemButtons[2]).trigger(e);
254+
expect(menuItemButtons[0].focus).toHaveBeenCalled();
255+
});
256+
257+
it('should call hideMenu if ESC is pressed', function() {
258+
spyOn(isolateScope, 'hideMenu');
259+
var e = $.Event("keyup");
260+
e.keyCode = 27;
261+
$(menu).trigger(e);
262+
expect(isolateScope.hideMenu).toHaveBeenCalled();
263+
});
264+
});
265+
});

0 commit comments

Comments
 (0)