Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

arale-autocomplete

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

arale-autocomplete - npm Package Compare versions

Comparing version 1.2.1 to 1.2.6

.npmignore

139

examples/data-source.md

@@ -7,2 +7,6 @@ # 数据源

<script>
seajs.use('../src/autocomplete.css');
</script>
在使用前先看下数据源的文档

@@ -19,11 +23,10 @@

````javascript
require('../src/autocomplete.css');
var AutoComplete = require('arale-autocomplete');
new AutoComplete({
trigger: '#acTrigger1',
dataSource: {
data: ['abc', 'abd', 'abe', 'acd']
}
}).render();
seajs.use('autocomplete', function(AutoComplete) {
new AutoComplete({
trigger: '#acTrigger1',
dataSource: {
data: ['abc', 'abd', 'abe', 'acd']
}
}).render();
});
````

@@ -38,7 +41,8 @@

````javascript
var AutoComplete = require('arale-autocomplete');
new AutoComplete({
trigger: '#acTrigger2',
dataSource: './data.json?q={{query}}'
}).render();
seajs.use('autocomplete', function(AutoComplete) {
new AutoComplete({
trigger: '#acTrigger2',
dataSource: './data.json?q={{query}}'
}).render();
});
````

@@ -53,21 +57,20 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
var local = ['ade', 'adf'];
new AutoComplete({
trigger: '#acTrigger3',
dataSource: function(value) {
var that = this;
$.ajax('./data.json', {
dataType: 'json'
})
.success(function(data) {
that.trigger('data', data.concat(local));
})
.error(function(data) {
that.trigger('data', {});
});
}
}).render();
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
var local = ['ade', 'adf'];
new AutoComplete({
trigger: '#acTrigger3',
dataSource: function(value) {
var that = this;
$.ajax('./data.json', {
dataType: 'json'
})
.success(function(data) {
that.trigger('data', data.concat(local));
})
.error(function(data) {
that.trigger('data', {});
});
}
}).render();
});
````

@@ -82,23 +85,22 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
new AutoComplete({
trigger: '#acTrigger4',
locator: 'my.mother.father.brothers',
dataSource: {
my: {
mother: {
father: {
brothers: [
'abc',
'abd',
'abe',
'acd'
]
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
new AutoComplete({
trigger: '#acTrigger4',
locator: 'my.mother.father.brothers',
dataSource: {
my: {
mother: {
father: {
brothers: [
'abc',
'abd',
'abe',
'acd'
]
}
}
}
}
}
}).render();
}).render();
});
````

@@ -113,20 +115,19 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
new AutoComplete({
trigger: '#acTrigger5',
filter: {
name: 'startsWith',
options: {
key: 'title'
}
},
dataSource: [
{title: 'abc', myprop: '123'},
{title: 'abd', myprop: '124'},
{title: 'abe', myprop: '125'},
{title: 'acd', myprop: '134'}
]
}).render();
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
new AutoComplete({
trigger: '#acTrigger5',
filter: {
name: 'startsWith',
options: {
key: 'title'
}
},
dataSource: [
{title: 'abc', myprop: '123'},
{title: 'abd', myprop: '124'},
{title: 'abe', myprop: '125'},
{title: 'acd', myprop: '134'}
]
}).render();
});
````

@@ -7,2 +7,6 @@ # Email 自动补全

<script>
seajs.use('../src/autocomplete.css');
</script>
这个功能很常用,在输入账号的时候希望补全常用的邮箱后缀

@@ -15,24 +19,23 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
var data = [
'163.com',
'126.com',
'gmail.com'
];
new AutoComplete({
trigger: '#example',
dataSource: function(query) {
var a = $.map(data, function(v, i) {
return query + '@' + v;
});
return a;
},
filter: '',
inputFilter: function(v){
return v.replace(/^(.*)@.*$/,'$1');
}
}).render();
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
var data = [
'163.com',
'126.com',
'gmail.com'
];
new AutoComplete({
trigger: '#example',
dataSource: function(query) {
var a = $.map(data, function(v, i) {
return query + '@' + v;
});
return a;
},
filter: '',
inputFilter: function(v){
return v.replace(/^(.*)@.*$/,'$1');
}
}).render();
});
````

@@ -7,2 +7,6 @@ # 过滤器

<script>
seajs.use('../src/autocomplete.css');
</script>
## 输出过滤

@@ -15,18 +19,17 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
new AutoComplete({
trigger: '#acTrigger1',
dataSource: ['abc', 'abd', 'abe', 'acd'],
filter: function(data, query) {
var result = [];
$.each(data, function(index, value) {
if (value.indexOf(query) > -1) {
result.push({matchKey: value});
}
});
return result;
}
}).render();
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
new AutoComplete({
trigger: '#acTrigger1',
dataSource: ['abc', 'abd', 'abe', 'acd'],
filter: function(data, query) {
var result = [];
$.each(data, function(index, value) {
if (value.indexOf(query) > -1) {
result.push({matchKey: value});
}
});
return result;
}
}).render();
});
````

@@ -43,17 +46,16 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
new AutoComplete({
trigger: '#acTrigger2',
dataSource: [
'abc@gmail.com',
'abd@gmail.com',
'abe@gmail.com',
'acd@gmail.com'
],
inputFilter: function(value) {
return value.split('@')[0];
}
}).render();
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
new AutoComplete({
trigger: '#acTrigger2',
dataSource: [
'abc@gmail.com',
'abd@gmail.com',
'abe@gmail.com',
'acd@gmail.com'
],
inputFilter: function(value) {
return value.split('@')[0];
}
}).render();
});
````

@@ -66,11 +68,9 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
new AutoComplete({
trigger: '#acTrigger3',
dataSource: ['abc abd', 'bcd tcd', 'cbdc abdc'],
filter: 'stringMatch'
}).render();
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
new AutoComplete({
trigger: '#acTrigger3',
dataSource: ['abc abd', 'bcd tcd', 'cbdc abdc'],
filter: 'stringMatch'
}).render();
});
````

@@ -8,2 +8,3 @@ # 基本操作

<script>
seajs.use('../src/autocomplete.css');
</script>

@@ -16,8 +17,8 @@

````javascript
require('../src/autocomplete.css');
var AutoComplete = require('arale-autocomplete');
new AutoComplete({
trigger: '#acTrigger1',
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
seajs.use('autocomplete', function(AutoComplete) {
new AutoComplete({
trigger: '#acTrigger1',
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
});
````

@@ -36,8 +37,9 @@

````javascript
var AutoComplete = require('arale-autocomplete');
new AutoComplete({
trigger: '#acTrigger2',
submitOnEnter: false,
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
seajs.use('autocomplete', function(AutoComplete) {
new AutoComplete({
trigger: '#acTrigger2',
submitOnEnter: false,
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
});
````

@@ -54,15 +56,14 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
var ac = new AutoComplete({
trigger: '#acTrigger3',
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
var ac = new AutoComplete({
trigger: '#acTrigger3',
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
$('#acTrigger3-extra').click(function(e) {
e.preventDefault();
var o = $(this), status = (o.html() === '开启');
o.html(status? '关闭' : '开启')
ac.set('disabled', status);
$('#acTrigger3-extra').click(function(e) {
e.preventDefault();
var o = $(this), status = (o.html() === '开启');
o.html(status? '关闭' : '开启')
ac.set('disabled', status);
});
});

@@ -78,8 +79,9 @@ ````

````javascript
var AutoComplete = require('arale-autocomplete');
new AutoComplete({
trigger: '#acTrigger5',
selectFirst: true,
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
seajs.use('autocomplete', function(AutoComplete) {
new AutoComplete({
trigger: '#acTrigger5',
selectFirst: true,
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
});
````

@@ -7,2 +7,6 @@ # 自定义模板

<script>
seajs.use('../src/autocomplete.css');
</script>
## 自定义模板

@@ -42,10 +46,9 @@

````javascript
var AutoComplete = require('arale-autocomplete');
var $ = require('jquery');
var ac = new AutoComplete({
trigger: '#acTrigger4',
template: $('#acTrigger4-template').html(),
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
seajs.use(['autocomplete', '$'], function(AutoComplete, $) {
var ac = new AutoComplete({
trigger: '#acTrigger4',
template: $('#acTrigger4-template').html(),
dataSource: ['abc', 'abd', 'abe', 'acd']
}).render();
});
````

@@ -15,2 +15,3 @@ # Textarea

<script>
seajs.use('../src/autocomplete.css');
</script>

@@ -21,3 +22,5 @@

<form action="">
<textarea id="acTrigger"></textarea>
<p><textarea class="acTrigger"></textarea></p>
<p style="display:none;"><textarea class="acTrigger"></textarea></p>
<p style="display:none;"><textarea class="acTrigger"></textarea></p>
</form>

@@ -36,39 +39,39 @@

````javascript
require('../src/autocomplete.css');
var TextareaComplete = require('../src/textarea-complete');
var $ = require('jquery');
new TextareaComplete({
trigger: '#acTrigger',
cursor: [15, 5],
dataSource: [
{nickName:'popomore', realName: 'Haoliang Gao'},
{nickName:'lepture', realName: 'Hsaoming Yang'},
{nickName:'afc163', realName: 'Xingmin Zhu'},
{nickName:'shawn', realName: 'Shuai Shao'}
],
submitOnEnter: false,
selectFirst: true,
template: $('#acTriggerTemplte').html(),
inputFilter: function(q) {
var m = q.match(/@[^@]*$/);
return (m && m.length) ? m[0] : '';
},
filter: function(data, query) {
var result = [], self = this;
if (!query) return result;
query = query.substring(1);
var reg = new RegExp('^' + query);
$.each(data, function(index, item) {
if (reg.test(item.nickName) || reg.test(item.realName)) {
result.push({
value: item.nickName,
text: item.nickName + ' (' + item.realName + ')'
seajs.use(['textarea-complete', '$'], function(TextareaComplete, $) {
$('.acTrigger').each(function(idx, elem) {
new TextareaComplete({
trigger: elem,
cursor: [14, 2],
dataSource: [
{nickName:'popomore', realName: 'Haoliang Gao'},
{nickName:'lepture', realName: 'Hsaoming Yang'},
{nickName:'afc163', realName: 'Xingmin Zhu'},
{nickName:'shawn', realName: 'Shuai Shao'}
],
submitOnEnter: false,
selectFirst: true,
template: $('#acTriggerTemplte').html(),
inputFilter: function(q) {
var m = q.match(/@[^@]*$/);
return (m && m.length) ? m[0] : '';
},
filter: function(data, query) {
var result = [], self = this;
if (!query) return result;
query = query.substring(1);
var reg = new RegExp('^' + query);
$.each(data, function(index, item) {
if (reg.test(item.nickName) || reg.test(item.realName)) {
result.push({
value: item.nickName,
text: item.nickName + ' (' + item.realName + ')'
});
}
});
return result;
}
});
return result;
}
}).render();
}).render();
});
});
````

@@ -5,2 +5,20 @@ # History

## 1.2.5
`tag:fixed` 不想说什么了,1.2.4 build 内容是错的
## 1.2.4
`tag:fixed` #91 data 不存在的时候按上下键报错
## 1.2.3
`tag:fixed` [#82](https://github.com/aralejs/autocomplete/issues/82) 当浮层设置高度, 出现滚动条时, 按上下键选中项需要在可视范围内
`tag:fixed` 页面上多个 textarea-complete 时, 修复 mirror 的引用 bug
## 1.2.2
`tag:improved` 升级 base 到 1.1.1, templatable 到 0.9.1, overlay 到 1.1.1
## 1.2.1

@@ -13,2 +31,4 @@

`tag:fixed` #72 修复输入特殊字符报错的问题
## 1.2.0

@@ -15,0 +35,0 @@

{
"name": "arale-autocomplete",
"version": "1.2.1",
"version": "1.2.6",
"description": "自动补全组件",

@@ -9,3 +9,7 @@ "keywords": [

"homepage": "http://aralejs.org/autocomplete/",
"author": "popomore <sakura9515@gmail.com>",
"author": "贯高 <sakura9515@gmail.com>",
"maintainers": [
"贯高 <sakura9515@gmail.com>",
"乔花 <shengyan1985@gmail.com>"
],
"repository": {

@@ -20,2 +24,6 @@ "type": "git",

"spm": {
"engines": {
"seajs": "2.2.1",
"seajs-text": "1.1.0"
},
"buildArgs": "--ignore jquery"

@@ -27,2 +35,3 @@ },

},
"main": "autocomplete.js",
"dependencies": {

@@ -32,5 +41,8 @@ "spm-jquery": "1.7.2",

"arale-templatable": "0.10.0",
"arale-overlay": "1.2.0"
"arale-overlay": "1.2.0",
"spm-handlebars-runtime": "1.3.0"
},
"devDependencies": {
"spm-expect.js": "0.3.1",
"spm-sinon": "1.6.0",
"spm-webpack": "~1.0.0"

@@ -37,0 +49,0 @@ },

@@ -12,2 +12,4 @@ # AutoComplete

AutoComplete 继承自 [overlay](http://aralejs.org/overlay/),可使用其中包括 [widget](http://aralejs.org/widget/)、[base](http://aralejs.org/base/)、[class](http://aralejs.org/class/)、[events](http://aralejs.org/events/)、[attribute](http://aralejs.org/base/docs/attribute.html)、[aspect](http://aralejs.org/base/docs/aspect.html) 的属性和方法。
## 使用说明

@@ -282,1 +284,5 @@

```
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/aralejs/autocomplete/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

@@ -9,11 +9,13 @@ var $ = require('spm-jquery');

var isIE = (window.navigator.userAgent || "").toLowerCase().indexOf("msie") !== -1;
// keyCode
var KEY = {
UP: 38,
DOWN: 40,
LEFT: 37,
RIGHT: 39,
ENTER: 13,
ESC: 27,
BACKSPACE: 8
UP: 38,
DOWN: 40,
LEFT: 37,
RIGHT: 39,
ENTER: 13,
ESC: 27,
BACKSPACE: 8
};

@@ -23,406 +25,436 @@

Implements: Templatable,
Implements: Templatable,
attrs: {
// 触发元素
trigger: {
value: null, // required
getter: function(val) {
return $(val);
}
},
classPrefix: 'ui-autocomplete',
align: {
baseXY: [0, '100%']
},
template: template,
submitOnEnter: true, // 回车是否会提交表单
dataSource: [], //数据源,支持 Array, URL, Object, Function
locator: 'data',
filter: undefined, // 输出过滤
inputFilter: function(v) {return v;}, // 输入过滤
disabled: false,
selectFirst: false,
delay: 100,
// 以下仅为组件使用
selectedIndex: undefined,
inputValue: null, // 同步输入框的 value
data: null
attrs: {
// 触发元素
trigger: {
value: null,
// required
getter: function (val) {
return $(val);
}
},
events: {
// mousedown 先于 blur 触发,选中后再触发 blur 隐藏浮层
// see _blurEvent
'mousedown [data-role=item]': function(e) {
var i = this.items.index(e.currentTarget);
this.set('selectedIndex', i);
this.selectItem();
this._firstMousedown = true;
},
'mousedown': function() {
this._secondMousedown = true;
},
'mouseenter [data-role=item]': function(e) {
var className = this.get('classPrefix') + '-item-hover';
if (this.currentItem) this.currentItem.removeClass(className);
$(e.currentTarget).addClass(className);
},
'mouseleave [data-role=item]': function(e) {
var className = this.get('classPrefix') + '-item-hover';
$(e.currentTarget).removeClass(className);
}
classPrefix: 'ui-autocomplete',
align: {
baseXY: [0, '100%']
},
templateHelpers: {
// 将匹配的高亮文字加上 hl 的样式
highlightItem: highlightItem
template: template,
submitOnEnter: true,
// 回车是否会提交表单
selectItem: true,
// 选中时是否调用 selectItem 方法
dataSource: [],
//数据源,支持 Array, URL, Object, Function
locator: 'data',
filter: undefined,
// 输出过滤
inputFilter: function (v) {
return v;
},
// 输入过滤
disabled: false,
selectFirst: false,
delay: 100,
// 以下仅为组件使用
selectedIndex: undefined,
inputValue: null,
// 同步输入框的 value
data: null
},
parseElement: function() {
this.set("model", {
classPrefix: this.get('classPrefix'),
items: []
});
AutoComplete.superclass.parseElement.call(this);
events: {
// mousedown 先于 blur 触发,选中后再触发 blur 隐藏浮层
// see _blurEvent
'mousedown [data-role=item]': function (e) {
var i = this.items.index(e.currentTarget);
this.set('selectedIndex', i);
if (this.get('selectItem')) {
this.selectItem();
this._firstMousedown = true;
}
},
'mousedown': function () {
this._secondMousedown = true;
},
'click [data-role=item]': function () {
// 在非 selectItem 时隐藏浮层
if (!this.get('selectItem')) {
this.hide();
}
},
'mouseenter [data-role=item]': function (e) {
var className = this.get('classPrefix') + '-item-hover';
if (this.currentItem) this.currentItem.removeClass(className);
$(e.currentTarget).addClass(className);
},
'mouseleave [data-role=item]': function (e) {
var className = this.get('classPrefix') + '-item-hover';
$(e.currentTarget).removeClass(className);
}
},
setup: function() {
var trigger = this.get('trigger'), that = this;
templateHelpers: {
// 将匹配的高亮文字加上 hl 的样式
highlightItem: highlightItem
},
AutoComplete.superclass.setup.call(this);
parseElement: function () {
this.set("model", {
classPrefix: this.get('classPrefix'),
items: []
});
AutoComplete.superclass.parseElement.call(this);
},
// 初始化数据源
this.dataSource = new DataSource({
source: this.get('dataSource')
}).on('data', this._filterData, this);
setup: function () {
var trigger = this.get('trigger'),
that = this;
this._initFilter(); // 初始化 filter
this._blurHide([trigger]);
this._tweakAlignDefaultValue();
AutoComplete.superclass.setup.call(this);
trigger.attr('autocomplete', 'off');
this.delegateEvents(trigger, 'blur.autocomplete', $.proxy(this._blurEvent, this));
this.delegateEvents(trigger, 'keydown.autocomplete', $.proxy(this._keydownEvent, this));
this.delegateEvents(trigger, 'keyup.autocomplete', function() {
clearTimeout(that._timeout);
that._timeout = setTimeout(function() {
that._timeout = null;
that._keyupEvent.call(that);
}, that.get('delay'));
});
// 初始化数据源
this.dataSource = new DataSource({
source: this.get('dataSource')
}).on('data', this._filterData, this);
},
this._initFilter(); // 初始化 filter
this._blurHide([trigger]);
this._tweakAlignDefaultValue();
destroy: function() {
this._clear();
this.element.remove();
AutoComplete.superclass.destroy.call(this);
},
trigger.attr('autocomplete', 'off');
this.delegateEvents(trigger, 'blur.autocomplete', $.proxy(this._blurEvent, this));
this.delegateEvents(trigger, 'keydown.autocomplete', $.proxy(this._keydownEvent, this));
this.delegateEvents(trigger, 'keyup.autocomplete', function () {
clearTimeout(that._timeout);
that._timeout = setTimeout(function () {
that._timeout = null;
that._keyupEvent.call(that);
}, that.get('delay'));
});
hide: function() {
// 隐藏的时候取消请求或回调
if (this._timeout) clearTimeout(this._timeout);
this.dataSource.abort();
AutoComplete.superclass.hide.call(this);
},
},
// Public Methods
// --------------
destroy: function () {
this._clear();
this.element.remove();
AutoComplete.superclass.destroy.call(this);
},
selectItem: function() {
this.hide();
hide: function () {
// 隐藏的时候取消请求或回调
if (this._timeout) clearTimeout(this._timeout);
this.dataSource.abort();
AutoComplete.superclass.hide.call(this);
},
var item = this.currentItem,
index = this.get('selectedIndex'),
data = this.get('data')[index];
// Public Methods
// --------------
selectItem: function () {
this.hide();
if (item) {
var matchKey = item.attr('data-value');
this.get('trigger').val(matchKey);
this.set('inputValue', matchKey);
this.trigger('itemSelect', data);
this._clear();
}
},
var item = this.currentItem,
index = this.get('selectedIndex'),
data = this.get('data')[index];
setInputValue: function(val) {
if (this.get('inputValue') !== val) {
// 进入处理流程
this._start = true;
this.set('inputValue', val);
// 避免光标移动到尾部 #44
var trigger = this.get('trigger');
if (trigger.val() !== val) {
trigger.val(val);
}
}
},
if (item) {
var matchKey = item.attr('data-value');
this.get('trigger').val(matchKey);
this.set('inputValue', matchKey, {
silent: true
});
this.trigger('itemSelect', data);
this._clear();
}
},
// Private Methods
// ---------------
setInputValue: function (val) {
if (this.get('inputValue') !== val) {
// 进入处理流程
this._start = true;
this.set('inputValue', val);
// 避免光标移动到尾部 #44
var trigger = this.get('trigger');
if (trigger.val() !== val) {
trigger.val(val);
}
}
},
// 1. 判断输入值,调用数据源
_onRenderInputValue: function(val) {
if (this._start && val) {
var oldQueryValue = this.queryValue;
this.queryValue = this.get('inputFilter').call(this, val);
// 如果 query 为空或者相等则不处理
if (this.queryValue && this.queryValue !== oldQueryValue) {
this.dataSource.abort();
this.dataSource.getData(this.queryValue);
}
} else {
this.queryValue = '';
}
if (val === '' || !this.queryValue) {
this.set('data', []);
this.hide();
}
delete this._start;
},
// Private Methods
// ---------------
// 1. 判断输入值,调用数据源
_onRenderInputValue: function (val) {
if (this._start && val) {
var oldQueryValue = this.queryValue;
this.queryValue = this.get('inputFilter').call(this, val);
// 如果 query 为空或者相等则不处理
if (this.queryValue && this.queryValue !== oldQueryValue) {
this.dataSource.abort();
this.dataSource.getData(this.queryValue);
}
} else {
this.queryValue = '';
}
if (val === '' || !this.queryValue) {
this.set('data', []);
this.hide();
}
delete this._start;
},
// 2. 数据源返回,过滤数据
_filterData: function(data) {
var filter = this.get('filter'),
locator = this.get('locator');
// 2. 数据源返回,过滤数据
_filterData: function (data) {
var filter = this.get('filter'),
locator = this.get('locator');
// 获取目标数据
data = locateResult(locator, data);
// 获取目标数据
data = locateResult(locator, data);
// 进行过滤
data = filter.func.call(this, data, this.queryValue, filter.options);
// 进行过滤
data = filter.func.call(this, data, this.queryValue, filter.options);
this.set('data', data);
},
this.set('data', data);
},
// 3. 通过数据渲染模板
_onRenderData: function(data) {
// 清除状态
this._clear();
// 3. 通过数据渲染模板
_onRenderData: function (data) {
// 清除状态
this._clear();
// 渲染下拉
this.set("model", {
items: data
});
// 渲染下拉
this.set("model", {
items: data
});
this.renderPartial('[data-role=items]');
this.renderPartial('[data-role=items]');
// 初始化下拉的状态
this.items = this.$('[data-role=items]').children();
this.currentItem = null;
// 初始化下拉的状态
this.items = this.$('[data-role=items]').children();
this.currentItem = null;
if (this.get('selectFirst')) {
this.set('selectedIndex', 0);
}
if (this.get('selectFirst')) {
this.set('selectedIndex', 0);
}
// data-role=items 无内容才隐藏
if ($.trim(this.$('[data-role=items]').text())) {
this.show();
} else {
this.hide();
}
},
// data-role=items 无内容才隐藏
if ($.trim(this.$('[data-role=items]').text())) {
this.show();
} else {
this.hide();
}
},
// 键盘控制上下移动
_onRenderSelectedIndex: function(index) {
if (index === -1) return;
var className = this.get('classPrefix') + '-item-hover';
if (this.currentItem) {
this.currentItem.removeClass(className);
}
this.currentItem = this.items
.eq(index)
.addClass(className);
// 键盘控制上下移动
_onRenderSelectedIndex: function (index) {
if (index === -1) return;
var className = this.get('classPrefix') + '-item-hover';
if (this.currentItem) {
this.currentItem.removeClass(className);
}
this.currentItem = this.items.eq(index).addClass(className);
this.trigger('indexChange', index, this.lastIndex);
this.lastIndex = index;
},
this.trigger('indexChange', index, this.lastIndex);
this.lastIndex = index;
_initFilter: function() {
var filter = this.get('filter');
// scroll current item into view
//this.currentItem.scrollIntoView();
var containerHeight = parseInt(this.get('height'));
if (!containerHeight) return;
// 设置 filter 的默认值
if (filter === undefined) {
// 异步请求的时候一般不需要过滤器
if (this.dataSource.get('type') === 'url') {
filter = null;
} else {
filter = {
name: 'startsWith',
func: Filter['startsWith'],
options: {
key: 'value'
}
};
}
var itemHeight = this.currentItem.parent().height() / this.items.length,
itemTop = Math.max(0, itemHeight * (index + 1) - containerHeight);
this.element.scrollTop(itemTop);
},
_initFilter: function () {
var filter = this.get('filter');
// 设置 filter 的默认值
if (filter === undefined) {
// 异步请求的时候一般不需要过滤器
if (this.dataSource.get('type') === 'url') {
filter = null;
} else {
filter = {
name: 'startsWith',
func: Filter['startsWith'],
options: {
key: 'value'
}
};
}
} else {
// object 的情况
// {
// name: '',
// options: {}
// }
if ($.isPlainObject(filter)) {
if (Filter[filter.name]) {
filter = {
name: filter.name,
func: Filter[filter.name],
options: filter.options
};
} else {
// object 的情况
// {
// name: '',
// options: {}
// }
if ($.isPlainObject(filter)) {
if (Filter[filter.name]) {
filter = {
name: filter.name,
func: Filter[filter.name],
options: filter.options
};
} else {
filter = null;
}
} else if ($.isFunction(filter)) {
filter = {
func: filter
};
} else {
// 从组件内置的 FILTER 获取
if (Filter[filter]) {
filter = {
name: filter,
func: Filter[filter]
};
} else {
filter = null;
}
}
filter = null;
}
// filter 为 null,设置为 default
if (!filter) {
filter = {
name: 'default',
func: Filter['default']
};
} else if ($.isFunction(filter)) {
filter = {
func: filter
};
} else {
// 从组件内置的 FILTER 获取
if (Filter[filter]) {
filter = {
name: filter,
func: Filter[filter]
};
} else {
filter = null;
}
this.set('filter', filter);
},
}
}
// filter 为 null,设置为 default
if (!filter) {
filter = {
name: 'default',
func: Filter['default']
};
}
this.set('filter', filter);
},
_blurEvent: function() {
if ($.browser.msie) return;
_blurEvent: function () {
if (isIE) return;
// https://github.com/aralejs/autocomplete/issues/26
if (!this._secondMousedown) {
this.hide();
} else if (this._firstMousedown) {
this.get('trigger').focus();
this.hide();
}
delete this._firstMousedown;
delete this._secondMousedown;
},
// https://github.com/aralejs/autocomplete/issues/26
if (!this._secondMousedown) {
this.hide();
} else if (this._firstMousedown) {
this.get('trigger').focus();
this.hide();
}
delete this._firstMousedown;
delete this._secondMousedown;
},
_keyupEvent: function() {
if (this.get('disabled')) return;
_keyupEvent: function () {
if (this.get('disabled')) return;
if (this._keyupStart) {
delete this._keyupStart;
// 获取输入的值
var v = this.get('trigger').val();
this.setInputValue(v);
}
},
if (this._keyupStart) {
delete this._keyupStart;
// 获取输入的值
var v = this.get('trigger').val();
this.setInputValue(v);
}
},
_keydownEvent: function(e) {
if (this.get('disabled')) return;
_keydownEvent: function (e) {
if (this.get('disabled')) return;
// 先清空状态
delete this._keyupStart;
// 先清空状态
delete this._keyupStart;
switch (e.which) {
case KEY.ESC:
this.hide();
break;
switch (e.which) {
case KEY.ESC:
this.hide();
break;
// top arrow
case KEY.UP:
this._keyUp(e);
break;
// top arrow
case KEY.UP:
this._keyUp(e);
break;
// bottom arrow
case KEY.DOWN:
this._keyDown(e);
break;
// bottom arrow
case KEY.DOWN:
this._keyDown(e);
break;
// left arrow
case KEY.LEFT:
// right arrow
case KEY.RIGHT:
break;
// left arrow
case KEY.LEFT:
// right arrow
case KEY.RIGHT:
break;
// enter
case KEY.ENTER:
this._keyEnter(e);
break;
// enter
case KEY.ENTER:
this._keyEnter(e);
break;
// default 继续执行 keyup
default:
this._keyupStart = true;
}
},
// default 继续执行 keyup
default:
this._keyupStart = true;
}
},
_keyUp: function(e) {
e.preventDefault();
if (this.get('data').length) {
if (!this.get('visible')) {
this.show();
return;
}
this._step(-1);
}
},
_keyUp: function (e) {
e.preventDefault();
var data = this.get('data');
if (data && data.length) {
if (!this.get('visible')) {
this.show();
return;
}
this._step(-1);
}
},
_keyDown: function(e) {
e.preventDefault();
if (this.get('data').length) {
if (!this.get('visible')) {
this.show();
return;
}
this._step(1);
}
},
_keyDown: function (e) {
e.preventDefault();
var data = this.get('data');
if (data && data.length) {
if (!this.get('visible')) {
this.show();
return;
}
this._step(1);
}
},
_keyEnter: function(e) {
if (this.get('visible')) {
this.selectItem();
_keyEnter: function (e) {
if (this.get('visible')) {
this.selectItem();
// 是否阻止回车提交表单
if (!this.get('submitOnEnter')) {
e.preventDefault();
}
}
},
// 是否阻止回车提交表单
if (!this.get('submitOnEnter')) {
e.preventDefault();
}
}
},
// 选项上下移动
_step: function(direction) {
var currentIndex = this.get('selectedIndex');
if (direction === -1) { // 反向
if (currentIndex > 0) {
this.set('selectedIndex', currentIndex - 1);
} else {
this.set('selectedIndex', this.items.length - 1);
}
} else if (direction === 1) { // 正向
if (currentIndex < this.items.length - 1) {
this.set('selectedIndex', currentIndex + 1);
} else {
this.set('selectedIndex', 0);
}
}
},
// 选项上下移动
_step: function (direction) {
if (!this.items) return;
var currentIndex = this.get('selectedIndex');
if (direction === -1) { // 反向
if (currentIndex > 0) {
this.set('selectedIndex', currentIndex - 1);
} else {
this.set('selectedIndex', this.items.length - 1);
}
} else if (direction === 1) { // 正向
if (currentIndex < this.items.length - 1) {
this.set('selectedIndex', currentIndex + 1);
} else {
this.set('selectedIndex', 0);
}
}
},
_clear: function() {
this.$('[data-role=items]').empty();
this.set('selectedIndex', -1);
delete this.items;
delete this.lastIndex;
delete this.currentItem;
},
_clear: function () {
this.$('[data-role=items]').empty();
this.set('selectedIndex', -1);
delete this.items;
delete this.lastIndex;
delete this.currentItem;
},
// 调整 align 属性的默认值
_tweakAlignDefaultValue: function() {
var align = this.get('align');
align.baseElement = this.get('trigger');
this.set('align', align);
}
// 调整 align 属性的默认值
_tweakAlignDefaultValue: function () {
var align = this.get('align');
align.baseElement = this.get('trigger');
this.set('align', align);
}

@@ -432,6 +464,10 @@

// 以便写测试用例
AutoComplete._filter = Filter;
module.exports = AutoComplete;
function isString(str) {
return Object.prototype.toString.call(str) === '[object String]';
return Object.prototype.toString.call(str) === '[object String]';
}

@@ -449,55 +485,59 @@

// 最后的返回值为 c
function locateResult(locator, data) {
if (!locator) {
return data;
if (!locator) {
return data;
}
if ($.isFunction(locator)) {
return locator.call(this, data);
} else if (isString(locator)) {
var s = locator.split('.'),
p = data;
while (s.length) {
var v = s.shift();
if (!p[v]) {
break;
}
p = p[v];
}
if ($.isFunction(locator)) {
return locator.call(this, data);
} else if (isString(locator)) {
var s = locator.split('.'), p = data;
while (s.length) {
var v = s.shift();
if (!p[v]) {
break;
}
p = p[v];
}
return p;
}
return data;
return p;
}
return data;
}
function highlightItem(classPrefix, matchKey) {
var index = this.highlightIndex,
cursor = 0, v = matchKey || this.matchKey || '', h = '';
if ($.isArray(index)) {
for (var i = 0, l = index.length; i < l; i++) {
var j = index[i], start, length;
if ($.isArray(j)) {
start = j[0];
length = j[1] - j[0];
} else {
start = j;
length = 1;
}
var index = this.highlightIndex,
cursor = 0,
v = matchKey || this.matchKey || '',
h = '';
if ($.isArray(index)) {
for (var i = 0, l = index.length; i < l; i++) {
var j = index[i],
start, length;
if ($.isArray(j)) {
start = j[0];
length = j[1] - j[0];
} else {
start = j;
length = 1;
}
if (start > cursor) {
h += v.substring(cursor, start);
}
if (start < v.length) {
h += '<span class="' + classPrefix + '-item-hl">' +
v.substr(start, length) +
'</span>';
}
cursor = start + length;
if (cursor >= v.length) {
break;
}
}
if (v.length > cursor) {
h += v.substring(cursor, v.length);
}
return h;
if (start > cursor) {
h += v.substring(cursor, start);
}
if (start < v.length) {
h += '<span class="' + classPrefix + '-item-hl">' + v.substr(start, length) + '</span>';
}
cursor = start + length;
if (cursor >= v.length) {
break;
}
}
return v;
}
if (v.length > cursor) {
h += v.substring(cursor, v.length);
}
return h;
}
return v;
}

@@ -6,99 +6,104 @@ var Base = require('arale-base');

attrs: {
source: null,
type: 'array'
},
attrs: {
source: null,
type: 'array'
},
initialize: function(config) {
DataSource.superclass.initialize.call(this, config);
initialize: function (config) {
DataSource.superclass.initialize.call(this, config);
// 每次发送请求会将 id 记录到 callbacks 中,返回后会从中删除
// 如果 abort 会清空 callbacks,之前的请求结果都不会执行
this.id = 0;
this.callbacks = [];
// 每次发送请求会将 id 记录到 callbacks 中,返回后会从中删除
// 如果 abort 会清空 callbacks,之前的请求结果都不会执行
this.id = 0;
this.callbacks = [];
var source = this.get('source');
if (isString(source)) {
this.set('type', 'url');
} else if ($.isArray(source)) {
this.set('type', 'array');
} else if ($.isPlainObject(source)) {
this.set('type', 'object');
} else if ($.isFunction(source)) {
this.set('type', 'function');
} else {
throw new Error('Source Type Error');
}
},
var source = this.get('source');
if (isString(source)) {
this.set('type', 'url');
} else if ($.isArray(source)) {
this.set('type', 'array');
} else if ($.isPlainObject(source)) {
this.set('type', 'object');
} else if ($.isFunction(source)) {
this.set('type', 'function');
} else {
throw new Error('Source Type Error');
}
},
getData: function(query) {
return this['_get' + capitalize(this.get('type') || '') + 'Data'](query);
},
getData: function (query) {
return this['_get' + capitalize(this.get('type') || '') + 'Data'](query);
},
abort: function() {
this.callbacks = [];
},
abort: function () {
this.callbacks = [];
},
// 完成数据请求,getData => done
_done: function(data) {
this.trigger('data', data);
},
// 完成数据请求,getData => done
_done: function (data) {
this.trigger('data', data);
},
_getUrlData: function(query) {
var that = this, options;
var obj = {
query: query ? encodeURIComponent(query) : '',
timestamp: new Date().getTime()
};
var url = this.get('source')
.replace(/{{(.*?)}}/g, function(all, match) {
return obj[match];
});
_getUrlData: function (query) {
var that = this,
options;
var obj = {
query: query ? encodeURIComponent(query) : '',
timestamp: new Date().getTime()
};
var url = this.get('source').replace(/{{(.*?)}}/g, function (all, match) {
return obj[match];
});
var callbackId = 'callback_' + this.id++;
this.callbacks.push(callbackId);
var callbackId = 'callback_' + this.id++;
this.callbacks.push(callbackId);
if (/^(https?:\/\/)/.test(url)) {
options = {dataType: 'jsonp'};
} else {
options = {dataType: 'json'};
}
$.ajax(url, options)
.success(function(data) {
if ($.inArray(callbackId, that.callbacks) > -1) {
delete that.callbacks[callbackId];
that._done(data);
}
})
.error(function() {
if ($.inArray(callbackId, that.callbacks) > -1) {
delete that.callbacks[callbackId];
that._done({});
}
});
},
if (/^(https?:\/\/)/.test(url)) {
options = {
dataType: 'jsonp'
};
} else {
options = {
dataType: 'json'
};
}
$.ajax(url, options).success(function (data) {
if ($.inArray(callbackId, that.callbacks) > -1) {
delete that.callbacks[callbackId];
that._done(data);
}
}).error(function () {
if ($.inArray(callbackId, that.callbacks) > -1) {
delete that.callbacks[callbackId];
that._done({});
}
});
},
_getArrayData: function() {
var source = this.get('source');
this._done(source);
return source;
},
_getArrayData: function () {
var source = this.get('source');
this._done(source);
return source;
},
_getObjectData: function() {
var source = this.get('source');
this._done(source);
return source;
},
_getObjectData: function () {
var source = this.get('source');
this._done(source);
return source;
},
_getFunctionData: function(query) {
var that = this, func = this.get('source');
// 如果返回 false 可阻止执行
function done(data) {
that._done(data);
}
var data = func.call(this, query, done);
if (data) {
this._done(data);
}
_getFunctionData: function (query) {
var that = this,
func = this.get('source');
// 如果返回 false 可阻止执行
function done(data) {
that._done(data);
}
var data = func.call(this, query, done);
if (data) {
this._done(data);
}
}
});

@@ -110,12 +115,9 @@

function isString(str) {
return Object.prototype.toString.call(str) === '[object String]';
return Object.prototype.toString.call(str) === '[object String]';
}
function capitalize(str) {
return str.replace(
/^([a-z])/,
function(f, m) {
return m.toUpperCase();
}
);
}
return str.replace(/^([a-z])/, function (f, m) {
return m.toUpperCase();
});
}
var $ = require('spm-jquery');
var Filter = {
'default': function(data, query, options) {
var result = [];
$.each(data, function(index, item) {
var o = {}, matchKey = getMatchKey(item, options);
if ($.isPlainObject(item)) {
o = $.extend({}, item);
}
o.matchKey = matchKey;
result.push(o);
});
return result;
},
'default': function (data, query, options) {
var result = [];
$.each(data, function (index, item) {
var o = {},
matchKey = getMatchKey(item, options);
if ($.isPlainObject(item)) {
o = $.extend({}, item);
}
o.matchKey = matchKey;
result.push(o);
});
return result;
},
// options: {
// key: 'value'
// }
'startsWith': function(data, query, options) {
var result = [], l = query.length,
reg = new RegExp('^' + escapeKeyword(query));
// options: {
// key: 'value'
// }
'startsWith': function (data, query, options) {
var result = [],
l = query.length,
reg = new RegExp('^' + escapeKeyword(query));
if (!l) return [];
if (!l) return [];
$.each(data, function(index, item) {
var o = {}, matchKey = getMatchKey(item, options);
$.each(data, function (index, item) {
var o = {},
matchKey = getMatchKey(item, options);
if ($.isPlainObject(item)) {
o = $.extend({}, item);
}
// 生成 item
// {
// ... // self property
// matchKey: '', // 匹配的内容
// highlightIndex: [] // 高亮的索引
// }
if (reg.test(matchKey)) {
o.matchKey = matchKey;
if (l > 0) {
o.highlightIndex = [[0, l]];
}
result.push(o);
}
});
return result;
},
if ($.isPlainObject(item)) {
o = $.extend({}, item);
}
// 生成 item
// {
// ... // self property
// matchKey: '', // 匹配的内容
// highlightIndex: [] // 高亮的索引
// }
if (reg.test(matchKey)) {
o.matchKey = matchKey;
if (l > 0) {
o.highlightIndex = [
[0, l]
];
}
result.push(o);
}
});
return result;
},
'stringMatch': function(data, query, options) {
query = query || '';
var result = [], l = query.length;
'stringMatch': function (data, query, options) {
query = query || '';
var result = [],
l = query.length;
if (!l) return [];
if (!l) return [];
$.each(data, function(index, item) {
var o = {}, matchKey = getMatchKey(item, options);
$.each(data, function (index, item) {
var o = {},
matchKey = getMatchKey(item, options);
if ($.isPlainObject(item)) {
o = $.extend({}, item);
}
if ($.isPlainObject(item)) {
o = $.extend({}, item);
}
if (matchKey.indexOf(query) > -1) {
o.matchKey = matchKey;
o.highlightIndex = stringMatch(matchKey, query);
result.push(o);
}
});
return result;
}
if (matchKey.indexOf(query) > -1) {
o.matchKey = matchKey;
o.highlightIndex = stringMatch(matchKey, query);
result.push(o);
}
});
return result;
}
};

@@ -76,35 +83,37 @@

function getMatchKey(item, options) {
if ($.isPlainObject(item)) {
// 默认取对象的 value 属性
var key = (options && options.key) || 'value';
return item[key] || '';
} else {
return item;
}
if ($.isPlainObject(item)) {
// 默认取对象的 value 属性
var key = (options && options.key) || 'value';
return item[key] || '';
} else {
return item;
}
}
function stringMatch(matchKey, query) {
var r = [], a = matchKey.split('');
var queryIndex = 0, q = query.split('');
for (var i = 0, l = a.length; i < l; i++) {
var v = a[i];
if (v == q[queryIndex]) {
if (queryIndex === q.length -1) {
r.push([i - q.length + 1,i + 1]);
queryIndex = 0;
continue;
}
queryIndex++;
} else {
queryIndex = 0;
}
var r = [],
a = matchKey.split('');
var queryIndex = 0,
q = query.split('');
for (var i = 0, l = a.length; i < l; i++) {
var v = a[i];
if (v == q[queryIndex]) {
if (queryIndex === q.length - 1) {
r.push([i - q.length + 1, i + 1]);
queryIndex = 0;
continue;
}
queryIndex++;
} else {
queryIndex = 0;
}
return r;
}
return r;
}
// 转义正则关键字
var keyword = /(\[|\[|\]|\^|\$|\||\(|\)|\{|\}|\+|\*|\?)/g;
function escapeKeyword (str) {
var keyword = /(\[|\[|\]|\^|\$|\||\(|\)|\{|\}|\+|\*|\?|\\)/g;
function escapeKeyword(str) {
return (str || '').replace(keyword, '\\$1');
}
}

@@ -1,533 +0,564 @@

define(function(require) {
var sinon = require('spm-sinon');
var expect = require('spm-expect.js');
var AutoComplete = require('../src/autocomplete');
var $ = require('spm-jquery');
var isIE = (window.navigator.userAgent || "").toLowerCase().indexOf("msie") !== -1;
var sinon = require('spm-sinon');
var expect = require('puerh');
var Filter = require('filter');
var AutoComplete = require('spm-autocomplete');
var $ = require('$');
AutoComplete._filter.test = function () {
return [];
};
Filter.test = function() {
return [];
};
describe('Autocomplete', function () {
describe('Autocomplete', function() {
var input, ac;
var input, ac;
beforeEach(function () {
input = $('<input id="test" type="text" value="" />').appendTo(document.body);
});
afterEach(function () {
input.remove();
if (ac) {
ac.destroy();
ac = null;
}
});
beforeEach(function() {
input = $('<input id="test" type="text" value="" />')
.appendTo(document.body);
});
afterEach(function() {
input.remove();
if (ac) {
ac.destroy();
ac = null;
}
});
it('normal usage', function () {
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
it('normal usage', function() {
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.setInputValue('a');
ac.setInputValue('a');
expect(ac.get('data')).to.eql([{
matchKey: 'abc',
highlightIndex: [
[0, 1]
]
},
{
matchKey: 'abd',
highlightIndex: [
[0, 1]
]
}]);
});
expect(ac.get('data')).to.eql([
{matchKey: 'abc', highlightIndex: [[0, 1]]},
{matchKey: 'abd', highlightIndex: [[0, 1]]}
]);
});
it('should hide when empty', function () {
var input = $('#test');
input.val('a');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
it('should hide when empty', function() {
var input = $('#test');
input.val('a');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.setInputValue('');
ac.setInputValue('');
expect(ac.get('visiable')).not.to.be.ok();
expect(ac.get('inputValue')).to.be('');
});
expect(ac.get('visiable')).not.to.be.ok();
expect(ac.get('inputValue')).to.be('');
});
it('should not call "getData" when empty', function () {
var input = $('#test');
input.val('a');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
it('should not call "getData" when empty', function() {
var input = $('#test');
input.val('a');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
var getData = sinon.spy(ac.dataSource, 'getData');
var getData = sinon.spy(ac.dataSource, 'getData');
ac.setInputValue('');
expect(getData.called).not.to.be(true);
ac.setInputValue('');
expect(getData).not.to.be.called();
ac.setInputValue('a');
expect(getData.called).to.be(true);
getData.restore();
});
ac.setInputValue('a');
expect(getData).to.be.called();
getData.restore();
});
it('render', function () {
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
it('render', function() {
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.setInputValue('a');
ac.setInputValue('a');
expect(ac.items.eq(0).data('value')).to.be('abc');
expect(ac.items.eq(0).text()).to.be('abc');
expect(ac.items.eq(0).find('.ui-autocomplete-item-hl').text()).to.be('a');
expect(ac.items.eq(1).data('value')).to.be('abd');
expect(ac.items.eq(1).text()).to.be('abd');
expect(ac.items.eq(1).find('.ui-autocomplete-item-hl').text()).to.be('a');
});
expect(ac.items.eq(0).data('value')).to.be('abc');
expect(ac.items.eq(0).text()).to.be('abc');
expect(ac.items.eq(0).find('.ui-autocomplete-item-hl').text()).to.be('a');
expect(ac.items.eq(1).data('value')).to.be('abd');
expect(ac.items.eq(1).text()).to.be('abd');
expect(ac.items.eq(1).find('.ui-autocomplete-item-hl').text()).to.be('a');
});
describe('inputValue', function () {
it('should be called when value changed', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
describe('inputValue', function() {
it('should be called when value changed', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
var spy = sinon.spy(ac, '_onRenderInputValue');
var spy = sinon.spy(ac, '_onRenderInputValue');
ac.setInputValue('a');
expect(spy.withArgs('a').calledOnce).to.be(true);
ac.setInputValue('a');
expect(spy).to.be.called.withArgs('a');
expect(spy).to.be.called.once();
ac._keyupEvent.call(ac);
expect(spy.calledOnce).to.be(true);
ac._keyupEvent.call(ac);
expect(spy).to.be.called.once();
ac.setInputValue('ab');
expect(spy.withArgs('ab').calledOnce).to.be(true);
ac.setInputValue('ab');
expect(spy).to.be.called.withArgs('ab');
expect(spy).to.be.called.twice();
ac.setInputValue('a');
expect(spy.withArgs('a').calledTwice).to.be(true);
ac.setInputValue('a');
expect(spy).to.be.called.withArgs('a');
expect(spy).to.be.called.thrice();
spy.restore();
});
spy.restore();
});
it('should filter the input', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
inputFilter: function(val) {
return 'filter-' + val;
},
dataSource: ['abc', 'abd', 'cbd']
}).render();
it('should filter the input', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
inputFilter: function (val) {
return 'filter-' + val;
},
dataSource: ['abc', 'abd', 'cbd']
}).render();
var spy = sinon.spy(ac.dataSource, 'getData');
var spy = sinon.spy(ac.dataSource, 'getData');
ac.setInputValue('a');
expect(spy).to.be.called.withArgs('filter-a');
expect(spy).to.be.called.once();
ac.setInputValue('a');
expect(spy.withArgs('filter-a').calledOnce).to.be(true);
ac.setInputValue('');
expect(spy).to.be.called.once();
spy.restore();
});
});
ac.setInputValue('');
expect(spy.calledOnce).to.be(true);
spy.restore();
});
});
describe('data locator', function() {
it('should support string', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: {
test: ['abc', 'abd', 'cbd']
},
locator: 'test'
}).render();
describe('data locator', function () {
it('should support string', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: {
test: ['abc', 'abd', 'cbd']
},
locator: 'test'
}).render();
ac.setInputValue('a');
expect(ac.get('data')).to.eql([
{matchKey: 'abc', highlightIndex: [[0, 1]]},
{matchKey: 'abd', highlightIndex: [[0, 1]]}
]);
});
ac.setInputValue('a');
expect(ac.get('data')).to.eql([{
matchKey: 'abc',
highlightIndex: [
[0, 1]
]
},
{
matchKey: 'abd',
highlightIndex: [
[0, 1]
]
}]);
});
it('should support dot string', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: {
test: {
more: ['abc', 'abd', 'cbd']
}
},
locator: 'test.more'
}).render();
it('should support dot string', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: {
test: {
more: ['abc', 'abd', 'cbd']
}
},
locator: 'test.more'
}).render();
ac.setInputValue('a');
expect(ac.get('data')).to.eql([
{matchKey: 'abc', highlightIndex: [[0, 1]]},
{matchKey: 'abd', highlightIndex: [[0, 1]]}
]);
});
ac.setInputValue('a');
expect(ac.get('data')).to.eql([{
matchKey: 'abc',
highlightIndex: [
[0, 1]
]
},
{
matchKey: 'abd',
highlightIndex: [
[0, 1]
]
}]);
});
it('should support function', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: {
test1: ['abc', 'cbd'],
test2: ['abd']
},
locator: function(data) {
return data.test1.concat(data.test2);
}
}).render();
it('should support function', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: {
test1: ['abc', 'cbd'],
test2: ['abd']
},
locator: function (data) {
return data.test1.concat(data.test2);
}
}).render();
ac.setInputValue('a');
expect(ac.get('data')).to.eql([
{matchKey: 'abc', highlightIndex: [[0, 1]]},
{matchKey: 'abd', highlightIndex: [[0, 1]]}
]);
});
});
ac.setInputValue('a');
expect(ac.get('data')).to.eql([{
matchKey: 'abc',
highlightIndex: [
[0, 1]
]
},
{
matchKey: 'abd',
highlightIndex: [
[0, 1]
]
}]);
});
});
it('should be hide when trigger blur #26', function() {
if ($.browser.msie) return;
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc']
}).render();
ac.setInputValue('a');
input.blur();
it('should be hide when trigger blur #26', function () {
if (isIE) return;
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc']
}).render();
ac.setInputValue('a');
input.blur();
expect(ac.get('visible')).not.to.be.ok();
});
expect(ac.get('visible')).not.to.be.ok();
});
it('should be hide when mousedown #26', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc']
}).render();
ac.setInputValue('a');
ac.items.eq(0).mousedown();
it('should be hide when mousedown #26', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc']
}).render();
ac.setInputValue('a');
ac.items.eq(0).mousedown();
expect(ac.get('visible')).not.to.be.ok();
});
expect(ac.get('visible')).not.to.be.ok();
});
it('should not be hide when mousedown #26', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
template: '<div><p data-role="other">a</p><ul data-role="items">{{#each items}}<li data-role="item">{{matchKey}}</li>{{/each}}</ul></div>',
dataSource: ['abc']
}).render();
ac.setInputValue('a');
expect(ac.get('visible')).to.be.ok();
ac.element.find('[data-role=other]').mousedown();
it('should not be hide when mousedown #26', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
template: '<div><p data-role="other">a</p><ul data-role="items">{{#each items}}<li data-role="item">{{matchKey}}</li>{{/each}}</ul></div>',
dataSource: ['abc']
}).render();
ac.setInputValue('a');
expect(ac.get('visible')).to.be.ok();
ac.element.find('[data-role=other]').mousedown();
expect(ac.get('visible')).to.be.ok();
});
expect(ac.get('visible')).to.be.ok();
});
describe('filter', function() {
it('should be "startsWith" by default', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: []
});
describe('filter', function () {
it('should be "startsWith" by default', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: []
});
expect(ac.get('filter')).to.eql({
name: 'startsWith',
func: Filter['startsWith'],
options: {
key: 'value'
}
});
});
it('should be "default" when ajax by default', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: './data.json'
});
var filter = ac.get('filter');
expect(ac.get('filter')).to.eql({
name: 'default',
func: Filter['default']
});
});
it('should be "default" when "", null, false', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: '',
dataSource: []
});
expect(filter.name).to.eql('startsWith');
expect(filter.options.key).to.eql("value");
});
it('should be "default" when ajax by default', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: './data.json'
});
expect(ac.get('filter')).to.eql({
name: 'default',
func: Filter['default']
});
});
it('should support string', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: 'test',
dataSource: []
});
expect(ac.get('filter').name).to.eql('default');
});
it('should be "default" when "", null, false', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: '',
dataSource: []
});
expect(ac.get('filter')).to.eql({
name: 'test',
func: Filter.test
});
});
expect(ac.get('filter').name).to.eql('default');
});
it('should support string', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: 'test',
dataSource: []
});
it('should support string but not exist', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: 'notExist',
dataSource: []
});
expect(ac.get('filter').name).to.eql('test');
});
expect(ac.get('filter')).to.eql({
name: 'default',
func: Filter['default']
});
});
it('should support function', function() {
var input = $('#test');
var func = function() {};
ac = new AutoComplete({
trigger: '#test',
filter: func,
dataSource: []
});
it('should support string but not exist', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: 'notExist',
dataSource: []
});
expect(ac.get('filter')).to.eql({
func: func
});
});
it('should support object', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: {
name: 'startsWith',
options: {
key: 'title'
}
},
dataSource: []
});
expect(ac.get('filter').name).to.eql('default');
});
it('should support function', function () {
var input = $('#test');
var func = function () {};
ac = new AutoComplete({
trigger: '#test',
filter: func,
dataSource: []
});
expect(ac.get('filter')).to.eql({
name: 'startsWith',
options: {
key: 'title'
},
func: Filter.startsWith
});
});
it('should support object but not exist', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: {
name: 'notExist'
},
dataSource: []
});
expect(ac.get('filter')).to.eql({
func: func
});
});
it('should support object', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: {
name: 'startsWith',
options: {
key: 'title'
}
},
dataSource: []
});
expect(ac.get('filter')).to.eql({
name: 'default',
func: Filter['default']
});
});
it('should be called with 3 param', function() {
var input = $('#test');
var spy = sinon.spy();
Filter.filter = spy;
ac = new AutoComplete({
trigger: '#test',
filter: {
name: 'filter',
options: {
key: 'value'
}
},
dataSource: ['abc']
}).render();
expect(ac.get('filter').name).to.eql('startsWith');
});
it('should support object but not exist', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
filter: {
name: 'notExist'
},
dataSource: []
});
ac.setInputValue('a');
expect(spy).to.be.called.withArgs(['abc'], 'a', {key: 'value'});
});
});
expect(ac.get('filter').name).to.eql('default');
});
it('should be called with 3 param', function () {
var input = $('#test');
var spy = sinon.spy();
AutoComplete._filter.filter = spy;
ac = new AutoComplete({
trigger: '#test',
filter: {
name: 'filter',
options: {
key: 'value'
}
},
dataSource: ['abc']
}).render();
it('select item', function() {
var input = $('#test'), beCalled = false;
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).on('itemSelect', function() {
beCalled = true;
}).render();
ac.setInputValue('a');
expect(spy.withArgs(['abc'], 'a', {
key: 'value'
}).called).to.be(true);
});
});
ac.setInputValue('a');
ac.set('selectedIndex', 0);
it('select item', function () {
var input = $('#test'),
beCalled = false;
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).on('itemSelect', function () {
beCalled = true;
}).render();
ac.selectItem();
expect(ac.get('visible')).to.be(false);
expect(input.val()).to.be('abc');
expect(ac.get('inputValue')).to.be('abc');
expect(beCalled).to.be.ok();
});
ac.setInputValue('a');
ac.set('selectedIndex', 0);
it('highlight item', function() {
var input = $('#test'), item;
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.selectItem();
expect(ac.get('visible')).to.be(false);
expect(input.val()).to.be('abc');
expect(ac.get('inputValue')).to.be('abc');
expect(beCalled).to.be.ok();
});
ac.set('data', [
{matchKey: 'abcdefg', highlightIndex: [[0, 1]]}
]);
item = ac.$('[data-role=item]')
.eq(0)
.find('.ui-autocomplete-item-hl');
expect(item.length).to.be(1);
expect(item.eq(0).text()).to.be('a');
delete ac.oldInput;
it('highlight item', function () {
var input = $('#test'),
item;
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.set('data', [
{matchKey: 'abcdefg', highlightIndex: [[1, 2], [3, 4]]}
]);
item = ac.$('[data-role=item]')
.eq(0)
.find('.ui-autocomplete-item-hl');
expect(item.length).to.be(2);
expect(item.eq(0).text()).to.be('b');
expect(item.eq(1).text()).to.be('d');
delete ac.oldInput;
ac.set('data', [{
matchKey: 'abcdefg',
highlightIndex: [
[0, 1]
]
}]);
item = ac.$('[data-role=item]').eq(0).find('.ui-autocomplete-item-hl');
expect(item.length).to.be(1);
expect(item.eq(0).text()).to.be('a');
delete ac.oldInput;
ac.set('data', [
{matchKey: 'abcdefg', highlightIndex: [[0, 1], [3, 7], [8, 9]]}
]);
item = ac.$('[data-role=item]')
.eq(0)
.find('.ui-autocomplete-item-hl');
expect(item.length).to.be(2);
expect(item.eq(0).text()).to.be('a');
expect(item.eq(1).text()).to.be('defg');
delete ac.oldInput;
ac.set('data', [{
matchKey: 'abcdefg',
highlightIndex: [
[1, 2],
[3, 4]
]
}]);
item = ac.$('[data-role=item]').eq(0).find('.ui-autocomplete-item-hl');
expect(item.length).to.be(2);
expect(item.eq(0).text()).to.be('b');
expect(item.eq(1).text()).to.be('d');
delete ac.oldInput;
ac.set('data', [
{matchKey: 'abcdefg', highlightIndex: [1, 4]}
]);
item = ac.$('[data-role=item]')
.eq(0)
.find('.ui-autocomplete-item-hl');
expect(item.length).to.be(2);
expect(item.eq(0).text()).to.be('b');
expect(item.eq(1).text()).to.be('e');
delete ac.oldInput;
ac.set('data', [{
matchKey: 'abcdefg',
highlightIndex: [
[0, 1],
[3, 7],
[8, 9]
]
}]);
item = ac.$('[data-role=item]').eq(0).find('.ui-autocomplete-item-hl');
expect(item.length).to.be(2);
expect(item.eq(0).text()).to.be('a');
expect(item.eq(1).text()).to.be('defg');
delete ac.oldInput;
ac.set('data', [
{matchKey: 'abcdefg', highlightIndex: [6, 8]}
]);
item = ac.$('[data-role=item]')
.eq(0)
.find('.ui-autocomplete-item-hl');
expect(item.length).to.be(1);
expect(item.eq(0).text()).to.be('g');
delete ac.oldInput;
});
ac.set('data', [{
matchKey: 'abcdefg',
highlightIndex: [1, 4]
}]);
item = ac.$('[data-role=item]').eq(0).find('.ui-autocomplete-item-hl');
expect(item.length).to.be(2);
expect(item.eq(0).text()).to.be('b');
expect(item.eq(1).text()).to.be('e');
delete ac.oldInput;
it('clear', function() {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.set('data', [{
matchKey: 'abcdefg',
highlightIndex: [6, 8]
}]);
item = ac.$('[data-role=item]').eq(0).find('.ui-autocomplete-item-hl');
expect(item.length).to.be(1);
expect(item.eq(0).text()).to.be('g');
delete ac.oldInput;
});
ac.setInputValue('a');
it('clear', function () {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac._clear();
expect(ac.$('[data-role=items]').html()).to.be('');
expect(ac.items).to.be(undefined);
expect(ac.currentItem).to.be(undefined);
expect(ac.currentItem).to.be(undefined);
expect(ac.get('selectedIndex')).to.be(-1);
});
ac.setInputValue('a');
it('do not show when async #14', function(done) {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: 'http://baidu.com'
}).render();
ac._clear();
expect(ac.$('[data-role=items]').html()).to.be('');
expect(ac.items).to.be(undefined);
expect(ac.currentItem).to.be(undefined);
expect(ac.currentItem).to.be(undefined);
expect(ac.get('selectedIndex')).to.be(-1);
});
var spy = sinon.stub($, 'ajax').returns({
success: function(callback) {
setTimeout(function() {
callback(['abc', 'abd', 'cbd']);
}, 50);
return this;
},
error: function(callback) {
}
});
it('do not show when async #14', function (done) {
var input = $('#test');
ac = new AutoComplete({
trigger: '#test',
dataSource: 'http://baidu.com'
}).render();
var t = ac.element.html();
var spy = sinon.stub($, 'ajax').returns({
success: function (callback) {
setTimeout(function () {
callback(['abc', 'abd', 'cbd']);
}, 50);
return this;
},
error: function (callback) {}
});
ac.setInputValue('a');
var t = ac.element.html();
setTimeout(function() {
expect(ac.get('visible')).to.be.ok();
spy.restore();
done();
}, 50);
ac.setInputValue('a');
});
setTimeout(function () {
expect(ac.get('visible')).to.be.ok();
spy.restore();
done();
}, 50);
it('should support selectFirst', function() {
ac = new AutoComplete({
trigger: '#test',
selectFirst: true,
dataSource: ['abc', 'abd', 'cbd']
}).render();
});
ac.setInputValue('a');
expect(ac.get('selectedIndex')).to.be(0);
it('should support selectFirst', function () {
ac = new AutoComplete({
trigger: '#test',
selectFirst: true,
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.setInputValue('a');
expect(ac.get('selectedIndex')).to.be(0);
});
it('should show when same value', function() {
ac = new AutoComplete({
trigger: '#test',
selectFirst: true,
dataSource: ['abc', 'abd', 'cbd']
}).render();
});
ac.setInputValue('a');
expect(ac.get('visible')).to.be.ok();
it('should show when same value', function () {
ac = new AutoComplete({
trigger: '#test',
selectFirst: true,
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.setInputValue('');
expect(ac.get('visible')).not.to.be.ok();
ac.setInputValue('a');
expect(ac.get('visible')).to.be.ok();
ac.setInputValue('a');
expect(ac.get('visible')).to.be.ok();
});
});
ac.setInputValue('');
expect(ac.get('visible')).not.to.be.ok();
});
ac.setInputValue('a');
expect(ac.get('visible')).to.be.ok();
});
it('should auto scroll #82', function () {
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'abe', 'acd', 'ace', 'acf', 'acg', 'ach', 'aci', 'acj', 'ack'],
style: {
'overflow': 'scroll'
},
height: 120
}).render();
ac.setInputValue('a');
expect(ac.get('visible')).to.be.ok();
ac._step(1);
expect(ac.element.scrollTop()).to.be(0);
ac._step(1);
expect(ac.element.scrollTop()).to.be(0);
ac._step(1);
expect(ac.element.scrollTop()).to.be(0);
ac._step(1);
expect(ac.element.scrollTop()).to.be(0);
ac._step(1);
expect(ac.element.scrollTop()).to.be(30);
});
});

@@ -1,189 +0,177 @@

define(function(require) {
var sinon = require('spm-sinon');
var expect = require('spm-expect.js');
var DataSource = require('../src/data-source');
var $ = require('spm-jquery');
var sinon = require('spm-sinon');
var expect = require('puerh');
var DataSource = require('data-source');
var $ = require('$');
describe('DataSource', function () {
describe('DataSource', function() {
var data;
var data;
beforeEach(function () {
data = ['about', 'abuse', 'but', 'buffter'];
});
beforeEach(function() {
data = [
'about',
'abuse',
'but',
'buffter'
];
});
afterEach(function () {
data = null;
});
afterEach(function() {
data = null;
});
it('error type', function () {
// not Boolean
expect(function () {
new DataSource({
source: true
});
}).to.throwError();
it('error type', function() {
// not Boolean
expect(function() {
new DataSource({
source: true
});
}).to.throwError();
// not Null
expect(function () {
new DataSource({
source: null
});
}).to.throwError();
// not Null
expect(function() {
new DataSource({
source: null
});
}).to.throwError();
// not Undefined
expect(function () {
new DataSource({
source: undefined
});
}).to.throwError();
// not Undefined
expect(function() {
new DataSource({
source: undefined
});
}).to.throwError();
// not DOM Element
expect(function () {
new DataSource({
source: document.body
});
}).to.throwError();
});
it('type is array', function () {
var spy = sinon.spy();
var param = [1, 2, 3];
var source = new DataSource({
source: param
}).on('data', spy).getData();
expect(spy.withArgs(param).called).to.be(true);
});
// not DOM Element
expect(function() {
new DataSource({
source: document.body
});
}).to.throwError();
});
it('type is array', function() {
var spy = sinon.spy();
var param = [1, 2, 3];
var source = new DataSource({
source: param
}).on('data', spy).getData();
expect(spy).to.be.called.withArgs(param);
});
it('type is object', function () {
var spy = sinon.spy();
var param = {
data: 1
};
var source = new DataSource({
source: param
}).on('data', spy).getData();
expect(spy.withArgs(param).called).to.be(true);
});
it('type is object', function() {
var spy = sinon.spy();
var param = {
data: 1
};
var source = new DataSource({
source: param
}).on('data', spy).getData();
expect(spy).to.be.called.withArgs(param);
});
it('type is function', function () {
var spy = sinon.spy();
var source = new DataSource({
source: function (q) {
return [
q + '@163.com'];
}
}).on('data', spy).getData('a');
expect(spy.withArgs(['a@163.com']).called).to.be(true);
});
it('type is function', function() {
var spy = sinon.spy();
var source = new DataSource({
source: function(q) {
return [
q + '@163.com'
];
}
}).on('data', spy).getData('a');
expect(spy).to.be.called.withArgs(['a@163.com']);
});
it('type is function return false', function () {
var spy = sinon.spy();
var source = new DataSource({
source: function (q) {
return false;
}
}).on('data', spy).getData('a');
expect(spy.called).not.to.be(true);
});
it('type is function return false', function() {
var spy = sinon.spy();
var source = new DataSource({
source: function(q) {
return false;
}
}).on('data', spy).getData('a');
expect(spy).not.to.be.called();
});
it('type is function async', function (done) {
var spy = sinon.spy();
var source = new DataSource({
source: function (q, done) {
setTimeout(function () {
done();
}, 10);
return false;
}
}).on('data', spy).getData('a');
it('type is function async', function(done) {
var spy = sinon.spy();
var source = new DataSource({
source: function(q, done) {
setTimeout(function() {
done();
}, 10);
return false;
}
}).on('data', spy).getData('a');
setTimeout(function () {
expect(spy.called).to.be(true);
done();
}, 500);
});
setTimeout(function() {
expect(spy).to.be.called();
done();
}, 500);
});
it('type is url', function () {
var spy = sinon.spy();
var stub = sinon.stub($, 'ajax').returns({
success: function (callback) {
callback([1, 2, 3]);
return this;
},
error: function (callback) {}
});
it('type is url', function() {
var spy = sinon.spy();
var stub = sinon.stub($, 'ajax').returns({
success: function(callback) {
callback([1, 2, 3]);
return this;
},
error: function(callback) {
}
});
var source = new DataSource({
source: './test.json?q={{query}}'
}).on('data', spy).getData('a');
//expect(stub.called).to.be(true);
expect(spy.withArgs([1, 2, 3]).called).to.be(true);
stub.restore();
});
var source = new DataSource({
source: './test.json?q={{query}}'
}).on('data', spy).getData('a');
expect(stub).to.be.called.match('./test.json?q=a');
expect(spy).to.be.called.withArgs([1, 2, 3]);
stub.restore();
});
it('type is url when error', function () {
var spy = sinon.spy();
var stub = sinon.stub($, 'ajax').returns({
success: function (callback) {
return this;
},
error: function (callback) {
callback();
return this;
}
});
it('type is url when error', function() {
var spy = sinon.spy();
var stub = sinon.stub($, 'ajax').returns({
success: function(callback) {
return this;
},
error: function(callback) {
callback();
return this;
}
});
var source = new DataSource({
source: './test.json?q={{query}}'
}).on('data', spy).getData('a');
expect(spy.withArgs({}).called).to.be(true);
stub.restore();
});
it('abort', function (done) {
var stub = sinon.stub($, 'ajax').returns({
success: function (callback) {
setTimeout(function () {
callback(['a']);
}, 10);
return this;
},
error: function (callback) {
return this;
}
});
var source = new DataSource({
source: './test.json?q={{query}}'
});
var source = new DataSource({
source: './test.json?q={{query}}'
}).on('data', spy).getData('a');
expect(spy).to.be.called.withArgs({});
stub.restore();
});
it('abort', function(done) {
var stub = sinon.stub($, 'ajax').returns({
success: function(callback) {
setTimeout(function() {
callback(['a']);
}, 10);
return this;
},
error: function(callback) {
return this;
}
});
var source = new DataSource({
source: './test.json?q={{query}}'
});
var spy = sinon.spy(source, '_done');
var spy = sinon.spy(source, '_done');
source.getData('a');
expect(source.callbacks.length).to.be(1);
source.getData('a');
expect(source.callbacks.length).to.be(1);
source.getData('a');
expect(source.callbacks.length).to.be(2);
source.getData('a');
expect(source.callbacks.length).to.be(2);
source.abort();
expect(source.callbacks.length).to.be(0);
source.abort();
expect(source.callbacks.length).to.be(0);
source.getData('a');
expect(source.callbacks.length).to.be(1);
source.getData('a');
expect(source.callbacks.length).to.be(1);
setTimeout(function() {
expect(spy).to.be.called.once();
stub.restore();
done();
}, 500);
});
});
});
setTimeout(function () {
expect(spy.calledOnce).to.be(true);
stub.restore();
done();
}, 500);
});
});

@@ -1,84 +0,134 @@

define(function(require) {
var expect = require('spm-expect.js');
var Filter = require('../src/filter');
var expect = require('puerh');
var Filter = require('filter');
describe('Filter', function () {
var data;
beforeEach(function () {
data = ['about',
{
value: 'abuse abbess'
},
{
title: 'absolute abbey'
}, 'but', 'buffer'];
});
afterEach(function () {
data = null;
});
describe('Filter', function() {
var data;
beforeEach(function() {
data = [
'about',
{value: 'abuse abbess'},
{title: 'absolute abbey'},
'but',
'buffer'
];
});
afterEach(function() {
data = null;
});
describe('default', function () {
it('return all', function () {
var result = Filter['default'](data);
expect(result).to.eql([{
matchKey: 'about'
},
{
matchKey: 'abuse abbess',
value: 'abuse abbess'
},
{
matchKey: '',
title: 'absolute abbey'
},
{
matchKey: 'but'
},
{
matchKey: 'buffer'
}]);
});
describe('default', function() {
it('return all', function() {
var result = Filter['default'](data);
expect(result).to.eql([
{matchKey: 'about'},
{matchKey: 'abuse abbess', value: 'abuse abbess'},
{matchKey: '', title: 'absolute abbey'},
{matchKey: 'but'},
{matchKey: 'buffer'}
]);
});
it('return all when set option key', function() {
var result = Filter['default'](data, 'a', {key: 'title'});
expect(result).to.eql([
{matchKey: 'about'},
{matchKey: '', value: 'abuse abbess'},
{matchKey: 'absolute abbey', title: 'absolute abbey'},
{matchKey: 'but'},
{matchKey: 'buffer'}
]);
});
});
it('return all when set option key', function () {
var result = Filter['default'](data, 'a', {
key: 'title'
});
expect(result).to.eql([{
matchKey: 'about'
},
{
matchKey: '',
value: 'abuse abbess'
},
{
matchKey: 'absolute abbey',
title: 'absolute abbey'
},
{
matchKey: 'but'
},
{
matchKey: 'buffer'
}]);
});
});
describe('startsWith', function() {
it('start width a', function() {
var result = Filter.startsWith(data, 'a');
expect(result).to.eql([
{matchKey: 'about', highlightIndex: [[0, 1]]},
{matchKey: 'abuse abbess', value: 'abuse abbess', highlightIndex: [[0, 1]]}
]);
});
describe('startsWith', function () {
it('start width a', function () {
var result = Filter.startsWith(data, 'a');
expect(result).to.eql([{
matchKey: 'about',
highlightIndex: [
[0, 1]
]
},
{
matchKey: 'abuse abbess',
value: 'abuse abbess',
highlightIndex: [
[0, 1]
]
}]);
});
it('start width none', function() {
var result = Filter.startsWith(data, '');
expect(result).to.eql([]);
});
it('start width none', function () {
var result = Filter.startsWith(data, '');
expect(result).to.eql([]);
});
it('start width more', function() {
var result = Filter.startsWith(data, 'abc');
expect(result).to.eql([]);
});
it('start width more', function () {
var result = Filter.startsWith(data, 'abc');
expect(result).to.eql([]);
});
it('option key is title', function() {
var result = Filter.startsWith(data, 'a', {key: 'title'});
expect(result).to.eql([
{matchKey: 'about', highlightIndex: [[0, 1]]},
{matchKey: 'absolute abbey', title: 'absolute abbey', highlightIndex: [[0, 1]]}
]);
});
});
it('option key is title', function () {
var result = Filter.startsWith(data, 'a', {
key: 'title'
});
expect(result).to.eql([{
matchKey: 'about',
highlightIndex: [
[0, 1]
]
},
{
matchKey: 'absolute abbey',
title: 'absolute abbey',
highlightIndex: [
[0, 1]
]
}]);
});
});
describe('stringMatch', function() {
it('match a', function() {
var result = Filter.stringMatch(data, 'ab', {key: 'title'});
expect(result).to.eql([
{matchKey: 'about', highlightIndex: [[0, 2]]},
{matchKey: 'absolute abbey', title: 'absolute abbey', highlightIndex: [[0, 2], [9, 11]]}
]);
});
});
describe('stringMatch', function () {
it('match a', function () {
var result = Filter.stringMatch(data, 'ab', {
key: 'title'
});
expect(result).to.eql([{
matchKey: 'about',
highlightIndex: [
[0, 2]
]
},
{
matchKey: 'absolute abbey',
title: 'absolute abbey',
highlightIndex: [
[0, 2],
[9, 11]
]
}]);
});
});
});
});

@@ -1,43 +0,59 @@

define(function(require) {
var expect = require('spm-expect.js');
var $ = require('spm-jquery');
var AutoComplete = require('../src/autocomplete');
var expect = require('puerh');
var $ = require('$');
var Filter = require('filter');
var AutoComplete = require('spm-autocomplete');
describe('Issue', function () {
it('#56 start with (', function () {
var data = ['about',
{
value: 'abuse'
},
{
title: 'absolute'
}, 'but', 'buffer', '(abc'];
var result = AutoComplete._filter.startsWith(data, '(a');
expect(result).to.eql([{
matchKey: '(abc',
highlightIndex: [
[0, 2]
]
}]);
});
describe('Issue', function() {
it('#56 start with (', function() {
var data = [
'about',
{value: 'abuse'},
{title: 'absolute'},
'but',
'buffer',
'(abc'
];
var result = Filter.startsWith(data, '(a');
expect(result).to.eql([
{matchKey: '(abc', highlightIndex: [[0, 2]]}
]);
});
it('#55 dont\'t change selectedIndex when hover', function () {
var ac, input = $('<input id="test" type="text" value="" />').appendTo(document.body);
it('#55 dont\'t change selectedIndex when hover', function() {
var ac, input = $('<input id="test" type="text" value="" />')
.appendTo(document.body);
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac = new AutoComplete({
trigger: '#test',
dataSource: ['abc', 'abd', 'cbd']
}).render();
ac.setInputValue('a');
var item = ac.$('li').eq(1);
item.mouseenter();
expect(item.hasClass('ui-autocomplete-item-hover')).to.be.ok();
item.mouseleave();
expect(item.hasClass('ui-autocomplete-item-hover')).not.to.be.ok();
ac.setInputValue('a');
var item = ac.$('li').eq(1);
item.mouseenter();
expect(item.hasClass('ui-autocomplete-item-hover')).to.be.ok();
expect(ac.get('selectedIndex')).to.be(-1);
expect(ac.get('selectedIndex')).to.be(-1);
input.remove();
ac.destroy();
});
input.remove();
ac.destroy();
});
});
it('#72 start with \\', function () {
var ac, input = $('<input id="test" type="text" value="" />').appendTo(document.body);
ac = new AutoComplete({
trigger: '#test',
dataSource: []
}).render();
expect(function () {
ac.setInputValue('\\');
}).not.to.throwError();
input.remove();
ac.destroy();
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc