arale-autocomplete
Advanced tools
Comparing version 1.2.1 to 1.2.6
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
287
70570
5
3
1504
+ Addedspm-handlebars-runtime@1.3.0