Mercurial > hg > Members > nobuyasu > TwitterBootstrap
comparison assets/js/bootstrap-typeahead.js @ 3:902636e4a800 draft
move some files
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 19 Sep 2012 22:33:03 +0900 |
parents | js/bootstrap-typeahead.js@cfa3e2e51af7 |
children |
comparison
equal
deleted
inserted
replaced
2:144c93c1c71c | 3:902636e4a800 |
---|---|
1 /* ============================================================= | |
2 * bootstrap-typeahead.js v2.1.1 | |
3 * http://twitter.github.com/bootstrap/javascript.html#typeahead | |
4 * ============================================================= | |
5 * Copyright 2012 Twitter, Inc. | |
6 * | |
7 * Licensed under the Apache License, Version 2.0 (the "License"); | |
8 * you may not use this file except in compliance with the License. | |
9 * You may obtain a copy of the License at | |
10 * | |
11 * http://www.apache.org/licenses/LICENSE-2.0 | |
12 * | |
13 * Unless required by applicable law or agreed to in writing, software | |
14 * distributed under the License is distributed on an "AS IS" BASIS, | |
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
16 * See the License for the specific language governing permissions and | |
17 * limitations under the License. | |
18 * ============================================================ */ | |
19 | |
20 | |
21 !function($){ | |
22 | |
23 "use strict"; // jshint ;_; | |
24 | |
25 | |
26 /* TYPEAHEAD PUBLIC CLASS DEFINITION | |
27 * ================================= */ | |
28 | |
29 var Typeahead = function (element, options) { | |
30 this.$element = $(element) | |
31 this.options = $.extend({}, $.fn.typeahead.defaults, options) | |
32 this.matcher = this.options.matcher || this.matcher | |
33 this.sorter = this.options.sorter || this.sorter | |
34 this.highlighter = this.options.highlighter || this.highlighter | |
35 this.updater = this.options.updater || this.updater | |
36 this.$menu = $(this.options.menu).appendTo('body') | |
37 this.source = this.options.source | |
38 this.shown = false | |
39 this.listen() | |
40 } | |
41 | |
42 Typeahead.prototype = { | |
43 | |
44 constructor: Typeahead | |
45 | |
46 , select: function () { | |
47 var val = this.$menu.find('.active').attr('data-value') | |
48 this.$element | |
49 .val(this.updater(val)) | |
50 .change() | |
51 return this.hide() | |
52 } | |
53 | |
54 , updater: function (item) { | |
55 return item | |
56 } | |
57 | |
58 , show: function () { | |
59 var pos = $.extend({}, this.$element.offset(), { | |
60 height: this.$element[0].offsetHeight | |
61 }) | |
62 | |
63 this.$menu.css({ | |
64 top: pos.top + pos.height | |
65 , left: pos.left | |
66 }) | |
67 | |
68 this.$menu.show() | |
69 this.shown = true | |
70 return this | |
71 } | |
72 | |
73 , hide: function () { | |
74 this.$menu.hide() | |
75 this.shown = false | |
76 return this | |
77 } | |
78 | |
79 , lookup: function (event) { | |
80 var items | |
81 | |
82 this.query = this.$element.val() | |
83 | |
84 if (!this.query || this.query.length < this.options.minLength) { | |
85 return this.shown ? this.hide() : this | |
86 } | |
87 | |
88 items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source | |
89 | |
90 return items ? this.process(items) : this | |
91 } | |
92 | |
93 , process: function (items) { | |
94 var that = this | |
95 | |
96 items = $.grep(items, function (item) { | |
97 return that.matcher(item) | |
98 }) | |
99 | |
100 items = this.sorter(items) | |
101 | |
102 if (!items.length) { | |
103 return this.shown ? this.hide() : this | |
104 } | |
105 | |
106 return this.render(items.slice(0, this.options.items)).show() | |
107 } | |
108 | |
109 , matcher: function (item) { | |
110 return ~item.toLowerCase().indexOf(this.query.toLowerCase()) | |
111 } | |
112 | |
113 , sorter: function (items) { | |
114 var beginswith = [] | |
115 , caseSensitive = [] | |
116 , caseInsensitive = [] | |
117 , item | |
118 | |
119 while (item = items.shift()) { | |
120 if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) | |
121 else if (~item.indexOf(this.query)) caseSensitive.push(item) | |
122 else caseInsensitive.push(item) | |
123 } | |
124 | |
125 return beginswith.concat(caseSensitive, caseInsensitive) | |
126 } | |
127 | |
128 , highlighter: function (item) { | |
129 var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&') | |
130 return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { | |
131 return '<strong>' + match + '</strong>' | |
132 }) | |
133 } | |
134 | |
135 , render: function (items) { | |
136 var that = this | |
137 | |
138 items = $(items).map(function (i, item) { | |
139 i = $(that.options.item).attr('data-value', item) | |
140 i.find('a').html(that.highlighter(item)) | |
141 return i[0] | |
142 }) | |
143 | |
144 items.first().addClass('active') | |
145 this.$menu.html(items) | |
146 return this | |
147 } | |
148 | |
149 , next: function (event) { | |
150 var active = this.$menu.find('.active').removeClass('active') | |
151 , next = active.next() | |
152 | |
153 if (!next.length) { | |
154 next = $(this.$menu.find('li')[0]) | |
155 } | |
156 | |
157 next.addClass('active') | |
158 } | |
159 | |
160 , prev: function (event) { | |
161 var active = this.$menu.find('.active').removeClass('active') | |
162 , prev = active.prev() | |
163 | |
164 if (!prev.length) { | |
165 prev = this.$menu.find('li').last() | |
166 } | |
167 | |
168 prev.addClass('active') | |
169 } | |
170 | |
171 , listen: function () { | |
172 this.$element | |
173 .on('blur', $.proxy(this.blur, this)) | |
174 .on('keypress', $.proxy(this.keypress, this)) | |
175 .on('keyup', $.proxy(this.keyup, this)) | |
176 | |
177 if ($.browser.chrome || $.browser.webkit || $.browser.msie) { | |
178 this.$element.on('keydown', $.proxy(this.keydown, this)) | |
179 } | |
180 | |
181 this.$menu | |
182 .on('click', $.proxy(this.click, this)) | |
183 .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) | |
184 } | |
185 | |
186 , move: function (e) { | |
187 if (!this.shown) return | |
188 | |
189 switch(e.keyCode) { | |
190 case 9: // tab | |
191 case 13: // enter | |
192 case 27: // escape | |
193 e.preventDefault() | |
194 break | |
195 | |
196 case 38: // up arrow | |
197 e.preventDefault() | |
198 this.prev() | |
199 break | |
200 | |
201 case 40: // down arrow | |
202 e.preventDefault() | |
203 this.next() | |
204 break | |
205 } | |
206 | |
207 e.stopPropagation() | |
208 } | |
209 | |
210 , keydown: function (e) { | |
211 this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27]) | |
212 this.move(e) | |
213 } | |
214 | |
215 , keypress: function (e) { | |
216 if (this.suppressKeyPressRepeat) return | |
217 this.move(e) | |
218 } | |
219 | |
220 , keyup: function (e) { | |
221 switch(e.keyCode) { | |
222 case 40: // down arrow | |
223 case 38: // up arrow | |
224 break | |
225 | |
226 case 9: // tab | |
227 case 13: // enter | |
228 if (!this.shown) return | |
229 this.select() | |
230 break | |
231 | |
232 case 27: // escape | |
233 if (!this.shown) return | |
234 this.hide() | |
235 break | |
236 | |
237 default: | |
238 this.lookup() | |
239 } | |
240 | |
241 e.stopPropagation() | |
242 e.preventDefault() | |
243 } | |
244 | |
245 , blur: function (e) { | |
246 var that = this | |
247 setTimeout(function () { that.hide() }, 150) | |
248 } | |
249 | |
250 , click: function (e) { | |
251 e.stopPropagation() | |
252 e.preventDefault() | |
253 this.select() | |
254 } | |
255 | |
256 , mouseenter: function (e) { | |
257 this.$menu.find('.active').removeClass('active') | |
258 $(e.currentTarget).addClass('active') | |
259 } | |
260 | |
261 } | |
262 | |
263 | |
264 /* TYPEAHEAD PLUGIN DEFINITION | |
265 * =========================== */ | |
266 | |
267 $.fn.typeahead = function (option) { | |
268 return this.each(function () { | |
269 var $this = $(this) | |
270 , data = $this.data('typeahead') | |
271 , options = typeof option == 'object' && option | |
272 if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) | |
273 if (typeof option == 'string') data[option]() | |
274 }) | |
275 } | |
276 | |
277 $.fn.typeahead.defaults = { | |
278 source: [] | |
279 , items: 8 | |
280 , menu: '<ul class="typeahead dropdown-menu"></ul>' | |
281 , item: '<li><a href="#"></a></li>' | |
282 , minLength: 1 | |
283 } | |
284 | |
285 $.fn.typeahead.Constructor = Typeahead | |
286 | |
287 | |
288 /* TYPEAHEAD DATA-API | |
289 * ================== */ | |
290 | |
291 $(function () { | |
292 $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { | |
293 var $this = $(this) | |
294 if ($this.data('typeahead')) return | |
295 e.preventDefault() | |
296 $this.typeahead($this.data()) | |
297 }) | |
298 }) | |
299 | |
300 }(window.jQuery); |