diff --git a/.gitignore b/.gitignore
index 8754ab6..3f3cc66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@ node_modules
sea-modules
tests/coverage.html
.cache
+dist/
diff --git a/.travis.yml b/.travis.yml
index e5c2daf..bf8de4c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,19 +1,16 @@
language: node_js
node_js:
- - 0.10
+ - "0.10"
install:
- - npm install mocha-browser nico
+ - npm install spm@ninja coveralls
before_script:
- - git clone git://github.com/aralejs/nico-arale.git _theme
- - node_modules/.bin/nico build --theme _theme -C _theme/nico.js
+ - node_modules/spm/bin/spm-install
script:
- - node_modules/.bin/mocha-browser _site/tests/runner.html -S
+ - node_modules/spm/bin/spm-test
after_success:
- - npm install jscoverage coveralls
- - node_modules/.bin/jscoverage --encoding=utf8 src _site/src-cov
- - node_modules/.bin/mocha-browser _site/tests/runner.html?cov -S -R lcov | node_modules/.bin/coveralls
+ - node_modules/spm/bin/spm-test --coveralls | node_modules/.bin/coveralls
diff --git a/HISTORY.md b/HISTORY.md
index b7bbd2f..c713272 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -2,6 +2,10 @@
---
+## 1.4.0
+
+迁移 spm@3.x
+
## 1.3.1
`tag:fixed` 修复 for/in 数组的 bug
@@ -86,7 +90,7 @@
`tag:new` [#11](https://github.com/aralejs/autocomplete/issues/11) 控制按键频率。
`tag:new` [#13](https://github.com/aralejs/autocomplete/issues/13) dataSource 支持 ajax。
-
+
`tag:new` [#15](https://github.com/aralejs/autocomplete/issues/15) 提供 selectFirst 参数。
`tag:new` [#16](https://github.com/aralejs/autocomplete/issues/16) dataSource 支持复杂的结构。
diff --git a/Makefile b/Makefile
deleted file mode 100644
index b5a4ee9..0000000
--- a/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-THEME = $(HOME)/.spm/themes/arale
-
-build-doc:
- @nico build -C $(THEME)/nico.js
-
-publish-doc: clean build-doc
- @spm publish --doc _site -s spmjs
-
-server:
- @nico server -C $(THEME)/nico.js
-
-watch:
- @nico server -C $(THEME)/nico.js --watch
-
-clean:
- @rm -fr _site
-
-
-runner = _site/tests/runner.html
-test-src:
- @mocha-browser ${runner} -S
-
-test-dist:
- @mocha-browser ${runner}?dist -S
-
-test: test-src test-dist
-
-output = _site/coverage.html
-coverage: build-doc
- @rm -fr _site/src-cov
- @jscoverage --encoding=utf8 src _site/src-cov
- @mocha-browser ${runner}?cov -S -R html-cov > ${output}
- @echo "Build coverage to ${output}"
-
-
-.PHONY: build-doc publish-doc server clean test coverage
-
-
diff --git a/autocomplete.js b/autocomplete.js
new file mode 100644
index 0000000..e03a36d
--- /dev/null
+++ b/autocomplete.js
@@ -0,0 +1 @@
+module.exports = require('./src/autocomplete');
diff --git a/dist/autocomplete-debug.js b/dist/autocomplete-debug.js
deleted file mode 100644
index 744bc19..0000000
--- a/dist/autocomplete-debug.js
+++ /dev/null
@@ -1,784 +0,0 @@
-define("arale/autocomplete/1.3.0/autocomplete-debug", [ "$-debug", "arale/overlay/1.1.2/overlay-debug", "arale/position/1.0.1/position-debug", "arale/iframe-shim/1.0.2/iframe-shim-debug", "arale/widget/1.1.1/widget-debug", "arale/base/1.1.1/base-debug", "arale/class/1.1.0/class-debug", "arale/events/1.1.0/events-debug", "arale/templatable/0.9.2/templatable-debug", "gallery/handlebars/1.0.2/handlebars-debug", "./data-source-debug", "./filter-debug", "./input-debug", "./autocomplete-debug.handlebars" ], function(require, exports, module) {
- var $ = require("$-debug");
- var Overlay = require("arale/overlay/1.1.2/overlay-debug");
- var Templatable = require("arale/templatable/0.9.2/templatable-debug");
- var DataSource = require("./data-source-debug");
- var Filter = require("./filter-debug");
- var Input = require("./input-debug");
- var IE678 = /\bMSIE [678]\.0\b/.test(navigator.userAgent);
- var template = require("./autocomplete-debug.handlebars");
- var AutoComplete = Overlay.extend({
- Implements: Templatable,
- attrs: {
- // 触发元素
- trigger: null,
- classPrefix: "ui-select",
- align: {
- baseXY: [ 0, "100%" ]
- },
- submitOnEnter: true,
- // 回车是否会提交表单
- dataSource: {
- //数据源,支持 Array, URL, Object, Function
- value: [],
- getter: function(val) {
- var that = this;
- if ($.isFunction(val)) {
- return function() {
- val.apply(that, arguments);
- };
- }
- return val;
- }
- },
- locator: "data",
- // 输出过滤
- filter: null,
- disabled: false,
- selectFirst: false,
- delay: 100,
- // 以下为模板相关
- model: {
- value: {
- items: []
- },
- getter: function(val) {
- val.classPrefix || (val.classPrefix = this.get("classPrefix"));
- return val;
- }
- },
- template: template,
- footer: "",
- header: "",
- html: "{{{label}}}",
- // 以下仅为组件使用
- selectedIndex: null,
- data: []
- },
- events: {
- "mousedown [data-role=items]": "_handleMouseDown",
- "click [data-role=item]": "_handleSelection",
- "mouseenter [data-role=item]": "_handleMouseMove",
- "mouseleave [data-role=item]": "_handleMouseMove"
- },
- templateHelpers: {
- // 将匹配的高亮文字加上 hl 的样式
- highlightItem: highlightItem,
- include: include
- },
- parseElement: function() {
- var t = [ "header", "footer", "html" ];
- for (var i in t) {
- this.templatePartials || (this.templatePartials = {});
- this.templatePartials[t[i]] = this.get(t[i]);
- }
- AutoComplete.superclass.parseElement.call(this);
- },
- setup: function() {
- AutoComplete.superclass.setup.call(this);
- this._isOpen = false;
- this._initInput();
- // 初始化输入框
- this._initDataSource();
- // 初始化数据源
- this._initFilter();
- // 初始化过滤器
- this._bindHandle();
- // 绑定事件
- this._blurHide([ $(this.get("trigger")) ]);
- this._tweakAlignDefaultValue();
- this.on("indexChanged", function(index) {
- // scroll current item into view
- //this.currentItem.scrollIntoView();
- var containerHeight = parseInt(this.get("height"), 10);
- if (!containerHeight) return;
- var itemHeight = this.items.parent().height() / this.items.length, itemTop = Math.max(0, itemHeight * (index + 1) - containerHeight);
- this.element.children().scrollTop(itemTop);
- });
- },
- show: function() {
- this._isOpen = true;
- // 无数据则不显示
- if (this._isEmpty()) return;
- AutoComplete.superclass.show.call(this);
- },
- hide: function() {
- // 隐藏的时候取消请求或回调
- if (this._timeout) clearTimeout(this._timeout);
- this.dataSource.abort();
- this._hide();
- },
- destroy: function() {
- this._clear();
- if (this.input) {
- this.input.destroy();
- this.input = null;
- }
- AutoComplete.superclass.destroy.call(this);
- },
- // Public Methods
- // --------------
- selectItem: function(index) {
- if (this.items) {
- if (index && this.items.length > index && index >= -1) {
- this.set("selectedIndex", index);
- }
- this._handleSelection();
- }
- },
- setInputValue: function(val) {
- this.input.setValue(val);
- },
- // Private Methods
- // ---------------
- // 数据源返回,过滤数据
- _filterData: function(data) {
- var filter = this.get("filter"), locator = this.get("locator");
- // 获取目标数据
- data = locateResult(locator, data);
- // 进行过滤
- data = filter.call(this, normalize(data), this.input.get("query"));
- this.set("data", data);
- },
- // 通过数据渲染模板
- _onRenderData: function(data) {
- data || (data = []);
- // 渲染下拉
- this.set("model", {
- items: data,
- query: this.input.get("query"),
- length: data.length
- });
- this.renderPartial();
- // 初始化下拉的状态
- this.items = this.$("[data-role=items]").children();
- if (this.get("selectFirst")) {
- this.set("selectedIndex", 0);
- }
- // 选中后会修改 input 的值并触发下一次渲染,但第二次渲染的结果不应该显示出来。
- this._isOpen && this.show();
- },
- // 键盘控制上下移动
- _onRenderSelectedIndex: function(index) {
- var hoverClass = this.get("classPrefix") + "-item-hover";
- this.items && this.items.removeClass(hoverClass);
- // -1 什么都不选
- if (index === -1) return;
- this.items.eq(index).addClass(hoverClass);
- this.trigger("indexChanged", index, this.lastIndex);
- this.lastIndex = index;
- },
- // 初始化
- // ------------
- _initDataSource: function() {
- this.dataSource = new DataSource({
- source: this.get("dataSource")
- });
- },
- _initInput: function() {
- this.input = new Input({
- element: this.get("trigger"),
- delay: this.get("delay")
- });
- },
- _initFilter: function() {
- var filter = this.get("filter");
- filter = initFilter(filter, this.dataSource);
- this.set("filter", filter);
- },
- // 事件绑定
- // ------------
- _bindHandle: function() {
- this.dataSource.on("data", this._filterData, this);
- this.input.on("blur", this.hide, this).on("focus", this._handleFocus, this).on("keyEnter", this._handleSelection, this).on("keyEsc", this.hide, this).on("keyUp keyDown", this.show, this).on("keyUp keyDown", this._handleStep, this).on("queryChanged", this._clear, this).on("queryChanged", this._hide, this).on("queryChanged", this._handleQueryChange, this).on("queryChanged", this.show, this);
- this.after("hide", function() {
- this.set("selectedIndex", -1);
- });
- // 选中后隐藏浮层
- this.on("itemSelected", function() {
- this._hide();
- });
- },
- // 选中的处理器
- // 1. 鼠标点击触发
- // 2. 回车触发
- // 3. selectItem 触发
- _handleSelection: function(e) {
- var isMouse = e ? e.type === "click" : false;
- var index = isMouse ? this.items.index(e.currentTarget) : this.get("selectedIndex");
- var item = this.items.eq(index);
- var data = this.get("data")[index];
- if (index >= 0 && item) {
- this.input.setValue(data.label);
- this.set("selectedIndex", index, {
- silent: true
- });
- // 是否阻止回车提交表单
- if (e && !isMouse && !this.get("submitOnEnter")) e.preventDefault();
- this.trigger("itemSelected", data, item);
- }
- },
- _handleFocus: function() {
- this._isOpen = true;
- },
- _handleMouseMove: function(e) {
- var hoverClass = this.get("classPrefix") + "-item-hover";
- this.items.removeClass(hoverClass);
- if (e.type === "mouseenter") {
- var index = this.items.index(e.currentTarget);
- this.set("selectedIndex", index, {
- silent: true
- });
- this.items.eq(index).addClass(hoverClass);
- }
- },
- _handleMouseDown: function(e) {
- if (IE678) {
- var trigger = this.input.get("element")[0];
- trigger.onbeforedeactivate = function() {
- window.event.returnValue = false;
- trigger.onbeforedeactivate = null;
- };
- }
- e.preventDefault();
- },
- _handleStep: function(e) {
- e.preventDefault();
- this.get("visible") && this._step(e.type === "keyUp" ? -1 : 1);
- },
- _handleQueryChange: function(val, prev) {
- if (this.get("disabled")) return;
- this.dataSource.abort();
- this.dataSource.getData(val);
- },
- // 选项上下移动
- _step: function(direction) {
- var currentIndex = this.get("selectedIndex");
- if (direction === -1) {
- // 反向
- if (currentIndex > -1) {
- 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", -1);
- }
- }
- },
- _clear: function() {
- this.$("[data-role=items]").empty();
- this.set("selectedIndex", -1);
- delete this.items;
- delete this.lastIndex;
- },
- _hide: function() {
- this._isOpen = false;
- AutoComplete.superclass.hide.call(this);
- },
- _isEmpty: function() {
- var data = this.get("data");
- return !(data && data.length > 0);
- },
- // 调整 align 属性的默认值
- _tweakAlignDefaultValue: function() {
- var align = this.get("align");
- align.baseElement = this.get("trigger");
- this.set("align", align);
- }
- });
- module.exports = AutoComplete;
- function isString(str) {
- return Object.prototype.toString.call(str) === "[object String]";
- }
- function isObject(obj) {
- return Object.prototype.toString.call(obj) === "[object Object]";
- }
- // 通过 locator 找到 data 中的某个属性的值
- // 1. locator 支持 function,函数返回值为结果
- // 2. locator 支持 string,而且支持点操作符寻址
- // data {
- // a: {
- // b: 'c'
- // }
- // }
- // locator 'a.b'
- // 最后的返回值为 c
- function locateResult(locator, data) {
- if (locator) {
- if ($.isFunction(locator)) {
- return locator.call(this, data);
- } else if (!$.isArray(data) && 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;
- }
- // 标准格式,不匹配则忽略
- //
- // {
- // label: '', 显示的字段
- // value: '', 匹配的字段
- // alias: [] 其他匹配的字段
- // }
- function normalize(data) {
- var result = [];
- $.each(data, function(index, item) {
- if (isString(item)) {
- result.push({
- label: item,
- value: item,
- alias: []
- });
- } else if (isObject(item)) {
- if (!item.value && !item.label) return;
- item.value || (item.value = item.label);
- item.label || (item.label = item.value);
- item.alias || (item.alias = []);
- result.push(item);
- }
- });
- return result;
- }
- // 初始化 filter
- // 支持的格式
- // 1. null: 使用默认的 startsWith
- // 2. string: 从 Filter 中找,如果不存在则用 default
- // 3. function: 自定义
- function initFilter(filter, dataSource) {
- // 字符串
- if (isString(filter)) {
- // 从组件内置的 FILTER 获取
- if (Filter[filter]) {
- filter = Filter[filter];
- } else {
- filter = Filter["default"];
- }
- } else if (!$.isFunction(filter)) {
- // 异步请求的时候不需要过滤器
- if (dataSource.get("type") === "url") {
- filter = Filter["default"];
- } else {
- filter = Filter["startsWith"];
- }
- }
- return filter;
- }
- function include(options) {
- var context = {};
- mergeContext(this);
- mergeContext(options.hash);
- return options.fn(context);
- function mergeContext(obj) {
- for (var k in obj) context[k] = obj[k];
- }
- }
- function highlightItem(label) {
- var index = this.highlightIndex, classPrefix = this.parent ? this.parent.classPrefix : "", cursor = 0, v = label || this.label || "", 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) {
- var className = classPrefix ? 'class="' + classPrefix + '-item-hl"' : "";
- h += "" + v.substr(start, length) + "";
- }
- cursor = start + length;
- if (cursor >= v.length) {
- break;
- }
- }
- if (v.length > cursor) {
- h += v.substring(cursor, v.length);
- }
- return h;
- }
- return v;
- }
-});
-
-define("arale/autocomplete/1.3.0/data-source-debug", [ "arale/base/1.1.1/base-debug", "arale/class/1.1.0/class-debug", "arale/events/1.1.0/events-debug", "$-debug" ], function(require, exports, module) {
- var Base = require("arale/base/1.1.1/base-debug");
- var $ = require("$-debug");
- var DataSource = Base.extend({
- attrs: {
- source: null,
- type: "array"
- },
- initialize: function(config) {
- DataSource.superclass.initialize.call(this, config);
- // 每次发送请求会将 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");
- }
- },
- getData: function(query) {
- return this["_get" + capitalize(this.get("type") || "") + "Data"](query);
- },
- abort: function() {
- this.callbacks = [];
- },
- // 完成数据请求,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];
- });
- 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({});
- }
- });
- },
- _getArrayData: 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);
- }
- }
- });
- module.exports = DataSource;
- function isString(str) {
- return Object.prototype.toString.call(str) === "[object String]";
- }
- function capitalize(str) {
- return str.replace(/^([a-z])/, function(f, m) {
- return m.toUpperCase();
- });
- }
-});
-
-define("arale/autocomplete/1.3.0/filter-debug", [ "$-debug" ], function(require, exports, module) {
- var $ = require("$-debug");
- var Filter = {
- "default": function(data) {
- return data;
- },
- startsWith: function(data, query) {
- query = query || "";
- var result = [], l = query.length, reg = new RegExp("^" + escapeKeyword(query));
- if (!l) return [];
- $.each(data, function(index, item) {
- var a, matchKeys = [ item.value ].concat(item.alias);
- // 匹配 value 和 alias 中的
- while (a = matchKeys.shift()) {
- if (reg.test(a)) {
- // 匹配和显示相同才有必要高亮
- if (item.label === a) {
- item.highlightIndex = [ [ 0, l ] ];
- }
- result.push(item);
- break;
- }
- }
- });
- return result;
- },
- stringMatch: function(data, query) {
- query = query || "";
- var result = [], l = query.length;
- if (!l) return [];
- $.each(data, function(index, item) {
- var a, matchKeys = [ item.value ].concat(item.alias);
- // 匹配 value 和 alias 中的
- while (a = matchKeys.shift()) {
- if (a.indexOf(query) > -1) {
- // 匹配和显示相同才有必要高亮
- if (item.label === a) {
- item.highlightIndex = stringMatch(a, query);
- }
- result.push(item);
- break;
- }
- }
- });
- return result;
- }
- };
- module.exports = Filter;
- // 转义正则关键字
- var keyword = /(\[|\[|\]|\^|\$|\||\(|\)|\{|\}|\+|\*|\?|\\)/g;
- function escapeKeyword(str) {
- return (str || "").replace(keyword, "\\$1");
- }
- 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;
- }
- }
- return r;
- }
-});
-
-define("arale/autocomplete/1.3.0/input-debug", [ "$-debug", "arale/base/1.1.1/base-debug", "arale/class/1.1.0/class-debug", "arale/events/1.1.0/events-debug" ], function(require, exports, module) {
- var $ = require("$-debug");
- var Base = require("arale/base/1.1.1/base-debug");
- var lteIE9 = /\bMSIE [6789]\.0\b/.test(navigator.userAgent);
- var specialKeyCodeMap = {
- 9: "tab",
- 27: "esc",
- 37: "left",
- 39: "right",
- 13: "enter",
- 38: "up",
- 40: "down"
- };
- var Input = Base.extend({
- attrs: {
- element: {
- value: null,
- setter: function(val) {
- return $(val);
- }
- },
- query: null,
- delay: 100
- },
- initialize: function() {
- Input.superclass.initialize.apply(this, arguments);
- // bind events
- this._bindEvents();
- // init query
- this.set("query", this.getValue());
- },
- focus: function() {
- this.get("element").focus();
- },
- getValue: function() {
- return this.get("element").val();
- },
- setValue: function(val, silent) {
- this.get("element").val(val);
- !silent && this._change();
- },
- destroy: function() {
- Input.superclass.destroy.call(this);
- },
- _bindEvents: function() {
- var timer, input = this.get("element");
- input.attr("autocomplete", "off").on("focus.autocomplete", wrapFn(this._handleFocus, this)).on("blur.autocomplete", wrapFn(this._handleBlur, this)).on("keydown.autocomplete", wrapFn(this._handleKeydown, this));
- // IE678 don't support input event
- // IE 9 does not fire an input event when the user removes characters from input filled by keyboard, cut, or drag operations.
- if (!lteIE9) {
- input.on("input.autocomplete", wrapFn(this._change, this));
- } else {
- var that = this, events = [ "keydown.autocomplete", "keypress.autocomplete", "cut.autocomplete", "paste.autocomplete" ].join(" ");
- input.on(events, wrapFn(function(e) {
- if (specialKeyCodeMap[e.which]) return;
- clearTimeout(timer);
- timer = setTimeout(function() {
- that._change.call(that, e);
- }, this.get("delay"));
- }, this));
- }
- },
- _change: function() {
- var newVal = this.getValue();
- var oldVal = this.get("query");
- var isSame = compare(oldVal, newVal);
- var isSameExpectWhitespace = isSame ? newVal.length !== oldVal.length : false;
- if (isSameExpectWhitespace) {
- this.trigger("whitespaceChanged", oldVal);
- }
- if (!isSame) {
- this.set("query", newVal);
- this.trigger("queryChanged", newVal, oldVal);
- }
- },
- _handleFocus: function(e) {
- this.trigger("focus", e);
- },
- _handleBlur: function(e) {
- this.trigger("blur", e);
- },
- _handleKeydown: function(e) {
- var keyName = specialKeyCodeMap[e.which];
- if (keyName) {
- var eventKey = "key" + ucFirst(keyName);
- this.trigger(e.type = eventKey, e);
- }
- }
- });
- module.exports = Input;
- function wrapFn(fn, context) {
- return function() {
- fn.apply(context, arguments);
- };
- }
- function compare(a, b) {
- a = (a || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
- b = (b || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
- return a === b;
- }
- function ucFirst(str) {
- return str.charAt(0).toUpperCase() + str.substring(1);
- }
-});
-
-define("arale/autocomplete/1.3.0/autocomplete-debug.handlebars", [ "gallery/handlebars/1.0.2/runtime-debug" ], function(require, exports, module) {
- var Handlebars = require("gallery/handlebars/1.0.2/runtime-debug");
- var template = Handlebars.template;
- module.exports = template(function(Handlebars, depth0, helpers, partials, data) {
- this.compilerInfo = [ 3, ">= 1.0.0-rc.4" ];
- helpers = helpers || {};
- for (var key in Handlebars.helpers) {
- helpers[key] = helpers[key] || Handlebars.helpers[key];
- }
- partials = partials || Handlebars.partials;
- data = data || {};
- var buffer = "", stack1, self = this, functionType = "function", escapeExpression = this.escapeExpression, helperMissing = helpers.helperMissing;
- function program1(depth0, data, depth1) {
- var buffer = "", stack1, stack2, options;
- buffer += '\n
\n \n ';
- options = {
- hash: {
- parent: depth1
- },
- inverse: self.noop,
- fn: self.program(2, program2, data),
- data: data
- };
- stack2 = (stack1 = helpers.include, stack1 ? stack1.call(depth0, options) : helperMissing.call(depth0, "include", options));
- if (stack2 || stack2 === 0) {
- buffer += stack2;
- }
- buffer += "\n \n \n ";
- return buffer;
- }
- function program2(depth0, data) {
- var stack1;
- stack1 = self.invokePartial(partials.html, "html", depth0, helpers, partials, data);
- if (stack1 || stack1 === 0) {
- return stack1;
- } else {
- return "";
- }
- }
- buffer += '\n
\n ';
- stack1 = self.invokePartial(partials.header, "header", depth0, helpers, partials, data);
- if (stack1 || stack1 === 0) {
- buffer += stack1;
- }
- buffer += '\n
\n ';
- stack1 = helpers.each.call(depth0, depth0.items, {
- hash: {},
- inverse: self.noop,
- fn: self.programWithDepth(1, program1, data, depth0),
- data: data
- });
- if (stack1 || stack1 === 0) {
- buffer += stack1;
- }
- buffer += "\n
\n ";
- stack1 = self.invokePartial(partials.footer, "footer", depth0, helpers, partials, data);
- if (stack1 || stack1 === 0) {
- buffer += stack1;
- }
- buffer += "\n
\n
\n";
- return buffer;
- });
-});
diff --git a/dist/autocomplete.js b/dist/autocomplete.js
deleted file mode 100644
index 2ed1316..0000000
--- a/dist/autocomplete.js
+++ /dev/null
@@ -1 +0,0 @@
-define("arale/autocomplete/1.3.0/autocomplete",["$","arale/overlay/1.1.2/overlay","arale/position/1.0.1/position","arale/iframe-shim/1.0.2/iframe-shim","arale/widget/1.1.1/widget","arale/base/1.1.1/base","arale/class/1.1.0/class","arale/events/1.1.0/events","arale/templatable/0.9.2/templatable","gallery/handlebars/1.0.2/handlebars","./data-source","./filter","./input","./autocomplete.handlebars"],function(a,b,c){function d(a){return"[object String]"===Object.prototype.toString.call(a)}function e(a){return"[object Object]"===Object.prototype.toString.call(a)}function f(a,b){if(a){if(k.isFunction(a))return a.call(this,b);if(!k.isArray(b)&&d(a)){for(var c=a.split("."),e=b;c.length;){var f=c.shift();if(!e[f])break;e=e[f]}return e}}return b}function g(a){var b=[];return k.each(a,function(a,c){if(d(c))b.push({label:c,value:c,alias:[]});else if(e(c)){if(!c.value&&!c.label)return;c.value||(c.value=c.label),c.label||(c.label=c.value),c.alias||(c.alias=[]),b.push(c)}}),b}function h(a,b){return d(a)?a=o[a]?o[a]:o["default"]:k.isFunction(a)||(a="url"===b.get("type")?o["default"]:o.startsWith),a}function i(a){function b(a){for(var b in a)c[b]=a[b]}var c={};return b(this),b(a.hash),a.fn(c)}function j(a){var b=this.highlightIndex,c=this.parent?this.parent.classPrefix:"",d=0,e=a||this.label||"",f="";if(k.isArray(b)){for(var g=0,h=b.length;h>g;g++){var i,j,l=b[g];if(k.isArray(l)?(i=l[0],j=l[1]-l[0]):(i=l,j=1),i>d&&(f+=e.substring(d,i)),i"+e.substr(i,j)+""}if(d=i+j,d>=e.length)break}return e.length>d&&(f+=e.substring(d,e.length)),f}return e}var k=a("$"),l=a("arale/overlay/1.1.2/overlay"),m=a("arale/templatable/0.9.2/templatable"),n=a("./data-source"),o=a("./filter"),p=a("./input"),q=/\bMSIE [678]\.0\b/.test(navigator.userAgent),r=a("./autocomplete.handlebars"),s=l.extend({Implements:m,attrs:{trigger:null,classPrefix:"ui-select",align:{baseXY:[0,"100%"]},submitOnEnter:!0,dataSource:{value:[],getter:function(a){var b=this;return k.isFunction(a)?function(){a.apply(b,arguments)}:a}},locator:"data",filter:null,disabled:!1,selectFirst:!1,delay:100,model:{value:{items:[]},getter:function(a){return a.classPrefix||(a.classPrefix=this.get("classPrefix")),a}},template:r,footer:"",header:"",html:"{{{label}}}",selectedIndex:null,data:[]},events:{"mousedown [data-role=items]":"_handleMouseDown","click [data-role=item]":"_handleSelection","mouseenter [data-role=item]":"_handleMouseMove","mouseleave [data-role=item]":"_handleMouseMove"},templateHelpers:{highlightItem:j,include:i},parseElement:function(){var a=["header","footer","html"];for(var b in a)this.templatePartials||(this.templatePartials={}),this.templatePartials[a[b]]=this.get(a[b]);s.superclass.parseElement.call(this)},setup:function(){s.superclass.setup.call(this),this._isOpen=!1,this._initInput(),this._initDataSource(),this._initFilter(),this._bindHandle(),this._blurHide([k(this.get("trigger"))]),this._tweakAlignDefaultValue(),this.on("indexChanged",function(a){var b=parseInt(this.get("height"),10);if(b){var c=this.items.parent().height()/this.items.length,d=Math.max(0,c*(a+1)-b);this.element.children().scrollTop(d)}})},show:function(){this._isOpen=!0,this._isEmpty()||s.superclass.show.call(this)},hide:function(){this._timeout&&clearTimeout(this._timeout),this.dataSource.abort(),this._hide()},destroy:function(){this._clear(),this.input&&(this.input.destroy(),this.input=null),s.superclass.destroy.call(this)},selectItem:function(a){this.items&&(a&&this.items.length>a&&a>=-1&&this.set("selectedIndex",a),this._handleSelection())},setInputValue:function(a){this.input.setValue(a)},_filterData:function(a){var b=this.get("filter"),c=this.get("locator");a=f(c,a),a=b.call(this,g(a),this.input.get("query")),this.set("data",a)},_onRenderData:function(a){a||(a=[]),this.set("model",{items:a,query:this.input.get("query"),length:a.length}),this.renderPartial(),this.items=this.$("[data-role=items]").children(),this.get("selectFirst")&&this.set("selectedIndex",0),this._isOpen&&this.show()},_onRenderSelectedIndex:function(a){var b=this.get("classPrefix")+"-item-hover";this.items&&this.items.removeClass(b),-1!==a&&(this.items.eq(a).addClass(b),this.trigger("indexChanged",a,this.lastIndex),this.lastIndex=a)},_initDataSource:function(){this.dataSource=new n({source:this.get("dataSource")})},_initInput:function(){this.input=new p({element:this.get("trigger"),delay:this.get("delay")})},_initFilter:function(){var a=this.get("filter");a=h(a,this.dataSource),this.set("filter",a)},_bindHandle:function(){this.dataSource.on("data",this._filterData,this),this.input.on("blur",this.hide,this).on("focus",this._handleFocus,this).on("keyEnter",this._handleSelection,this).on("keyEsc",this.hide,this).on("keyUp keyDown",this.show,this).on("keyUp keyDown",this._handleStep,this).on("queryChanged",this._clear,this).on("queryChanged",this._hide,this).on("queryChanged",this._handleQueryChange,this).on("queryChanged",this.show,this),this.after("hide",function(){this.set("selectedIndex",-1)}),this.on("itemSelected",function(){this._hide()})},_handleSelection:function(a){var b=a?"click"===a.type:!1,c=b?this.items.index(a.currentTarget):this.get("selectedIndex"),d=this.items.eq(c),e=this.get("data")[c];c>=0&&d&&(this.input.setValue(e.label),this.set("selectedIndex",c,{silent:!0}),!a||b||this.get("submitOnEnter")||a.preventDefault(),this.trigger("itemSelected",e,d))},_handleFocus:function(){this._isOpen=!0},_handleMouseMove:function(a){var b=this.get("classPrefix")+"-item-hover";if(this.items.removeClass(b),"mouseenter"===a.type){var c=this.items.index(a.currentTarget);this.set("selectedIndex",c,{silent:!0}),this.items.eq(c).addClass(b)}},_handleMouseDown:function(a){if(q){var b=this.input.get("element")[0];b.onbeforedeactivate=function(){window.event.returnValue=!1,b.onbeforedeactivate=null}}a.preventDefault()},_handleStep:function(a){a.preventDefault(),this.get("visible")&&this._step("keyUp"===a.type?-1:1)},_handleQueryChange:function(a){this.get("disabled")||(this.dataSource.abort(),this.dataSource.getData(a))},_step:function(a){var b=this.get("selectedIndex");-1===a?b>-1?this.set("selectedIndex",b-1):this.set("selectedIndex",this.items.length-1):1===a&&(b0)},_tweakAlignDefaultValue:function(){var a=this.get("align");a.baseElement=this.get("trigger"),this.set("align",a)}});c.exports=s}),define("arale/autocomplete/1.3.0/data-source",["arale/base/1.1.1/base","arale/class/1.1.0/class","arale/events/1.1.0/events","$"],function(a,b,c){function d(a){return"[object String]"===Object.prototype.toString.call(a)}function e(a){return a.replace(/^([a-z])/,function(a,b){return b.toUpperCase()})}var f=a("arale/base/1.1.1/base"),g=a("$"),h=f.extend({attrs:{source:null,type:"array"},initialize:function(a){h.superclass.initialize.call(this,a),this.id=0,this.callbacks=[];var b=this.get("source");if(d(b))this.set("type","url");else if(g.isArray(b))this.set("type","array");else if(g.isPlainObject(b))this.set("type","object");else{if(!g.isFunction(b))throw new Error("Source Type Error");this.set("type","function")}},getData:function(a){return this["_get"+e(this.get("type")||"")+"Data"](a)},abort:function(){this.callbacks=[]},_done:function(a){this.trigger("data",a)},_getUrlData:function(a){var b,c=this,d={query:a?encodeURIComponent(a):"",timestamp:(new Date).getTime()},e=this.get("source").replace(/\{\{(.*?)\}\}/g,function(a,b){return d[b]}),f="callback_"+this.id++;this.callbacks.push(f),b=/^(https?:\/\/)/.test(e)?{dataType:"jsonp"}:{dataType:"json"},g.ajax(e,b).success(function(a){g.inArray(f,c.callbacks)>-1&&(delete c.callbacks[f],c._done(a))}).error(function(){g.inArray(f,c.callbacks)>-1&&(delete c.callbacks[f],c._done({}))})},_getArrayData:function(){var a=this.get("source");return this._done(a),a},_getObjectData:function(){var a=this.get("source");return this._done(a),a},_getFunctionData:function(a){function b(a){c._done(a)}var c=this,d=this.get("source"),e=d.call(this,a,b);e&&this._done(e)}});c.exports=h}),define("arale/autocomplete/1.3.0/filter",["$"],function(a,b,c){function d(a){return(a||"").replace(h,"\\$1")}function e(a,b){for(var c=[],d=a.split(""),e=0,f=b.split(""),g=0,h=d.length;h>g;g++){var i=d[g];if(i===f[e]){if(e===f.length-1){c.push([g-f.length+1,g+1]),e=0;continue}e++}else e=0}return c}var f=a("$"),g={"default":function(a){return a},startsWith:function(a,b){b=b||"";var c=[],e=b.length,g=new RegExp("^"+d(b));return e?(f.each(a,function(a,b){for(var d,f=[b.value].concat(b.alias);d=f.shift();)if(g.test(d)){b.label===d&&(b.highlightIndex=[[0,e]]),c.push(b);break}}),c):[]},stringMatch:function(a,b){b=b||"";var c=[],d=b.length;return d?(f.each(a,function(a,d){for(var f,g=[d.value].concat(d.alias);f=g.shift();)if(f.indexOf(b)>-1){d.label===f&&(d.highlightIndex=e(f,b)),c.push(d);break}}),c):[]}};c.exports=g;var h=/(\[|\[|\]|\^|\$|\||\(|\)|\{|\}|\+|\*|\?|\\)/g}),define("arale/autocomplete/1.3.0/input",["$","arale/base/1.1.1/base","arale/class/1.1.0/class","arale/events/1.1.0/events"],function(a,b,c){function d(a,b){return function(){a.apply(b,arguments)}}function e(a,b){return a=(a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," "),b=(b||"").replace(/^\s*/g,"").replace(/\s{2,}/g," "),a===b}function f(a){return a.charAt(0).toUpperCase()+a.substring(1)}var g=a("$"),h=a("arale/base/1.1.1/base"),i=/\bMSIE [6789]\.0\b/.test(navigator.userAgent),j={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},k=h.extend({attrs:{element:{value:null,setter:function(a){return g(a)}},query:null,delay:100},initialize:function(){k.superclass.initialize.apply(this,arguments),this._bindEvents(),this.set("query",this.getValue())},focus:function(){this.get("element").focus()},getValue:function(){return this.get("element").val()},setValue:function(a,b){this.get("element").val(a),!b&&this._change()},destroy:function(){k.superclass.destroy.call(this)},_bindEvents:function(){var a,b=this.get("element");if(b.attr("autocomplete","off").on("focus.autocomplete",d(this._handleFocus,this)).on("blur.autocomplete",d(this._handleBlur,this)).on("keydown.autocomplete",d(this._handleKeydown,this)),i){var c=this,e=["keydown.autocomplete","keypress.autocomplete","cut.autocomplete","paste.autocomplete"].join(" ");b.on(e,d(function(b){j[b.which]||(clearTimeout(a),a=setTimeout(function(){c._change.call(c,b)},this.get("delay")))},this))}else b.on("input.autocomplete",d(this._change,this))},_change:function(){var a=this.getValue(),b=this.get("query"),c=e(b,a),d=c?a.length!==b.length:!1;d&&this.trigger("whitespaceChanged",b),c||(this.set("query",a),this.trigger("queryChanged",a,b))},_handleFocus:function(a){this.trigger("focus",a)},_handleBlur:function(a){this.trigger("blur",a)},_handleKeydown:function(a){var b=j[a.which];if(b){var c="key"+f(b);this.trigger(a.type=c,a)}}});c.exports=k}),define("arale/autocomplete/1.3.0/autocomplete.handlebars",["gallery/handlebars/1.0.2/runtime"],function(a,b,c){var d=a("gallery/handlebars/1.0.2/runtime"),e=d.template;c.exports=e(function(a,b,c,d,e){function f(a,b,d){var e,f,h,i="";return i+='\n \n \n ',h={hash:{parent:d},inverse:k.noop,fn:k.program(2,g,b),data:b},e=c.include,f=e?e.call(a,h):n.call(a,"include",h),(f||0===f)&&(i+=f),i+="\n \n \n "}function g(a,b){var e;return e=k.invokePartial(d.html,"html",a,c,d,b),e||0===e?e:""}this.compilerInfo=[3,">= 1.0.0-rc.4"],c=c||{};for(var h in a.helpers)c[h]=c[h]||a.helpers[h];d=d||a.partials,e=e||{};var i,j="",k=this,l="function",m=this.escapeExpression,n=c.helperMissing;return j+='\n
\n ',i=k.invokePartial(d.header,"header",b,c,d,e),(i||0===i)&&(j+=i),j+='\n
\n ',i=c.each.call(b,b.items,{hash:{},inverse:k.noop,fn:k.programWithDepth(1,f,e,b),data:e}),(i||0===i)&&(j+=i),j+="\n
\n ",i=k.invokePartial(d.footer,"footer",b,c,d,e),(i||0===i)&&(j+=i),j+="\n
\n
\n"})});
diff --git a/package.json b/package.json
index fc64b6d..4e032d0 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,10 @@
{
- "family": "arale",
- "name": "autocomplete",
- "version": "1.3.0",
+ "name": "arale-autocomplete",
+ "version": "1.4.0",
"description": "自动补全组件",
- "keywords": ["widget"],
+ "keywords": [
+ "widget"
+ ],
"homepage": "http://aralejs.org/autocomplete/",
"author": "popomore ",
"maintainers": [
@@ -19,18 +20,24 @@
},
"license": "MIT",
"spm": {
- "alias": {
- "$": "$",
- "templatable": "arale/templatable/0.9.2/templatable",
- "base": "arale/base/1.1.1/base",
- "overlay": "arale/overlay/1.1.2/overlay"
+ "main": "autocomplete.js",
+ "dependencies": {
+ "jquery": "1.7.2",
+ "arale-templatable": "0.10.0",
+ "arale-base": "1.2.0",
+ "arale-overlay": "1.2.0",
+ "handlebars-runtime": "1.3.0"
+ },
+ "devDependencies": {
+ "alice-select": "1.1.0",
+ "expect.js": "0.3.1",
+ "sinon": "1.6.0"
},
- "devAlias": {
- "select.css": "alice/select/1.0.1/select.css"
+ "engines": {
+ "seajs": "2.2.1",
+ "seajs-text": "1.1.0"
},
- "output": [
- "autocomplete.js"
- ]
+ "buildArgs": "--ignore jquery"
},
"scripts": {
"test": "make test"
diff --git a/src/autocomplete.js b/src/autocomplete.js
index 28c0e96..c670085 100644
--- a/src/autocomplete.js
+++ b/src/autocomplete.js
@@ -1,505 +1,487 @@
-define(function(require, exports, module) {
- var $ = require('$');
- var Overlay = require('overlay');
- var Templatable = require('templatable');
- var DataSource = require('./data-source');
- var Filter = require('./filter');
- var Input = require('./input');
-
- var IE678 = /\bMSIE [678]\.0\b/.test(navigator.userAgent);
- var template = require('./autocomplete.handlebars');
-
- var AutoComplete = Overlay.extend({
-
- Implements: Templatable,
-
- attrs: {
- // 触发元素
- trigger: null,
- classPrefix: 'ui-select',
- align: {
- baseXY: [0, '100%']
- },
- submitOnEnter: true, // 回车是否会提交表单
- dataSource: { //数据源,支持 Array, URL, Object, Function
- value: [],
- getter: function(val) {
- var that = this;
- if ($.isFunction(val)) {
- return function() {
- val.apply(that, arguments);
- };
- }
- return val;
- }
- },
- locator: 'data',
- // 输出过滤
- filter: null,
- disabled: false,
- selectFirst: false,
- delay: 100,
- // 以下为模板相关
- model: {
- value: {
- items: []
- },
- getter: function(val) {
- val.classPrefix || (val.classPrefix = this.get('classPrefix'));
- return val;
- }
- },
- template: template,
- footer: '',
- header: '',
- html: '{{{label}}}',
- // 以下仅为组件使用
- selectedIndex: null,
- data: []
- },
-
- events: {
- 'mousedown [data-role=items]': '_handleMouseDown',
- 'click [data-role=item]': '_handleSelection',
- 'mouseenter [data-role=item]': '_handleMouseMove',
- 'mouseleave [data-role=item]': '_handleMouseMove'
+var $ = require('jquery');
+var Overlay = require('arale-overlay');
+var Templatable = require('arale-templatable');
+var DataSource = require('./data-source');
+var Filter = require('./filter');
+var Input = require('./input');
+
+var IE678 = /\bMSIE [678]\.0\b/.test(navigator.userAgent);
+var template = require('./autocomplete.handlebars');
+
+var AutoComplete = Overlay.extend({
+
+ Implements: Templatable,
+
+ attrs: {
+ // 触发元素
+ trigger: null,
+ classPrefix: 'ui-select',
+ align: {
+ baseXY: [0, '100%']
},
-
- templateHelpers: {
- // 将匹配的高亮文字加上 hl 的样式
- highlightItem: highlightItem,
- include: include
+ submitOnEnter: true,
+ // 回车是否会提交表单
+ dataSource: { //数据源,支持 Array, URL, Object, Function
+ value: [],
+ getter: function (val) {
+ var that = this;
+ if ($.isFunction(val)) {
+ return function () {
+ val.apply(that, arguments);
+ };
+ }
+ return val;
+ }
},
-
- parseElement: function() {
- var that = this;
- this.templatePartials || (this.templatePartials = {});
- $.each(['header', 'footer', 'html'], function( index, item ) {
- that.templatePartials[item] = that.get(item);
- });
- AutoComplete.superclass.parseElement.call(this);
+ locator: 'data',
+ // 输出过滤
+ filter: null,
+ disabled: false,
+ selectFirst: false,
+ delay: 100,
+ // 以下为模板相关
+ model: {
+ value: {
+ items: []
+ },
+ getter: function (val) {
+ val.classPrefix || (val.classPrefix = this.get('classPrefix'));
+ return val;
+ }
},
-
- setup: function() {
- AutoComplete.superclass.setup.call(this);
-
- this._isOpen = false;
- this._initInput(); // 初始化输入框
- this._initDataSource(); // 初始化数据源
- this._initFilter(); // 初始化过滤器
- this._bindHandle(); // 绑定事件
- this._blurHide([$(this.get('trigger'))]);
- this._tweakAlignDefaultValue();
-
- this.on('indexChanged', function(index) {
- // scroll current item into view
- //this.currentItem.scrollIntoView();
- var containerHeight = parseInt(this.get('height'), 10);
- if (!containerHeight) return;
-
- var itemHeight = this.items.parent().height() / this.items.length,
+ template: template,
+ footer: '',
+ header: '',
+ html: '{{{label}}}',
+ // 以下仅为组件使用
+ selectedIndex: null,
+ data: []
+ },
+
+ events: {
+ 'mousedown [data-role=items]': '_handleMouseDown',
+ 'click [data-role=item]': '_handleSelection',
+ 'mouseenter [data-role=item]': '_handleMouseMove',
+ 'mouseleave [data-role=item]': '_handleMouseMove'
+ },
+
+ templateHelpers: {
+ // 将匹配的高亮文字加上 hl 的样式
+ highlightItem: highlightItem,
+ include: include
+ },
+
+ parseElement: function () {
+ var that = this;
+ this.templatePartials || (this.templatePartials = {});
+ $.each(['header', 'footer', 'html'], function (index, item) {
+ that.templatePartials[item] = that.get(item);
+ });
+ AutoComplete.superclass.parseElement.call(this);
+ },
+
+ setup: function () {
+ AutoComplete.superclass.setup.call(this);
+
+ this._isOpen = false;
+ this._initInput(); // 初始化输入框
+ this._initDataSource(); // 初始化数据源
+ this._initFilter(); // 初始化过滤器
+ this._bindHandle(); // 绑定事件
+ this._blurHide([$(this.get('trigger'))]);
+ this._tweakAlignDefaultValue();
+
+ this.on('indexChanged', function (index) {
+ // scroll current item into view
+ //this.currentItem.scrollIntoView();
+ var containerHeight = parseInt(this.get('height'), 10);
+ if (!containerHeight) return;
+
+ var itemHeight = this.items.parent().height() / this.items.length,
itemTop = Math.max(0, itemHeight * (index + 1) - containerHeight);
- this.element.children().scrollTop(itemTop);
- });
- },
-
- show: function() {
- this._isOpen = true;
- // 无数据则不显示
- if (this._isEmpty()) return;
- AutoComplete.superclass.show.call(this);
- },
+ this.element.children().scrollTop(itemTop);
+ });
+ },
+
+ show: function () {
+ this._isOpen = true;
+ // 无数据则不显示
+ if (this._isEmpty()) return;
+ AutoComplete.superclass.show.call(this);
+ },
+
+ hide: function () {
+ // 隐藏的时候取消请求或回调
+ if (this._timeout) clearTimeout(this._timeout);
+ this.dataSource.abort();
+ this._hide();
+ },
+
+ destroy: function () {
+ this._clear();
+ if (this.input) {
+ this.input.destroy();
+ this.input = null;
+ }
+ AutoComplete.superclass.destroy.call(this);
+ },
- hide: function() {
- // 隐藏的时候取消请求或回调
- if (this._timeout) clearTimeout(this._timeout);
- this.dataSource.abort();
- this._hide();
- },
- destroy: function() {
- this._clear();
- if (this.input) {
- this.input.destroy();
- this.input = null;
+ // Public Methods
+ // --------------
+ selectItem: function (index) {
+ if (this.items) {
+ if (index && this.items.length > index && index >= -1) {
+ this.set('selectedIndex', index);
}
- AutoComplete.superclass.destroy.call(this);
- },
+ this._handleSelection();
+ }
+ },
+ setInputValue: function (val) {
+ this.input.setValue(val);
+ },
- // Public Methods
- // --------------
+ // Private Methods
+ // ---------------
- selectItem: function(index) {
- if (this.items) {
- if (index &&
- this.items.length > index && index >= -1) {
- this.set('selectedIndex', index);
- }
- this._handleSelection();
- }
- },
+ // 数据源返回,过滤数据
+ _filterData: function (data) {
+ var filter = this.get('filter'),
+ locator = this.get('locator');
- setInputValue: function(val) {
- this.input.setValue(val);
- },
+ // 获取目标数据
+ data = locateResult(locator, data);
- // Private Methods
- // ---------------
+ // 进行过滤
+ data = filter.call(this, normalize(data), this.input.get('query'));
+ this.set('data', data);
+ },
- // 数据源返回,过滤数据
- _filterData: function(data) {
- var filter = this.get('filter'),
- locator = this.get('locator');
+ // 通过数据渲染模板
+ _onRenderData: function (data) {
+ data || (data = []);
- // 获取目标数据
- data = locateResult(locator, data);
+ // 渲染下拉
+ this.set('model', {
+ items: data,
+ query: this.input.get('query'),
+ length: data.length
+ });
- // 进行过滤
- data = filter.call(this, normalize(data), this.input.get('query'));
+ this.renderPartial();
- this.set('data', data);
- },
+ // 初始化下拉的状态
+ this.items = this.$('[data-role=items]').children();
- // 通过数据渲染模板
- _onRenderData: function(data) {
- data || (data = []);
+ if (this.get('selectFirst')) {
+ this.set('selectedIndex', 0);
+ }
- // 渲染下拉
- this.set('model', {
- items: data,
- query: this.input.get('query'),
- length: data.length
- });
+ // 选中后会修改 input 的值并触发下一次渲染,但第二次渲染的结果不应该显示出来。
+ this._isOpen && this.show();
+ },
- this.renderPartial();
+ // 键盘控制上下移动
+ _onRenderSelectedIndex: function (index) {
+ var hoverClass = this.get('classPrefix') + '-item-hover';
+ this.items && this.items.removeClass(hoverClass);
- // 初始化下拉的状态
- this.items = this.$('[data-role=items]').children();
+ // -1 什么都不选
+ if (index === -1) return;
- if (this.get('selectFirst')) {
- this.set('selectedIndex', 0);
- }
+ this.items.eq(index).addClass(hoverClass);
+ this.trigger('indexChanged', index, this.lastIndex);
+ this.lastIndex = index;
+ },
- // 选中后会修改 input 的值并触发下一次渲染,但第二次渲染的结果不应该显示出来。
- this._isOpen && this.show();
- },
+ // 初始化
+ // ------------
+ _initDataSource: function () {
+ this.dataSource = new DataSource({
+ source: this.get('dataSource')
+ });
+ },
- // 键盘控制上下移动
- _onRenderSelectedIndex: function(index) {
- var hoverClass = this.get('classPrefix') + '-item-hover';
- this.items && this.items.removeClass(hoverClass);
+ _initInput: function () {
+ this.input = new Input({
+ element: this.get('trigger'),
+ delay: this.get('delay')
+ });
+ },
- // -1 什么都不选
- if (index === -1) return;
+ _initFilter: function () {
+ var filter = this.get('filter');
+ filter = initFilter(filter, this.dataSource);
+ this.set('filter', filter);
+ },
- this.items.eq(index).addClass(hoverClass);
- this.trigger('indexChanged', index, this.lastIndex);
- this.lastIndex = index;
- },
+ // 事件绑定
+ // ------------
+ _bindHandle: function () {
+ this.dataSource.on('data', this._filterData, this);
- // 初始化
- // ------------
+ this.input.on('blur', this.hide, this).on('focus', this._handleFocus, this).on('keyEnter', this._handleSelection, this).on('keyEsc', this.hide, this).on('keyUp keyDown', this.show, this).on('keyUp keyDown', this._handleStep, this).on('queryChanged', this._clear, this).on('queryChanged', this._hide, this).on('queryChanged', this._handleQueryChange, this).on('queryChanged', this.show, this);
- _initDataSource: function() {
- this.dataSource = new DataSource({
- source: this.get('dataSource')
- });
- },
+ this.after('hide', function () {
+ this.set('selectedIndex', -1);
+ });
- _initInput: function() {
- this.input = new Input({
- element: this.get('trigger'),
- delay: this.get('delay')
+ // 选中后隐藏浮层
+ this.on('itemSelected', function () {
+ this._hide();
+ });
+ },
+
+ // 选中的处理器
+ // 1. 鼠标点击触发
+ // 2. 回车触发
+ // 3. selectItem 触发
+ _handleSelection: function (e) {
+ var isMouse = e ? e.type === 'click' : false;
+ var index = isMouse ? this.items.index(e.currentTarget) : this.get('selectedIndex');
+ var item = this.items.eq(index);
+ var data = this.get('data')[index];
+
+ if (index >= 0 && item) {
+ this.input.setValue(data.label);
+ this.set('selectedIndex', index, {
+ silent: true
});
- },
- _initFilter: function() {
- var filter = this.get('filter');
- filter = initFilter(filter, this.dataSource);
- this.set('filter', filter);
- },
-
- // 事件绑定
- // ------------
-
- _bindHandle: function() {
- this.dataSource
- .on('data', this._filterData, this);
-
- this.input
- .on('blur', this.hide, this)
- .on('focus', this._handleFocus, this)
- .on('keyEnter', this._handleSelection, this)
- .on('keyEsc', this.hide, this)
- .on('keyUp keyDown', this.show, this)
- .on('keyUp keyDown', this._handleStep, this)
- .on('queryChanged', this._clear, this)
- .on('queryChanged', this._hide, this)
- .on('queryChanged', this._handleQueryChange, this)
- .on('queryChanged', this.show, this);
-
- this.after('hide', function() {
- this.set('selectedIndex', -1);
- });
+ // 是否阻止回车提交表单
+ if (e && !isMouse && !this.get('submitOnEnter')) e.preventDefault();
- // 选中后隐藏浮层
- this.on('itemSelected', function() {
- this._hide();
+ this.trigger('itemSelected', data, item);
+ }
+ },
+
+ _handleFocus: function () {
+ this._isOpen = true;
+ },
+
+ _handleMouseMove: function (e) {
+ var hoverClass = this.get('classPrefix') + '-item-hover';
+ this.items.removeClass(hoverClass);
+ if (e.type === 'mouseenter') {
+ var index = this.items.index(e.currentTarget);
+ this.set('selectedIndex', index, {
+ silent: true
});
- },
-
- // 选中的处理器
- // 1. 鼠标点击触发
- // 2. 回车触发
- // 3. selectItem 触发
- _handleSelection: function(e) {
- var isMouse = e ? e.type === 'click' : false;
- var index = isMouse ? this.items.index(e.currentTarget) : this.get('selectedIndex');
- var item = this.items.eq(index);
- var data = this.get('data')[index];
-
- if (index >= 0 && item) {
- this.input.setValue(data.label);
- this.set('selectedIndex', index, {silent: true});
-
- // 是否阻止回车提交表单
- if (e && !isMouse && !this.get('submitOnEnter')) e.preventDefault();
-
- this.trigger('itemSelected', data, item);
- }
- },
-
- _handleFocus: function() {
- this._isOpen = true;
- },
-
- _handleMouseMove: function(e) {
- var hoverClass = this.get('classPrefix') + '-item-hover';
- this.items.removeClass(hoverClass);
- if (e.type === 'mouseenter') {
- var index = this.items.index(e.currentTarget);
- this.set('selectedIndex', index, {
- silent: true
- });
- this.items.eq(index).addClass(hoverClass);
- }
- },
-
- _handleMouseDown: function(e) {
- if (IE678) {
- var trigger = this.input.get('element')[0];
- trigger.onbeforedeactivate = function() {
- window.event.returnValue = false;
- trigger.onbeforedeactivate = null;
- };
+ this.items.eq(index).addClass(hoverClass);
+ }
+ },
+
+ _handleMouseDown: function (e) {
+ if (IE678) {
+ var trigger = this.input.get('element')[0];
+ trigger.onbeforedeactivate = function () {
+ window.event.returnValue = false;
+ trigger.onbeforedeactivate = null;
+ };
+ }
+ e.preventDefault();
+ },
+
+ _handleStep: function (e) {
+ e.preventDefault();
+ this.get('visible') && this._step(e.type === 'keyUp' ? -1 : 1);
+ },
+
+ _handleQueryChange: function (val, prev) {
+ if (this.get('disabled')) return;
+
+ this.dataSource.abort();
+ this.dataSource.getData(val);
+ },
+
+ // 选项上下移动
+ _step: function (direction) {
+ var currentIndex = this.get('selectedIndex');
+ if (direction === -1) { // 反向
+ if (currentIndex > -1) {
+ this.set('selectedIndex', currentIndex - 1);
+ } else {
+ this.set('selectedIndex', this.items.length - 1);
}
- e.preventDefault();
- },
-
- _handleStep: function(e) {
- e.preventDefault();
- this.get('visible') &&
- this._step(e.type === 'keyUp' ? -1 : 1);
- },
-
- _handleQueryChange: function(val, prev) {
- if (this.get('disabled')) return;
-
- this.dataSource.abort();
- this.dataSource.getData(val);
- },
-
- // 选项上下移动
- _step: function(direction) {
- var currentIndex = this.get('selectedIndex');
- if (direction === -1) { // 反向
- if (currentIndex > -1) {
- 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', -1);
- }
+ } else if (direction === 1) { // 正向
+ if (currentIndex < this.items.length - 1) {
+ this.set('selectedIndex', currentIndex + 1);
+ } else {
+ this.set('selectedIndex', -1);
}
- },
-
- _clear: function() {
- this.$('[data-role=items]').empty();
- this.set('selectedIndex', -1);
- delete this.items;
- delete this.lastIndex;
- },
-
- _hide: function() {
- this._isOpen = false;
- AutoComplete.superclass.hide.call(this);
- },
-
- _isEmpty: function() {
- var data = this.get('data');
- return !(data && data.length > 0);
- },
-
- // 调整 align 属性的默认值
- _tweakAlignDefaultValue: function() {
- var align = this.get('align');
- align.baseElement = this.get('trigger');
- this.set('align', align);
}
- });
-
- module.exports = AutoComplete;
-
- function isString(str) {
- return Object.prototype.toString.call(str) === '[object String]';
- }
-
- function isObject(obj) {
- return Object.prototype.toString.call(obj) === '[object Object]';
+ },
+
+ _clear: function () {
+ this.$('[data-role=items]').empty();
+ this.set('selectedIndex', -1);
+ delete this.items;
+ delete this.lastIndex;
+ },
+
+ _hide: function () {
+ this._isOpen = false;
+ AutoComplete.superclass.hide.call(this);
+ },
+
+ _isEmpty: function () {
+ var data = this.get('data');
+ return !(data && data.length > 0);
+ },
+
+ // 调整 align 属性的默认值
+ _tweakAlignDefaultValue: function () {
+ var align = this.get('align');
+ align.baseElement = this.get('trigger');
+ this.set('align', align);
}
+});
- // 通过 locator 找到 data 中的某个属性的值
- // 1. locator 支持 function,函数返回值为结果
- // 2. locator 支持 string,而且支持点操作符寻址
- // data {
- // a: {
- // b: 'c'
- // }
- // }
- // locator 'a.b'
- // 最后的返回值为 c
-
- function locateResult(locator, data) {
- if (locator) {
- if ($.isFunction(locator)) {
- return locator.call(this, data);
- } else if (!$.isArray(data) && isString(locator)) {
- var s = locator.split('.'),
+module.exports = AutoComplete;
+
+function isString(str) {
+ return Object.prototype.toString.call(str) === '[object String]';
+}
+
+function isObject(obj) {
+ return Object.prototype.toString.call(obj) === '[object Object]';
+}
+
+// 通过 locator 找到 data 中的某个属性的值
+// 1. locator 支持 function,函数返回值为结果
+// 2. locator 支持 string,而且支持点操作符寻址
+// data {
+// a: {
+// b: 'c'
+// }
+// }
+// locator 'a.b'
+// 最后的返回值为 c
+
+function locateResult(locator, data) {
+ if (locator) {
+ if ($.isFunction(locator)) {
+ return locator.call(this, data);
+ } else if (!$.isArray(data) && isString(locator)) {
+ var s = locator.split('.'),
p = data;
- while (s.length) {
- var v = s.shift();
- if (!p[v]) {
- break;
- }
- p = p[v];
+ while (s.length) {
+ var v = s.shift();
+ if (!p[v]) {
+ break;
}
- return p;
+ p = p[v];
}
+ return p;
}
- return data;
- }
-
- // 标准格式,不匹配则忽略
- //
- // {
- // label: '', 显示的字段
- // value: '', 匹配的字段
- // alias: [] 其他匹配的字段
- // }
-
- function normalize(data) {
- var result = [];
- $.each(data, function(index, item) {
- if (isString(item)) {
- result.push({
- label: item,
- value: item,
- alias: []
- });
- } else if (isObject(item)) {
- if (!item.value && !item.label) return;
- item.value || (item.value = item.label);
- item.label || (item.label = item.value);
- item.alias || (item.alias = []);
- result.push(item);
- }
- });
- return result;
}
-
- // 初始化 filter
- // 支持的格式
- // 1. null: 使用默认的 startsWith
- // 2. string: 从 Filter 中找,如果不存在则用 default
- // 3. function: 自定义
-
- function initFilter(filter, dataSource) {
- // 字符串
- if (isString(filter)) {
- // 从组件内置的 FILTER 获取
- if (Filter[filter]) {
- filter = Filter[filter];
- } else {
- filter = Filter['default'];
- }
+ return data;
+}
+
+// 标准格式,不匹配则忽略
+//
+// {
+// label: '', 显示的字段
+// value: '', 匹配的字段
+// alias: [] 其他匹配的字段
+// }
+
+function normalize(data) {
+ var result = [];
+ $.each(data, function (index, item) {
+ if (isString(item)) {
+ result.push({
+ label: item,
+ value: item,
+ alias: []
+ });
+ } else if (isObject(item)) {
+ if (!item.value && !item.label) return;
+ item.value || (item.value = item.label);
+ item.label || (item.label = item.value);
+ item.alias || (item.alias = []);
+ result.push(item);
}
- // 非函数为默认值
- else if (!$.isFunction(filter)) {
- // 异步请求的时候不需要过滤器
- if (dataSource.get('type') === 'url') {
- filter = Filter['default'];
- } else {
- filter = Filter['startsWith'];
- }
+ });
+ return result;
+}
+
+// 初始化 filter
+// 支持的格式
+// 1. null: 使用默认的 startsWith
+// 2. string: 从 Filter 中找,如果不存在则用 default
+// 3. function: 自定义
+
+function initFilter(filter, dataSource) {
+ // 字符串
+ if (isString(filter)) {
+ // 从组件内置的 FILTER 获取
+ if (Filter[filter]) {
+ filter = Filter[filter];
+ } else {
+ filter = Filter['default'];
+ }
+ }
+ // 非函数为默认值
+ else if (!$.isFunction(filter)) {
+ // 异步请求的时候不需要过滤器
+ if (dataSource.get('type') === 'url') {
+ filter = Filter['default'];
+ } else {
+ filter = Filter['startsWith'];
}
- return filter;
}
+ return filter;
+}
- function include(options) {
- var context = {};
-
- mergeContext(this);
- mergeContext(options.hash);
- return options.fn(context);
+function include(options) {
+ var context = {};
- function mergeContext(obj) {
- for(var k in obj) context[k] = obj[k];
- }
+ mergeContext(this);
+ mergeContext(options.hash);
+ return options.fn(context);
+
+ function mergeContext(obj) {
+ for (var k in obj) context[k] = obj[k];
}
+}
- function highlightItem(label) {
- var index = this.highlightIndex,
+function highlightItem(label) {
+ var index = this.highlightIndex,
classPrefix = this.parent ? this.parent.classPrefix : '',
cursor = 0,
v = label || this.label || '',
h = '';
- if ($.isArray(index)) {
- for (var i = 0, l = index.length; i < l; i++) {
- var j = index[i],
+ 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 ($.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) {
- var className = classPrefix ? ('class="' + classPrefix + '-item-hl"') : '';
- h += '' +
- v.substr(start, length) +
- '';
- }
- cursor = start + length;
- if (cursor >= v.length) {
- break;
- }
+ if (start > cursor) {
+ h += v.substring(cursor, start);
}
- if (v.length > cursor) {
- h += v.substring(cursor, v.length);
+ if (start < v.length) {
+ var className = classPrefix ? ('class="' + classPrefix + '-item-hl"') : '';
+ h += '' + v.substr(start, length) + '';
}
- return h;
+ cursor = start + length;
+ if (cursor >= v.length) {
+ break;
+ }
+ }
+ if (v.length > cursor) {
+ h += v.substring(cursor, v.length);
}
- return v;
+ return h;
}
-});
+ return v;
+}
\ No newline at end of file
diff --git a/src/data-source.js b/src/data-source.js
index 5be98b1..c625539 100644
--- a/src/data-source.js
+++ b/src/data-source.js
@@ -1,127 +1,119 @@
-define(function(require, exports, module) {
- var Base = require('base');
- var $ = require('$');
-
- var DataSource = Base.extend({
-
- attrs: {
- source: null,
- type: 'array'
- },
-
- initialize: function(config) {
- DataSource.superclass.initialize.call(this, config);
-
- // 每次发送请求会将 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 Base = require('arale-base');
+var $ = require('jquery');
+
+var DataSource = Base.extend({
+
+ attrs: {
+ source: null,
+ type: 'array'
+ },
+
+ initialize: function (config) {
+ DataSource.superclass.initialize.call(this, config);
+
+ // 每次发送请求会将 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');
+ }
+ },
- 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,
+ _getUrlData: function (query) {
+ var that = this,
options;
- var obj = {
- query: query ? encodeURIComponent(query) : '',
- timestamp: new Date().getTime()
+ 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);
+
+ if (/^(https?:\/\/)/.test(url)) {
+ options = {
+ dataType: 'jsonp'
};
- var url = this.get('source')
- .replace(/\{\{(.*?)\}\}/g, function(all, match) {
- return obj[match];
- });
-
- 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({});
- }
- });
- },
-
- _getArrayData: 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) {
+ } else {
+ options = {
+ dataType: 'json'
+ };
+ }
+ $.ajax(url, options).success(function (data) {
+ if ($.inArray(callbackId, that.callbacks) > -1) {
+ delete that.callbacks[callbackId];
that._done(data);
}
- var data = func.call(this, query, done);
- if (data) {
- this._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;
+ },
+
+ _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);
+ }
+ }
+});
- module.exports = DataSource;
+module.exports = DataSource;
- function isString(str) {
- return Object.prototype.toString.call(str) === '[object String]';
- }
+function isString(str) {
+ return Object.prototype.toString.call(str) === '[object String]';
+}
- function capitalize(str) {
- return str.replace(
- /^([a-z])/,
- function(f, m) {
- return m.toUpperCase();
- }
- );
- }
-});
+function capitalize(str) {
+ return str.replace(/^([a-z])/, function (f, m) {
+ return m.toUpperCase();
+ });
+}
\ No newline at end of file
diff --git a/src/filter.js b/src/filter.js
index 5130163..231849f 100644
--- a/src/filter.js
+++ b/src/filter.js
@@ -1,93 +1,91 @@
-define(function(require, exports, module) {
- var $ = require('$');
+var $ = require('jquery');
- var Filter = {
- 'default': function(data) {
- return data;
- },
+var Filter = {
+ 'default': function (data) {
+ return data;
+ },
- 'startsWith': function(data, query) {
- query = query || '';
- var result = [],
+ 'startsWith': function (data, query) {
+ query = query || '';
+ var result = [],
l = query.length,
reg = new RegExp('^' + escapeKeyword(query));
- if (!l) return [];
+ if (!l) return [];
- $.each(data, function(index, item) {
- var a, matchKeys = [item.value].concat(item.alias);
+ $.each(data, function (index, item) {
+ var a, matchKeys = [item.value].concat(item.alias);
- // 匹配 value 和 alias 中的
- while (a = matchKeys.shift()) {
- if (reg.test(a)) {
- // 匹配和显示相同才有必要高亮
- if (item.label === a) {
- item.highlightIndex = [
- [0, l]
- ];
- }
- result.push(item);
- break;
+ // 匹配 value 和 alias 中的
+ while (a = matchKeys.shift()) {
+ if (reg.test(a)) {
+ // 匹配和显示相同才有必要高亮
+ if (item.label === a) {
+ item.highlightIndex = [
+ [0, l]
+ ];
}
+ result.push(item);
+ break;
}
- });
- return result;
- },
+ }
+ });
+ return result;
+ },
- 'stringMatch': function(data, query) {
- query = query || '';
- var result = [],
+ 'stringMatch': function (data, query) {
+ query = query || '';
+ var result = [],
l = query.length;
- if (!l) return [];
+ if (!l) return [];
- $.each(data, function(index, item) {
- var a, matchKeys = [item.value].concat(item.alias);
+ $.each(data, function (index, item) {
+ var a, matchKeys = [item.value].concat(item.alias);
- // 匹配 value 和 alias 中的
- while (a = matchKeys.shift()) {
- if (a.indexOf(query) > -1) {
- // 匹配和显示相同才有必要高亮
- if (item.label === a) {
- item.highlightIndex = stringMatch(a, query);
- }
- result.push(item);
- break;
+ // 匹配 value 和 alias 中的
+ while (a = matchKeys.shift()) {
+ if (a.indexOf(query) > -1) {
+ // 匹配和显示相同才有必要高亮
+ if (item.label === a) {
+ item.highlightIndex = stringMatch(a, query);
}
+ result.push(item);
+ break;
}
- });
- return result;
- }
- };
+ }
+ });
+ return result;
+ }
+};
- module.exports = Filter;
+module.exports = Filter;
- // 转义正则关键字
- var keyword = /(\[|\[|\]|\^|\$|\||\(|\)|\{|\}|\+|\*|\?|\\)/g;
+// 转义正则关键字
+var keyword = /(\[|\[|\]|\^|\$|\||\(|\)|\{|\}|\+|\*|\?|\\)/g;
- function escapeKeyword(str) {
- return (str || '').replace(keyword, '\\$1');
- }
+function escapeKeyword(str) {
+ return (str || '').replace(keyword, '\\$1');
+}
- function stringMatch(matchKey, query) {
- var r = [],
+function stringMatch(matchKey, query) {
+ var r = [],
a = matchKey.split('');
- var queryIndex = 0,
+ 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 {
+ 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;
+}
\ No newline at end of file
diff --git a/src/input.js b/src/input.js
index 44f1fbe..797b945 100644
--- a/src/input.js
+++ b/src/input.js
@@ -1,138 +1,127 @@
-define(function(require, exports, module) {
- var $ = require('$');
- var Base = require('base');
-
- var lteIE9 = /\bMSIE [6789]\.0\b/.test(navigator.userAgent);
- var specialKeyCodeMap = {
- 9: 'tab',
- 27: 'esc',
- 37: 'left',
- 39: 'right',
- 13: 'enter',
- 38: 'up',
- 40: 'down'
- };
-
- var Input = Base.extend({
-
- attrs: {
- element: {
- value: null,
- setter: function(val) {
- return $(val);
- }
- },
- query: null,
- delay: 100
- },
-
- initialize: function() {
- Input.superclass.initialize.apply(this, arguments);
-
- // bind events
- this._bindEvents();
-
- // init query
- this.set('query', this.getValue());
- },
-
- focus: function() {
- this.get('element').focus();
- },
-
- getValue: function() {
- return this.get('element').val();
- },
-
- setValue: function(val, silent) {
- this.get('element').val(val);
- !silent && this._change();
- },
-
- destroy: function() {
- Input.superclass.destroy.call(this);
- },
-
- _bindEvents: function() {
- var timer, input = this.get('element');
-
- input
- .attr('autocomplete', 'off')
- .on('focus.autocomplete', wrapFn(this._handleFocus, this))
- .on('blur.autocomplete', wrapFn(this._handleBlur, this))
- .on('keydown.autocomplete', wrapFn(this._handleKeydown, this));
-
- // IE678 don't support input event
- // IE 9 does not fire an input event when the user removes characters from input filled by keyboard, cut, or drag operations.
- if (!lteIE9) {
- input.on('input.autocomplete', wrapFn(this._change, this));
- } else {
- var that = this,
- events = [
- 'keydown.autocomplete',
- 'keypress.autocomplete',
- 'cut.autocomplete',
- 'paste.autocomplete'
- ].join(' ');
-
- input.on(events, wrapFn(function(e) {
- if (specialKeyCodeMap[e.which]) return;
-
- clearTimeout(timer);
- timer = setTimeout(function() {
- that._change.call(that, e);
- }, this.get('delay'));
- }, this));
+var $ = require('jquery');
+var Base = require('arale-base');
+
+var lteIE9 = /\bMSIE [6789]\.0\b/.test(navigator.userAgent);
+var specialKeyCodeMap = {
+ 9: 'tab',
+ 27: 'esc',
+ 37: 'left',
+ 39: 'right',
+ 13: 'enter',
+ 38: 'up',
+ 40: 'down'
+};
+
+var Input = Base.extend({
+
+ attrs: {
+ element: {
+ value: null,
+ setter: function (val) {
+ return $(val);
}
},
+ query: null,
+ delay: 100
+ },
+
+ initialize: function () {
+ Input.superclass.initialize.apply(this, arguments);
+
+ // bind events
+ this._bindEvents();
+
+ // init query
+ this.set('query', this.getValue());
+ },
+
+ focus: function () {
+ this.get('element').focus();
+ },
+
+ getValue: function () {
+ return this.get('element').val();
+ },
+
+ setValue: function (val, silent) {
+ this.get('element').val(val);
+ !silent && this._change();
+ },
+
+ destroy: function () {
+ Input.superclass.destroy.call(this);
+ },
+
+ _bindEvents: function () {
+ var timer, input = this.get('element');
+
+ input.attr('autocomplete', 'off').on('focus.autocomplete', wrapFn(this._handleFocus, this)).on('blur.autocomplete', wrapFn(this._handleBlur, this)).on('keydown.autocomplete', wrapFn(this._handleKeydown, this));
+
+ // IE678 don't support input event
+ // IE 9 does not fire an input event when the user removes characters from input filled by keyboard, cut, or drag operations.
+ if (!lteIE9) {
+ input.on('input.autocomplete', wrapFn(this._change, this));
+ } else {
+ var that = this,
+ events = ['keydown.autocomplete', 'keypress.autocomplete', 'cut.autocomplete', 'paste.autocomplete'].join(' ');
+
+ input.on(events, wrapFn(function (e) {
+ if (specialKeyCodeMap[e.which]) return;
+
+ clearTimeout(timer);
+ timer = setTimeout(function () {
+ that._change.call(that, e);
+ }, this.get('delay'));
+ }, this));
+ }
+ },
- _change: function() {
- var newVal = this.getValue();
- var oldVal = this.get('query');
- var isSame = compare(oldVal, newVal);
- var isSameExpectWhitespace = isSame ? (newVal.length !== oldVal.length) : false;
+ _change: function () {
+ var newVal = this.getValue();
+ var oldVal = this.get('query');
+ var isSame = compare(oldVal, newVal);
+ var isSameExpectWhitespace = isSame ? (newVal.length !== oldVal.length) : false;
- if (isSameExpectWhitespace) {
- this.trigger('whitespaceChanged', oldVal);
- }
- if (!isSame) {
- this.set('query', newVal);
- this.trigger('queryChanged', newVal, oldVal);
- }
- },
+ if (isSameExpectWhitespace) {
+ this.trigger('whitespaceChanged', oldVal);
+ }
+ if (!isSame) {
+ this.set('query', newVal);
+ this.trigger('queryChanged', newVal, oldVal);
+ }
+ },
- _handleFocus: function(e) {
- this.trigger('focus', e);
- },
+ _handleFocus: function (e) {
+ this.trigger('focus', e);
+ },
- _handleBlur: function(e) {
- this.trigger('blur', e);
- },
+ _handleBlur: function (e) {
+ this.trigger('blur', e);
+ },
- _handleKeydown: function(e) {
- var keyName = specialKeyCodeMap[e.which];
- if (keyName) {
- var eventKey = 'key' + ucFirst(keyName);
- this.trigger(e.type = eventKey, e);
- }
+ _handleKeydown: function (e) {
+ var keyName = specialKeyCodeMap[e.which];
+ if (keyName) {
+ var eventKey = 'key' + ucFirst(keyName);
+ this.trigger(e.type = eventKey, e);
}
- });
+ }
+});
- module.exports = Input;
+module.exports = Input;
- function wrapFn(fn, context) {
- return function() {
- fn.apply(context, arguments);
- };
- }
+function wrapFn(fn, context) {
+ return function () {
+ fn.apply(context, arguments);
+ };
+}
- function compare(a, b) {
- a = (a || '').replace(/^\s*/g, '').replace(/\s{2,}/g, ' ');
- b = (b || '').replace(/^\s*/g, '').replace(/\s{2,}/g, ' ');
- return a === b;
- }
+function compare(a, b) {
+ a = (a || '').replace(/^\s*/g, '').replace(/\s{2,}/g, ' ');
+ b = (b || '').replace(/^\s*/g, '').replace(/\s{2,}/g, ' ');
+ return a === b;
+}
- function ucFirst(str) {
- return str.charAt(0).toUpperCase() + str.substring(1);
- }
-});
+function ucFirst(str) {
+ return str.charAt(0).toUpperCase() + str.substring(1);
+}
\ No newline at end of file
diff --git a/tests/autocomplete-spec.js b/tests/autocomplete-spec.js
index 720bb63..92997aa 100644
--- a/tests/autocomplete-spec.js
+++ b/tests/autocomplete-spec.js
@@ -1,39 +1,93 @@
-define(function(require) {
- var sinon = require('sinon');
- var expect = require('expect');
- var Filter = require('filter');
- var AutoComplete = require('autocomplete');
- var $ = require('$');
- require('select.css');
+var sinon = require('sinon');
+var expect = require('expect.js');
+var Filter = require('../src/filter');
+var AutoComplete = require('../src/autocomplete');
+var $ = require('jquery');
+require('alice-select');
- Filter.test = function() {
- return [];
- };
+Filter.test = function () {
+ return [];
+};
- describe('Autocomplete', function() {
+describe('Autocomplete', function () {
- var input, ac;
+ var input, ac;
- beforeEach(function() {
- input = $('')
- .appendTo(document.body);
- });
- afterEach(function() {
- input.remove();
- if (ac) {
- ac.destroy();
- ac = null;
- }
- });
+ beforeEach(function () {
+ input = $('').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();
+
+ ac.setInputValue('a');
+
+ expect(ac.get('data')).to.eql([{
+ label: 'abc',
+ value: 'abc',
+ alias: [],
+ highlightIndex: [
+ [0, 1]
+ ]
+ },
+ {
+ label: 'abd',
+ value: 'abd',
+ alias: [],
+ 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('normal usage', function() {
+ ac.setInputValue('');
+
+ expect(ac.get('visiable')).not.to.be.ok();
+ expect(ac.input.getValue()).to.be('');
+ });
+
+ it('render', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: ['abc', 'abd', 'cbd']
+ }).render();
+
+ ac.setInputValue('a');
+
+ expect(ac.items.length).to.be(2);
+ expect(ac.items.eq(0).text().replace(/\s/g, '')).to.be('abc');
+ expect(ac.items.eq(1).text().replace(/\s/g, '')).to.be('abd');
+ });
+
+ describe('data locator', function () {
+ it('should support string', function () {
ac = new AutoComplete({
trigger: '#test',
- dataSource: ['abc', 'abd', 'cbd']
+ dataSource: {
+ test: ['abc', 'abd', 'cbd']
+ },
+ locator: 'test'
}).render();
ac.setInputValue('a');
-
expect(ac.get('data')).to.eql([{
label: 'abc',
value: 'abc',
@@ -41,7 +95,8 @@ define(function(require) {
highlightIndex: [
[0, 1]
]
- }, {
+ },
+ {
label: 'abd',
value: 'abd',
alias: [],
@@ -51,549 +106,492 @@ define(function(require) {
}]);
});
- it('should hide when empty', function() {
- var input = $('#test');
- input.val('a');
+ it('should support dot string', function () {
ac = new AutoComplete({
trigger: '#test',
- dataSource: ['abc', 'abd', 'cbd']
+ dataSource: {
+ test: {
+ more: ['abc', 'abd', 'cbd']
+ }
+ },
+ locator: 'test.more'
}).render();
- ac.setInputValue('');
-
- expect(ac.get('visiable')).not.to.be.ok();
- expect(ac.input.getValue()).to.be('');
+ ac.setInputValue('a');
+ expect(ac.get('data')).to.eql([{
+ label: 'abc',
+ value: 'abc',
+ alias: [],
+ highlightIndex: [
+ [0, 1]
+ ]
+ },
+ {
+ label: 'abd',
+ value: 'abd',
+ alias: [],
+ highlightIndex: [
+ [0, 1]
+ ]
+ }]);
});
- it('render', function() {
+ it('should support function', function () {
ac = new AutoComplete({
trigger: '#test',
- dataSource: ['abc', 'abd', 'cbd']
+ 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([{
+ label: 'abc',
+ value: 'abc',
+ alias: [],
+ highlightIndex: [
+ [0, 1]
+ ]
+ },
+ {
+ label: 'abd',
+ value: 'abd',
+ alias: [],
+ highlightIndex: [
+ [0, 1]
+ ]
+ }]);
+ });
- expect(ac.items.length).to.be(2);
- expect(ac.items.eq(0).text().replace(/\s/g, '')).to.be('abc');
- expect(ac.items.eq(1).text().replace(/\s/g, '')).to.be('abd');
+ it('wrong locator', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: {
+ test: ['abc', 'abd', 'cbd']
+ },
+ locator: 'wrong'
+ }).render();
+
+ ac.setInputValue('a');
+ expect(ac.get('data')).to.eql([]);
});
+ });
- describe('data locator', function() {
- it('should support string', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: {
- test: ['abc', 'abd', 'cbd']
- },
- locator: 'test'
- }).render();
-
- ac.setInputValue('a');
- expect(ac.get('data')).to.eql([{
- label: 'abc',
- value: 'abc',
- alias: [],
- highlightIndex: [
- [0, 1]
- ]
- }, {
- label: 'abd',
- value: 'abd',
- alias: [],
- 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();
+
+ expect(ac.get('visible')).not.to.be.ok();
+ });
- it('should support dot string', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: {
- test: {
- more: ['abc', 'abd', 'cbd']
- }
- },
- locator: 'test.more'
- }).render();
-
- ac.setInputValue('a');
- expect(ac.get('data')).to.eql([{
- label: 'abc',
- value: 'abc',
- alias: [],
- highlightIndex: [
- [0, 1]
- ]
- }, {
- label: 'abd',
- value: 'abd',
- alias: [],
- highlightIndex: [
- [0, 1]
- ]
- }]);
- });
+ it('should be hide when mousedown #26', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: ['abc']
+ }).render();
+ ac.setInputValue('a');
+ ac.items.eq(0).click();
- it('should support function', function() {
- 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([{
- label: 'abc',
- value: 'abc',
- alias: [],
- highlightIndex: [
- [0, 1]
- ]
- }, {
- label: 'abd',
- value: 'abd',
- alias: [],
- highlightIndex: [
- [0, 1]
- ]
- }]);
- });
+ expect(ac.get('visible')).not.to.be.ok();
+ });
+
+ it('should not be hide when mousedown #26', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ template: 'a
{{#each items}}- {{label}}
{{/each}}
',
+ 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();
+ });
- it('wrong locator', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: {
- test: ['abc', 'abd', 'cbd']
- },
- locator: 'wrong'
- }).render();
-
- ac.setInputValue('a');
- expect(ac.get('data')).to.eql([]);
+ describe('filter', function () {
+ it('should be "startsWith" by default', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: []
});
+ expect(ac.get('filter')).to.eql(Filter['startsWith']);
});
-
- it('should be hide when trigger blur #26', function() {
- if ($.browser.msie) return;
- var input = $('#test');
+ it('should be "default" when ajax by default', function () {
ac = new AutoComplete({
trigger: '#test',
- dataSource: ['abc']
- }).render();
- ac.setInputValue('a');
- input.blur();
-
- expect(ac.get('visible')).not.to.be.ok();
+ dataSource: './data.json'
+ });
+ expect(ac.get('filter')).to.eql(Filter['default']);
});
-
- it('should be hide when mousedown #26', function() {
+ it('should be "default" when "", null, false', function () {
ac = new AutoComplete({
trigger: '#test',
- dataSource: ['abc']
- }).render();
- ac.setInputValue('a');
- ac.items.eq(0).click();
+ filter: '',
+ dataSource: []
+ });
- expect(ac.get('visible')).not.to.be.ok();
+ expect(ac.get('filter')).to.eql(Filter['default']);
});
-
- it('should not be hide when mousedown #26', function() {
+ it('should support string', function () {
ac = new AutoComplete({
trigger: '#test',
- template: 'a
{{#each items}}- {{label}}
{{/each}}
',
- dataSource: ['abc']
- }).render();
- ac.setInputValue('a');
- expect(ac.get('visible')).to.be.ok();
- ac.element.find('[data-role=other]').mousedown();
+ filter: 'test',
+ dataSource: []
+ });
- expect(ac.get('visible')).to.be.ok();
+ expect(ac.get('filter')).to.eql(Filter.test);
});
- describe('filter', function() {
- it('should be "startsWith" by default', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: []
- });
- expect(ac.get('filter')).to.eql(Filter['startsWith']);
- });
- it('should be "default" when ajax by default', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: './data.json'
- });
- expect(ac.get('filter')).to.eql(Filter['default']);
- });
- it('should be "default" when "", null, false', function() {
- ac = new AutoComplete({
- trigger: '#test',
- filter: '',
- dataSource: []
- });
-
- expect(ac.get('filter')).to.eql(Filter['default']);
- });
- it('should support string', function() {
- ac = new AutoComplete({
- trigger: '#test',
- filter: 'test',
- dataSource: []
- });
-
- expect(ac.get('filter')).to.eql(Filter.test);
+ it('should support string but not exist', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ filter: 'notExist',
+ dataSource: []
});
- it('should support string but not exist', function() {
- ac = new AutoComplete({
- trigger: '#test',
- filter: 'notExist',
- dataSource: []
- });
-
- expect(ac.get('filter')).to.eql(Filter['default']);
- });
- it('should support function', function() {
- var func = function() {};
- ac = new AutoComplete({
- trigger: '#test',
- filter: func,
- dataSource: []
- });
-
- expect(ac.get('filter')).to.eql(func);
- });
- it('should support object but not exist', function() {
- ac = new AutoComplete({
- trigger: '#test',
- filter: 'notExist',
- dataSource: []
- });
-
- expect(ac.get('filter')).to.eql(Filter['default']);
- });
- it('should be called with 3 param', function() {
- var spy = sinon.spy();
- Filter.filter = spy;
- ac = new AutoComplete({
- trigger: '#test',
- filter: 'filter',
- dataSource: ['abc']
- }).render();
-
- ac.setInputValue('a');
- var data = [{
- label: 'abc',
- value: 'abc',
- alias: []
- }];
- expect(spy.withArgs(data, 'a').called).to.be.ok();
- });
+ expect(ac.get('filter')).to.eql(Filter['default']);
});
-
- it('select item', function() {
- var input = $('#test'),
- spy = sinon.spy();
+ it('should support function', function () {
+ var func = function () {};
ac = new AutoComplete({
trigger: '#test',
- dataSource: ['abc', 'abd', 'cbd']
- }).on('itemSelected', spy).render();
+ filter: func,
+ dataSource: []
+ });
- ac.setInputValue('a');
- ac.set('selectedIndex', 0);
- ac.selectItem();
- expect(ac.get('visible')).to.be(false);
- expect(input.val()).to.be('abc');
- expect(ac.input.getValue()).to.be('abc');
- expect(spy.called).to.be.ok();
-
- ac.setInputValue('ab');
- ac.selectItem(1);
- expect(ac.get('visible')).to.be(false);
- expect(input.val()).to.be('abd');
- expect(ac.input.getValue()).to.be('abd');
- expect(spy.calledTwice).to.be.ok();
+ expect(ac.get('filter')).to.eql(func);
});
-
- it('highlight item', function() {
- var item;
+ it('should support object but not exist', function () {
ac = new AutoComplete({
trigger: '#test',
- html: '{{{highlightItem label}}}',
- dataSource: ['abc', 'abd', 'cbd']
- }).render();
+ filter: 'notExist',
+ dataSource: []
+ });
- ac.set('data', [{
- label: 'abcdefg',
- highlightIndex: [
- [0, 1]
- ]
- }]);
- item = ac.$('[data-role=item]')
- .eq(0)
- .find('.ui-select-item-hl');
- expect(item.length).to.be(1);
- expect(item.eq(0).text()).to.be('a');
-
- ac.set('data', [{
- label: 'abcdefg',
- highlightIndex: [
- [1, 2],
- [3, 4]
- ]
- }]);
- item = ac.$('[data-role=item]')
- .eq(0)
- .find('.ui-select-item-hl');
- expect(item.length).to.be(2);
- expect(item.eq(0).text()).to.be('b');
- expect(item.eq(1).text()).to.be('d');
-
- ac.set('data', [{
- label: 'abcdefg',
- highlightIndex: [
- [0, 1],
- [3, 7],
- [8, 9]
- ]
- }]);
- item = ac.$('[data-role=item]')
- .eq(0)
- .find('.ui-select-item-hl');
- expect(item.length).to.be(2);
- expect(item.eq(0).text()).to.be('a');
- expect(item.eq(1).text()).to.be('defg');
-
- ac.set('data', [{
- label: 'abcdefg',
- highlightIndex: [1, 4]
- }]);
- item = ac.$('[data-role=item]')
- .eq(0)
- .find('.ui-select-item-hl');
- expect(item.length).to.be(2);
- expect(item.eq(0).text()).to.be('b');
- expect(item.eq(1).text()).to.be('e');
-
- ac.set('data', [{
- label: 'abcdefg',
- highlightIndex: [6, 8]
- }]);
- item = ac.$('[data-role=item]')
- .eq(0)
- .find('.ui-select-item-hl');
- expect(item.length).to.be(1);
- expect(item.eq(0).text()).to.be('g');
-
- ac.set('data', [{
- label: 'abcdefg',
- highlightIndex: 0
- }]);
- item = ac.$('.ui-select-item-hl');
- expect(item.length).to.be(0);
+ expect(ac.get('filter')).to.eql(Filter['default']);
});
-
- it('clear', function() {
+ it('should be called with 3 param', function () {
+ var spy = sinon.spy();
+ Filter.filter = spy;
ac = new AutoComplete({
trigger: '#test',
- dataSource: ['abc', 'abd', 'cbd']
+ filter: 'filter',
+ dataSource: ['abc']
}).render();
ac.setInputValue('a');
-
- 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 data = [{
+ label: 'abc',
+ value: 'abc',
+ alias: []
+ }];
+ expect(spy.withArgs(data, 'a').called).to.be.ok();
});
+ });
- it('do not show when async #14', function(done) {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: 'http://baidu.com'
- }).render();
+ it('select item', function () {
+ var input = $('#test'),
+ spy = sinon.spy();
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: ['abc', 'abd', 'cbd']
+ }).on('itemSelected', spy).render();
+
+ ac.setInputValue('a');
+ ac.set('selectedIndex', 0);
+ ac.selectItem();
+ expect(ac.get('visible')).to.be(false);
+ expect(input.val()).to.be('abc');
+ expect(ac.input.getValue()).to.be('abc');
+ expect(spy.called).to.be.ok();
+
+ ac.setInputValue('ab');
+ ac.selectItem(1);
+ expect(ac.get('visible')).to.be(false);
+ expect(input.val()).to.be('abd');
+ expect(ac.input.getValue()).to.be('abd');
+ expect(spy.calledTwice).to.be.ok();
+ });
- var spy = sinon.stub($, 'ajax').returns({
- success: function(callback) {
- setTimeout(function() {
- callback(['abc', 'abd', 'cbd']);
- }, 50);
- return this;
- },
- error: function() {}
- });
+ it('highlight item', function () {
+ var item;
+ ac = new AutoComplete({
+ trigger: '#test',
+ html: '{{{highlightItem label}}}',
+ dataSource: ['abc', 'abd', 'cbd']
+ }).render();
+
+ ac.set('data', [{
+ label: 'abcdefg',
+ highlightIndex: [
+ [0, 1]
+ ]
+ }]);
+ item = ac.$('[data-role=item]').eq(0).find('.ui-select-item-hl');
+ expect(item.length).to.be(1);
+ expect(item.eq(0).text()).to.be('a');
+
+ ac.set('data', [{
+ label: 'abcdefg',
+ highlightIndex: [
+ [1, 2],
+ [3, 4]
+ ]
+ }]);
+ item = ac.$('[data-role=item]').eq(0).find('.ui-select-item-hl');
+ expect(item.length).to.be(2);
+ expect(item.eq(0).text()).to.be('b');
+ expect(item.eq(1).text()).to.be('d');
+
+ ac.set('data', [{
+ label: 'abcdefg',
+ highlightIndex: [
+ [0, 1],
+ [3, 7],
+ [8, 9]
+ ]
+ }]);
+ item = ac.$('[data-role=item]').eq(0).find('.ui-select-item-hl');
+ expect(item.length).to.be(2);
+ expect(item.eq(0).text()).to.be('a');
+ expect(item.eq(1).text()).to.be('defg');
+
+ ac.set('data', [{
+ label: 'abcdefg',
+ highlightIndex: [1, 4]
+ }]);
+ item = ac.$('[data-role=item]').eq(0).find('.ui-select-item-hl');
+ expect(item.length).to.be(2);
+ expect(item.eq(0).text()).to.be('b');
+ expect(item.eq(1).text()).to.be('e');
+
+ ac.set('data', [{
+ label: 'abcdefg',
+ highlightIndex: [6, 8]
+ }]);
+ item = ac.$('[data-role=item]').eq(0).find('.ui-select-item-hl');
+ expect(item.length).to.be(1);
+ expect(item.eq(0).text()).to.be('g');
+
+ ac.set('data', [{
+ label: 'abcdefg',
+ highlightIndex: 0
+ }]);
+ item = ac.$('.ui-select-item-hl');
+ expect(item.length).to.be(0);
+ });
- ac.setInputValue('a');
+ it('clear', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: ['abc', 'abd', 'cbd']
+ }).render();
- setTimeout(function() {
- expect(ac.get('visible')).to.be.ok();
- spy.restore();
- done();
- }, 50);
+ ac.setInputValue('a');
+ 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);
+ });
+
+ it('do not show when async #14', function (done) {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: 'http://baidu.com'
+ }).render();
+
+ var spy = sinon.stub($, 'ajax').returns({
+ success: function (callback) {
+ setTimeout(function () {
+ callback(['abc', 'abd', 'cbd']);
+ }, 50);
+ return this;
+ },
+ error: function () {}
});
- it('should support selectFirst', function() {
- ac = new AutoComplete({
- trigger: '#test',
- selectFirst: true,
- dataSource: ['abc', 'abd', 'cbd']
- }).render();
+ ac.setInputValue('a');
- ac.setInputValue('a');
- expect(ac.get('selectedIndex')).to.be(0);
+ 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();
- 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('selectedIndex')).to.be(0);
- ac.setInputValue('a');
- expect(ac.get('visible')).to.be.ok();
- ac.setInputValue('');
- expect(ac.get('visible')).not.to.be.ok();
+ });
+
+ 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();
- });
+ ac.setInputValue('a');
+ expect(ac.get('visible')).to.be.ok();
- it('normalize', function() {
- ac = new AutoComplete({
- trigger: '#test',
- filter: 'default',
- dataSource: [
- 'aa',
- 'ba', {
- title: 'ab'
- }, {
- value: 'ac'
- }, {
- label: 'bc',
- other: 'bc'
- }, {
- label: 'ad',
- value: 'ad'
- }, {
- label: 'ae',
- value: 'ae',
- alias: ['be']
- }
- ]
- }).render();
+ ac.setInputValue('');
+ expect(ac.get('visible')).not.to.be.ok();
- ac.setInputValue('a');
- expect(ac.get('data')).to.eql([{
- label: 'aa',
- value: 'aa',
- alias: []
- }, {
- label: 'ba',
- value: 'ba',
- alias: []
- }, {
- label: 'ac',
- value: 'ac',
- alias: []
- }, {
+ ac.setInputValue('a');
+ expect(ac.get('visible')).to.be.ok();
+ });
+
+ it('normalize', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ filter: 'default',
+ dataSource: ['aa', 'ba',
+ {
+ title: 'ab'
+ },
+ {
+ value: 'ac'
+ },
+ {
label: 'bc',
- value: 'bc',
- alias: [],
other: 'bc'
- }, {
+ },
+ {
label: 'ad',
- value: 'ad',
- alias: []
- }, {
+ value: 'ad'
+ },
+ {
label: 'ae',
value: 'ae',
alias: ['be']
- }]);
- });
-
- it('should step', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: ['abc', 'abd', 'cbd']
- }).render();
-
- ac.setInputValue('a');
-
- ac.items.eq(1).mouseenter();
- expect(ac.get('selectedIndex')).to.be(1);
+ }]
+ }).render();
+
+ ac.setInputValue('a');
+ expect(ac.get('data')).to.eql([{
+ label: 'aa',
+ value: 'aa',
+ alias: []
+ },
+ {
+ label: 'ba',
+ value: 'ba',
+ alias: []
+ },
+ {
+ label: 'ac',
+ value: 'ac',
+ alias: []
+ },
+ {
+ label: 'bc',
+ value: 'bc',
+ alias: [],
+ other: 'bc'
+ },
+ {
+ label: 'ad',
+ value: 'ad',
+ alias: []
+ },
+ {
+ label: 'ae',
+ value: 'ae',
+ alias: ['be']
+ }]);
+ });
- triggerKeyEvent(input, 40);
- expect(ac.get('selectedIndex')).to.be(-1);
+ it('should step', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: ['abc', 'abd', 'cbd']
+ }).render();
- triggerKeyEvent(input, 40);
- expect(ac.get('selectedIndex')).to.be(0);
+ ac.setInputValue('a');
- triggerKeyEvent(input, 38);
- expect(ac.get('selectedIndex')).to.be(-1);
+ ac.items.eq(1).mouseenter();
+ expect(ac.get('selectedIndex')).to.be(1);
- triggerKeyEvent(input, 38);
- expect(ac.get('selectedIndex')).to.be(1);
- });
+ triggerKeyEvent(input, 40);
+ expect(ac.get('selectedIndex')).to.be(-1);
- it('input focus', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: ['abc', 'abd', 'cbd']
- }).render();
+ triggerKeyEvent(input, 40);
+ expect(ac.get('selectedIndex')).to.be(0);
- input.focus();
- expect(ac._isOpen).to.be.ok();
- });
+ triggerKeyEvent(input, 38);
+ expect(ac.get('selectedIndex')).to.be(-1);
- it('dataSource should call on ac', function() {
- var spy = sinon.spy();
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: spy
- }).render();
- ac.setInputValue('a');
- expect(spy.calledOn(ac)).to.be.ok();
- });
+ triggerKeyEvent(input, 38);
+ expect(ac.get('selectedIndex')).to.be(1);
+ });
- it('should auto scroll #82', function() {
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: ['abc', 'abd', 'abe', 'acd', 'ace', 'acf', 'acg', 'ach', 'aci', 'acj', 'ack'],
- height: 123
- }).render();
- ac.element.children().css('overflow', 'scroll');
+ it('input focus', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: ['abc', 'abd', 'cbd']
+ }).render();
- ac.setInputValue('a');
- expect(ac.get('visible')).to.be.ok();
+ input.focus();
+ expect(ac._isOpen).to.be.ok();
+ });
- var content = ac.element.children();
- ac._step(1);
- expect(content.scrollTop()).to.be(0);
- ac._step(1);
- expect(content.scrollTop()).to.be(0);
- ac._step(1);
- expect(content.scrollTop()).to.be(0);
- ac._step(1);
- expect(content.scrollTop()).to.be(41);
- });
+ it('dataSource should call on ac', function () {
+ var spy = sinon.spy();
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: spy
+ }).render();
+ ac.setInputValue('a');
+ expect(spy.calledOn(ac)).to.be.ok();
});
- function triggerKeyEvent(el, keyCode) {
- var e = jQuery.Event('keydown.autocomplete');
- e.which = keyCode;
- el.trigger(e);
- }
+ it('should auto scroll #82', function () {
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: ['abc', 'abd', 'abe', 'acd', 'ace', 'acf', 'acg', 'ach', 'aci', 'acj', 'ack'],
+ height: 123
+ }).render();
+ ac.element.children().css('overflow', 'scroll');
+
+ ac.setInputValue('a');
+ expect(ac.get('visible')).to.be.ok();
+
+ var content = ac.element.children();
+ ac._step(1);
+ expect(content.scrollTop()).to.be(0);
+ ac._step(1);
+ expect(content.scrollTop()).to.be(0);
+ ac._step(1);
+ expect(content.scrollTop()).to.be(0);
+ ac._step(1);
+ expect(content.scrollTop()).to.be(41);
+ });
});
+
+function triggerKeyEvent(el, keyCode) {
+ var e = $.Event('keydown.autocomplete');
+ e.which = keyCode;
+ el.trigger(e);
+}
diff --git a/tests/data-source-spec.js b/tests/data-source-spec.js
index 7e80abb..902dd7a 100644
--- a/tests/data-source-spec.js
+++ b/tests/data-source-spec.js
@@ -1,185 +1,177 @@
-define(function(require) {
- var sinon = require('sinon');
- var expect = require('expect');
- var DataSource = require('data-source');
- var $ = require('$');
-
- describe('DataSource', function() {
-
- var data;
-
- beforeEach(function() {
- data = [
- 'about',
- 'abuse',
- 'but',
- 'buffter'
- ];
- });
+var sinon = require('sinon');
+var expect = require('expect.js');
+var DataSource = require('../src/data-source');
+var $ = require('jquery');
- afterEach(function() {
- data = null;
- });
+describe('DataSource', function () {
- 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 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];
- new DataSource({
- source: param
- }).on('data', spy).getData();
- expect(spy.withArgs(param).called).to.be.ok();
- });
+ var data;
- it('type is object', function() {
- var spy = sinon.spy();
- var param = {
- data: 1
- };
- new DataSource({
- source: param
- }).on('data', spy).getData();
- expect(spy.withArgs(param).called).to.be.ok();
- });
+ beforeEach(function () {
+ data = ['about', 'abuse', 'but', 'buffter'];
+ });
- it('type is function', function() {
- var spy = sinon.spy();
- new DataSource({
- source: function(q) {
- return [
- q + '@163.com'
- ];
- }
- }).on('data', spy).getData('a');
- expect(spy.withArgs(['a@163.com']).called).to.be.ok();
- });
+ afterEach(function () {
+ data = null;
+ });
- it('type is function return false', function() {
- var spy = sinon.spy();
+ it('error type', function () {
+ // not Boolean
+ expect(function () {
new DataSource({
- source: function() {
- return false;
- }
- }).on('data', spy).getData('a');
- expect(spy.called).not.to.be.ok();
- });
+ source: true
+ });
+ }).to.throwError();
- it('type is function async', function(done) {
- var spy = sinon.spy();
+ // not Null
+ expect(function () {
new DataSource({
- source: function(q, done) {
- setTimeout(function() {
- done();
- }, 10);
- return false;
- }
- }).on('data', spy).getData('a');
-
- setTimeout(function() {
- expect(spy.called).to.be.ok();
- 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() {}
+ source: null
});
+ }).to.throwError();
+ // not Undefined
+ expect(function () {
new DataSource({
- source: './test.json?q={{query}}'
- }).on('data', spy).getData('a');
- expect(stub.calledWithMatch('./test.json?q=a')).to.be.ok();
- expect(spy.withArgs([1, 2, 3]).called).to.be.ok();
- stub.restore();
- });
-
- it('type is url when error', function() {
- var spy = sinon.spy();
- var stub = sinon.stub($, 'ajax').returns({
- success: function() {
- return this;
- },
- error: function(callback) {
- callback();
- return this;
- }
+ source: undefined
});
+ }).to.throwError();
+ // not DOM Element
+ expect(function () {
new DataSource({
- source: './test.json?q={{query}}'
- }).on('data', spy).getData('a');
- expect(spy.withArgs({}).called).to.be.ok();
- stub.restore();
- });
- it('abort', function(done) {
- var stub = sinon.stub($, 'ajax').returns({
- success: function(callback) {
- setTimeout(function() {
- callback(['a']);
- }, 10);
- return this;
- },
- error: function() {
- return this;
- }
- });
- var source = new DataSource({
- source: './test.json?q={{query}}'
+ source: document.body
});
+ }).to.throwError();
+ });
+ it('type is array', function () {
+ var spy = sinon.spy();
+ var param = [1, 2, 3];
+ new DataSource({
+ source: param
+ }).on('data', spy).getData();
+ expect(spy.withArgs(param).called).to.be.ok();
+ });
+
+ it('type is object', function () {
+ var spy = sinon.spy();
+ var param = {
+ data: 1
+ };
+ new DataSource({
+ source: param
+ }).on('data', spy).getData();
+ expect(spy.withArgs(param).called).to.be.ok();
+ });
+
+ it('type is function', function () {
+ var spy = sinon.spy();
+ new DataSource({
+ source: function (q) {
+ return [
+ q + '@163.com'];
+ }
+ }).on('data', spy).getData('a');
+ expect(spy.withArgs(['a@163.com']).called).to.be.ok();
+ });
- var spy = sinon.spy(source, '_done');
+ it('type is function return false', function () {
+ var spy = sinon.spy();
+ new DataSource({
+ source: function () {
+ return false;
+ }
+ }).on('data', spy).getData('a');
+ expect(spy.called).not.to.be.ok();
+ });
- source.getData('a');
- expect(source.callbacks.length).to.be(1);
+ it('type is function async', function (done) {
+ var spy = sinon.spy();
+ new DataSource({
+ source: function (q, done) {
+ setTimeout(function () {
+ done();
+ }, 10);
+ return false;
+ }
+ }).on('data', spy).getData('a');
+
+ setTimeout(function () {
+ expect(spy.called).to.be.ok();
+ done();
+ }, 500);
+ });
- source.getData('a');
- expect(source.callbacks.length).to.be(2);
+ 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 () {}
+ });
- source.abort();
- expect(source.callbacks.length).to.be(0);
+ new DataSource({
+ source: './test.json?q={{query}}'
+ }).on('data', spy).getData('a');
+ expect(stub.calledWithMatch('./test.json?q=a')).to.be.ok();
+ expect(spy.withArgs([1, 2, 3]).called).to.be.ok();
+ stub.restore();
+ });
- source.getData('a');
- expect(source.callbacks.length).to.be(1);
+ it('type is url when error', function () {
+ var spy = sinon.spy();
+ var stub = sinon.stub($, 'ajax').returns({
+ success: function () {
+ return this;
+ },
+ error: function (callback) {
+ callback();
+ return this;
+ }
+ });
- setTimeout(function() {
- expect(spy.calledOnce).to.be.ok();
- stub.restore();
- done();
- }, 500);
+ new DataSource({
+ source: './test.json?q={{query}}'
+ }).on('data', spy).getData('a');
+ expect(spy.withArgs({}).called).to.be.ok();
+ stub.restore();
+ });
+ it('abort', function (done) {
+ var stub = sinon.stub($, 'ajax').returns({
+ success: function (callback) {
+ setTimeout(function () {
+ callback(['a']);
+ }, 10);
+ return this;
+ },
+ error: function () {
+ return this;
+ }
+ });
+ var source = new DataSource({
+ source: './test.json?q={{query}}'
});
+
+ 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(2);
+
+ source.abort();
+ expect(source.callbacks.length).to.be(0);
+
+ source.getData('a');
+ expect(source.callbacks.length).to.be(1);
+
+ setTimeout(function () {
+ expect(spy.calledOnce).to.be.ok();
+ stub.restore();
+ done();
+ }, 500);
});
-});
+});
\ No newline at end of file
diff --git a/tests/filter-spec.js b/tests/filter-spec.js
index 0055718..141ef3d 100644
--- a/tests/filter-spec.js
+++ b/tests/filter-spec.js
@@ -1,158 +1,174 @@
-define(function(require) {
- var expect = require('expect');
- var Filter = require('filter');
+var expect = require('expect.js');
+var Filter = require('../src/filter');
- describe('Filter', function() {
- describe('startsWith', function() {
- var data;
- beforeEach(function() {
- data = [{
- label: 'aa1',
- value: 'aa2',
- alias: []
- }, {
- label: 'ba1',
- value: 'ba2',
- alias: []
- }, {
- label: 'ac1',
- value: 'ac2',
- alias: []
- }, {
- label: 'bc1',
- value: 'bc2',
- alias: [],
- other: 'bc2'
- }, {
- label: 'ad1',
- value: 'ad2',
- alias: []
- }, {
- label: 'ae1',
- value: 'ae2',
- alias: ['be']
- }];
- });
- afterEach(function() {
- data = null;
- });
+describe('Filter', function () {
+ describe('startsWith', function () {
+ var data;
+ beforeEach(function () {
+ data = [{
+ label: 'aa1',
+ value: 'aa2',
+ alias: []
+ },
+ {
+ label: 'ba1',
+ value: 'ba2',
+ alias: []
+ },
+ {
+ label: 'ac1',
+ value: 'ac2',
+ alias: []
+ },
+ {
+ label: 'bc1',
+ value: 'bc2',
+ alias: [],
+ other: 'bc2'
+ },
+ {
+ label: 'ad1',
+ value: 'ad2',
+ alias: []
+ },
+ {
+ label: 'ae1',
+ value: 'ae2',
+ alias: ['be']
+ }];
+ });
+ afterEach(function () {
+ data = null;
+ });
- it('start width a', function() {
- var result = Filter.startsWith(data, 'a');
- expect(result).to.eql([{
- label: 'aa1',
- value: 'aa2',
- alias: []
- }, {
- label: 'ac1',
- value: 'ac2',
- alias: []
- }, {
- label: 'ad1',
- value: 'ad2',
- alias: []
- }, {
- label: 'ae1',
- value: 'ae2',
- alias: ['be']
- }]);
- });
+ it('start width a', function () {
+ var result = Filter.startsWith(data, 'a');
+ expect(result).to.eql([{
+ label: 'aa1',
+ value: 'aa2',
+ alias: []
+ },
+ {
+ label: 'ac1',
+ value: 'ac2',
+ alias: []
+ },
+ {
+ label: 'ad1',
+ value: 'ad2',
+ alias: []
+ },
+ {
+ label: 'ae1',
+ value: 'ae2',
+ alias: ['be']
+ }]);
+ });
- it('start width b', function() {
- var result = Filter.startsWith(data, 'b');
- expect(result).to.eql([{
- label: 'ba1',
- value: 'ba2',
- alias: []
- }, {
- label: 'bc1',
- value: 'bc2',
- alias: [],
- other: 'bc2'
- }, {
- label: 'ae1',
- value: 'ae2',
- alias: ['be']
- }]);
- });
+ it('start width b', function () {
+ var result = Filter.startsWith(data, 'b');
+ expect(result).to.eql([{
+ label: 'ba1',
+ value: 'ba2',
+ alias: []
+ },
+ {
+ label: 'bc1',
+ value: 'bc2',
+ alias: [],
+ other: 'bc2'
+ },
+ {
+ label: 'ae1',
+ value: 'ae2',
+ alias: ['be']
+ }]);
+ });
- 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([]);
});
+ });
- describe('stringMatch', function() {
- it('match a', function() {
- var data = [{
- label: 'abc1',
- value: 'abc',
- alias: []
- }, {
- label: 'bcd1',
- value: 'bcd',
- alias: []
- }, {
- label: 'dce1',
- value: 'dce',
- alias: ['bcd']
- }];
- var result = Filter.stringMatch(data, 'bc');
- expect(result).to.eql([{
- label: 'abc1',
- value: 'abc',
- alias: []
- }, {
- label: 'bcd1',
- value: 'bcd',
- alias: []
- }, {
- label: 'dce1',
- value: 'dce',
- alias: ['bcd']
- }]);
- });
+ describe('stringMatch', function () {
+ it('match a', function () {
+ var data = [{
+ label: 'abc1',
+ value: 'abc',
+ alias: []
+ },
+ {
+ label: 'bcd1',
+ value: 'bcd',
+ alias: []
+ },
+ {
+ label: 'dce1',
+ value: 'dce',
+ alias: ['bcd']
+ }];
+ var result = Filter.stringMatch(data, 'bc');
+ expect(result).to.eql([{
+ label: 'abc1',
+ value: 'abc',
+ alias: []
+ },
+ {
+ label: 'bcd1',
+ value: 'bcd',
+ alias: []
+ },
+ {
+ label: 'dce1',
+ value: 'dce',
+ alias: ['bcd']
+ }]);
+ });
- it('highlight', function() {
- var data = [{
- label: 'abc',
- value: 'abc',
- alias: []
- }, {
- label: 'bcd',
- value: 'bcd',
- alias: []
- }, {
- label: 'dce',
- value: 'dce',
- alias: ['bcd']
- }];
- var result = Filter.stringMatch(data, 'bc');
- expect(result).to.eql([{
- label: 'abc',
- value: 'abc',
- alias: [],
- highlightIndex: [
- [1, 3]
- ]
- }, {
- label: 'bcd',
- value: 'bcd',
- alias: [],
- highlightIndex: [
- [0, 2]
- ]
- }, {
- label: 'dce',
- value: 'dce',
- alias: ['bcd']
- }]);
- });
+ it('highlight', function () {
+ var data = [{
+ label: 'abc',
+ value: 'abc',
+ alias: []
+ },
+ {
+ label: 'bcd',
+ value: 'bcd',
+ alias: []
+ },
+ {
+ label: 'dce',
+ value: 'dce',
+ alias: ['bcd']
+ }];
+ var result = Filter.stringMatch(data, 'bc');
+ expect(result).to.eql([{
+ label: 'abc',
+ value: 'abc',
+ alias: [],
+ highlightIndex: [
+ [1, 3]
+ ]
+ },
+ {
+ label: 'bcd',
+ value: 'bcd',
+ alias: [],
+ highlightIndex: [
+ [0, 2]
+ ]
+ },
+ {
+ label: 'dce',
+ value: 'dce',
+ alias: ['bcd']
+ }]);
});
});
-});
+});
\ No newline at end of file
diff --git a/tests/input-spec.js b/tests/input-spec.js
index c141c0f..d9154b7 100644
--- a/tests/input-spec.js
+++ b/tests/input-spec.js
@@ -1,88 +1,75 @@
-define(function(require) {
- var $ = require('$');
- var expect = require('expect');
- var Input = require('input');
- var sinon = require('sinon');
+var $ = require('jquery');
+var expect = require('expect.js');
+var Input = require('../src/input');
+var sinon = require('sinon');
- describe('Input', function() {
- it('should trigger events when query changed', function() {
- var spy1 = sinon.spy();
- var spy2 = sinon.spy();
- var dom = $('').appendTo(document.body);
- var input = new Input({
- element: dom
- })
- .on('queryChanged', spy1)
- .on('whitespaceChanged', spy2);
+describe('Input', function () {
+ it('should trigger events when query changed', function () {
+ var spy1 = sinon.spy();
+ var spy2 = sinon.spy();
+ var dom = $('').appendTo(document.body);
+ var input = new Input({
+ element: dom
+ }).on('queryChanged', spy1).on('whitespaceChanged', spy2);
- input.setValue('a');
- expect(spy1.withArgs('a', '').called).to.be.ok();
- expect(spy2.called).not.to.be.ok();
+ input.setValue('a');
+ expect(spy1.withArgs('a', '').called).to.be.ok();
+ expect(spy2.called).not.to.be.ok();
- input.setValue('a ');
- expect(spy1.callCount).to.be(2);
- expect(spy2.called).not.to.be.ok();
+ input.setValue('a ');
+ expect(spy1.callCount).to.be(2);
+ expect(spy2.called).not.to.be.ok();
- input.setValue('a ');
- expect(spy1.callCount).to.be(2);
- expect(spy2.withArgs('a ').called).to.be.ok();
+ input.setValue('a ');
+ expect(spy1.callCount).to.be(2);
+ expect(spy2.withArgs('a ').called).to.be.ok();
- input.destroy();
- dom.remove();
- });
+ input.destroy();
+ dom.remove();
+ });
- it('should trigger any events', function() {
- var spy1 = sinon.spy();
- var spy2 = sinon.spy();
- var spy3 = sinon.spy();
- var spy4 = sinon.spy();
- var spy5 = sinon.spy();
- var spy6 = sinon.spy();
- var spy7 = sinon.spy();
- var spy8 = sinon.spy();
- var spy9 = sinon.spy();
- var dom = $('').appendTo(document.body);
- var input = new Input({
- element: dom
- })
- .on('focus', spy1)
- .on('blur', spy2)
- .on('keyTab', spy3)
- .on('keyEsc', spy4)
- .on('keyUp', spy5)
- .on('keyDown', spy6)
- .on('keyLeft', spy7)
- .on('keyRight', spy8)
- .on('keyEnter', spy9);
+ it('should trigger any events', function () {
+ var spy1 = sinon.spy();
+ var spy2 = sinon.spy();
+ var spy3 = sinon.spy();
+ var spy4 = sinon.spy();
+ var spy5 = sinon.spy();
+ var spy6 = sinon.spy();
+ var spy7 = sinon.spy();
+ var spy8 = sinon.spy();
+ var spy9 = sinon.spy();
+ var dom = $('').appendTo(document.body);
+ var input = new Input({
+ element: dom
+ }).on('focus', spy1).on('blur', spy2).on('keyTab', spy3).on('keyEsc', spy4).on('keyUp', spy5).on('keyDown', spy6).on('keyLeft', spy7).on('keyRight', spy8).on('keyEnter', spy9);
- input.focus();
- dom.blur();
- triggerKeyEvent(dom, 9);
- triggerKeyEvent(dom, 13);
- triggerKeyEvent(dom, 27);
- triggerKeyEvent(dom, 37);
- triggerKeyEvent(dom, 38);
- triggerKeyEvent(dom, 39);
- triggerKeyEvent(dom, 40);
+ input.focus();
+ dom.blur();
+ triggerKeyEvent(dom, 9);
+ triggerKeyEvent(dom, 13);
+ triggerKeyEvent(dom, 27);
+ triggerKeyEvent(dom, 37);
+ triggerKeyEvent(dom, 38);
+ triggerKeyEvent(dom, 39);
+ triggerKeyEvent(dom, 40);
- expect(spy1.callCount).to.be(1);
- expect(spy2.callCount).to.be(1);
- expect(spy3.callCount).to.be(1);
- expect(spy4.callCount).to.be(1);
- expect(spy5.callCount).to.be(1);
- expect(spy6.callCount).to.be(1);
- expect(spy7.callCount).to.be(1);
- expect(spy8.callCount).to.be(1);
- expect(spy9.callCount).to.be(1);
+ expect(spy1.callCount).to.be(1);
+ expect(spy2.callCount).to.be(1);
+ expect(spy3.callCount).to.be(1);
+ expect(spy4.callCount).to.be(1);
+ expect(spy5.callCount).to.be(1);
+ expect(spy6.callCount).to.be(1);
+ expect(spy7.callCount).to.be(1);
+ expect(spy8.callCount).to.be(1);
+ expect(spy9.callCount).to.be(1);
- input.destroy();
- dom.remove();
- });
+ input.destroy();
+ dom.remove();
});
-
- function triggerKeyEvent(el, keyCode) {
- var e = jQuery.Event('keydown.autocomplete');
- e.which = keyCode;
- el.trigger(e);
- }
});
+
+function triggerKeyEvent(el, keyCode) {
+ var e = $.Event('keydown.autocomplete');
+ e.which = keyCode;
+ el.trigger(e);
+}
diff --git a/tests/issue-spec.js b/tests/issue-spec.js
index c2b11d0..824970c 100644
--- a/tests/issue-spec.js
+++ b/tests/issue-spec.js
@@ -1,58 +1,62 @@
-define(function(require) {
- var expect = require('expect');
- var $ = require('$');
- var AutoComplete = require('autocomplete');
- var Filter = require('filter');
-
- describe('Issue', function() {
- it('#56 start with (', function() {
- var data = [
- {label: 'about1', value: 'about', alias: []},
- {label: '(abc1', value: '(abc', alias: []}
- ];
- var result = Filter.startsWith(data, '(a');
- expect(result).to.eql([
- {label: '(abc1', value: '(abc', alias: []}
- ]);
- });
-
- xit('#55 dont\'t change selectedIndex when hover', function() {
- var ac, input = $('')
- .appendTo(document.body);
-
- 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();
-
- expect(ac.get('selectedIndex')).to.be(-1);
-
- input.remove();
- ac.destroy();
- });
-
- it('#72 start with \\', function() {
- var ac, input = $('')
- .appendTo(document.body);
-
- ac = new AutoComplete({
- trigger: '#test',
- dataSource: []
- }).render();
-
- expect(function() {
- ac.setInputValue('\\');
- }).not.to.throwError();
-
- input.remove();
- ac.destroy();
- });
+var expect = require('expect.js');
+var $ = require('jquery');
+var AutoComplete = require('../src/autocomplete');
+var Filter = require('../src/filter');
+
+describe('Issue', function () {
+ it('#56 start with (', function () {
+ var data = [{
+ label: 'about1',
+ value: 'about',
+ alias: []
+ },
+ {
+ label: '(abc1',
+ value: '(abc',
+ alias: []
+ }];
+ var result = Filter.startsWith(data, '(a');
+ expect(result).to.eql([{
+ label: '(abc1',
+ value: '(abc',
+ alias: []
+ }]);
});
-});
+
+ xit('#55 dont\'t change selectedIndex when hover', function () {
+ var ac, input = $('').appendTo(document.body);
+
+ 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();
+
+ expect(ac.get('selectedIndex')).to.be(-1);
+
+ input.remove();
+ ac.destroy();
+ });
+
+ it('#72 start with \\', function () {
+ var ac, input = $('').appendTo(document.body);
+
+ ac = new AutoComplete({
+ trigger: '#test',
+ dataSource: []
+ }).render();
+
+ expect(function () {
+ ac.setInputValue('\\');
+ }).not.to.throwError();
+
+ input.remove();
+ ac.destroy();
+ });
+});
\ No newline at end of file