Skip to content

Commit

Permalink
Merge pull request #86 from tamtakoe/v0.2.21
Browse files Browse the repository at this point in the history
v0.2.21
  • Loading branch information
tamtakoe committed May 10, 2016
2 parents e9a346d + 4165b09 commit e0834ad
Show file tree
Hide file tree
Showing 23 changed files with 336 additions and 154 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
## 0.2.21

#### Features

- **oi-select-options:**
- `minlength` is minimum length of query for searching

- **list-placeholder:** placeholder for dropdown list if no items found

#### Bug Fixes

- **oi-options:**
- `select as` works correct with object data source, and with zero id
- `disable when` items don't add on click `enter`

- **oiSelectAscSort** works correct with different locales (f.e. Turkish)

- **oi-select** fix memory leak

## 0.2.20

#### Features
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#oi.select — AngularJS directive of select element

**[Download 0.2.20](https://github.com/tamtakoe/oi.select/tree/master/dist)**
**[Download 0.2.21](https://github.com/tamtakoe/oi.select/tree/master/dist)**

## Features

Expand Down Expand Up @@ -87,6 +87,9 @@ Use `oi-select` directive:
* `ng-disabled` — specifies that a drop-down list should be disabled
* `multiple` — specifies that multiple options can be selected at once
* `multiple-limit` — maximum number of options that can be selected at once
* `placeholder` — native placeholder
* `multiple-placeholder` — placeholder which is shown in multiple mode near chosen options
* `list-placeholder` — placeholder which is shown in list if no elements found
* `readonly` — specifies that an input field is read-only
* `autofocus` — specifies that an input field should automatically get focus when the page loads
* `oi-select-options` — object with options. You can override them in `oiSelectProvider.options`
Expand All @@ -104,6 +107,7 @@ Use `oi-select` directive:
* `newItemFn` — function which get query and return new item object or promise. F.e. `'addItem($query)'`
* `removeItemFn` — function which get removed item model and return any value or promise. If promise was rejected, item wouldn't removed. F.e. `'removeItem($item)'`
* `maxlength` — maximum number of characters allowed in the input
* `minlength` — minimum number of characters for searching

### oiSelect service
* `options` — default options which we can override in `oiSelectProvider.options`
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "https://github.com/tamtakoe"
},
"name": "oi.select",
"version": "0.2.20",
"version": "0.2.21",
"main": ["./dist/select-tpls.min.js", "./dist/select.min.css"],
"dependencies": {
"angular": ">=1.2",
Expand Down
114 changes: 82 additions & 32 deletions dist/select-tpls.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ angular.module('oi.select')
editItem: false,
newItem: false,
closeList: true,
saveTrigger: 'enter tab blur'
saveTrigger: 'enter tab blur',
minlength: 0
},
version: {
full: '0.2.20',
full: '0.2.21',
major: 0,
minor: 2,
dot: 20
dot: 21
},
$get: function() {
return {
Expand Down Expand Up @@ -141,7 +142,7 @@ angular.module('oi.select')
}

return function () {
$document[0].removeEventListener('click', clickHandler);
$document[0].removeEventListener('click', clickHandler, true);
element[0].removeEventListener('mousedown', mousedownHandler, true);
element[0].removeEventListener('blur', blurHandler, true);
inputElement.off('focus', focusHandler);
Expand Down Expand Up @@ -292,18 +293,6 @@ angular.module('oi.select')
return true;
}

function objToArr(obj) {
var arr = [];

angular.forEach(obj, function (value, key) {
if (key.toString().charAt(0) !== '$') {
arr.push(value);
}
});

return arr;
}

//lodash _.intersection + filter + invert
function intersection(xArr, yArr, xFilter, yFilter, invert) {
var i, j, n, filteredX, filteredY, out = invert ? [].concat(xArr) : [];
Expand All @@ -326,7 +315,7 @@ angular.module('oi.select')
function getValue(valueName, item, scope, getter) {
var locals = {};

//'name.subname' -> {name: {subname: list}}'
//'name.subname' -> {name: {subname: item}} -> locals'
valueName.split('.').reduce(function (previousValue, currentItem, index, arr) {
return previousValue[currentItem] = index < arr.length - 1 ? {} : item;
}, locals);
Expand All @@ -339,11 +328,11 @@ angular.module('oi.select')
bindFocusBlur: bindFocusBlur,
scrollActiveOption: scrollActiveOption,
groupsIsEmpty: groupsIsEmpty,
objToArr: objToArr,
getValue: getValue,
intersection: intersection
}
}]);

angular.module('oi.select')

.directive('oiSelect', ['$document', '$q', '$timeout', '$parse', '$interpolate', '$injector', '$filter', '$animate', 'oiUtils', 'oiSelect', function($document, $q, $timeout, $parse, $interpolate, $injector, $filter, $animate, oiUtils, oiSelect) {
Expand All @@ -365,11 +354,24 @@ angular.module('oi.select')

var selectAsName = / as /.test(match[0]) && match[1], //item.modelValue
displayName = match[2] || match[1], //item.label
valueName = match[5] || match[7], //item
valueName = match[5] || match[7], //item (value)
keyName = match[6], //(key)
groupByName = match[3] || '', //item.groupName
disableWhenName = match[4] || '', //item.disableWhenName
trackByName = match[9] || displayName, //item.id
valueMatches = match[8].match(VALUES_REGEXP); //collection
valueMatches = match[8].match(VALUES_REGEXP), //collection
valueTitle = valueName,
keyTitle = keyName;

if (keyName) { //convert object data sources format to array data sources format
valueName = 'i';
selectAsName = valueName + '.' + (selectAsName || valueTitle);
trackByName = valueName + '.' + keyName;
displayName = valueName + '.' + displayName;
keyName = valueName + '.' + keyName;
groupByName = groupByName ? valueName + '.' + groupByName: undefined;
disableWhenName = disableWhenName ? valueName + '.' + disableWhenName: undefined;
}

var valuesName = valueMatches[1], //collection
filteredValuesName = valuesName + (valueMatches[3] || ''), //collection | filter
Expand All @@ -384,6 +386,7 @@ angular.module('oi.select')
trackByFn = $parse(trackByName);

var multiplePlaceholderFn = $interpolate(attrs.multiplePlaceholder || ''),
listPlaceholderFn = $interpolate(attrs.listPlaceholder || ''),
placeholderFn = $interpolate(attrs.placeholder || ''),
optionsFn = $parse(attrs.oiSelectOptions),
isOldAngular = angular.version.major <= 1 && angular.version.minor <= 3;
Expand All @@ -405,6 +408,7 @@ angular.module('oi.select')
listElement = angular.element(element[0].querySelector('.select-dropdown')),
placeholder = placeholderFn(scope),
multiplePlaceholder = multiplePlaceholderFn(scope),
listPlaceholder = listPlaceholderFn(scope),
elementOptions = optionsFn(scope.$parent) || {},
options = angular.extend({cleanModel: elementOptions.newItem === 'prompt'}, oiSelect.options, elementOptions),
editItem = options.editItem,
Expand Down Expand Up @@ -531,10 +535,12 @@ angular.module('oi.select')
});

scope.$watch('query', function(inputValue, oldValue) {
if (saveOn(inputValue.slice(0, -1), inputValue.slice(-1))) {
return;
}
//terminated symbol
if (saveOn(inputValue.slice(0, -1), inputValue.slice(-1))) return;

//length less then minlength
if (String(inputValue).length < options.minlength) return;

//We don't get matches if nothing added into matches list
if (inputValue !== oldValue && (!scope.oldQuery || inputValue) && !matchesWereReset) {
listElement[0].scrollTop = 0;
Expand Down Expand Up @@ -572,6 +578,12 @@ angular.module('oi.select')
});
});

scope.$watch('isEmptyList', function(isEmptyList) {
$animate[isEmptyList ? 'addClass' : 'removeClass'](element, 'emptyList', !isOldAngular && {
tempClasses: 'emptyList-animate'
});
});

scope.$watch('showLoader', function(isLoading) {
$animate[isLoading ? 'addClass' : 'removeClass'](element, 'loading', !isOldAngular && {
tempClasses: 'loading-animate'
Expand Down Expand Up @@ -766,6 +778,9 @@ angular.module('oi.select')
resetMatches();

element[0].addEventListener('click', click, true); //triggered before add or delete item event
scope.$on('$destroy', function() {
element[0].removeEventListener('click', click, true);
});
element.on('focus', focus);
element.on('blur', blur);

Expand All @@ -791,6 +806,9 @@ angular.module('oi.select')
}

function click(event) {
//query length less then minlength
if (scope.query.length < options.minlength) return;

//option is disabled
if (oiUtils.contains(element[0], event.target, 'disabled')) return;

Expand Down Expand Up @@ -844,7 +862,7 @@ angular.module('oi.select')
selectedOrder = triggerName !== 'blur' ? scope.order[scope.selectorPosition] : null, //do not save selected element in dropdown list on blur
itemPromise;

if (isTriggered && (isNewItem || selectedOrder)) {
if (isTriggered && (isNewItem || selectedOrder && !getDisableWhen(selectedOrder))) {
scope.showLoader = true;
itemPromise = $q.when(selectedOrder || newItemFn(scope.$parent, {$query: query}));

Expand Down Expand Up @@ -891,7 +909,7 @@ angular.module('oi.select')
}

function getDisableWhen(item) {
return oiUtils.getValue(valueName, item, scope.$parent, disableWhenFn);
return scope.isEmptyList || oiUtils.getValue(valueName, item, scope.$parent, disableWhenFn);
}

function getGroupName(option) {
Expand All @@ -906,7 +924,7 @@ angular.module('oi.select')
value = value instanceof Array ? value : value ? [value]: [];

return value.filter(function(item) {
return item && (item instanceof Array && item.length || selectAsFn || getLabel(item));
return item !== undefined && (item instanceof Array && item.length || selectAsFn || getLabel(item));
});
}

Expand All @@ -915,6 +933,8 @@ angular.module('oi.select')
}

function getMatches(query, selectedAs) {
scope.isEmptyList = false;

if (timeoutPromise && waitTime) {
$timeout.cancel(timeoutPromise); //cancel previous timeout
}
Expand All @@ -936,14 +956,44 @@ angular.module('oi.select')

return $q.when(values.$promise || values)
.then(function(values) {

scope.groups = {};

if (values && keyName) {
//convert object data sources format to array data sources format
var arr = [];

angular.forEach(values, function (value, key) {
if (key.toString().charAt(0) !== '$') {
var item = {};

item[keyTitle] = key;
item[valueTitle] = value;
arr.push(item);
}
});

values = arr;
}

if (values && !selectedAs) {
var outputValues = multiple ? scope.output : [];
var filteredList = listFilter(oiUtils.objToArr(values), query, getLabel, listFilterOptionsFn(scope.$parent), element);
var filteredList = listFilter(values, query, getLabel, listFilterOptionsFn(scope.$parent), element);
var withoutIntersection = oiUtils.intersection(filteredList, outputValues, trackBy, trackBy, true);
var filteredOutput = filter(withoutIntersection);

//add element with placeholder to empty list
if (!filteredOutput.length) {
scope.isEmptyList = true;

if (listPlaceholder) {
var context = {};

displayFn.assign(context, listPlaceholder);
filteredOutput = [context[valueName]]
}
}

scope.groups = group(filteredOutput);
}
updateGroupPos();
Expand Down Expand Up @@ -1058,7 +1108,7 @@ angular.module('oi.select')

if (query.length > 0 || angular.isNumber(query)) {
label = label.toString();
query = oiSelectEscape(query.toString());
query = oiSelectEscape(query);

html = label.replace(new RegExp(query, 'gi'), '<strong>$&</strong>');
} else {
Expand All @@ -1074,16 +1124,16 @@ angular.module('oi.select')
var i, j, isFound, output, output1 = [], output2 = [], output3 = [], output4 = [];

if (query) {
query = oiSelectEscape(String(query));
query = oiSelectEscape(query).toLocaleLowerCase();

for (i = 0, isFound = false; i < input.length; i++) {
isFound = getLabel(input[i]).match(new RegExp(query, "i"));
isFound = getLabel(input[i]).toLocaleLowerCase().match(new RegExp(query));

if (!isFound && options && (options.length || options.fields)) {
for (j = 0; j < options.length; j++) {
if (isFound) break;

isFound = String(input[i][options[j]]).match(new RegExp(query, "i"));
isFound = String(input[i][options[j]]).toLocaleLowerCase().match(new RegExp(query));
}
}

Expand All @@ -1092,7 +1142,7 @@ angular.module('oi.select')
}
}
for (i = 0; i < output1.length; i++) {
if (getLabel(output1[i]).match(new RegExp('^' + query, "i"))) {
if (getLabel(output1[i]).toLocaleLowerCase().match(new RegExp('^' + query))) {
output2.push(output1[i]);
} else {
output3.push(output1[i]);
Expand Down
Loading

0 comments on commit e0834ad

Please sign in to comment.