Merge pull request #2078 from umbraco/temp-U4-10107
fixes: U4-10107 Weird UI bugs with filter dropdowns
This commit is contained in:
@@ -155,7 +155,6 @@ angular.module('umbraco.directives')
|
||||
var els = ["INPUT","A","BUTTON"];
|
||||
if(els.indexOf(el) >= 0){return;}
|
||||
|
||||
// ignore children of links and buttons
|
||||
// ignore clicks on new overlay
|
||||
var parents = $(event.target).parents("a,button,.umb-overlay");
|
||||
if(parents.length > 0){
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbDropdown
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in versions 7.7.0</b>: Use this component to render a dropdown menu.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="MyDropdown.Controller as vm">
|
||||
|
||||
<div style="position: relative;">
|
||||
|
||||
<umb-button
|
||||
type="button"
|
||||
label="Toggle dropdown"
|
||||
action="vm.toggle()">
|
||||
</umb-button>
|
||||
|
||||
<umb-dropdown ng-if="vm.dropdownOpen" on-close="vm.close()" umb-keyboard-list>
|
||||
<umb-dropdown-item
|
||||
ng-repeat="item in vm.items">
|
||||
<a href="" ng-click="vm.select(item)">{{ item.name }}</a>
|
||||
</umb-dropdown-item>
|
||||
</umb-dropdown>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function Controller() {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.dropdownOpen = false;
|
||||
vm.items = [
|
||||
{ "name": "Item 1" },
|
||||
{ "name": "Item 2" },
|
||||
{ "name": "Item 3" }
|
||||
];
|
||||
|
||||
vm.toggle = toggle;
|
||||
vm.close = close;
|
||||
vm.select = select;
|
||||
|
||||
function toggle() {
|
||||
vm.dropdownOpen = true;
|
||||
}
|
||||
|
||||
function close() {
|
||||
vm.dropdownOpen = false;
|
||||
}
|
||||
|
||||
function select(item) {
|
||||
// Do your magic here
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("MyDropdown.Controller", Controller);
|
||||
})();
|
||||
</pre>
|
||||
|
||||
<h3>Use in combination with</h3>
|
||||
<ul>
|
||||
<li>{@link umbraco.directives.directive:umbDropdownItem umbDropdownItem}</li>
|
||||
<li>{@link umbraco.directives.directive:umbKeyboardList umbKeyboardList}</li>
|
||||
</ul>
|
||||
|
||||
@param {callback} onClose Callback when the dropdown menu closes. When you click outside or press esc.
|
||||
|
||||
**/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function umbDropdown($document) {
|
||||
|
||||
function link(scope, element, attr, ctrl) {
|
||||
|
||||
scope.close = function() {
|
||||
if (scope.onClose) {
|
||||
scope.onClose();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle keydown events
|
||||
function keydown(event) {
|
||||
// press escape
|
||||
if(event.keyCode === 27) {
|
||||
scope.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
// Stop to listen typing.
|
||||
function stopListening() {
|
||||
$document.off('keydown', keydown);
|
||||
}
|
||||
|
||||
// Start listening to key typing.
|
||||
$document.on('keydown', keydown);
|
||||
|
||||
// Stop listening when scope is destroyed.
|
||||
scope.$on('$destroy', stopListening);
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: true,
|
||||
templateUrl: 'views/components/umb-dropdown.html',
|
||||
scope: {
|
||||
onClose: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbDropdown', umbDropdown);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbDropdownItem
|
||||
@restrict E
|
||||
|
||||
@description
|
||||
<b>Added in versions 7.7.0</b>: Use this directive to construct a dropdown item. See documentation for {@link umbraco.directives.directive:umbDropdown umbDropdown}.
|
||||
|
||||
**/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function umbDropdownItem() {
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: true,
|
||||
templateUrl: 'views/components/umb-dropdown-item.html',
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbDropdownItem', umbDropdownItem);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbKeyboardList
|
||||
@restrict E
|
||||
|
||||
@description
|
||||
<b>Added in versions 7.7.0</b>: Use this directive to add arrow up and down keyboard shortcuts to a list. Use this together with the {@link umbraco.directives.directive:umbDropdown umbDropdown} component to make easy accessible dropdown menus.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div>
|
||||
<ul umb-keyboard-list>
|
||||
<li><a href="">Item 1</a></li>
|
||||
<li><a href="">Item 2</a></li>
|
||||
<li><a href="">Item 3</a></li>
|
||||
<li><a href="">Item 4</a></li>
|
||||
<li><a href="">Item 5</a></li>
|
||||
<li><a href="">Item 6</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Use in combination with</h3>
|
||||
<ul>
|
||||
<li>{@link umbraco.directives.directive:umbDropdown umbDropdown}</li>
|
||||
</ul>
|
||||
|
||||
**/
|
||||
|
||||
angular.module('umbraco.directives')
|
||||
.directive('umbKeyboardList', ['$document', '$timeout', function ($document, $timeout) {
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function (scope, element, attr) {
|
||||
|
||||
var listItems = [];
|
||||
var currentIndex = 0;
|
||||
var focusSet = false;
|
||||
|
||||
$timeout(function(){
|
||||
// get list of all links in the list
|
||||
listItems = element.find("li a");
|
||||
});
|
||||
|
||||
// Handle keydown events
|
||||
function keydown(event) {
|
||||
$timeout(function(){
|
||||
checkFocus();
|
||||
// arrow down
|
||||
if (event.keyCode === 40) {
|
||||
arrowDown();
|
||||
}
|
||||
// arrow up
|
||||
if (event.keyCode === 38) {
|
||||
arrowUp();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkFocus() {
|
||||
var found = false;
|
||||
|
||||
// check if any element has focus
|
||||
angular.forEach(listItems, function (item, index) {
|
||||
if ($(item).is(":focus")) {
|
||||
// if an element already has focus set the
|
||||
// currentIndex so we navigate from that element
|
||||
currentIndex = index;
|
||||
focusSet = true;
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
|
||||
// If we don't find an element with focus we reset the currentIndex and the focusSet flag
|
||||
// we do this because you can have navigated away from the list with tab and we want to reset it if you navigate back
|
||||
if (!found) {
|
||||
currentIndex = 0;
|
||||
focusSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
function arrowDown() {
|
||||
if (currentIndex < listItems.length - 1) {
|
||||
// only bump the current index if the focus is already
|
||||
// set else we just want to focus the first element
|
||||
if (focusSet) {
|
||||
currentIndex++;
|
||||
}
|
||||
listItems[currentIndex].focus();
|
||||
focusSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
function arrowUp() {
|
||||
if (currentIndex > 0) {
|
||||
currentIndex--;
|
||||
listItems[currentIndex].focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Stop to listen typing.
|
||||
function stopListening() {
|
||||
$document.off('keydown', keydown);
|
||||
}
|
||||
|
||||
// Start listening to key typing.
|
||||
$document.on('keydown', keydown);
|
||||
|
||||
// Stop listening when scope is destroyed.
|
||||
scope.$on('$destroy', stopListening);
|
||||
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -0,0 +1 @@
|
||||
<li ng-transclude></li>
|
||||
@@ -0,0 +1 @@
|
||||
<ul class="dropdown-menu db" on-outside-click="close()" ng-transclude></ul>
|
||||
@@ -68,6 +68,7 @@
|
||||
}
|
||||
];
|
||||
|
||||
vm.toggleFilter = toggleFilter;
|
||||
vm.setUsersViewState = setUsersViewState;
|
||||
vm.selectLayout = selectLayout;
|
||||
vm.selectUser = selectUser;
|
||||
@@ -117,6 +118,28 @@
|
||||
return found ? found.label : sortKey;
|
||||
}
|
||||
|
||||
function toggleFilter(type) {
|
||||
// hack: on-outside-click prevents us from closing the dropdown when clicking on another link
|
||||
// so I had to do this manually
|
||||
switch (type) {
|
||||
case "state":
|
||||
vm.page.showStatusFilter = !vm.page.showStatusFilter;
|
||||
vm.page.showGroupFilter = false;
|
||||
vm.page.showOrderByFilter = false;
|
||||
break;
|
||||
case "group":
|
||||
vm.page.showGroupFilter = !vm.page.showGroupFilter;
|
||||
vm.page.showStatusFilter = false;
|
||||
vm.page.showOrderByFilter = false;
|
||||
break;
|
||||
case "orderBy":
|
||||
vm.page.showOrderByFilter = !vm.page.showOrderByFilter;
|
||||
vm.page.showStatusFilter = false;
|
||||
vm.page.showGroupFilter = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function setUsersViewState(state) {
|
||||
|
||||
if (state === "createUser") {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<div ng-controller="Umbraco.Editors.Users.UsersController as vm" class="clearfix">
|
||||
|
||||
|
||||
|
||||
<umb-load-indicator ng-show="vm.loading"></umb-load-indicator>
|
||||
|
||||
<!-- Users Overview -->
|
||||
@@ -102,51 +100,51 @@
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
|
||||
<!-- State filter -->
|
||||
<div class="dropdown pull-right" ng-if="vm.userStatesFilter.length > 0">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" ng-click="vm.showStatusFilter = !vm.showStatusFilter">
|
||||
<div style="position: relative;" ng-if="vm.userStatesFilter.length > 0">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" ng-click="vm.toggleFilter('state')">
|
||||
<span>Status:</span>
|
||||
<span class="bold truncate dib" style="margin-left: 5px; margin-right: 3px; max-width: 150px;">{{ vm.getFilterName(vm.userStatesFilter) }}</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul ng-if="vm.showStatusFilter" on-outside-click="vm.showStatusFilter = false;" class="dropdown-menu db" role="menu" aria-labelledby="dropdownMenu">
|
||||
<li ng-repeat="userState in vm.userStatesFilter" style="padding: 5px 10px;">
|
||||
<umb-dropdown class="pull-right" ng-if="vm.page.showStatusFilter" on-close="vm.page.showStatusFilter = false;">
|
||||
<umb-dropdown-item ng-repeat="userState in vm.userStatesFilter | filter:{ count: '!0', key: '!All'}" style="padding: 8px 20px 8px 16px;">
|
||||
<div class="flex items-center">
|
||||
<input style="margin-right: 7px; margin-top: 2px;" type="checkbox" ng-model="userState.selected" ng-change="vm.setUserStatesFilter(userState)" />
|
||||
{{ userState.name }} ({{userState.count}})
|
||||
<input id="state-{{$index}}" type="checkbox" ng-model="userState.selected" ng-change="vm.setUserStatesFilter(userState)" style="margin-right: 10px; margin-top: -3px;" />
|
||||
<label for="state-{{$index}}">{{ userState.name }} ({{userState.count}})</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</umb-dropdown-item>
|
||||
</umb-dropdown>
|
||||
</div>
|
||||
|
||||
<!-- Groups filter -->
|
||||
<div class="dropdown pull-right">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" ng-click="vm.showGroupFilter = !vm.showGroupFilter">
|
||||
<div style="position: relative;">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" ng-click="vm.toggleFilter('group')">
|
||||
<span><localize key="general_groups"></localize>:</span>
|
||||
<span class="bold truncate dib" style="margin-left: 5px; margin-right: 3px; max-width: 150px;">{{ vm.getFilterName(vm.userGroups) }}</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul ng-if="vm.showGroupFilter" on-outside-click="vm.showGroupFilter = false;" class="dropdown-menu db" role="menu" aria-labelledby="dropdownMenu">
|
||||
<li ng-repeat="userGroup in vm.userGroups" style="padding: 5px 10px;">
|
||||
<umb-dropdown class="pull-right" ng-if="vm.page.showGroupFilter" on-close="vm.page.showGroupFilter = false;">
|
||||
<umb-dropdown-item ng-repeat="userGroup in vm.userGroups" style="padding: 8px 20px 8px 16px;">
|
||||
<div class="flex items-center">
|
||||
<input style="margin-right: 7px; margin-top: 2px;" type="checkbox" ng-model="userGroup.selected" ng-change="vm.setUserGroupFilter(userGroup)" />
|
||||
{{ userGroup.name }}
|
||||
<input id="group-{{$index}}" type="checkbox" ng-model="userGroup.selected" ng-change="vm.setUserGroupFilter(userGroup)" style="margin-right: 10px; margin-top: -3px;" />
|
||||
<label for="group-{{$index}}">{{ userGroup.name }}</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</umb-dropdown-item>
|
||||
</umb-dropdown>
|
||||
</div>
|
||||
|
||||
<!-- Order By -->
|
||||
<div class="dropdown pull-right">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" data-toggle="dropdown">
|
||||
<div style="position: relative;">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" ng-click="vm.toggleFilter('orderBy')">
|
||||
<span>Order by:</span>
|
||||
<span class="bold" style="margin-left: 2px;">{{ vm.getSortLabel(vm.usersOptions.orderBy, vm.usersOptions.orderDirection) }} </span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
|
||||
<li ng-repeat="sortData in vm.userSortData">
|
||||
<a tabindex="-1" href="#" ng-click="vm.setOrderByFilter(sortData.key, sortData.direction)" prevent-default>{{sortData.label}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<umb-dropdown class="pull-right" ng-if="vm.page.showOrderByFilter" on-close="vm.page.showOrderByFilter = false;" umb-keyboard-list>
|
||||
<umb-dropdown-item ng-repeat="sortData in vm.userSortData">
|
||||
<a href="#" ng-click="vm.setOrderByFilter(sortData.key, sortData.direction)" prevent-default>{{sortData.label}}</a>
|
||||
</umb-dropdown-item>
|
||||
</umb-dropdown>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user