Skip to content
This repository was archived by the owner on Oct 2, 2019. It is now read-only.

Commit 81657b4

Browse files
committed
chore(build): v0.3.0
1 parent 521eaf4 commit 81657b4

File tree

2 files changed

+180
-22
lines changed

2 files changed

+180
-22
lines changed

dist/select.css

+44
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,34 @@
33
font-weight: bold;
44
}
55

6+
.ui-select-offscreen {
7+
clip: rect(0 0 0 0) !important;
8+
width: 1px !important;
9+
height: 1px !important;
10+
border: 0 !important;
11+
margin: 0 !important;
12+
padding: 0 !important;
13+
overflow: hidden !important;
14+
position: absolute !important;
15+
outline: 0 !important;
16+
left: 0px !important;
17+
top: 0px !important;
18+
}
619

720
/* Select2 theme */
821

22+
/* Mark invalid Select2 */
23+
.ng-dirty.ng-invalid > a.select2-choice {
24+
border-color: #D44950;
25+
}
926

1027
/* Selectize theme */
1128

29+
/* Helper class to show styles when focus */
30+
.selectize-input.selectize-focus{
31+
border-color: #007FBB !important;
32+
}
33+
1234
/* Fix input width for Selectize theme */
1335
.selectize-control > .selectize-input > input {
1436
width: 100%;
@@ -19,9 +41,26 @@
1941
width: 100%;
2042
}
2143

44+
/* Mark invalid Selectize */
45+
.ng-dirty.ng-invalid > div.selectize-input {
46+
border-color: #D44950;
47+
}
48+
2249

2350
/* Bootstrap theme */
2451

52+
/* Helper class to show styles when focus */
53+
.btn-default-focus {
54+
color: #333;
55+
background-color: #EBEBEB;
56+
border-color: #ADADAD;
57+
text-decoration: none;
58+
outline: 5px auto -webkit-focus-ring-color;
59+
outline-offset: -2px;
60+
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
61+
}
62+
63+
2564
/* Fix Bootstrap dropdown position when inside a input-group */
2665
.input-group > .ui-select-bootstrap.dropdown {
2766
/* Instead of relative */
@@ -61,3 +100,8 @@
61100
.ui-select-search.ng-hide-add {
62101
display: none !important;
63102
}
103+
104+
/* Mark invalid Bootstrap */
105+
.ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match {
106+
border-color: #D44950;
107+
}

dist/select.js

+136-22
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ angular.module('ui.select', [])
5555
* keyIdentifier = undefined
5656
*/
5757
self.parse = function(expression) {
58+
if (!expression) {
59+
throw uiSelectMinErr('repeat', "Expected 'repeat' expression.");
60+
}
61+
5862
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
5963

6064
if (!match) {
@@ -112,6 +116,8 @@ angular.module('ui.select', [])
112116
ctrl.items = [];
113117
ctrl.selected = undefined;
114118
ctrl.open = false;
119+
ctrl.focus = false;
120+
ctrl.focusser = undefined; //Reference to input element used to handle focus events
115121
ctrl.disabled = undefined; // Initialized inside uiSelect directive link function
116122
ctrl.resetSearchInput = undefined; // Initialized inside uiSelect directive link function
117123
ctrl.refreshDelay = undefined; // Initialized inside uiSelectChoices directive link function
@@ -125,17 +131,22 @@ angular.module('ui.select', [])
125131
function _resetSearchInput() {
126132
if (ctrl.resetSearchInput) {
127133
ctrl.search = EMPTY_SEARCH;
134+
//reset activeIndex
135+
if (ctrl.selected && ctrl.items.length) {
136+
ctrl.activeIndex = ctrl.items.indexOf(ctrl.selected);
137+
}
128138
}
129139
}
130140

131141
// When the user clicks on ui-select, displays the dropdown list
132-
ctrl.activate = function() {
142+
ctrl.activate = function(initSearchValue) {
133143
if (!ctrl.disabled) {
134144
_resetSearchInput();
135145
ctrl.open = true;
136146

137147
// Give it time to appear before focus
138148
$timeout(function() {
149+
ctrl.search = initSearchValue || ctrl.search;
139150
_searchInput[0].focus();
140151
});
141152
}
@@ -198,6 +209,7 @@ angular.module('ui.select', [])
198209
if (ctrl.open) {
199210
_resetSearchInput();
200211
ctrl.open = false;
212+
ctrl.focusser[0].focus();
201213
}
202214
};
203215

@@ -235,7 +247,7 @@ angular.module('ui.select', [])
235247
_searchInput.on('keydown', function(e) {
236248
// Keyboard shortcuts are all about the items,
237249
// does not make sense (and will crash) if ctrl.items is empty
238-
if (ctrl.items.length > 0) {
250+
if (ctrl.items && ctrl.items.length >= 0) {
239251
var key = e.which;
240252

241253
$scope.$apply(function() {
@@ -280,8 +292,8 @@ angular.module('ui.select', [])
280292
}])
281293

282294
.directive('uiSelect',
283-
['$document', 'uiSelectConfig', 'uiSelectMinErr',
284-
function($document, uiSelectConfig, uiSelectMinErr) {
295+
['$document', 'uiSelectConfig', 'uiSelectMinErr', '$compile',
296+
function($document, uiSelectConfig, uiSelectMinErr, $compile) {
285297

286298
return {
287299
restrict: 'EA',
@@ -301,6 +313,98 @@ angular.module('ui.select', [])
301313
var $select = ctrls[0];
302314
var ngModel = ctrls[1];
303315

316+
//Idea from: https://github.com/ivaynberg/select2/blob/79b5bf6db918d7560bdd959109b7bcfb47edaf43/select2.js#L1954
317+
var focusser = angular.element("<input ng-disabled='$select.disabled' class='ui-select-focusser ui-select-offscreen' type='text' aria-haspopup='true' role='button' />");
318+
$compile(focusser)(scope);
319+
$select.focusser = focusser;
320+
321+
element.append(focusser);
322+
focusser.bind("focus", function(){
323+
scope.$evalAsync(function(){
324+
$select.focus = true;
325+
});
326+
});
327+
focusser.bind("blur", function(){
328+
scope.$evalAsync(function(){
329+
$select.focus = false;
330+
});
331+
});
332+
focusser.bind("keydown", function(e){
333+
334+
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
335+
return;
336+
}
337+
338+
if (e.which == KEY.DOWN || e.which == KEY.UP || e.which == KEY.ENTER || e.which == KEY.SPACE){
339+
e.preventDefault();
340+
e.stopPropagation();
341+
$select.activate();
342+
}
343+
344+
scope.$digest();
345+
});
346+
347+
focusser.bind("keyup input", function(e){
348+
349+
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || e.which == KEY.ENTER) {
350+
return;
351+
}
352+
353+
$select.activate(focusser.val()); //User pressed some regualar key, so we pass it to the search input
354+
focusser.val('');
355+
scope.$digest();
356+
357+
});
358+
359+
//TODO Refactor to reuse the KEY object from uiSelectCtrl
360+
var KEY = {
361+
TAB: 9,
362+
ENTER: 13,
363+
ESC: 27,
364+
SPACE: 32,
365+
LEFT: 37,
366+
UP: 38,
367+
RIGHT: 39,
368+
DOWN: 40,
369+
SHIFT: 16,
370+
CTRL: 17,
371+
ALT: 18,
372+
PAGE_UP: 33,
373+
PAGE_DOWN: 34,
374+
HOME: 36,
375+
END: 35,
376+
BACKSPACE: 8,
377+
DELETE: 46,
378+
isArrow: function (k) {
379+
k = k.which ? k.which : k;
380+
switch (k) {
381+
case KEY.LEFT:
382+
case KEY.RIGHT:
383+
case KEY.UP:
384+
case KEY.DOWN:
385+
return true;
386+
}
387+
return false;
388+
},
389+
isControl: function (e) {
390+
var k = e.which;
391+
switch (k) {
392+
case KEY.SHIFT:
393+
case KEY.CTRL:
394+
case KEY.ALT:
395+
return true;
396+
}
397+
398+
if (e.metaKey) return true;
399+
400+
return false;
401+
},
402+
isFunctionKey: function (k) {
403+
k = k.which ? k.which : k;
404+
return k >= 112 && k <= 123;
405+
}
406+
};
407+
304408
attrs.$observe('disabled', function() {
305409
// No need to use $eval() (thanks to ng-disabled) since we already get a boolean instead of a string
306410
$select.disabled = attrs.disabled !== undefined ? attrs.disabled : false;
@@ -372,8 +476,8 @@ angular.module('ui.select', [])
372476
}])
373477

374478
.directive('uiSelectChoices',
375-
['uiSelectConfig', 'RepeatParser', 'uiSelectMinErr',
376-
function(uiSelectConfig, RepeatParser, uiSelectMinErr) {
479+
['uiSelectConfig', 'RepeatParser', 'uiSelectMinErr', '$compile',
480+
function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile) {
377481

378482
return {
379483
restrict: 'EA',
@@ -388,17 +492,27 @@ angular.module('ui.select', [])
388492

389493
compile: function(tElement, tAttrs) {
390494
var repeat = RepeatParser.parse(tAttrs.repeat);
495+
return function link(scope, element, attrs, $select, transcludeFn) {
496+
497+
var rows = element.querySelectorAll('.ui-select-choices-row');
498+
if (rows.length !== 1) {
499+
throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", rows.length);
500+
}
501+
502+
rows.attr('ng-repeat', RepeatParser.getNgRepeatExpression(repeat.lhs, '$select.items', repeat.trackByExp))
503+
.attr('ng-mouseenter', '$select.activeIndex = $index')
504+
.attr('ng-click', '$select.select(' + repeat.lhs + ')');
391505

392-
var rows = tElement.querySelectorAll('.ui-select-choices-row');
393-
if (rows.length !== 1) {
394-
throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", rows.length);
395-
}
396506

397-
rows.attr('ng-repeat', RepeatParser.getNgRepeatExpression(repeat.lhs, '$select.items', repeat.trackByExp))
398-
.attr('ng-mouseenter', '$select.activeIndex = $index')
399-
.attr('ng-click', '$select.select(' + repeat.lhs + ')');
507+
transcludeFn(function(clone) {
508+
var rowsInner = element.querySelectorAll('.ui-select-choices-row-inner');
509+
if (rowsInner.length !== 1)
510+
throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);
511+
512+
rowsInner.append(clone);
513+
$compile(element)(scope);
514+
});
400515

401-
return function link(scope, element, attrs, $select) {
402516
$select.parseRepeatAttr(attrs.repeat);
403517

404518
scope.$watch('$select.search', function() {
@@ -447,18 +561,18 @@ angular.module('ui.select', [])
447561
}
448562

449563
return function(matchItem, query) {
450-
return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
564+
return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
451565
};
452566
});
453567

454568
angular.module('ui.select').run(['$templateCache', function ($templateCache) {
455-
$templateCache.put('bootstrap/choices.tpl.html', '<ul class="ui-select-choices ui-select-choices-content dropdown-menu" role="menu" aria-labelledby="dLabel" ng-show="$select.items.length> 0"> <li class="ui-select-choices-row" ng-class="{active: $select.activeIndex===$index}"> <a href="javascript:void(0)" ng-transclude></a> </li> </ul> ');
456-
$templateCache.put('bootstrap/match.tpl.html', '<button type="button" class="btn btn-default form-control ui-select-match" ng-hide="$select.open" ng-disabled="$select.disabled" ng-click="$select.activate()"> <span ng-hide="$select.selected !==undefined" class="text-muted">{{$select.placeholder}}</span> <span ng-show="$select.selected !==undefined" ng-transclude></span> <span class="caret"></span> </button> ');
457-
$templateCache.put('bootstrap/select.tpl.html', '<div class="ui-select-bootstrap dropdown" ng-class="{open: $select.open}"> <div class="ui-select-match"></div> <input type="text" autocomplete="off" tabindex="" class="form-control ui-select-search" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-show="$select.open"> <div class="ui-select-choices"></div> </div> ');
458-
$templateCache.put('select2/choices.tpl.html', '<ul class="ui-select-choices ui-select-choices-content select2-results"> <li class="ui-select-choices-row" ng-class="{\'select2-highlighted\': $select.activeIndex===$index}"> <div class="select2-result-label" ng-transclude></div> </li> </ul> ');
569+
$templateCache.put('bootstrap/choices.tpl.html', '<ul class="ui-select-choices ui-select-choices-content dropdown-menu" role="menu" aria-labelledby="dLabel" ng-show="$select.items.length> 0"> <li class="ui-select-choices-row" ng-class="{active: $select.activeIndex===$index}"> <a class="ui-select-choices-row-inner" href="javascript:void(0)"></a> </li> </ul> ');
570+
$templateCache.put('bootstrap/match.tpl.html', '<button type="button" class="btn btn-default form-control ui-select-match" tabindex="-1" ng-hide="$select.open" ng-disabled="$select.disabled" ng-class="{\'btn-default-focus\':$select.focus}"; ng-click="$select.activate()"> <span ng-hide="$select.selected !==undefined" class="text-muted">{{$select.placeholder}}</span> <span ng-show="$select.selected !==undefined" ng-transclude></span> <span class="caret"></span> </button> ');
571+
$templateCache.put('bootstrap/select.tpl.html', '<div class="ui-select-bootstrap dropdown" ng-class="{open: $select.open}"> <div class="ui-select-match"></div> <input type="text" autocomplete="off" tabindex="-1" class="form-control ui-select-search" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-show="$select.open"> <div class="ui-select-choices"></div> </div> ');
572+
$templateCache.put('select2/choices.tpl.html', '<ul class="ui-select-choices ui-select-choices-content select2-results"> <li class="ui-select-choices-row" ng-class="{\'select2-highlighted\': $select.activeIndex===$index}"> <div class="select2-result-label ui-select-choices-row-inner"></div> </li> </ul> ');
459573
$templateCache.put('select2/match.tpl.html', '<a class="select2-choice ui-select-match" ng-class="{\'select2-default\': $select.selected===undefined}" ng-click="$select.activate()"> <span ng-hide="$select.selected !==undefined" class="select2-chosen">{{$select.placeholder}}</span> <span ng-show="$select.selected !==undefined" class="select2-chosen" ng-transclude></span> <span class="select2-arrow"><b></b></span> </a> ');
460-
$templateCache.put('select2/select.tpl.html', '<div class="select2 select2-container" ng-class="{\'select2-container-active select2-dropdown-open\': $select.open, \'select2-container-disabled\': $select.disabled}"> <div class="ui-select-match"></div> <div class="select2-drop select2-with-searchbox select2-drop-active" ng-class="{\'select2-display-none\': !$select.open}"> <div class="select2-search"> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="ui-select-search select2-input" ng-model="$select.search"> </div> <div class="ui-select-choices"></div> </div> </div> ');
461-
$templateCache.put('selectize/choices.tpl.html', '<div ng-show="$select.open" class="ui-select-choices selectize-dropdown single"> <div class="ui-select-choices-content selectize-dropdown-content"> <div class="ui-select-choices-row" ng-class="{\'active\': $select.activeIndex===$index}"> <div class="option" data-selectable ng-transclude></div> </div> </div> </div> ');
574+
$templateCache.put('select2/select.tpl.html', '<div class="select2 select2-container" ng-class="{\'select2-container-active select2-dropdown-open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus }"> <div class="ui-select-match"></div> <div class="select2-drop select2-with-searchbox select2-drop-active" ng-class="{\'select2-display-none\': !$select.open}"> <div class="select2-search"> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="ui-select-search select2-input" ng-model="$select.search"> </div> <div class="ui-select-choices"></div> </div> </div> ');
575+
$templateCache.put('selectize/choices.tpl.html', '<div ng-show="$select.open" class="ui-select-choices selectize-dropdown single"> <div class="ui-select-choices-content selectize-dropdown-content"> <div class="ui-select-choices-row" ng-class="{\'active\': $select.activeIndex===$index}"> <div class="option ui-select-choices-row-inner" data-selectable></div> </div> </div> </div> ');
462576
$templateCache.put('selectize/match.tpl.html', '<div ng-hide="$select.open || $select.selected===undefined" class="ui-select-match" ng-transclude></div> ');
463-
$templateCache.put('selectize/select.tpl.html', '<div class="selectize-control single"> <div class="selectize-input" ng-class="{\'focus\': $select.open, \'disabled\': $select.disabled}" ng-click="$select.activate()"> <div class="ui-select-match"></div> <input type="text" autocomplete="off" tabindex="" class="ui-select-search" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-hide="$select.selected && !$select.open" ng-disabled="$select.disabled"> </div> <div class="ui-select-choices"></div> </div> ');
577+
$templateCache.put('selectize/select.tpl.html', '<div class="selectize-control single"> <div class="selectize-input" ng-class="{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}" ng-click="$select.activate()"> <div class="ui-select-match"></div> <input type="text" autocomplete="off" tabindex="-1" class="ui-select-search" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-hide="$select.selected && !$select.open" ng-disabled="$select.disabled"> </div> <div class="ui-select-choices"></div> </div> ');
464578
}]);

0 commit comments

Comments
 (0)