angular-ui-select-rails 0.12.1.1 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc9f5c04458b517d77af56fcb38133499073df28
|
4
|
+
data.tar.gz: 523e9f2cbd1e8c6594b44fa43bf48ec99432a6b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c066b129c7fd056d53ed48d167362310b53a05d81bf7eb8ec451e37afc733728ca790b96b4c3380443ed8ab4e6059d7d2a232f8c73af28851367d97e10df44c
|
7
|
+
data.tar.gz: 5c7102048d9055cad7698b837f65a725e30e175b56998d5836ad7e2eeb8570d07cca2db6916063ee856522f565c987262dd64d173fd1928c5b3d20244a9f3298
|
@@ -1,14 +1,13 @@
|
|
1
1
|
/*!
|
2
2
|
* ui-select
|
3
3
|
* http://github.com/angular-ui/ui-select
|
4
|
-
* Version: 0.
|
4
|
+
* Version: 0.18.1 - 2016-07-10T00:18:10.535Z
|
5
5
|
* License: MIT
|
6
6
|
*/
|
7
7
|
|
8
8
|
|
9
9
|
(function () {
|
10
10
|
"use strict";
|
11
|
-
|
12
11
|
var KEY = {
|
13
12
|
TAB: 9,
|
14
13
|
ENTER: 13,
|
@@ -42,7 +41,7 @@ var KEY = {
|
|
42
41
|
return true;
|
43
42
|
}
|
44
43
|
|
45
|
-
if (e.metaKey) return true;
|
44
|
+
if (e.metaKey || e.ctrlKey || e.altKey) return true;
|
46
45
|
|
47
46
|
return false;
|
48
47
|
},
|
@@ -55,6 +54,13 @@ var KEY = {
|
|
55
54
|
},
|
56
55
|
isHorizontalMovement: function (k){
|
57
56
|
return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k);
|
57
|
+
},
|
58
|
+
toSeparator: function (k) {
|
59
|
+
var sep = {ENTER:"\n",TAB:"\t",SPACE:" "}[k];
|
60
|
+
if (sep) return sep;
|
61
|
+
// return undefined for special keys other than enter, tab or space.
|
62
|
+
// no way to use them to cut strings.
|
63
|
+
return KEY[k] ? undefined : k;
|
58
64
|
}
|
59
65
|
};
|
60
66
|
|
@@ -103,6 +109,9 @@ var uis = angular.module('ui.select', [])
|
|
103
109
|
placeholder: '', // Empty by default, like HTML tag <select>
|
104
110
|
refreshDelay: 1000, // In milliseconds
|
105
111
|
closeOnSelect: true,
|
112
|
+
skipFocusser: false,
|
113
|
+
dropdownPosition: 'auto',
|
114
|
+
removeSelected: true,
|
106
115
|
generateId: function() {
|
107
116
|
return latestId++;
|
108
117
|
},
|
@@ -138,11 +147,11 @@ var uis = angular.module('ui.select', [])
|
|
138
147
|
*/
|
139
148
|
.filter('highlight', function() {
|
140
149
|
function escapeRegexp(queryToEscape) {
|
141
|
-
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
|
150
|
+
return ('' + queryToEscape).replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
|
142
151
|
}
|
143
152
|
|
144
153
|
return function(matchItem, query) {
|
145
|
-
return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
|
154
|
+
return query && matchItem ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
|
146
155
|
};
|
147
156
|
})
|
148
157
|
|
@@ -167,9 +176,34 @@ var uis = angular.module('ui.select', [])
|
|
167
176
|
};
|
168
177
|
}]);
|
169
178
|
|
179
|
+
/**
|
180
|
+
* Debounces functions
|
181
|
+
*
|
182
|
+
* Taken from UI Bootstrap $$debounce source code
|
183
|
+
* See https://github.com/angular-ui/bootstrap/blob/master/src/debounce/debounce.js
|
184
|
+
*
|
185
|
+
*/
|
186
|
+
uis.factory('$$uisDebounce', ['$timeout', function($timeout) {
|
187
|
+
return function(callback, debounceTime) {
|
188
|
+
var timeoutPromise;
|
189
|
+
|
190
|
+
return function() {
|
191
|
+
var self = this;
|
192
|
+
var args = Array.prototype.slice.call(arguments);
|
193
|
+
if (timeoutPromise) {
|
194
|
+
$timeout.cancel(timeoutPromise);
|
195
|
+
}
|
196
|
+
|
197
|
+
timeoutPromise = $timeout(function() {
|
198
|
+
callback.apply(self, args);
|
199
|
+
}, debounceTime);
|
200
|
+
};
|
201
|
+
};
|
202
|
+
}]);
|
203
|
+
|
170
204
|
uis.directive('uiSelectChoices',
|
171
|
-
['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile',
|
172
|
-
function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile) {
|
205
|
+
['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile', '$window',
|
206
|
+
function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile, $window) {
|
173
207
|
|
174
208
|
return {
|
175
209
|
restrict: 'EA',
|
@@ -177,6 +211,9 @@ uis.directive('uiSelectChoices',
|
|
177
211
|
replace: true,
|
178
212
|
transclude: true,
|
179
213
|
templateUrl: function(tElement) {
|
214
|
+
// Needed so the uiSelect can detect the transcluded content
|
215
|
+
tElement.addClass('ui-select-choices');
|
216
|
+
|
180
217
|
// Gets theme attribute from parent (ui-select)
|
181
218
|
var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
|
182
219
|
return theme + '/choices.tpl.html';
|
@@ -186,43 +223,59 @@ uis.directive('uiSelectChoices',
|
|
186
223
|
|
187
224
|
if (!tAttrs.repeat) throw uiSelectMinErr('repeat', "Expected 'repeat' expression.");
|
188
225
|
|
189
|
-
|
226
|
+
// var repeat = RepeatParser.parse(attrs.repeat);
|
227
|
+
var groupByExp = tAttrs.groupBy;
|
228
|
+
var groupFilterExp = tAttrs.groupFilter;
|
190
229
|
|
191
|
-
|
192
|
-
var
|
193
|
-
|
230
|
+
if (groupByExp) {
|
231
|
+
var groups = tElement.querySelectorAll('.ui-select-choices-group');
|
232
|
+
if (groups.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-group but got '{0}'.", groups.length);
|
233
|
+
groups.attr('ng-repeat', RepeatParser.getGroupNgRepeatExpression());
|
234
|
+
}
|
194
235
|
|
195
|
-
|
236
|
+
var parserResult = RepeatParser.parse(tAttrs.repeat);
|
196
237
|
|
197
|
-
|
198
|
-
|
238
|
+
var choices = tElement.querySelectorAll('.ui-select-choices-row');
|
239
|
+
if (choices.length !== 1) {
|
240
|
+
throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", choices.length);
|
241
|
+
}
|
199
242
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
groups.attr('ng-repeat', RepeatParser.getGroupNgRepeatExpression());
|
204
|
-
}
|
243
|
+
choices.attr('ng-repeat', parserResult.repeatExpression(groupByExp))
|
244
|
+
.attr('ng-if', '$select.open'); //Prevent unnecessary watches when dropdown is closed
|
245
|
+
|
205
246
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
247
|
+
var rowsInner = tElement.querySelectorAll('.ui-select-choices-row-inner');
|
248
|
+
if (rowsInner.length !== 1) {
|
249
|
+
throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);
|
250
|
+
}
|
251
|
+
rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat
|
210
252
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
253
|
+
// If IE8 then need to target rowsInner to apply the ng-click attr as choices will not capture the event.
|
254
|
+
var clickTarget = $window.document.addEventListener ? choices : rowsInner;
|
255
|
+
clickTarget.attr('ng-click', '$select.select(' + parserResult.itemName + ',$select.skipFocusser,$event)');
|
256
|
+
|
257
|
+
return function link(scope, element, attrs, $select) {
|
215
258
|
|
216
|
-
|
217
|
-
|
218
|
-
rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat
|
259
|
+
|
260
|
+
$select.parseRepeatAttr(attrs.repeat, groupByExp, groupFilterExp); //Result ready at $select.parserResult
|
219
261
|
|
220
|
-
$
|
262
|
+
$select.disableChoiceExpression = attrs.uiDisableChoice;
|
263
|
+
$select.onHighlightCallback = attrs.onHighlight;
|
264
|
+
|
265
|
+
$select.dropdownPosition = attrs.position ? attrs.position.toLowerCase() : uiSelectConfig.dropdownPosition;
|
266
|
+
|
267
|
+
scope.$on('$destroy', function() {
|
268
|
+
choices.remove();
|
269
|
+
});
|
221
270
|
|
222
271
|
scope.$watch('$select.search', function(newValue) {
|
223
272
|
if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
|
224
273
|
$select.activeIndex = $select.tagging.isActivated ? -1 : 0;
|
225
|
-
$select.
|
274
|
+
if (!attrs.minimumInputLength || $select.search.length >= attrs.minimumInputLength) {
|
275
|
+
$select.refresh(attrs.refresh);
|
276
|
+
} else {
|
277
|
+
$select.items = [];
|
278
|
+
}
|
226
279
|
});
|
227
280
|
|
228
281
|
attrs.$observe('refreshDelay', function() {
|
@@ -242,8 +295,8 @@ uis.directive('uiSelectChoices',
|
|
242
295
|
* put as much logic in the controller (instead of the link functions) as possible so it can be easily tested.
|
243
296
|
*/
|
244
297
|
uis.controller('uiSelectCtrl',
|
245
|
-
['$scope', '$element', '$timeout', '$filter', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig',
|
246
|
-
function($scope, $element, $timeout, $filter, RepeatParser, uiSelectMinErr, uiSelectConfig) {
|
298
|
+
['$scope', '$element', '$timeout', '$filter', '$$uisDebounce', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', '$injector', '$window',
|
299
|
+
function($scope, $element, $timeout, $filter, $$uisDebounce, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse, $injector, $window) {
|
247
300
|
|
248
301
|
var ctrl = this;
|
249
302
|
|
@@ -253,9 +306,11 @@ uis.controller('uiSelectCtrl',
|
|
253
306
|
ctrl.searchEnabled = uiSelectConfig.searchEnabled;
|
254
307
|
ctrl.sortable = uiSelectConfig.sortable;
|
255
308
|
ctrl.refreshDelay = uiSelectConfig.refreshDelay;
|
309
|
+
ctrl.paste = uiSelectConfig.paste;
|
256
310
|
|
257
|
-
ctrl.removeSelected =
|
311
|
+
ctrl.removeSelected = uiSelectConfig.removeSelected; //If selected item(s) should be removed from dropdown list
|
258
312
|
ctrl.closeOnSelect = true; //Initialized inside uiSelect directive link function
|
313
|
+
ctrl.skipFocusser = false; //Set to true to avoid returning focus to ctrl when item is selected
|
259
314
|
ctrl.search = EMPTY_SEARCH;
|
260
315
|
|
261
316
|
ctrl.activeIndex = 0; //Dropdown of choices
|
@@ -266,6 +321,8 @@ uis.controller('uiSelectCtrl',
|
|
266
321
|
ctrl.disabled = false;
|
267
322
|
ctrl.selected = undefined;
|
268
323
|
|
324
|
+
ctrl.dropdownPosition = 'auto';
|
325
|
+
|
269
326
|
ctrl.focusser = undefined; //Reference to input element used to handle focus events
|
270
327
|
ctrl.resetSearchInput = true;
|
271
328
|
ctrl.multiple = undefined; // Initialized inside uiSelect directive link function
|
@@ -275,23 +332,54 @@ uis.controller('uiSelectCtrl',
|
|
275
332
|
ctrl.lockChoiceExpression = undefined; // Initialized inside uiSelectMatch directive link function
|
276
333
|
ctrl.clickTriggeredSelect = false;
|
277
334
|
ctrl.$filter = $filter;
|
335
|
+
ctrl.$element = $element;
|
336
|
+
|
337
|
+
// Use $injector to check for $animate and store a reference to it
|
338
|
+
ctrl.$animate = (function () {
|
339
|
+
try {
|
340
|
+
return $injector.get('$animate');
|
341
|
+
} catch (err) {
|
342
|
+
// $animate does not exist
|
343
|
+
return null;
|
344
|
+
}
|
345
|
+
})();
|
278
346
|
|
279
347
|
ctrl.searchInput = $element.querySelectorAll('input.ui-select-search');
|
280
348
|
if (ctrl.searchInput.length !== 1) {
|
281
349
|
throw uiSelectMinErr('searchInput', "Expected 1 input.ui-select-search but got '{0}'.", ctrl.searchInput.length);
|
282
350
|
}
|
283
|
-
|
351
|
+
|
284
352
|
ctrl.isEmpty = function() {
|
285
|
-
return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '';
|
353
|
+
return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '' || (ctrl.multiple && ctrl.selected.length === 0);
|
286
354
|
};
|
287
355
|
|
356
|
+
function _findIndex(collection, predicate, thisArg){
|
357
|
+
if (collection.findIndex){
|
358
|
+
return collection.findIndex(predicate, thisArg);
|
359
|
+
} else {
|
360
|
+
var list = Object(collection);
|
361
|
+
var length = list.length >>> 0;
|
362
|
+
var value;
|
363
|
+
|
364
|
+
for (var i = 0; i < length; i++) {
|
365
|
+
value = list[i];
|
366
|
+
if (predicate.call(thisArg, value, i, list)) {
|
367
|
+
return i;
|
368
|
+
}
|
369
|
+
}
|
370
|
+
return -1;
|
371
|
+
}
|
372
|
+
}
|
373
|
+
|
288
374
|
// Most of the time the user does not want to empty the search input when in typeahead mode
|
289
375
|
function _resetSearchInput() {
|
290
376
|
if (ctrl.resetSearchInput || (ctrl.resetSearchInput === undefined && uiSelectConfig.resetSearchInput)) {
|
291
377
|
ctrl.search = EMPTY_SEARCH;
|
292
378
|
//reset activeIndex
|
293
379
|
if (ctrl.selected && ctrl.items.length && !ctrl.multiple) {
|
294
|
-
ctrl.activeIndex = ctrl.items
|
380
|
+
ctrl.activeIndex = _findIndex(ctrl.items, function(item){
|
381
|
+
return angular.equals(this, item);
|
382
|
+
}, ctrl.selected);
|
295
383
|
}
|
296
384
|
}
|
297
385
|
}
|
@@ -325,14 +413,46 @@ uis.controller('uiSelectCtrl',
|
|
325
413
|
ctrl.activeIndex = 0;
|
326
414
|
}
|
327
415
|
|
328
|
-
|
329
|
-
$
|
330
|
-
|
331
|
-
|
332
|
-
|
416
|
+
var container = $element.querySelectorAll('.ui-select-choices-content');
|
417
|
+
var searchInput = $element.querySelectorAll('.ui-select-search');
|
418
|
+
if (ctrl.$animate && ctrl.$animate.on && ctrl.$animate.enabled(container[0])) {
|
419
|
+
var animateHandler = function(elem, phase) {
|
420
|
+
if (phase === 'start' && ctrl.items.length === 0) {
|
421
|
+
// Only focus input after the animation has finished
|
422
|
+
ctrl.$animate.off('removeClass', searchInput[0], animateHandler);
|
423
|
+
$timeout(function () {
|
424
|
+
ctrl.focusSearchInput(initSearchValue);
|
425
|
+
});
|
426
|
+
} else if (phase === 'close') {
|
427
|
+
// Only focus input after the animation has finished
|
428
|
+
ctrl.$animate.off('enter', container[0], animateHandler);
|
429
|
+
$timeout(function () {
|
430
|
+
ctrl.focusSearchInput(initSearchValue);
|
431
|
+
});
|
432
|
+
}
|
433
|
+
};
|
434
|
+
|
435
|
+
if (ctrl.items.length > 0) {
|
436
|
+
ctrl.$animate.on('enter', container[0], animateHandler);
|
437
|
+
} else {
|
438
|
+
ctrl.$animate.on('removeClass', searchInput[0], animateHandler);
|
439
|
+
}
|
440
|
+
} else {
|
441
|
+
$timeout(function () {
|
442
|
+
ctrl.focusSearchInput(initSearchValue);
|
443
|
+
if(!ctrl.tagging.isActivated && ctrl.items.length > 1) {
|
444
|
+
_ensureHighlightVisible();
|
445
|
+
}
|
446
|
+
});
|
447
|
+
}
|
333
448
|
}
|
334
449
|
};
|
335
450
|
|
451
|
+
ctrl.focusSearchInput = function (initSearchValue) {
|
452
|
+
ctrl.search = initSearchValue || ctrl.search;
|
453
|
+
ctrl.searchInput[0].focus();
|
454
|
+
};
|
455
|
+
|
336
456
|
ctrl.findGroupByName = function(name) {
|
337
457
|
return ctrl.groups && ctrl.groups.filter(function(group) {
|
338
458
|
return group.name === name;
|
@@ -378,18 +498,50 @@ uis.controller('uiSelectCtrl',
|
|
378
498
|
ctrl.isGrouped = !!groupByExp;
|
379
499
|
ctrl.itemProperty = ctrl.parserResult.itemName;
|
380
500
|
|
501
|
+
//If collection is an Object, convert it to Array
|
502
|
+
|
503
|
+
var originalSource = ctrl.parserResult.source;
|
504
|
+
|
505
|
+
//When an object is used as source, we better create an array and use it as 'source'
|
506
|
+
var createArrayFromObject = function(){
|
507
|
+
var origSrc = originalSource($scope);
|
508
|
+
$scope.$uisSource = Object.keys(origSrc).map(function(v){
|
509
|
+
var result = {};
|
510
|
+
result[ctrl.parserResult.keyName] = v;
|
511
|
+
result.value = origSrc[v];
|
512
|
+
return result;
|
513
|
+
});
|
514
|
+
};
|
515
|
+
|
516
|
+
if (ctrl.parserResult.keyName){ // Check for (key,value) syntax
|
517
|
+
createArrayFromObject();
|
518
|
+
ctrl.parserResult.source = $parse('$uisSource' + ctrl.parserResult.filters);
|
519
|
+
$scope.$watch(originalSource, function(newVal, oldVal){
|
520
|
+
if (newVal !== oldVal) createArrayFromObject();
|
521
|
+
}, true);
|
522
|
+
}
|
523
|
+
|
381
524
|
ctrl.refreshItems = function (data){
|
382
525
|
data = data || ctrl.parserResult.source($scope);
|
383
526
|
var selectedItems = ctrl.selected;
|
384
527
|
//TODO should implement for single mode removeSelected
|
385
|
-
if ((angular.isArray(selectedItems) && !selectedItems.length) || !ctrl.removeSelected) {
|
528
|
+
if (ctrl.isEmpty() || (angular.isArray(selectedItems) && !selectedItems.length) || !ctrl.multiple || !ctrl.removeSelected) {
|
386
529
|
ctrl.setItemsFn(data);
|
387
530
|
}else{
|
388
|
-
if ( data !== undefined ) {
|
389
|
-
var filteredItems = data.filter(function(i) {
|
531
|
+
if ( data !== undefined && data !== null ) {
|
532
|
+
var filteredItems = data.filter(function(i) {
|
533
|
+
return angular.isArray(selectedItems) ? selectedItems.every(function(selectedItem) {
|
534
|
+
return !angular.equals(i, selectedItem);
|
535
|
+
}) : !angular.equals(i, selectedItems);
|
536
|
+
});
|
390
537
|
ctrl.setItemsFn(filteredItems);
|
391
538
|
}
|
392
539
|
}
|
540
|
+
if (ctrl.dropdownPosition === 'auto' || ctrl.dropdownPosition === 'up'){
|
541
|
+
$scope.calculateDropdownPos();
|
542
|
+
}
|
543
|
+
|
544
|
+
$scope.$broadcast('uis:refresh');
|
393
545
|
};
|
394
546
|
|
395
547
|
// See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L259
|
@@ -406,7 +558,11 @@ uis.controller('uiSelectCtrl',
|
|
406
558
|
//Remove already selected items (ex: while searching)
|
407
559
|
//TODO Should add a test
|
408
560
|
ctrl.refreshItems(items);
|
409
|
-
|
561
|
+
|
562
|
+
//update the view value with fresh data from items, if there is a valid model value
|
563
|
+
if(angular.isDefined(ctrl.ngModel.$modelValue)) {
|
564
|
+
ctrl.ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
|
565
|
+
}
|
410
566
|
}
|
411
567
|
}
|
412
568
|
});
|
@@ -435,18 +591,14 @@ uis.controller('uiSelectCtrl',
|
|
435
591
|
}
|
436
592
|
};
|
437
593
|
|
438
|
-
ctrl.setActiveItem = function(item) {
|
439
|
-
ctrl.activeIndex = ctrl.items.indexOf(item);
|
440
|
-
};
|
441
|
-
|
442
594
|
ctrl.isActive = function(itemScope) {
|
443
595
|
if ( !ctrl.open ) {
|
444
596
|
return false;
|
445
597
|
}
|
446
598
|
var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]);
|
447
|
-
var isActive = itemIndex
|
599
|
+
var isActive = itemIndex == ctrl.activeIndex;
|
448
600
|
|
449
|
-
if ( !isActive ||
|
601
|
+
if ( !isActive || itemIndex < 0 ) {
|
450
602
|
return false;
|
451
603
|
}
|
452
604
|
|
@@ -457,18 +609,49 @@ uis.controller('uiSelectCtrl',
|
|
457
609
|
return isActive;
|
458
610
|
};
|
459
611
|
|
612
|
+
var _isItemSelected = function (item) {
|
613
|
+
return (ctrl.selected && angular.isArray(ctrl.selected) &&
|
614
|
+
ctrl.selected.filter(function (selection) { return angular.equals(selection, item); }).length > 0);
|
615
|
+
};
|
616
|
+
|
617
|
+
var disabledItems = [];
|
618
|
+
|
619
|
+
function _updateItemDisabled(item, isDisabled) {
|
620
|
+
var disabledItemIndex = disabledItems.indexOf(item);
|
621
|
+
if (isDisabled && disabledItemIndex === -1) {
|
622
|
+
disabledItems.push(item);
|
623
|
+
}
|
624
|
+
|
625
|
+
if (!isDisabled && disabledItemIndex > -1) {
|
626
|
+
disabledItems.splice(disabledItemIndex, 0);
|
627
|
+
}
|
628
|
+
}
|
629
|
+
|
630
|
+
function _isItemDisabled(item) {
|
631
|
+
return disabledItems.indexOf(item) > -1;
|
632
|
+
}
|
633
|
+
|
460
634
|
ctrl.isDisabled = function(itemScope) {
|
461
635
|
|
462
636
|
if (!ctrl.open) return;
|
463
637
|
|
464
|
-
var
|
638
|
+
var item = itemScope[ctrl.itemProperty];
|
639
|
+
var itemIndex = ctrl.items.indexOf(item);
|
465
640
|
var isDisabled = false;
|
466
|
-
|
641
|
+
|
642
|
+
if (itemIndex >= 0 && (angular.isDefined(ctrl.disableChoiceExpression) || ctrl.multiple)) {
|
643
|
+
|
644
|
+
if (item.isTag) return false;
|
467
645
|
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
646
|
+
if (ctrl.multiple) {
|
647
|
+
isDisabled = _isItemSelected(item);
|
648
|
+
}
|
649
|
+
|
650
|
+
if (!isDisabled && angular.isDefined(ctrl.disableChoiceExpression)) {
|
651
|
+
isDisabled = !!(itemScope.$eval(ctrl.disableChoiceExpression));
|
652
|
+
}
|
653
|
+
|
654
|
+
_updateItemDisabled(item, isDisabled);
|
472
655
|
}
|
473
656
|
|
474
657
|
return isDisabled;
|
@@ -477,16 +660,18 @@ uis.controller('uiSelectCtrl',
|
|
477
660
|
|
478
661
|
// When the user selects an item with ENTER or clicks the dropdown
|
479
662
|
ctrl.select = function(item, skipFocusser, $event) {
|
480
|
-
if (item === undefined || !item
|
663
|
+
if (item === undefined || !_isItemDisabled(item)) {
|
481
664
|
|
482
|
-
if ( ! ctrl.items && ! ctrl.search ) return;
|
665
|
+
if ( ! ctrl.items && ! ctrl.search && ! ctrl.tagging.isActivated) return;
|
483
666
|
|
484
|
-
if (!item || !item
|
667
|
+
if (!item || !_isItemDisabled(item)) {
|
485
668
|
if(ctrl.tagging.isActivated) {
|
486
|
-
// if taggingLabel is disabled
|
669
|
+
// if taggingLabel is disabled and item is undefined we pull from ctrl.search
|
487
670
|
if ( ctrl.taggingLabel === false ) {
|
488
671
|
if ( ctrl.activeIndex < 0 ) {
|
489
|
-
item
|
672
|
+
if (item === undefined) {
|
673
|
+
item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : ctrl.search;
|
674
|
+
}
|
490
675
|
if (!item || angular.equals( ctrl.items[0], item ) ) {
|
491
676
|
return;
|
492
677
|
}
|
@@ -505,7 +690,7 @@ uis.controller('uiSelectCtrl',
|
|
505
690
|
// create new item on the fly if we don't already have one;
|
506
691
|
// use tagging function if we have one
|
507
692
|
if ( ctrl.tagging.fct !== undefined && typeof item === 'string' ) {
|
508
|
-
item = ctrl.tagging.fct(
|
693
|
+
item = ctrl.tagging.fct(item);
|
509
694
|
if (!item) return;
|
510
695
|
// if item type is 'string', apply the tagging label
|
511
696
|
} else if ( typeof item === 'string' ) {
|
@@ -515,7 +700,7 @@ uis.controller('uiSelectCtrl',
|
|
515
700
|
}
|
516
701
|
}
|
517
702
|
// search ctrl.selected for dupes potentially caused by tagging and return early if found
|
518
|
-
if (
|
703
|
+
if (_isItemSelected(item)) {
|
519
704
|
ctrl.close(skipFocusser);
|
520
705
|
return;
|
521
706
|
}
|
@@ -577,18 +762,56 @@ uis.controller('uiSelectCtrl',
|
|
577
762
|
}
|
578
763
|
};
|
579
764
|
|
580
|
-
|
581
|
-
|
765
|
+
// Set default function for locked choices - avoids unnecessary
|
766
|
+
// logic if functionality is not being used
|
767
|
+
ctrl.isLocked = function () {
|
768
|
+
return false;
|
769
|
+
};
|
770
|
+
|
771
|
+
$scope.$watch(function () {
|
772
|
+
return angular.isDefined(ctrl.lockChoiceExpression) && ctrl.lockChoiceExpression !== "";
|
773
|
+
}, _initaliseLockedChoices);
|
774
|
+
|
775
|
+
function _initaliseLockedChoices(doInitalise) {
|
776
|
+
if(!doInitalise) return;
|
777
|
+
|
778
|
+
var lockedItems = [];
|
779
|
+
|
780
|
+
function _updateItemLocked(item, isLocked) {
|
781
|
+
var lockedItemIndex = lockedItems.indexOf(item);
|
782
|
+
if (isLocked && lockedItemIndex === -1) {
|
783
|
+
lockedItems.push(item);
|
784
|
+
}
|
582
785
|
|
583
|
-
if (
|
584
|
-
|
585
|
-
|
786
|
+
if (!isLocked && lockedItemIndex > -1) {
|
787
|
+
lockedItems.splice(lockedItemIndex, 0);
|
788
|
+
}
|
789
|
+
}
|
790
|
+
|
791
|
+
function _isItemlocked(item) {
|
792
|
+
return lockedItems.indexOf(item) > -1;
|
793
|
+
}
|
794
|
+
|
795
|
+
ctrl.isLocked = function (itemScope, itemIndex) {
|
796
|
+
var isLocked = false,
|
797
|
+
item = ctrl.selected[itemIndex];
|
798
|
+
|
799
|
+
if(item) {
|
800
|
+
if (itemScope) {
|
801
|
+
isLocked = !!(itemScope.$eval(ctrl.lockChoiceExpression));
|
802
|
+
_updateItemLocked(item, isLocked);
|
803
|
+
} else {
|
804
|
+
isLocked = _isItemlocked(item);
|
805
|
+
}
|
586
806
|
}
|
587
807
|
|
588
808
|
return isLocked;
|
589
|
-
|
809
|
+
};
|
810
|
+
}
|
811
|
+
|
590
812
|
|
591
813
|
var sizeWatch = null;
|
814
|
+
var updaterScheduled = false;
|
592
815
|
ctrl.sizeSearchInput = function() {
|
593
816
|
|
594
817
|
var input = ctrl.searchInput[0],
|
@@ -610,12 +833,18 @@ uis.controller('uiSelectCtrl',
|
|
610
833
|
ctrl.searchInput.css('width', '10px');
|
611
834
|
$timeout(function() { //Give tags time to render correctly
|
612
835
|
if (sizeWatch === null && !updateIfVisible(calculateContainerWidth())) {
|
613
|
-
sizeWatch = $scope.$watch(
|
614
|
-
if (
|
615
|
-
|
616
|
-
|
836
|
+
sizeWatch = $scope.$watch(function() {
|
837
|
+
if (!updaterScheduled) {
|
838
|
+
updaterScheduled = true;
|
839
|
+
$scope.$$postDigest(function() {
|
840
|
+
updaterScheduled = false;
|
841
|
+
if (updateIfVisible(calculateContainerWidth())) {
|
842
|
+
sizeWatch();
|
843
|
+
sizeWatch = null;
|
844
|
+
}
|
845
|
+
});
|
617
846
|
}
|
618
|
-
});
|
847
|
+
}, angular.noop);
|
619
848
|
}
|
620
849
|
});
|
621
850
|
};
|
@@ -636,7 +865,7 @@ uis.controller('uiSelectCtrl',
|
|
636
865
|
break;
|
637
866
|
case KEY.ENTER:
|
638
867
|
if(ctrl.open && (ctrl.tagging.isActivated || ctrl.activeIndex >= 0)){
|
639
|
-
ctrl.select(ctrl.items[ctrl.activeIndex]); // Make sure at least one dropdown item is highlighted before adding if not in tagging mode
|
868
|
+
ctrl.select(ctrl.items[ctrl.activeIndex], ctrl.skipFocusser); // Make sure at least one dropdown item is highlighted before adding if not in tagging mode
|
640
869
|
} else {
|
641
870
|
ctrl.activate(false, true); //In case its the search input in 'multiple' mode
|
642
871
|
}
|
@@ -655,6 +884,11 @@ uis.controller('uiSelectCtrl',
|
|
655
884
|
|
656
885
|
var key = e.which;
|
657
886
|
|
887
|
+
if (~[KEY.ENTER,KEY.ESC].indexOf(key)){
|
888
|
+
e.preventDefault();
|
889
|
+
e.stopPropagation();
|
890
|
+
}
|
891
|
+
|
658
892
|
// if(~[KEY.ESC,KEY.TAB].indexOf(key)){
|
659
893
|
// //TODO: SEGURO?
|
660
894
|
// ctrl.close();
|
@@ -701,18 +935,45 @@ uis.controller('uiSelectCtrl',
|
|
701
935
|
|
702
936
|
});
|
703
937
|
|
704
|
-
// If tagging try to split by tokens and add items
|
705
938
|
ctrl.searchInput.on('paste', function (e) {
|
706
|
-
var data
|
707
|
-
|
708
|
-
|
709
|
-
|
939
|
+
var data;
|
940
|
+
|
941
|
+
if (window.clipboardData && window.clipboardData.getData) { // IE
|
942
|
+
data = window.clipboardData.getData('Text');
|
943
|
+
} else {
|
944
|
+
data = (e.originalEvent || e).clipboardData.getData('text/plain');
|
945
|
+
}
|
946
|
+
|
947
|
+
// Prepend the current input field text to the paste buffer.
|
948
|
+
data = ctrl.search + data;
|
949
|
+
|
950
|
+
if (data && data.length > 0) {
|
951
|
+
// If tagging try to split by tokens and add items
|
952
|
+
if (ctrl.taggingTokens.isActivated) {
|
953
|
+
var items = [];
|
954
|
+
for (var i = 0; i < ctrl.taggingTokens.tokens.length; i++) { // split by first token that is contained in data
|
955
|
+
var separator = KEY.toSeparator(ctrl.taggingTokens.tokens[i]) || ctrl.taggingTokens.tokens[i];
|
956
|
+
if (data.indexOf(separator) > -1) {
|
957
|
+
items = data.split(separator);
|
958
|
+
break; // only split by one token
|
959
|
+
}
|
960
|
+
}
|
961
|
+
if (items.length === 0) {
|
962
|
+
items = [data];
|
963
|
+
}
|
964
|
+
var oldsearch = ctrl.search;
|
710
965
|
angular.forEach(items, function (item) {
|
711
|
-
var newItem = ctrl.tagging.fct(item);
|
966
|
+
var newItem = ctrl.tagging.fct ? ctrl.tagging.fct(item) : item;
|
712
967
|
if (newItem) {
|
713
968
|
ctrl.select(newItem, true);
|
714
969
|
}
|
715
970
|
});
|
971
|
+
ctrl.search = oldsearch || EMPTY_SEARCH;
|
972
|
+
e.preventDefault();
|
973
|
+
e.stopPropagation();
|
974
|
+
} else if (ctrl.paste) {
|
975
|
+
ctrl.paste(data);
|
976
|
+
ctrl.search = EMPTY_SEARCH;
|
716
977
|
e.preventDefault();
|
717
978
|
e.stopPropagation();
|
718
979
|
}
|
@@ -751,10 +1012,16 @@ uis.controller('uiSelectCtrl',
|
|
751
1012
|
}
|
752
1013
|
}
|
753
1014
|
|
1015
|
+
var onResize = $$uisDebounce(function() {
|
1016
|
+
ctrl.sizeSearchInput();
|
1017
|
+
}, 50);
|
1018
|
+
|
1019
|
+
angular.element($window).bind('resize', onResize);
|
1020
|
+
|
754
1021
|
$scope.$on('$destroy', function() {
|
755
1022
|
ctrl.searchInput.off('keyup keydown tagged blur paste');
|
1023
|
+
angular.element($window).off('resize', onResize);
|
756
1024
|
});
|
757
|
-
|
758
1025
|
}]);
|
759
1026
|
|
760
1027
|
uis.directive('uiSelect',
|
@@ -776,11 +1043,22 @@ uis.directive('uiSelect',
|
|
776
1043
|
controllerAs: '$select',
|
777
1044
|
compile: function(tElement, tAttrs) {
|
778
1045
|
|
1046
|
+
// Allow setting ngClass on uiSelect
|
1047
|
+
var match = /{(.*)}\s*{(.*)}/.exec(tAttrs.ngClass);
|
1048
|
+
if(match) {
|
1049
|
+
var combined = '{'+ match[1] +', '+ match[2] +'}';
|
1050
|
+
tAttrs.ngClass = combined;
|
1051
|
+
tElement.attr('ng-class', combined);
|
1052
|
+
}
|
1053
|
+
|
779
1054
|
//Multiple or Single depending if multiple attribute presence
|
780
1055
|
if (angular.isDefined(tAttrs.multiple))
|
781
|
-
tElement.append(
|
1056
|
+
tElement.append('<ui-select-multiple/>').removeAttr('multiple');
|
782
1057
|
else
|
783
|
-
tElement.append(
|
1058
|
+
tElement.append('<ui-select-single/>');
|
1059
|
+
|
1060
|
+
if (tAttrs.inputId)
|
1061
|
+
tElement.querySelectorAll('input.ui-select-search')[0].id = tAttrs.inputId;
|
784
1062
|
|
785
1063
|
return function(scope, element, attrs, ctrls, transcludeFn) {
|
786
1064
|
|
@@ -800,9 +1078,14 @@ uis.directive('uiSelect',
|
|
800
1078
|
}
|
801
1079
|
}();
|
802
1080
|
|
1081
|
+
scope.$watch('skipFocusser', function() {
|
1082
|
+
var skipFocusser = scope.$eval(attrs.skipFocusser);
|
1083
|
+
$select.skipFocusser = skipFocusser !== undefined ? skipFocusser : uiSelectConfig.skipFocusser;
|
1084
|
+
});
|
1085
|
+
|
803
1086
|
$select.onSelectCallback = $parse(attrs.onSelect);
|
804
1087
|
$select.onRemoveCallback = $parse(attrs.onRemove);
|
805
|
-
|
1088
|
+
|
806
1089
|
//Set reference to ngModel from uiSelectCtrl
|
807
1090
|
$select.ngModel = ngModel;
|
808
1091
|
|
@@ -812,14 +1095,13 @@ uis.directive('uiSelect',
|
|
812
1095
|
|
813
1096
|
if(attrs.tabindex){
|
814
1097
|
attrs.$observe('tabindex', function(value) {
|
815
|
-
$select.focusInput.attr(
|
816
|
-
element.removeAttr(
|
1098
|
+
$select.focusInput.attr('tabindex', value);
|
1099
|
+
element.removeAttr('tabindex');
|
817
1100
|
});
|
818
1101
|
}
|
819
1102
|
|
820
|
-
scope.$watch(
|
821
|
-
|
822
|
-
$select.searchEnabled = searchEnabled !== undefined ? searchEnabled : uiSelectConfig.searchEnabled;
|
1103
|
+
scope.$watch(function () { return scope.$eval(attrs.searchEnabled); }, function(newVal) {
|
1104
|
+
$select.searchEnabled = newVal !== undefined ? newVal : uiSelectConfig.searchEnabled;
|
823
1105
|
});
|
824
1106
|
|
825
1107
|
scope.$watch('sortable', function() {
|
@@ -827,6 +1109,16 @@ uis.directive('uiSelect',
|
|
827
1109
|
$select.sortable = sortable !== undefined ? sortable : uiSelectConfig.sortable;
|
828
1110
|
});
|
829
1111
|
|
1112
|
+
attrs.$observe('limit', function() {
|
1113
|
+
//Limit the number of selections allowed
|
1114
|
+
$select.limit = (angular.isDefined(attrs.limit)) ? parseInt(attrs.limit, 10) : undefined;
|
1115
|
+
});
|
1116
|
+
|
1117
|
+
scope.$watch('removeSelected', function() {
|
1118
|
+
var removeSelected = scope.$eval(attrs.removeSelected);
|
1119
|
+
$select.removeSelected = removeSelected !== undefined ? removeSelected : uiSelectConfig.removeSelected;
|
1120
|
+
});
|
1121
|
+
|
830
1122
|
attrs.$observe('disabled', function() {
|
831
1123
|
// No need to use $eval() (thanks to ng-disabled) since we already get a boolean instead of a string
|
832
1124
|
$select.disabled = attrs.disabled !== undefined ? attrs.disabled : false;
|
@@ -838,6 +1130,10 @@ uis.directive('uiSelect',
|
|
838
1130
|
$select.resetSearchInput = resetSearchInput !== undefined ? resetSearchInput : true;
|
839
1131
|
});
|
840
1132
|
|
1133
|
+
attrs.$observe('paste', function() {
|
1134
|
+
$select.paste = scope.$eval(attrs.paste);
|
1135
|
+
});
|
1136
|
+
|
841
1137
|
attrs.$observe('tagging', function() {
|
842
1138
|
if(attrs.tagging !== undefined)
|
843
1139
|
{
|
@@ -903,11 +1199,16 @@ uis.directive('uiSelect',
|
|
903
1199
|
}
|
904
1200
|
|
905
1201
|
if (!contains && !$select.clickTriggeredSelect) {
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
1202
|
+
var skipFocusser;
|
1203
|
+
if (!$select.skipFocusser) {
|
1204
|
+
//Will lose focus only with certain targets
|
1205
|
+
var focusableControls = ['input','button','textarea','select'];
|
1206
|
+
var targetController = angular.element(e.target).controller('uiSelect'); //To check if target is other ui-select
|
1207
|
+
skipFocusser = targetController && targetController !== $select; //To check if target is other ui-select
|
1208
|
+
if (!skipFocusser) skipFocusser = ~focusableControls.indexOf(e.target.tagName.toLowerCase()); //Check if target is input, button or textarea
|
1209
|
+
} else {
|
1210
|
+
skipFocusser = true;
|
1211
|
+
}
|
911
1212
|
$select.close(skipFocusser);
|
912
1213
|
scope.$digest();
|
913
1214
|
}
|
@@ -945,6 +1246,13 @@ uis.directive('uiSelect',
|
|
945
1246
|
throw uiSelectMinErr('transcluded', "Expected 1 .ui-select-choices but got '{0}'.", transcludedChoices.length);
|
946
1247
|
}
|
947
1248
|
element.querySelectorAll('.ui-select-choices').replaceWith(transcludedChoices);
|
1249
|
+
|
1250
|
+
var transcludedNoChoice = transcluded.querySelectorAll('.ui-select-no-choice');
|
1251
|
+
transcludedNoChoice.removeAttr('ui-select-no-choice'); //To avoid loop in case directive as attr
|
1252
|
+
transcludedNoChoice.removeAttr('data-ui-select-no-choice'); // Properly handle HTML5 data-attributes
|
1253
|
+
if (transcludedNoChoice.length == 1) {
|
1254
|
+
element.querySelectorAll('.ui-select-no-choice').replaceWith(transcludedNoChoice);
|
1255
|
+
}
|
948
1256
|
});
|
949
1257
|
|
950
1258
|
// Support for appending the select field to the body when its open
|
@@ -1006,6 +1314,9 @@ uis.directive('uiSelect',
|
|
1006
1314
|
element[0].style.left = '';
|
1007
1315
|
element[0].style.top = '';
|
1008
1316
|
element[0].style.width = originalWidth;
|
1317
|
+
|
1318
|
+
// Set focus back on to the moved element
|
1319
|
+
$select.setFocus();
|
1009
1320
|
}
|
1010
1321
|
|
1011
1322
|
// Hold on to a reference to the .ui-select-dropdown element for direction support.
|
@@ -1013,42 +1324,103 @@ uis.directive('uiSelect',
|
|
1013
1324
|
directionUpClassName = 'direction-up';
|
1014
1325
|
|
1015
1326
|
// Support changing the direction of the dropdown if there isn't enough space to render it.
|
1016
|
-
scope.$watch('$select.open', function(
|
1017
|
-
if (isOpen) {
|
1018
|
-
dropdown = angular.element(element).querySelectorAll('.ui-select-dropdown');
|
1019
|
-
if (dropdown === null) {
|
1020
|
-
return;
|
1021
|
-
}
|
1327
|
+
scope.$watch('$select.open', function() {
|
1022
1328
|
|
1023
|
-
|
1024
|
-
|
1329
|
+
if ($select.dropdownPosition === 'auto' || $select.dropdownPosition === 'up'){
|
1330
|
+
scope.calculateDropdownPos();
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
});
|
1334
|
+
|
1335
|
+
var setDropdownPosUp = function(offset, offsetDropdown){
|
1336
|
+
|
1337
|
+
offset = offset || uisOffset(element);
|
1338
|
+
offsetDropdown = offsetDropdown || uisOffset(dropdown);
|
1339
|
+
|
1340
|
+
dropdown[0].style.position = 'absolute';
|
1341
|
+
dropdown[0].style.top = (offsetDropdown.height * -1) + 'px';
|
1342
|
+
element.addClass(directionUpClassName);
|
1343
|
+
|
1344
|
+
};
|
1345
|
+
|
1346
|
+
var setDropdownPosDown = function(offset, offsetDropdown){
|
1347
|
+
|
1348
|
+
element.removeClass(directionUpClassName);
|
1349
|
+
|
1350
|
+
offset = offset || uisOffset(element);
|
1351
|
+
offsetDropdown = offsetDropdown || uisOffset(dropdown);
|
1352
|
+
|
1353
|
+
dropdown[0].style.position = '';
|
1354
|
+
dropdown[0].style.top = '';
|
1355
|
+
|
1356
|
+
};
|
1357
|
+
|
1358
|
+
var calculateDropdownPosAfterAnimation = function() {
|
1359
|
+
// Delay positioning the dropdown until all choices have been added so its height is correct.
|
1360
|
+
$timeout(function() {
|
1361
|
+
if ($select.dropdownPosition === 'up') {
|
1362
|
+
//Go UP
|
1363
|
+
setDropdownPosUp();
|
1364
|
+
} else {
|
1365
|
+
//AUTO
|
1366
|
+
element.removeClass(directionUpClassName);
|
1025
1367
|
|
1026
|
-
// Delay positioning the dropdown until all choices have been added so its height is correct.
|
1027
|
-
$timeout(function(){
|
1028
1368
|
var offset = uisOffset(element);
|
1029
1369
|
var offsetDropdown = uisOffset(dropdown);
|
1030
1370
|
|
1371
|
+
//https://code.google.com/p/chromium/issues/detail?id=342307#c4
|
1372
|
+
var scrollTop = $document[0].documentElement.scrollTop || $document[0].body.scrollTop; //To make it cross browser (blink, webkit, IE, Firefox).
|
1373
|
+
|
1031
1374
|
// Determine if the direction of the dropdown needs to be changed.
|
1032
|
-
if (offset.top + offset.height + offsetDropdown.height >
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1375
|
+
if (offset.top + offset.height + offsetDropdown.height > scrollTop + $document[0].documentElement.clientHeight) {
|
1376
|
+
//Go UP
|
1377
|
+
setDropdownPosUp(offset, offsetDropdown);
|
1378
|
+
}else{
|
1379
|
+
//Go DOWN
|
1380
|
+
setDropdownPosDown(offset, offsetDropdown);
|
1036
1381
|
}
|
1382
|
+
}
|
1037
1383
|
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1384
|
+
// Display the dropdown once it has been positioned.
|
1385
|
+
dropdown[0].style.opacity = 1;
|
1386
|
+
});
|
1387
|
+
};
|
1388
|
+
|
1389
|
+
scope.calculateDropdownPos = function() {
|
1390
|
+
if ($select.open) {
|
1391
|
+
dropdown = angular.element(element).querySelectorAll('.ui-select-dropdown');
|
1392
|
+
|
1393
|
+
if (dropdown.length === 0) {
|
1394
|
+
return;
|
1395
|
+
}
|
1396
|
+
|
1397
|
+
// Hide the dropdown so there is no flicker until $timeout is done executing.
|
1398
|
+
dropdown[0].style.opacity = 0;
|
1399
|
+
|
1400
|
+
if (!uisOffset(dropdown).height && $select.$animate && $select.$animate.on && $select.$animate.enabled(dropdown)) {
|
1401
|
+
var needsCalculated = true;
|
1402
|
+
|
1403
|
+
$select.$animate.on('enter', dropdown, function (elem, phase) {
|
1404
|
+
if (phase === 'close' && needsCalculated) {
|
1405
|
+
calculateDropdownPosAfterAnimation();
|
1406
|
+
needsCalculated = false;
|
1407
|
+
}
|
1408
|
+
});
|
1409
|
+
} else {
|
1410
|
+
calculateDropdownPosAfterAnimation();
|
1411
|
+
}
|
1041
1412
|
} else {
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1413
|
+
if (dropdown === null || dropdown.length === 0) {
|
1414
|
+
return;
|
1415
|
+
}
|
1045
1416
|
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1417
|
+
// Reset the position of the dropdown.
|
1418
|
+
dropdown[0].style.opacity = 0;
|
1419
|
+
dropdown[0].style.position = '';
|
1420
|
+
dropdown[0].style.top = '';
|
1421
|
+
element.removeClass(directionUpClassName);
|
1050
1422
|
}
|
1051
|
-
}
|
1423
|
+
};
|
1052
1424
|
};
|
1053
1425
|
}
|
1054
1426
|
};
|
@@ -1061,10 +1433,15 @@ uis.directive('uiSelectMatch', ['uiSelectConfig', function(uiSelectConfig) {
|
|
1061
1433
|
replace: true,
|
1062
1434
|
transclude: true,
|
1063
1435
|
templateUrl: function(tElement) {
|
1436
|
+
// Needed so the uiSelect can detect the transcluded content
|
1437
|
+
tElement.addClass('ui-select-match');
|
1438
|
+
|
1439
|
+
var parent = tElement.parent();
|
1064
1440
|
// Gets theme attribute from parent (ui-select)
|
1065
|
-
var theme =
|
1066
|
-
var multi =
|
1067
|
-
|
1441
|
+
var theme = getAttribute(parent, 'theme') || uiSelectConfig.theme;
|
1442
|
+
var multi = angular.isDefined(getAttribute(parent, 'multiple'));
|
1443
|
+
|
1444
|
+
return theme + (multi ? '/match-multiple.tpl.html' : '/match.tpl.html');
|
1068
1445
|
},
|
1069
1446
|
link: function(scope, element, attrs, $select) {
|
1070
1447
|
$select.lockChoiceExpression = attrs.uiLockChoice;
|
@@ -1085,6 +1462,17 @@ uis.directive('uiSelectMatch', ['uiSelectConfig', function(uiSelectConfig) {
|
|
1085
1462
|
|
1086
1463
|
}
|
1087
1464
|
};
|
1465
|
+
|
1466
|
+
function getAttribute(elem, attribute) {
|
1467
|
+
if (elem[0].hasAttribute(attribute))
|
1468
|
+
return elem.attr(attribute);
|
1469
|
+
|
1470
|
+
if (elem[0].hasAttribute('data-' + attribute))
|
1471
|
+
return elem.attr('data-' + attribute);
|
1472
|
+
|
1473
|
+
if (elem[0].hasAttribute('x-' + attribute))
|
1474
|
+
return elem.attr('x-' + attribute);
|
1475
|
+
}
|
1088
1476
|
}]);
|
1089
1477
|
|
1090
1478
|
uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelectMinErr, $timeout) {
|
@@ -1098,7 +1486,10 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1098
1486
|
$select = $scope.$select,
|
1099
1487
|
ngModel;
|
1100
1488
|
|
1101
|
-
|
1489
|
+
if (angular.isUndefined($select.selected))
|
1490
|
+
$select.selected = [];
|
1491
|
+
|
1492
|
+
//Wait for link fn to inject it
|
1102
1493
|
$scope.$evalAsync(function(){ ngModel = $scope.ngModel; });
|
1103
1494
|
|
1104
1495
|
ctrl.activeMatchIndex = -1;
|
@@ -1110,19 +1501,23 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1110
1501
|
|
1111
1502
|
ctrl.refreshComponent = function(){
|
1112
1503
|
//Remove already selected items
|
1113
|
-
//e.g. When user clicks on a selection, the selected array changes and
|
1504
|
+
//e.g. When user clicks on a selection, the selected array changes and
|
1114
1505
|
//the dropdown should remove that item
|
1115
|
-
$select.refreshItems
|
1116
|
-
|
1506
|
+
if($select.refreshItems){
|
1507
|
+
$select.refreshItems();
|
1508
|
+
}
|
1509
|
+
if($select.sizeSearchInput){
|
1510
|
+
$select.sizeSearchInput();
|
1511
|
+
}
|
1117
1512
|
};
|
1118
1513
|
|
1119
1514
|
// Remove item from multiple select
|
1120
1515
|
ctrl.removeChoice = function(index){
|
1121
1516
|
|
1122
|
-
|
1517
|
+
// if the choice is locked, don't remove it
|
1518
|
+
if($select.isLocked(null, index)) return false;
|
1123
1519
|
|
1124
|
-
|
1125
|
-
if(removedChoice._uiSelectChoiceLocked) return;
|
1520
|
+
var removedChoice = $select.selected[index];
|
1126
1521
|
|
1127
1522
|
var locals = {};
|
1128
1523
|
locals[$select.parserResult.itemName] = removedChoice;
|
@@ -1141,11 +1536,12 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1141
1536
|
|
1142
1537
|
ctrl.updateModel();
|
1143
1538
|
|
1539
|
+
return true;
|
1144
1540
|
};
|
1145
1541
|
|
1146
1542
|
ctrl.getPlaceholder = function(){
|
1147
1543
|
//Refactor single?
|
1148
|
-
if($select.selected.length) return;
|
1544
|
+
if($select.selected && $select.selected.length) return;
|
1149
1545
|
return $select.placeholder;
|
1150
1546
|
};
|
1151
1547
|
|
@@ -1162,11 +1558,15 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1162
1558
|
//$select.selected = raw selected objects (ignoring any property binding)
|
1163
1559
|
|
1164
1560
|
$select.multiple = true;
|
1165
|
-
$select.removeSelected = true;
|
1166
1561
|
|
1167
1562
|
//Input that will handle focus
|
1168
1563
|
$select.focusInput = $select.searchInput;
|
1169
1564
|
|
1565
|
+
//Properly check for empty if set to multiple
|
1566
|
+
ngModel.$isEmpty = function(value) {
|
1567
|
+
return !value || value.length === 0;
|
1568
|
+
};
|
1569
|
+
|
1170
1570
|
//From view --> model
|
1171
1571
|
ngModel.$parsers.unshift(function () {
|
1172
1572
|
var locals = {},
|
@@ -1183,7 +1583,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1183
1583
|
|
1184
1584
|
// From model --> view
|
1185
1585
|
ngModel.$formatters.unshift(function (inputValue) {
|
1186
|
-
var data = $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
|
1586
|
+
var data = $select.parserResult && $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
|
1187
1587
|
locals = {},
|
1188
1588
|
result;
|
1189
1589
|
if (!data) return inputValue;
|
@@ -1194,10 +1594,13 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1194
1594
|
locals[$select.parserResult.itemName] = list[p];
|
1195
1595
|
result = $select.parserResult.modelMapper(scope, locals);
|
1196
1596
|
if($select.parserResult.trackByExp){
|
1197
|
-
var
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1597
|
+
var propsItemNameMatches = /(\w*)\./.exec($select.parserResult.trackByExp);
|
1598
|
+
var matches = /\.([^\s]+)/.exec($select.parserResult.trackByExp);
|
1599
|
+
if(propsItemNameMatches && propsItemNameMatches.length > 0 && propsItemNameMatches[1] == $select.parserResult.itemName){
|
1600
|
+
if(matches && matches.length>0 && result[matches[1]] == value[matches[1]]){
|
1601
|
+
resultMultiple.unshift(list[p]);
|
1602
|
+
return true;
|
1603
|
+
}
|
1201
1604
|
}
|
1202
1605
|
}
|
1203
1606
|
if (angular.equals(result,value)){
|
@@ -1209,7 +1612,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1209
1612
|
};
|
1210
1613
|
if (!inputValue) return resultMultiple; //If ngModel was undefined
|
1211
1614
|
for (var k = inputValue.length - 1; k >= 0; k--) {
|
1212
|
-
//Check model array of currently selected items
|
1615
|
+
//Check model array of currently selected items
|
1213
1616
|
if (!checkFnMultiple($select.selected, inputValue[k])){
|
1214
1617
|
//Check model array of all items available
|
1215
1618
|
if (!checkFnMultiple(data, inputValue[k])){
|
@@ -1220,11 +1623,14 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1220
1623
|
}
|
1221
1624
|
return resultMultiple;
|
1222
1625
|
});
|
1223
|
-
|
1224
|
-
//Watch for external model changes
|
1626
|
+
|
1627
|
+
//Watch for external model changes
|
1225
1628
|
scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) {
|
1226
1629
|
if (oldValue != newValue){
|
1227
|
-
|
1630
|
+
//update the view value with fresh data from items, if there is a valid model value
|
1631
|
+
if(angular.isDefined(ngModel.$modelValue)) {
|
1632
|
+
ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
|
1633
|
+
}
|
1228
1634
|
$selectMultiple.refreshComponent();
|
1229
1635
|
}
|
1230
1636
|
});
|
@@ -1234,16 +1640,20 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1234
1640
|
if(!angular.isArray(ngModel.$viewValue)){
|
1235
1641
|
// Have tolerance for null or undefined values
|
1236
1642
|
if(angular.isUndefined(ngModel.$viewValue) || ngModel.$viewValue === null){
|
1237
|
-
|
1643
|
+
ngModel.$viewValue = [];
|
1238
1644
|
} else {
|
1239
1645
|
throw uiSelectMinErr('multiarr', "Expected model value to be array but got '{0}'", ngModel.$viewValue);
|
1240
1646
|
}
|
1241
1647
|
}
|
1242
1648
|
$select.selected = ngModel.$viewValue;
|
1649
|
+
$selectMultiple.refreshComponent();
|
1243
1650
|
scope.$evalAsync(); //To force $digest
|
1244
1651
|
};
|
1245
1652
|
|
1246
1653
|
scope.$on('uis:select', function (event, item) {
|
1654
|
+
if($select.selected.length >= $select.limit) {
|
1655
|
+
return;
|
1656
|
+
}
|
1247
1657
|
$select.selected.push(item);
|
1248
1658
|
$selectMultiple.updateModel();
|
1249
1659
|
});
|
@@ -1314,11 +1724,16 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1314
1724
|
case KEY.BACKSPACE:
|
1315
1725
|
// Remove selected item and select previous/first
|
1316
1726
|
if(~$selectMultiple.activeMatchIndex){
|
1317
|
-
$selectMultiple.removeChoice(curr)
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1727
|
+
if($selectMultiple.removeChoice(curr)) {
|
1728
|
+
return prev;
|
1729
|
+
} else {
|
1730
|
+
return curr;
|
1731
|
+
}
|
1732
|
+
|
1733
|
+
} else {
|
1734
|
+
// If nothing yet selected, select last item
|
1735
|
+
return last;
|
1736
|
+
}
|
1322
1737
|
break;
|
1323
1738
|
case KEY.DELETE:
|
1324
1739
|
// Remove selected item and select next item
|
@@ -1379,12 +1794,22 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1379
1794
|
stashArr = stashArr.slice(1,stashArr.length);
|
1380
1795
|
}
|
1381
1796
|
newItem = $select.tagging.fct($select.search);
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1797
|
+
// verify the new tag doesn't match the value of a possible selection choice or an already selected item.
|
1798
|
+
if (
|
1799
|
+
stashArr.some(function (origItem) {
|
1800
|
+
return angular.equals(origItem, newItem);
|
1801
|
+
}) ||
|
1802
|
+
$select.selected.some(function (origItem) {
|
1803
|
+
return angular.equals(origItem, newItem);
|
1804
|
+
})
|
1805
|
+
) {
|
1806
|
+
scope.$evalAsync(function () {
|
1807
|
+
$select.activeIndex = 0;
|
1808
|
+
$select.items = items;
|
1809
|
+
});
|
1385
1810
|
return;
|
1386
1811
|
}
|
1387
|
-
newItem.isTag = true;
|
1812
|
+
if (newItem) newItem.isTag = true;
|
1388
1813
|
// handle newItem string and stripping dupes in tagging string context
|
1389
1814
|
} else {
|
1390
1815
|
// find any tagging items already in the $select.items array and store them
|
@@ -1433,12 +1858,23 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1433
1858
|
items = items.slice(dupeIndex+1,items.length-1);
|
1434
1859
|
} else {
|
1435
1860
|
items = [];
|
1436
|
-
items.push(newItem);
|
1861
|
+
if (newItem) items.push(newItem);
|
1437
1862
|
items = items.concat(stashArr);
|
1438
1863
|
}
|
1439
1864
|
scope.$evalAsync( function () {
|
1440
1865
|
$select.activeIndex = 0;
|
1441
1866
|
$select.items = items;
|
1867
|
+
|
1868
|
+
if ($select.isGrouped) {
|
1869
|
+
// update item references in groups, so that indexOf will work after angular.copy
|
1870
|
+
var itemsWithoutTag = newItem ? items.slice(1) : items;
|
1871
|
+
$select.setItemsFn(itemsWithoutTag);
|
1872
|
+
if (newItem) {
|
1873
|
+
// add tag item as a new group
|
1874
|
+
$select.items.unshift(newItem);
|
1875
|
+
$select.groups.unshift({name: '', items: [newItem], tagging: true});
|
1876
|
+
}
|
1877
|
+
}
|
1442
1878
|
});
|
1443
1879
|
}
|
1444
1880
|
});
|
@@ -1469,9 +1905,11 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1469
1905
|
// handle the object tagging implementation
|
1470
1906
|
} else {
|
1471
1907
|
var mockObj = tempArr[i];
|
1472
|
-
mockObj
|
1908
|
+
if (angular.isObject(mockObj)) {
|
1909
|
+
mockObj.isTag = true;
|
1910
|
+
}
|
1473
1911
|
if ( angular.equals(mockObj, needle) ) {
|
1474
|
-
|
1912
|
+
dupeIndex = i;
|
1475
1913
|
}
|
1476
1914
|
}
|
1477
1915
|
}
|
@@ -1488,6 +1926,25 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
|
|
1488
1926
|
}
|
1489
1927
|
};
|
1490
1928
|
}]);
|
1929
|
+
|
1930
|
+
uis.directive('uiSelectNoChoice',
|
1931
|
+
['uiSelectConfig', function (uiSelectConfig) {
|
1932
|
+
return {
|
1933
|
+
restrict: 'EA',
|
1934
|
+
require: '^uiSelect',
|
1935
|
+
replace: true,
|
1936
|
+
transclude: true,
|
1937
|
+
templateUrl: function (tElement) {
|
1938
|
+
// Needed so the uiSelect can detect the transcluded content
|
1939
|
+
tElement.addClass('ui-select-no-choice');
|
1940
|
+
|
1941
|
+
// Gets theme attribute from parent (ui-select)
|
1942
|
+
var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
|
1943
|
+
return theme + '/no-choice.tpl.html';
|
1944
|
+
}
|
1945
|
+
};
|
1946
|
+
}]);
|
1947
|
+
|
1491
1948
|
uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $compile) {
|
1492
1949
|
return {
|
1493
1950
|
restrict: 'EA',
|
@@ -1508,14 +1965,14 @@ uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $comp
|
|
1508
1965
|
|
1509
1966
|
//From model --> view
|
1510
1967
|
ngModel.$formatters.unshift(function (inputValue) {
|
1511
|
-
var data = $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
|
1968
|
+
var data = $select.parserResult && $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
|
1512
1969
|
locals = {},
|
1513
1970
|
result;
|
1514
1971
|
if (data){
|
1515
1972
|
var checkFnSingle = function(d){
|
1516
1973
|
locals[$select.parserResult.itemName] = d;
|
1517
1974
|
result = $select.parserResult.modelMapper(scope, locals);
|
1518
|
-
return result
|
1975
|
+
return result === inputValue;
|
1519
1976
|
};
|
1520
1977
|
//If possible pass same object stored in $select.selected
|
1521
1978
|
if ($select.selected && checkFnSingle($select.selected)) {
|
@@ -1612,44 +2069,48 @@ uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $comp
|
|
1612
2069
|
}
|
1613
2070
|
};
|
1614
2071
|
}]);
|
2072
|
+
|
1615
2073
|
// Make multiple matches sortable
|
1616
2074
|
uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', function($timeout, uiSelectConfig, uiSelectMinErr) {
|
1617
2075
|
return {
|
1618
|
-
require: '
|
1619
|
-
link: function(scope, element, attrs,
|
2076
|
+
require: ['^^uiSelect', '^ngModel'],
|
2077
|
+
link: function(scope, element, attrs, ctrls) {
|
1620
2078
|
if (scope[attrs.uiSelectSort] === null) {
|
1621
|
-
throw uiSelectMinErr('sort',
|
2079
|
+
throw uiSelectMinErr('sort', 'Expected a list to sort');
|
1622
2080
|
}
|
1623
2081
|
|
2082
|
+
var $select = ctrls[0];
|
2083
|
+
var $ngModel = ctrls[1];
|
2084
|
+
|
1624
2085
|
var options = angular.extend({
|
1625
2086
|
axis: 'horizontal'
|
1626
2087
|
},
|
1627
2088
|
scope.$eval(attrs.uiSelectSortOptions));
|
1628
2089
|
|
1629
|
-
var axis = options.axis
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
2090
|
+
var axis = options.axis;
|
2091
|
+
var draggingClassName = 'dragging';
|
2092
|
+
var droppingClassName = 'dropping';
|
2093
|
+
var droppingBeforeClassName = 'dropping-before';
|
2094
|
+
var droppingAfterClassName = 'dropping-after';
|
1634
2095
|
|
1635
2096
|
scope.$watch(function(){
|
1636
2097
|
return $select.sortable;
|
1637
|
-
}, function(
|
1638
|
-
if (
|
2098
|
+
}, function(newValue){
|
2099
|
+
if (newValue) {
|
1639
2100
|
element.attr('draggable', true);
|
1640
2101
|
} else {
|
1641
2102
|
element.removeAttr('draggable');
|
1642
2103
|
}
|
1643
2104
|
});
|
1644
2105
|
|
1645
|
-
element.on('dragstart', function(
|
2106
|
+
element.on('dragstart', function(event) {
|
1646
2107
|
element.addClass(draggingClassName);
|
1647
2108
|
|
1648
|
-
(
|
2109
|
+
(event.dataTransfer || event.originalEvent.dataTransfer).setData('text', scope.$index.toString());
|
1649
2110
|
});
|
1650
2111
|
|
1651
2112
|
element.on('dragend', function() {
|
1652
|
-
|
2113
|
+
removeClass(draggingClassName);
|
1653
2114
|
});
|
1654
2115
|
|
1655
2116
|
var move = function(from, to) {
|
@@ -1657,27 +2118,33 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
|
|
1657
2118
|
this.splice(to, 0, this.splice(from, 1)[0]);
|
1658
2119
|
};
|
1659
2120
|
|
1660
|
-
var
|
1661
|
-
|
2121
|
+
var removeClass = function(className) {
|
2122
|
+
angular.forEach($select.$element.querySelectorAll('.' + className), function(el){
|
2123
|
+
angular.element(el).removeClass(className);
|
2124
|
+
});
|
2125
|
+
};
|
1662
2126
|
|
1663
|
-
|
2127
|
+
var dragOverHandler = function(event) {
|
2128
|
+
event.preventDefault();
|
2129
|
+
|
2130
|
+
var offset = axis === 'vertical' ? event.offsetY || event.layerY || (event.originalEvent ? event.originalEvent.offsetY : 0) : event.offsetX || event.layerX || (event.originalEvent ? event.originalEvent.offsetX : 0);
|
1664
2131
|
|
1665
2132
|
if (offset < (this[axis === 'vertical' ? 'offsetHeight' : 'offsetWidth'] / 2)) {
|
1666
|
-
|
2133
|
+
removeClass(droppingAfterClassName);
|
1667
2134
|
element.addClass(droppingBeforeClassName);
|
1668
2135
|
|
1669
2136
|
} else {
|
1670
|
-
|
2137
|
+
removeClass(droppingBeforeClassName);
|
1671
2138
|
element.addClass(droppingAfterClassName);
|
1672
2139
|
}
|
1673
2140
|
};
|
1674
2141
|
|
1675
2142
|
var dropTimeout;
|
1676
2143
|
|
1677
|
-
var dropHandler = function(
|
1678
|
-
|
2144
|
+
var dropHandler = function(event) {
|
2145
|
+
event.preventDefault();
|
1679
2146
|
|
1680
|
-
var droppedItemIndex = parseInt((
|
2147
|
+
var droppedItemIndex = parseInt((event.dataTransfer || event.originalEvent.dataTransfer).getData('text'), 10);
|
1681
2148
|
|
1682
2149
|
// prevent event firing multiple times in firefox
|
1683
2150
|
$timeout.cancel(dropTimeout);
|
@@ -1687,9 +2154,9 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
|
|
1687
2154
|
};
|
1688
2155
|
|
1689
2156
|
var _dropHandler = function(droppedItemIndex) {
|
1690
|
-
var theList = scope.$eval(attrs.uiSelectSort)
|
1691
|
-
|
1692
|
-
|
2157
|
+
var theList = scope.$eval(attrs.uiSelectSort);
|
2158
|
+
var itemToMove = theList[droppedItemIndex];
|
2159
|
+
var newIndex = null;
|
1693
2160
|
|
1694
2161
|
if (element.hasClass(droppingBeforeClassName)) {
|
1695
2162
|
if (droppedItemIndex < scope.$index) {
|
@@ -1707,6 +2174,8 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
|
|
1707
2174
|
|
1708
2175
|
move.apply(theList, [droppedItemIndex, newIndex]);
|
1709
2176
|
|
2177
|
+
$ngModel.$setViewValue(Date.now());
|
2178
|
+
|
1710
2179
|
scope.$apply(function() {
|
1711
2180
|
scope.$emit('uiSelectSort:change', {
|
1712
2181
|
array: theList,
|
@@ -1716,9 +2185,9 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
|
|
1716
2185
|
});
|
1717
2186
|
});
|
1718
2187
|
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
2188
|
+
removeClass(droppingClassName);
|
2189
|
+
removeClass(droppingBeforeClassName);
|
2190
|
+
removeClass(droppingAfterClassName);
|
1722
2191
|
|
1723
2192
|
element.off('drop', dropHandler);
|
1724
2193
|
};
|
@@ -1734,13 +2203,14 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
|
|
1734
2203
|
element.on('drop', dropHandler);
|
1735
2204
|
});
|
1736
2205
|
|
1737
|
-
element.on('dragleave', function(
|
1738
|
-
if (
|
2206
|
+
element.on('dragleave', function(event) {
|
2207
|
+
if (event.target != element) {
|
1739
2208
|
return;
|
1740
2209
|
}
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
2210
|
+
|
2211
|
+
removeClass(droppingClassName);
|
2212
|
+
removeClass(droppingBeforeClassName);
|
2213
|
+
removeClass(droppingAfterClassName);
|
1744
2214
|
|
1745
2215
|
element.off('dragover', dragOverHandler);
|
1746
2216
|
element.off('drop', dropHandler);
|
@@ -1771,18 +2241,58 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
|
|
1771
2241
|
*/
|
1772
2242
|
self.parse = function(expression) {
|
1773
2243
|
|
1774
|
-
|
2244
|
+
|
2245
|
+
var match;
|
2246
|
+
//var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression);
|
2247
|
+
// If an array is used as collection
|
2248
|
+
|
2249
|
+
// if (isObjectCollection){
|
2250
|
+
// 000000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000055555555555000000000000000000000066666666600000000
|
2251
|
+
match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(\s*[\s\S]+?)?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
|
2252
|
+
|
2253
|
+
// 1 Alias
|
2254
|
+
// 2 Item
|
2255
|
+
// 3 Key on (key,value)
|
2256
|
+
// 4 Value on (key,value)
|
2257
|
+
// 5 Source expression (including filters)
|
2258
|
+
// 6 Track by
|
1775
2259
|
|
1776
2260
|
if (!match) {
|
1777
2261
|
throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
|
1778
2262
|
expression);
|
1779
2263
|
}
|
2264
|
+
|
2265
|
+
var source = match[5],
|
2266
|
+
filters = '';
|
2267
|
+
|
2268
|
+
// When using (key,value) ui-select requires filters to be extracted, since the object
|
2269
|
+
// is converted to an array for $select.items
|
2270
|
+
// (in which case the filters need to be reapplied)
|
2271
|
+
if (match[3]) {
|
2272
|
+
// Remove any enclosing parenthesis
|
2273
|
+
source = match[5].replace(/(^\()|(\)$)/g, '');
|
2274
|
+
// match all after | but not after ||
|
2275
|
+
var filterMatch = match[5].match(/^\s*(?:[\s\S]+?)(?:[^\|]|\|\|)+([\s\S]*)\s*$/);
|
2276
|
+
if(filterMatch && filterMatch[1].trim()) {
|
2277
|
+
filters = filterMatch[1];
|
2278
|
+
source = source.replace(filters, '');
|
2279
|
+
}
|
2280
|
+
}
|
1780
2281
|
|
1781
2282
|
return {
|
1782
|
-
itemName: match[2], // (lhs) Left-hand side,
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
2283
|
+
itemName: match[4] || match[2], // (lhs) Left-hand side,
|
2284
|
+
keyName: match[3], //for (key, value) syntax
|
2285
|
+
source: $parse(source),
|
2286
|
+
filters: filters,
|
2287
|
+
trackByExp: match[6],
|
2288
|
+
modelMapper: $parse(match[1] || match[4] || match[2]),
|
2289
|
+
repeatExpression: function (grouped) {
|
2290
|
+
var expression = this.itemName + ' in ' + (grouped ? '$group.items' : '$select.items');
|
2291
|
+
if (this.trackByExp) {
|
2292
|
+
expression += ' track by ' + this.trackByExp;
|
2293
|
+
}
|
2294
|
+
return expression;
|
2295
|
+
}
|
1786
2296
|
};
|
1787
2297
|
|
1788
2298
|
};
|
@@ -1791,26 +2301,22 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
|
|
1791
2301
|
return '$group in $select.groups';
|
1792
2302
|
};
|
1793
2303
|
|
1794
|
-
self.getNgRepeatExpression = function(itemName, source, trackByExp, grouped) {
|
1795
|
-
var expression = itemName + ' in ' + (grouped ? '$group.items' : source);
|
1796
|
-
if (trackByExp) {
|
1797
|
-
expression += ' track by ' + trackByExp;
|
1798
|
-
}
|
1799
|
-
return expression;
|
1800
|
-
};
|
1801
2304
|
}]);
|
1802
2305
|
|
1803
2306
|
}());
|
1804
|
-
angular.module("ui.select").run(["$templateCache", function($templateCache) {$templateCache.put("bootstrap/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu\" role=\"listbox\" ng-show=\"$select.items.length > 0\"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><a href=\"
|
1805
|
-
$templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected\"><span class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$selectMultiple.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$selectMultiple.removeChoice($index)\"> ×</span> <span uis-transclude-append=\"\"></span></span></span></span>");
|
1806
|
-
$templateCache.put("bootstrap/match.tpl.html","<div class=\"ui-select-match\" ng-hide=\"$select.open\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\"><span tabindex=\"-1\" class=\"btn btn-default form-control ui-select-toggle\" aria-label=\"{{ $select.baseTitle }} activate\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activate()\" style=\"outline: 0;\"><span ng-show=\"$select.isEmpty()\" class=\"ui-select-placeholder text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"ui-select-match-text pull-left\" ng-class=\"{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}\" ng-transclude=\"\"></span> <i class=\"caret pull-right\" ng-click=\"$select.toggle($event)\"></i> <a ng-show=\"$select.allowClear && !$select.isEmpty()\" aria-label=\"{{ $select.baseTitle }} clear\" style=\"margin-right: 10px\" ng-click=\"$select.clear($event)\" class=\"btn btn-xs btn-link pull-right\"><i class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></i></a></span></div>");
|
1807
|
-
$templateCache.put("bootstrap/
|
1808
|
-
$templateCache.put("bootstrap/select.tpl.html","<div class=\"ui-select-container ui-select-bootstrap dropdown\" ng-class=\"{open: $select.open}\"><div class=\"ui-select-match\"></div><input type=\"
|
1809
|
-
$templateCache.put("
|
1810
|
-
$templateCache.put("select2/
|
2307
|
+
angular.module("ui.select").run(["$templateCache", function($templateCache) {$templateCache.put("bootstrap/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu\" role=\"listbox\" ng-show=\"$select.open && $select.items.length > 0\"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div ng-attr-id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><a href=\"\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>");
|
2308
|
+
$templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected track by $index\"><span class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$selectMultiple.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$selectMultiple.removeChoice($index)\"> ×</span> <span uis-transclude-append=\"\"></span></span></span></span>");
|
2309
|
+
$templateCache.put("bootstrap/match.tpl.html","<div class=\"ui-select-match\" ng-hide=\"$select.open && $select.searchEnabled\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\"><span tabindex=\"-1\" class=\"btn btn-default form-control ui-select-toggle\" aria-label=\"{{ $select.baseTitle }} activate\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activate()\" style=\"outline: 0;\"><span ng-show=\"$select.isEmpty()\" class=\"ui-select-placeholder text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"ui-select-match-text pull-left\" ng-class=\"{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}\" ng-transclude=\"\"></span> <i class=\"caret pull-right\" ng-click=\"$select.toggle($event)\"></i> <a ng-show=\"$select.allowClear && !$select.isEmpty() && ($select.disabled !== true)\" aria-label=\"{{ $select.baseTitle }} clear\" style=\"margin-right: 10px\" ng-click=\"$select.clear($event)\" class=\"btn btn-xs btn-link pull-right\"><i class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></i></a></span></div>");
|
2310
|
+
$templateCache.put("bootstrap/no-choice.tpl.html","<ul class=\"ui-select-no-choice dropdown-menu\" ng-show=\"$select.items.length == 0\"><li ng-transclude=\"\"></li></ul>");
|
2311
|
+
$templateCache.put("bootstrap/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple ui-select-bootstrap dropdown form-control\" ng-class=\"{open: $select.open}\"><div><div class=\"ui-select-match\"></div><input type=\"search\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search input-xs\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-click=\"$select.activate()\" ng-model=\"$select.search\" role=\"combobox\" aria-label=\"{{ $select.baseTitle }}\" ondrop=\"return false;\"></div><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div>");
|
2312
|
+
$templateCache.put("bootstrap/select.tpl.html","<div class=\"ui-select-container ui-select-bootstrap dropdown\" ng-class=\"{open: $select.open}\"><div class=\"ui-select-match\"></div><input type=\"search\" autocomplete=\"off\" tabindex=\"-1\" aria-expanded=\"true\" aria-label=\"{{ $select.baseTitle }}\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"form-control ui-select-search\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-show=\"$select.searchEnabled && $select.open\"><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div>");
|
2313
|
+
$templateCache.put("select2/choices.tpl.html","<ul tabindex=\"-1\" class=\"ui-select-choices ui-select-choices-content select2-results\"><li class=\"ui-select-choices-group\" ng-class=\"{\'select2-result-with-children\': $select.choiceGrouped($group) }\"><div ng-show=\"$select.choiceGrouped($group)\" class=\"ui-select-choices-group-label select2-result-label\" ng-bind=\"$group.name\"></div><ul role=\"listbox\" id=\"ui-select-choices-{{ $select.generatedId }}\" ng-class=\"{\'select2-result-sub\': $select.choiceGrouped($group), \'select2-result-single\': !$select.choiceGrouped($group) }\"><li role=\"option\" ng-attr-id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{\'select2-highlighted\': $select.isActive(this), \'select2-disabled\': $select.isDisabled(this)}\"><div class=\"select2-result-label ui-select-choices-row-inner\"></div></li></ul></li></ul>");
|
2314
|
+
$templateCache.put("select2/match-multiple.tpl.html","<span class=\"ui-select-match\"><li class=\"ui-select-match-item select2-search-choice\" ng-repeat=\"$item in $select.selected track by $index\" ng-class=\"{\'select2-search-choice-focus\':$selectMultiple.activeMatchIndex === $index, \'select2-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span uis-transclude-append=\"\"></span> <a href=\"javascript:;\" class=\"ui-select-match-close select2-search-choice-close\" ng-click=\"$selectMultiple.removeChoice($index)\" tabindex=\"-1\"></a></li></span>");
|
1811
2315
|
$templateCache.put("select2/match.tpl.html","<a class=\"select2-choice ui-select-match\" ng-class=\"{\'select2-default\': $select.isEmpty()}\" ng-click=\"$select.toggle($event)\" aria-label=\"{{ $select.baseTitle }} select\"><span ng-show=\"$select.isEmpty()\" class=\"select2-chosen\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"select2-chosen\" ng-transclude=\"\"></span> <abbr ng-if=\"$select.allowClear && !$select.isEmpty()\" class=\"select2-search-choice-close\" ng-click=\"$select.clear($event)\"></abbr> <span class=\"select2-arrow ui-select-toggle\"><b></b></span></a>");
|
1812
|
-
$templateCache.put("select2/
|
1813
|
-
$templateCache.put("select2/select.tpl.html","<div class=\"ui-select-container select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled
|
2316
|
+
$templateCache.put("select2/no-choice.tpl.html","<div class=\"ui-select-no-choice dropdown\" ng-show=\"$select.items.length == 0\"><div class=\"dropdown-content\"><div data-selectable=\"\" ng-transclude=\"\"></div></div></div>");
|
2317
|
+
$templateCache.put("select2/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple select2 select2-container select2-container-multi\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}\"><ul class=\"select2-choices\"><span class=\"ui-select-match\"></span><li class=\"select2-search-field\"><input type=\"search\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"select2-input ui-select-search\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-model=\"$select.search\" ng-click=\"$select.activate()\" style=\"width: 34px;\" ondrop=\"return false;\"></li></ul><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open || $select.items.length === 0}\"><div class=\"ui-select-choices\"></div></div></div>");
|
2318
|
+
$templateCache.put("select2/select.tpl.html","<div class=\"ui-select-container select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus, \'select2-allowclear\': $select.allowClear && !$select.isEmpty()}\"><div class=\"ui-select-match\"></div><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"select2-search\" ng-show=\"$select.searchEnabled\"><input type=\"search\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div></div>");
|
1814
2319
|
$templateCache.put("selectize/choices.tpl.html","<div ng-show=\"$select.open\" class=\"ui-select-choices ui-select-dropdown selectize-dropdown single\"><div class=\"ui-select-choices-content selectize-dropdown-content\"><div class=\"ui-select-choices-group optgroup\" role=\"listbox\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label optgroup-header\" ng-bind=\"$group.name\"></div><div role=\"option\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\"><div class=\"option ui-select-choices-row-inner\" data-selectable=\"\"></div></div></div></div></div>");
|
1815
|
-
$templateCache.put("selectize/match.tpl.html","<div ng-hide=\"($select.open || $select.isEmpty())\" class=\"ui-select-match\" ng-transclude=\"\"></div>");
|
1816
|
-
$templateCache.put("selectize/
|
2320
|
+
$templateCache.put("selectize/match.tpl.html","<div ng-hide=\"$select.searchEnabled && ($select.open || $select.isEmpty())\" class=\"ui-select-match\" ng-transclude=\"\"></div>");
|
2321
|
+
$templateCache.put("selectize/no-choice.tpl.html","<div class=\"ui-select-no-choice selectize-dropdown\" ng-show=\"$select.items.length == 0\"><div class=\"selectize-dropdown-content\"><div data-selectable=\"\" ng-transclude=\"\"></div></div></div>");
|
2322
|
+
$templateCache.put("selectize/select.tpl.html","<div class=\"ui-select-container selectize-control single\" ng-class=\"{\'open\': $select.open}\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.open && !$select.searchEnabled ? $select.toggle($event) : $select.activate()\"><div class=\"ui-select-match\"></div><input type=\"search\" autocomplete=\"off\" tabindex=\"-1\" class=\"ui-select-search ui-select-toggle\" ng-click=\"$select.toggle($event)\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-hide=\"!$select.searchEnabled || (!$select.isEmpty() && !$select.open)\" ng-disabled=\"$select.disabled\" aria-label=\"{{ $select.baseTitle }}\"></div><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div>");}]);
|