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

Commit e166672

Browse files
authored
Merge branch 'master' into master
2 parents fb1bc85 + 2b0b17b commit e166672

File tree

8 files changed

+147
-31
lines changed

8 files changed

+147
-31
lines changed

src/bootstrap/select-multiple.tpl.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
autocapitalize="off"
99
spellcheck="false"
1010
class="ui-select-search input-xs"
11-
placeholder="{{$selectMultiple.getPlaceholder()}}"
11+
placeholder="{{$select.getPlaceholder()}}"
1212
ng-disabled="$select.disabled"
1313
ng-click="$select.activate()"
1414
ng-model="$select.search"
1515
role="combobox"
1616
aria-expanded="{{$select.open}}"
1717
aria-label="{{$select.baseTitle}}"
1818
ng-class="{'spinner': $select.refreshing}"
19-
ondrop="return false;">
19+
data-disallow-drop=data-disallow-drop>
2020
</div>
2121
<div class="ui-select-choices"></div>
2222
<div class="ui-select-no-choice"></div>

src/select2/select-multiple.tpl.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
aria-label="{{ $select.baseTitle }}"
1717
aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}"
1818
class="select2-input ui-select-search"
19-
placeholder="{{$selectMultiple.getPlaceholder()}}"
19+
placeholder="{{$select.getPlaceholder()}}"
2020
ng-disabled="$select.disabled"
2121
ng-hide="$select.disabled"
2222
ng-model="$select.search"
2323
ng-click="$select.activate()"
2424
style="width: 34px;"
25-
ondrop="return false;">
25+
data-disallow-drop=data-disallow-drop>
2626
</li>
2727
</ul>
2828
<div class="ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active"

src/selectize/select-multiple.tpl.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
<input type="search" autocomplete="off" tabindex="-1"
77
class="ui-select-search"
88
ng-class="{'ui-select-search-hidden':!$select.searchEnabled}"
9-
placeholder="{{$selectMultiple.getPlaceholder()}}"
9+
placeholder="{{$select.getPlaceholder()}}"
1010
ng-model="$select.search"
1111
ng-disabled="$select.disabled"
1212
aria-expanded="{{$select.open}}"
1313
aria-label="{{ $select.baseTitle }}"
14-
ondrop="return false;">
14+
data-disallow-drop=data-disallow-drop>
1515
</div>
1616
<div class="ui-select-choices"></div>
1717
<div class="ui-select-no-choice"></div>
18-
</div>
18+
</div>

src/uiSelectController.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ uis.controller('uiSelectCtrl',
6565
return isNil(ctrl.selected) || ctrl.selected === '' || (ctrl.multiple && ctrl.selected.length === 0);
6666
};
6767

68+
ctrl.getPlaceholder = function(){
69+
if(ctrl.selected && ctrl.selected.length) return;
70+
return ctrl.placeholder;
71+
};
72+
6873
function _findIndex(collection, predicate, thisArg){
6974
if (collection.findIndex){
7075
return collection.findIndex(predicate, thisArg);
@@ -88,10 +93,14 @@ uis.controller('uiSelectCtrl',
8893
if (ctrl.resetSearchInput) {
8994
ctrl.search = EMPTY_SEARCH;
9095
//reset activeIndex
91-
if (ctrl.selected && ctrl.items.length && !ctrl.multiple) {
92-
ctrl.activeIndex = _findIndex(ctrl.items, function(item){
93-
return angular.equals(this, item);
94-
}, ctrl.selected);
96+
if (!ctrl.multiple) {
97+
if (ctrl.selected && ctrl.items.length) {
98+
ctrl.activeIndex = _findIndex(ctrl.items, function(item){
99+
return angular.equals(this, item);
100+
}, ctrl.selected);
101+
} else {
102+
ctrl.activeIndex = 0;
103+
}
95104
}
96105
}
97106
}
@@ -468,11 +477,11 @@ uis.controller('uiSelectCtrl',
468477
ctrl.toggle = function(e) {
469478
if (ctrl.open) {
470479
ctrl.close();
471-
e.preventDefault();
472-
e.stopPropagation();
473480
} else {
474481
ctrl.activate();
475482
}
483+
e.preventDefault();
484+
e.stopPropagation();
476485
};
477486

478487
// Set default function for locked choices - avoids unnecessary

src/uiSelectDirective.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
uis.directive('uiSelect',
2-
['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout',
3-
function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout) {
2+
['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout', '$window',
3+
function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout, $window) {
44

55
return {
66
restrict: 'EA',
@@ -206,11 +206,15 @@ uis.directive('uiSelect',
206206
$select.clickTriggeredSelect = false;
207207
}
208208

209-
// See Click everywhere but here event http://stackoverflow.com/questions/12931369
210-
$document.on('click', onDocumentClick);
209+
// See Click everywhere but here. Similar approach to http://stackoverflow.com/questions/12931369
210+
// but using the capture phase instead of bubble phase of the event propagation.
211+
//
212+
// Using the capture phase avoids problems that araise when event.stopPropatagion()
213+
// is called before the event reaches the `document`.
214+
$window.document.addEventListener('click', onDocumentClick, true);
211215

212216
scope.$on('$destroy', function() {
213-
$document.off('click', onDocumentClick);
217+
$window.document.removeEventListener('click', onDocumentClick, true);
214218
});
215219

216220
// Move transcluded elements to their correct position in main template

src/uiSelectMultipleDirective.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,6 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
6262
return true;
6363
};
6464

65-
ctrl.getPlaceholder = function(){
66-
//Refactor single?
67-
if($select.selected && $select.selected.length) return;
68-
return $select.placeholder;
69-
};
70-
7165

7266
}],
7367
controllerAs: '$selectMultiple',

src/uiSelectSortDirective.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
3131
}
3232
});
3333

34+
if (element.data('disallowDrop')) {
35+
return;
36+
}
37+
3438
element.on('dragstart', function(event) {
3539
element.addClass(draggingClassName);
3640

test/select.spec.js

Lines changed: 112 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ describe('ui-select tests', function () {
1515
Escape: 27
1616
};
1717

18+
var defaultPlaceholder = 'Pick one...';
19+
1820
function isNil(value) {
1921
return angular.isUndefined(value) || value === null;
2022
}
@@ -191,6 +193,10 @@ describe('ui-select tests', function () {
191193
return $(el).find('.ui-select-match > span:first > span[ng-transclude]:not(.ng-hide)').text();
192194
}
193195

196+
function getMatchPlaceholder(el) {
197+
return el.find('.ui-select-search').attr('placeholder')
198+
}
199+
194200
function clickItem(el, text) {
195201

196202
if (!isDropdownOpened(el)) {
@@ -740,6 +746,28 @@ describe('ui-select tests', function () {
740746
el2.remove();
741747
});
742748

749+
it('should close an opened select clicking outside with stopPropagation()', function () {
750+
var el1 = createUiSelect();
751+
var el2 = $('<div></div>');
752+
el1.appendTo(document.body);
753+
el2.appendTo(document.body);
754+
755+
el2.on('click', function (e) {
756+
e.stopPropagation()
757+
});
758+
759+
expect(isDropdownOpened(el1)).toEqual(false);
760+
clickMatch(el1);
761+
expect(isDropdownOpened(el1)).toEqual(true);
762+
763+
// Using a native dom click() to make sure the test fails when it should.
764+
el2[0].click();
765+
766+
expect(isDropdownOpened(el1)).toEqual(false);
767+
el1.remove();
768+
el2.remove();
769+
});
770+
743771
it('should bind model correctly (with object as source)', function () {
744772
var el = compileTemplate(
745773
'<ui-select ng-model="selection.selected"> \
@@ -846,6 +874,20 @@ describe('ui-select tests', function () {
846874
expect(getMatchLabel(el)).toEqual('-- None Selected --');
847875
});
848876

877+
it('should not have active option when model cleared', function () {
878+
var el = createUiSelect();
879+
880+
clickItem(el, 'Samantha');
881+
expect(el.scope().$select.activeIndex).toBe(5);
882+
883+
scope.selection.selected = null;
884+
scope.$digest();
885+
886+
el.find(".ui-select-toggle").click();
887+
888+
expect(el.scope().$select.activeIndex).toBe(0);
889+
});
890+
849891
describe('backspace reset option', function () {
850892
it('should undefined model when pressing BACKSPACE key if backspaceReset=true', function () {
851893
var el = createUiSelect();
@@ -1860,7 +1902,9 @@ describe('ui-select tests', function () {
18601902
function createUiSelectMultiple(attrs) {
18611903
var attrsHtml = '',
18621904
choicesAttrsHtml = '',
1863-
matchesAttrsHtml = '';
1905+
matchesAttrsHtml = '',
1906+
matchesPlaceholder = defaultPlaceholder;
1907+
18641908
if (attrs !== undefined) {
18651909
if (attrs.disabled !== undefined) { attrsHtml += ' ng-disabled="' + attrs.disabled + '"'; }
18661910
if (attrs.required !== undefined) { attrsHtml += ' ng-required="' + attrs.required + '"'; }
@@ -1870,24 +1914,26 @@ describe('ui-select tests', function () {
18701914
if (attrs.taggingTokens !== undefined) { attrsHtml += ' tagging-tokens="' + attrs.taggingTokens + '"'; }
18711915
if (attrs.taggingLabel !== undefined) { attrsHtml += ' tagging-label="' + attrs.taggingLabel + '"'; }
18721916
if (attrs.inputId !== undefined) { attrsHtml += ' input-id="' + attrs.inputId + '"'; }
1873-
if (attrs.groupBy !== undefined) { choicesAttrsHtml += ' group-by="' + attrs.groupBy + '"'; }
1874-
if (attrs.uiDisableChoice !== undefined) { choicesAttrsHtml += ' ui-disable-choice="' + attrs.uiDisableChoice + '"'; }
1875-
if (attrs.lockChoice !== undefined) { matchesAttrsHtml += ' ui-lock-choice="' + attrs.lockChoice + '"'; }
18761917
if (attrs.removeSelected !== undefined) { attrsHtml += ' remove-selected="' + attrs.removeSelected + '"'; }
18771918
if (attrs.resetSearchInput !== undefined) { attrsHtml += ' reset-search-input="' + attrs.resetSearchInput + '"'; }
18781919
if (attrs.limit !== undefined) { attrsHtml += ' limit="' + attrs.limit + '"'; }
18791920
if (attrs.onSelect !== undefined) { attrsHtml += ' on-select="' + attrs.onSelect + '"'; }
18801921
if (attrs.removeSelected !== undefined) { attrsHtml += ' remove-selected="' + attrs.removeSelected + '"'; }
1881-
if (attrs.refresh !== undefined) { choicesAttrsHtml += ' refresh="' + attrs.refresh + '"'; }
1882-
if (attrs.refreshDelay !== undefined) { choicesAttrsHtml += ' refresh-delay="' + attrs.refreshDelay + '"'; }
18831922
if (attrs.spinnerEnabled !== undefined) { attrsHtml += ' spinner-enabled="' + attrs.spinnerEnabled + '"'; }
18841923
if (attrs.spinnerClass !== undefined) { attrsHtml += ' spinner-class="' + attrs.spinnerClass + '"'; }
1924+
if (attrs.groupBy !== undefined) { choicesAttrsHtml += ' group-by="' + attrs.groupBy + '"'; }
1925+
if (attrs.uiDisableChoice !== undefined) { choicesAttrsHtml += ' ui-disable-choice="' + attrs.uiDisableChoice + '"'; }
1926+
if (attrs.refresh !== undefined) { choicesAttrsHtml += ' refresh="' + attrs.refresh + '"'; }
1927+
if (attrs.refreshDelay !== undefined) { choicesAttrsHtml += ' refresh-delay="' + attrs.refreshDelay + '"'; }
1928+
if (attrs.lockChoice !== undefined) { matchesAttrsHtml += ' ui-lock-choice="' + attrs.lockChoice + '"'; }
18851929
if (attrs.uiSelectHeaderGroupSelectable !== undefined) { choicesAttrsHtml += ' ui-select-header-group-selectable'; }
18861930
}
18871931

1932+
matchesAttrsHtml += ' placeholder="' + matchesPlaceholder + '"';
1933+
18881934
return compileTemplate(
18891935
'<ui-select multiple ng-model="selection.selectedMultiple"' + attrsHtml + ' theme="bootstrap" style="width: 800px;"> \
1890-
<ui-select-match "' + matchesAttrsHtml + ' placeholder="Pick one...">{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match> \
1936+
<ui-select-match ' + matchesAttrsHtml + '>{{$item.name}} &lt;{{$item.email}}&gt;</ui-select-match> \
18911937
<ui-select-choices repeat="person in people | filter: $select.search"' + choicesAttrsHtml + '> \
18921938
<div ng-bind-html="person.name | highlight: $select.search"></div> \
18931939
<div ng-bind-html="person.email | highlight: $select.search"></div> \
@@ -2958,6 +3004,65 @@ describe('ui-select tests', function () {
29583004
triggerKeydown(searchInput, Key.Enter);
29593005
expect(el.scope().$select.activeIndex).toBe(2);
29603006
});
3007+
3008+
it('should not display the placeholder when tag is selected (by default)', function () {
3009+
var placeholderText = defaultPlaceholder;
3010+
3011+
var el = createUiSelectMultiple({
3012+
tagging: '',
3013+
taggingLabel: ''
3014+
});
3015+
3016+
var $select = el.scope().$select; // uiSelectCtrl
3017+
3018+
expect($select.selected).toEqual([]);
3019+
expect($select.getPlaceholder()).toEqual(placeholderText);
3020+
expect(getMatchPlaceholder(el)).toEqual(placeholderText); // get placeholder
3021+
3022+
clickItem(el, scope.people[0].name);
3023+
expect($select.selected).toEqual([scope.people[0]]);
3024+
expect(getMatchLabel(el)).toEqual(''); // empty text
3025+
expect(getMatchPlaceholder(el)).toEqual(''); // empty placeholder
3026+
3027+
clickItem(el, scope.people[1].name);
3028+
expect($select.selected).toEqual([scope.people[0], scope.people[1]]);
3029+
expect(getMatchLabel(el)).toEqual('');
3030+
expect(getMatchPlaceholder(el)).toEqual('');
3031+
});
3032+
3033+
// Could be needed when e.g. tag is shown below the input
3034+
it('should display the placeholder when tag is selected (if user overrides .getPlaceholder())', function () {
3035+
var placeholderText = defaultPlaceholder;
3036+
3037+
var el = createUiSelectMultiple({
3038+
tagging: '',
3039+
taggingLabel: ''
3040+
});
3041+
var $select = el.scope().$select;
3042+
3043+
/**
3044+
* In case user wants to show placeholder when the text is empty - they can override $select.getPlaceholder.
3045+
* Cannot do this with $selectMultiple, bc <ui-select-multiple is appended inside the library
3046+
* This override closes #1796
3047+
*/
3048+
$select.getPlaceholder = function() {
3049+
return $select.placeholder;
3050+
};
3051+
3052+
expect($select.selected).toEqual([]);
3053+
expect(getMatchLabel(el)).toEqual('');
3054+
expect(getMatchPlaceholder(el)).toEqual(placeholderText);
3055+
3056+
clickItem(el, scope.people[0].name);
3057+
expect($select.selected).toEqual([scope.people[0]]);
3058+
expect(getMatchLabel(el)).toEqual(''); // empty text
3059+
expect(getMatchPlaceholder(el)).toEqual(placeholderText); // show placeholder
3060+
3061+
clickItem(el, scope.people[1].name);
3062+
expect($select.selected).toEqual([scope.people[0], scope.people[1]]);
3063+
expect(getMatchLabel(el)).toEqual('');
3064+
expect(getMatchPlaceholder(el)).toEqual(placeholderText);
3065+
});
29613066
});
29623067

29633068
describe('resetSearchInput option multiple', function () {

0 commit comments

Comments
 (0)