1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.ReactTypeahead=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | function classNames() {
|
9 | var classes = '';
|
10 | var arg;
|
11 |
|
12 | for (var i = 0; i < arguments.length; i++) {
|
13 | arg = arguments[i];
|
14 | if (!arg) {
|
15 | continue;
|
16 | }
|
17 |
|
18 | if ('string' === typeof arg || 'number' === typeof arg) {
|
19 | classes += ' ' + arg;
|
20 | } else if (Object.prototype.toString.call(arg) === '[object Array]') {
|
21 | classes += ' ' + classNames.apply(null, arg);
|
22 | } else if ('object' === typeof arg) {
|
23 | for (var key in arg) {
|
24 | if (!arg.hasOwnProperty(key) || !arg[key]) {
|
25 | continue;
|
26 | }
|
27 | classes += ' ' + key;
|
28 | }
|
29 | }
|
30 | }
|
31 | return classes.substr(1);
|
32 | }
|
33 |
|
34 |
|
35 | if (typeof module !== 'undefined' && module.exports) {
|
36 | module.exports = classNames;
|
37 | }
|
38 |
|
39 |
|
40 | if (typeof define !== 'undefined' && define.amd) {
|
41 | define('classnames', [], function() {
|
42 | return classNames;
|
43 | });
|
44 | }
|
45 |
|
46 | },{}],2:[function(require,module,exports){
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | (function() {
|
56 |
|
57 | var root = this;
|
58 |
|
59 | var fuzzy = {};
|
60 |
|
61 |
|
62 | if (typeof exports !== 'undefined') {
|
63 | module.exports = fuzzy;
|
64 | } else {
|
65 | root.fuzzy = fuzzy;
|
66 | }
|
67 |
|
68 |
|
69 |
|
70 | fuzzy.simpleFilter = function(pattern, array) {
|
71 | return array.filter(function(string) {
|
72 | return fuzzy.test(pattern, string);
|
73 | });
|
74 | };
|
75 |
|
76 |
|
77 | fuzzy.test = function(pattern, string) {
|
78 | return fuzzy.match(pattern, string) !== null;
|
79 | };
|
80 |
|
81 |
|
82 |
|
83 | fuzzy.match = function(pattern, string, opts) {
|
84 | opts = opts || {};
|
85 | var patternIdx = 0
|
86 | , result = []
|
87 | , len = string.length
|
88 | , totalScore = 0
|
89 | , currScore = 0
|
90 |
|
91 | , pre = opts.pre || ''
|
92 |
|
93 | , post = opts.post || ''
|
94 |
|
95 |
|
96 | , compareString = opts.caseSensitive && string || string.toLowerCase()
|
97 | , ch, compareChar;
|
98 |
|
99 | pattern = opts.caseSensitive && pattern || pattern.toLowerCase();
|
100 |
|
101 |
|
102 |
|
103 | for(var idx = 0; idx < len; idx++) {
|
104 | ch = string[idx];
|
105 | if(compareString[idx] === pattern[patternIdx]) {
|
106 | ch = pre + ch + post;
|
107 | patternIdx += 1;
|
108 |
|
109 |
|
110 | currScore += 1 + currScore;
|
111 | } else {
|
112 | currScore = 0;
|
113 | }
|
114 | totalScore += currScore;
|
115 | result[result.length] = ch;
|
116 | }
|
117 |
|
118 |
|
119 | if(patternIdx === pattern.length) {
|
120 | return {rendered: result.join(''), score: totalScore};
|
121 | }
|
122 |
|
123 | return null;
|
124 | };
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | fuzzy.filter = function(pattern, arr, opts) {
|
151 | opts = opts || {};
|
152 | return arr
|
153 | .reduce(function(prev, element, idx, arr) {
|
154 | var str = element;
|
155 | if(opts.extract) {
|
156 | str = opts.extract(element);
|
157 | }
|
158 | var rendered = fuzzy.match(pattern, str, opts);
|
159 | if(rendered != null) {
|
160 | prev[prev.length] = {
|
161 | string: rendered.rendered
|
162 | , score: rendered.score
|
163 | , index: idx
|
164 | , original: element
|
165 | };
|
166 | }
|
167 | return prev;
|
168 | }, [])
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | .sort(function(a,b) {
|
174 | var compare = b.score - a.score;
|
175 | if(compare) return compare;
|
176 | return a.index - b.index;
|
177 | });
|
178 | };
|
179 |
|
180 |
|
181 | }());
|
182 |
|
183 |
|
184 | },{}],3:[function(require,module,exports){
|
185 | var Accessor = {
|
186 | IDENTITY_FN: function (input) {
|
187 | return input;
|
188 | },
|
189 |
|
190 | generateAccessor: function (field) {
|
191 | return function (object) {
|
192 | return object[field];
|
193 | };
|
194 | },
|
195 |
|
196 | generateOptionToStringFor: function (prop) {
|
197 | if (typeof prop === 'string') {
|
198 | return this.generateAccessor(prop);
|
199 | } else if (typeof prop === 'function') {
|
200 | return prop;
|
201 | } else {
|
202 | return this.IDENTITY_FN;
|
203 | }
|
204 | },
|
205 |
|
206 | valueForOption: function (option, object) {
|
207 | if (typeof option === 'string') {
|
208 | return object[option];
|
209 | } else if (typeof option === 'function') {
|
210 | return option(object);
|
211 | } else {
|
212 | return object;
|
213 | }
|
214 | }
|
215 | };
|
216 |
|
217 | module.exports = Accessor;
|
218 |
|
219 | },{}],4:[function(require,module,exports){
|
220 |
|
221 |
|
222 |
|
223 | var KeyEvent = KeyEvent || {};
|
224 | KeyEvent.DOM_VK_UP = KeyEvent.DOM_VK_UP || 38;
|
225 | KeyEvent.DOM_VK_DOWN = KeyEvent.DOM_VK_DOWN || 40;
|
226 | KeyEvent.DOM_VK_BACK_SPACE = KeyEvent.DOM_VK_BACK_SPACE || 8;
|
227 | KeyEvent.DOM_VK_RETURN = KeyEvent.DOM_VK_RETURN || 13;
|
228 | KeyEvent.DOM_VK_ENTER = KeyEvent.DOM_VK_ENTER || 14;
|
229 | KeyEvent.DOM_VK_ESCAPE = KeyEvent.DOM_VK_ESCAPE || 27;
|
230 | KeyEvent.DOM_VK_TAB = KeyEvent.DOM_VK_TAB || 9;
|
231 |
|
232 | module.exports = KeyEvent;
|
233 |
|
234 | },{}],5:[function(require,module,exports){
|
235 | var Typeahead = require('./typeahead');
|
236 | var Tokenizer = require('./tokenizer');
|
237 |
|
238 | module.exports = {
|
239 | Typeahead: Typeahead,
|
240 | Tokenizer: Tokenizer
|
241 | };
|
242 |
|
243 | },{"./tokenizer":6,"./typeahead":8}],6:[function(require,module,exports){
|
244 | var Accessor = require('../accessor');
|
245 | var React = window.React || require('react');
|
246 | var Token = require('./token');
|
247 | var KeyEvent = require('../keyevent');
|
248 | var Typeahead = require('../typeahead');
|
249 | var classNames = require('classnames');
|
250 |
|
251 | function _arraysAreDifferent(array1, array2) {
|
252 | if (array1.length != array2.length) {
|
253 | return true;
|
254 | }
|
255 | for (var i = array2.length - 1; i >= 0; i--) {
|
256 | if (array2[i] !== array1[i]) {
|
257 | return true;
|
258 | }
|
259 | }
|
260 | }
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 | var TypeaheadTokenizer = React.createClass({
|
268 | displayName: 'TypeaheadTokenizer',
|
269 |
|
270 | propTypes: {
|
271 | name: React.PropTypes.string,
|
272 | options: React.PropTypes.array,
|
273 | customClasses: React.PropTypes.object,
|
274 | allowCustomValues: React.PropTypes.number,
|
275 | defaultSelected: React.PropTypes.array,
|
276 | initialValue: React.PropTypes.string,
|
277 | placeholder: React.PropTypes.string,
|
278 | disabled: React.PropTypes.bool,
|
279 | inputProps: React.PropTypes.object,
|
280 | onTokenRemove: React.PropTypes.func,
|
281 | onKeyDown: React.PropTypes.func,
|
282 | onKeyPress: React.PropTypes.func,
|
283 | onKeyUp: React.PropTypes.func,
|
284 | onTokenAdd: React.PropTypes.func,
|
285 | onFocus: React.PropTypes.func,
|
286 | onBlur: React.PropTypes.func,
|
287 | filterOption: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.func]),
|
288 | displayOption: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.func]),
|
289 | formInputOption: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.func]),
|
290 | maxVisible: React.PropTypes.number,
|
291 | defaultClassNames: React.PropTypes.bool
|
292 | },
|
293 |
|
294 | getInitialState: function () {
|
295 | return {
|
296 |
|
297 |
|
298 | selected: this.props.defaultSelected.slice(0)
|
299 | };
|
300 | },
|
301 |
|
302 | getDefaultProps: function () {
|
303 | return {
|
304 | options: [],
|
305 | defaultSelected: [],
|
306 | customClasses: {},
|
307 | allowCustomValues: 0,
|
308 | initialValue: "",
|
309 | placeholder: "",
|
310 | disabled: false,
|
311 | inputProps: {},
|
312 | defaultClassNames: true,
|
313 | filterOption: null,
|
314 | displayOption: function (token) {
|
315 | return token;
|
316 | },
|
317 | formInputOption: null,
|
318 | onKeyDown: function (event) {},
|
319 | onKeyPress: function (event) {},
|
320 | onKeyUp: function (event) {},
|
321 | onFocus: function (event) {},
|
322 | onBlur: function (event) {},
|
323 | onTokenAdd: function () {},
|
324 | onTokenRemove: function () {}
|
325 | };
|
326 | },
|
327 |
|
328 | componentWillReceiveProps: function (nextProps) {
|
329 |
|
330 | if (_arraysAreDifferent(this.props.defaultSelected, nextProps.defaultSelected)) {
|
331 | this.setState({ selected: nextProps.defaultSelected.slice(0) });
|
332 | }
|
333 | },
|
334 |
|
335 | focus: function () {
|
336 | this.refs.typeahead.focus();
|
337 | },
|
338 |
|
339 | getSelectedTokens: function () {
|
340 | return this.state.selected;
|
341 | },
|
342 |
|
343 |
|
344 |
|
345 | _renderTokens: function () {
|
346 | var tokenClasses = {};
|
347 | tokenClasses[this.props.customClasses.token] = !!this.props.customClasses.token;
|
348 | var classList = classNames(tokenClasses);
|
349 | var result = this.state.selected.map(function (selected) {
|
350 | var displayString = Accessor.valueForOption(this.props.displayOption, selected);
|
351 | var value = Accessor.valueForOption(this.props.formInputOption || this.props.displayOption, selected);
|
352 | return React.createElement(
|
353 | Token,
|
354 | { key: displayString, className: classList,
|
355 | onRemove: this._removeTokenForValue,
|
356 | object: selected,
|
357 | value: value,
|
358 | name: this.props.name },
|
359 | displayString
|
360 | );
|
361 | }, this);
|
362 | return result;
|
363 | },
|
364 |
|
365 | _getOptionsForTypeahead: function () {
|
366 |
|
367 | return this.props.options;
|
368 | },
|
369 |
|
370 | _onKeyDown: function (event) {
|
371 |
|
372 | if (event.keyCode === KeyEvent.DOM_VK_BACK_SPACE) {
|
373 | return this._handleBackspace(event);
|
374 | }
|
375 | this.props.onKeyDown(event);
|
376 | },
|
377 |
|
378 | _handleBackspace: function (event) {
|
379 |
|
380 | if (!this.state.selected.length) {
|
381 | return;
|
382 | }
|
383 |
|
384 |
|
385 |
|
386 | var entry = this.refs.typeahead.refs.entry;
|
387 | if (entry.selectionStart == entry.selectionEnd && entry.selectionStart == 0) {
|
388 | this._removeTokenForValue(this.state.selected[this.state.selected.length - 1]);
|
389 | event.preventDefault();
|
390 | }
|
391 | },
|
392 |
|
393 | _removeTokenForValue: function (value) {
|
394 | var index = this.state.selected.indexOf(value);
|
395 | if (index == -1) {
|
396 | return;
|
397 | }
|
398 |
|
399 | this.state.selected.splice(index, 1);
|
400 | this.setState({ selected: this.state.selected });
|
401 | this.props.onTokenRemove(value);
|
402 | return;
|
403 | },
|
404 |
|
405 | _addTokenForValue: function (value) {
|
406 | if (this.state.selected.indexOf(value) != -1) {
|
407 | return;
|
408 | }
|
409 | this.state.selected.push(value);
|
410 | this.setState({ selected: this.state.selected });
|
411 | this.refs.typeahead.setEntryText("");
|
412 | this.props.onTokenAdd(value);
|
413 | },
|
414 |
|
415 | render: function () {
|
416 | var classes = {};
|
417 | classes[this.props.customClasses.typeahead] = !!this.props.customClasses.typeahead;
|
418 | var classList = classNames(classes);
|
419 | var tokenizerClasses = [this.props.defaultClassNames && "typeahead-tokenizer"];
|
420 | tokenizerClasses[this.props.className] = !!this.props.className;
|
421 | var tokenizerClassList = classNames(tokenizerClasses);
|
422 |
|
423 | return React.createElement(
|
424 | 'div',
|
425 | { className: tokenizerClassList },
|
426 | this._renderTokens(),
|
427 | React.createElement(Typeahead, { ref: 'typeahead',
|
428 | className: classList,
|
429 | placeholder: this.props.placeholder,
|
430 | disabled: this.props.disabled,
|
431 | inputProps: this.props.inputProps,
|
432 | allowCustomValues: this.props.allowCustomValues,
|
433 | customClasses: this.props.customClasses,
|
434 | options: this._getOptionsForTypeahead(),
|
435 | initialValue: this.props.initialValue,
|
436 | maxVisible: this.props.maxVisible,
|
437 | onOptionSelected: this._addTokenForValue,
|
438 | onKeyDown: this._onKeyDown,
|
439 | onKeyPress: this.props.onKeyPress,
|
440 | onKeyUp: this.props.onKeyUp,
|
441 | onFocus: this.props.onFocus,
|
442 | onBlur: this.props.onBlur,
|
443 | displayOption: this.props.displayOption,
|
444 | defaultClassNames: this.props.defaultClassNames,
|
445 | filterOption: this.props.filterOption })
|
446 | );
|
447 | }
|
448 | });
|
449 |
|
450 | module.exports = TypeaheadTokenizer;
|
451 |
|
452 | },{"../accessor":3,"../keyevent":4,"../typeahead":8,"./token":7,"classnames":1,"react":"react"}],7:[function(require,module,exports){
|
453 | var React = window.React || require('react');
|
454 | var classNames = require('classnames');
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 | var Token = React.createClass({
|
461 | displayName: 'Token',
|
462 |
|
463 | propTypes: {
|
464 | className: React.PropTypes.string,
|
465 | name: React.PropTypes.string,
|
466 | children: React.PropTypes.string,
|
467 | object: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]),
|
468 | onRemove: React.PropTypes.func,
|
469 | value: React.PropTypes.string
|
470 | },
|
471 |
|
472 | render: function () {
|
473 | var className = classNames(["typeahead-token", this.props.className]);
|
474 |
|
475 | return React.createElement(
|
476 | 'div',
|
477 | { className: className },
|
478 | this._renderHiddenInput(),
|
479 | this.props.children,
|
480 | this._renderCloseButton()
|
481 | );
|
482 | },
|
483 |
|
484 | _renderHiddenInput: function () {
|
485 |
|
486 | if (!this.props.name) {
|
487 | return null;
|
488 | }
|
489 |
|
490 | return React.createElement('input', {
|
491 | type: 'hidden',
|
492 | name: this.props.name + '[]',
|
493 | value: this.props.value || this.props.object
|
494 | });
|
495 | },
|
496 |
|
497 | _renderCloseButton: function () {
|
498 | if (!this.props.onRemove) {
|
499 | return "";
|
500 | }
|
501 | return React.createElement(
|
502 | 'a',
|
503 | { className: 'typeahead-token-close', href: '#', onClick: function (event) {
|
504 | this.props.onRemove(this.props.object);
|
505 | event.preventDefault();
|
506 | }.bind(this) },
|
507 | '×'
|
508 | );
|
509 | }
|
510 | });
|
511 |
|
512 | module.exports = Token;
|
513 |
|
514 | },{"classnames":1,"react":"react"}],8:[function(require,module,exports){
|
515 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
516 |
|
517 | var Accessor = require('../accessor');
|
518 | var React = window.React || require('react');
|
519 | var TypeaheadSelector = require('./selector');
|
520 | var KeyEvent = require('../keyevent');
|
521 | var fuzzy = require('fuzzy');
|
522 | var classNames = require('classnames');
|
523 |
|
524 |
|
525 |
|
526 |
|
527 |
|
528 |
|
529 |
|
530 | var Typeahead = React.createClass({
|
531 | displayName: 'Typeahead',
|
532 |
|
533 | propTypes: {
|
534 | name: React.PropTypes.string,
|
535 | customClasses: React.PropTypes.object,
|
536 | maxVisible: React.PropTypes.number,
|
537 | options: React.PropTypes.array,
|
538 | allowCustomValues: React.PropTypes.number,
|
539 | initialValue: React.PropTypes.string,
|
540 | value: React.PropTypes.string,
|
541 | placeholder: React.PropTypes.string,
|
542 | disabled: React.PropTypes.bool,
|
543 | textarea: React.PropTypes.bool,
|
544 | inputProps: React.PropTypes.object,
|
545 | onOptionSelected: React.PropTypes.func,
|
546 | onChange: React.PropTypes.func,
|
547 | onKeyDown: React.PropTypes.func,
|
548 | onKeyPress: React.PropTypes.func,
|
549 | onKeyUp: React.PropTypes.func,
|
550 | onFocus: React.PropTypes.func,
|
551 | onBlur: React.PropTypes.func,
|
552 | filterOption: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.func]),
|
553 | displayOption: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.func]),
|
554 | formInputOption: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.func]),
|
555 | defaultClassNames: React.PropTypes.bool,
|
556 | customListComponent: React.PropTypes.oneOfType([React.PropTypes.element, React.PropTypes.func]),
|
557 | showOptionsWhenEmpty: React.PropTypes.bool
|
558 | },
|
559 |
|
560 | getDefaultProps: function () {
|
561 | return {
|
562 | options: [],
|
563 | customClasses: {},
|
564 | allowCustomValues: 0,
|
565 | initialValue: "",
|
566 | value: "",
|
567 | placeholder: "",
|
568 | disabled: false,
|
569 | textarea: false,
|
570 | inputProps: {},
|
571 | onOptionSelected: function (option) {},
|
572 | onChange: function (event) {},
|
573 | onKeyDown: function (event) {},
|
574 | onKeyPress: function (event) {},
|
575 | onKeyUp: function (event) {},
|
576 | onFocus: function (event) {},
|
577 | onBlur: function (event) {},
|
578 | filterOption: null,
|
579 | defaultClassNames: true,
|
580 | customListComponent: TypeaheadSelector,
|
581 | showOptionsWhenEmpty: false
|
582 | };
|
583 | },
|
584 |
|
585 | getInitialState: function () {
|
586 | return {
|
587 |
|
588 | visible: this.getOptionsForValue(this.props.initialValue, this.props.options),
|
589 |
|
590 |
|
591 | entryValue: this.props.value || this.props.initialValue,
|
592 |
|
593 |
|
594 | selection: this.props.value,
|
595 |
|
596 |
|
597 | selectionIndex: null
|
598 | };
|
599 | },
|
600 |
|
601 | _shouldSkipSearch: function (input) {
|
602 | var emptyValue = !input || input.trim().length == 0;
|
603 | return !this.props.showOptionsWhenEmpty && emptyValue;
|
604 | },
|
605 |
|
606 | getOptionsForValue: function (value, options) {
|
607 | if (this._shouldSkipSearch(value)) {
|
608 | return [];
|
609 | }
|
610 |
|
611 | var filterOptions = this._generateFilterFunction();
|
612 | var result = filterOptions(value, options);
|
613 | if (this.props.maxVisible) {
|
614 | result = result.slice(0, this.props.maxVisible);
|
615 | }
|
616 | return result;
|
617 | },
|
618 |
|
619 | setEntryText: function (value) {
|
620 | this.refs.entry.value = value;
|
621 | this._onTextEntryUpdated();
|
622 | },
|
623 |
|
624 | focus: function () {
|
625 | this.refs.entry.focus();
|
626 | },
|
627 |
|
628 | _hasCustomValue: function () {
|
629 | if (this.props.allowCustomValues > 0 && this.state.entryValue.length >= this.props.allowCustomValues && this.state.visible.indexOf(this.state.entryValue) < 0) {
|
630 | return true;
|
631 | }
|
632 | return false;
|
633 | },
|
634 |
|
635 | _getCustomValue: function () {
|
636 | if (this._hasCustomValue()) {
|
637 | return this.state.entryValue;
|
638 | }
|
639 | return null;
|
640 | },
|
641 |
|
642 | _renderIncrementalSearchResults: function () {
|
643 |
|
644 | if (this._shouldSkipSearch(this.state.entryValue)) {
|
645 | return "";
|
646 | }
|
647 |
|
648 |
|
649 | if (this.state.selection) {
|
650 | return "";
|
651 | }
|
652 |
|
653 | return React.createElement(this.props.customListComponent, {
|
654 | ref: 'sel', options: this.state.visible,
|
655 | onOptionSelected: this._onOptionSelected,
|
656 | allowCustomValues: this.props.allowCustomValues,
|
657 | customValue: this._getCustomValue(),
|
658 | customClasses: this.props.customClasses,
|
659 | selectionIndex: this.state.selectionIndex,
|
660 | defaultClassNames: this.props.defaultClassNames,
|
661 | displayOption: Accessor.generateOptionToStringFor(this.props.displayOption) });
|
662 | },
|
663 |
|
664 | getSelection: function () {
|
665 | var index = this.state.selectionIndex;
|
666 | if (this._hasCustomValue()) {
|
667 | if (index === 0) {
|
668 | return this.state.entryValue;
|
669 | } else {
|
670 | index--;
|
671 | }
|
672 | }
|
673 | return this.state.visible[index];
|
674 | },
|
675 |
|
676 | _onOptionSelected: function (option, event) {
|
677 | var nEntry = this.refs.entry;
|
678 | nEntry.focus();
|
679 |
|
680 | var displayOption = Accessor.generateOptionToStringFor(this.props.displayOption);
|
681 | var optionString = displayOption(option, 0);
|
682 |
|
683 | var formInputOption = Accessor.generateOptionToStringFor(this.props.formInputOption || displayOption);
|
684 | var formInputOptionString = formInputOption(option);
|
685 |
|
686 | nEntry.value = optionString;
|
687 | this.setState({ visible: this.getOptionsForValue(optionString, this.props.options),
|
688 | selection: formInputOptionString,
|
689 | entryValue: optionString });
|
690 | return this.props.onOptionSelected(option, event);
|
691 | },
|
692 |
|
693 | _onTextEntryUpdated: function () {
|
694 | var value = this.refs.entry.value;
|
695 | this.setState({ visible: this.getOptionsForValue(value, this.props.options),
|
696 | selection: '',
|
697 | entryValue: value });
|
698 | },
|
699 |
|
700 | _onEnter: function (event) {
|
701 | var selection = this.getSelection();
|
702 | if (!selection) {
|
703 | return this.props.onKeyDown(event);
|
704 | }
|
705 | return this._onOptionSelected(selection, event);
|
706 | },
|
707 |
|
708 | _onEscape: function () {
|
709 | this.setState({
|
710 | selectionIndex: null
|
711 | });
|
712 | },
|
713 |
|
714 | _onTab: function (event) {
|
715 | var selection = this.getSelection();
|
716 | var option = selection ? selection : this.state.visible.length > 0 ? this.state.visible[0] : null;
|
717 |
|
718 | if (option === null && this._hasCustomValue()) {
|
719 | option = this._getCustomValue();
|
720 | }
|
721 |
|
722 | if (option !== null) {
|
723 | return this._onOptionSelected(option, event);
|
724 | }
|
725 | },
|
726 |
|
727 | eventMap: function (event) {
|
728 | var events = {};
|
729 |
|
730 | events[KeyEvent.DOM_VK_UP] = this.navUp;
|
731 | events[KeyEvent.DOM_VK_DOWN] = this.navDown;
|
732 | events[KeyEvent.DOM_VK_RETURN] = events[KeyEvent.DOM_VK_ENTER] = this._onEnter;
|
733 | events[KeyEvent.DOM_VK_ESCAPE] = this._onEscape;
|
734 | events[KeyEvent.DOM_VK_TAB] = this._onTab;
|
735 |
|
736 | return events;
|
737 | },
|
738 |
|
739 | _nav: function (delta) {
|
740 | if (!this._hasHint()) {
|
741 | return;
|
742 | }
|
743 | var newIndex = this.state.selectionIndex === null ? delta == 1 ? 0 : delta : this.state.selectionIndex + delta;
|
744 | var length = this.state.visible.length;
|
745 | if (this._hasCustomValue()) {
|
746 | length += 1;
|
747 | }
|
748 |
|
749 | if (newIndex < 0) {
|
750 | newIndex += length;
|
751 | } else if (newIndex >= length) {
|
752 | newIndex -= length;
|
753 | }
|
754 |
|
755 | this.setState({ selectionIndex: newIndex });
|
756 | },
|
757 |
|
758 | navDown: function () {
|
759 | this._nav(1);
|
760 | },
|
761 |
|
762 | navUp: function () {
|
763 | this._nav(-1);
|
764 | },
|
765 |
|
766 | _onChange: function (event) {
|
767 | if (this.props.onChange) {
|
768 | this.props.onChange(event);
|
769 | }
|
770 |
|
771 | this._onTextEntryUpdated();
|
772 | },
|
773 |
|
774 | _onKeyDown: function (event) {
|
775 |
|
776 |
|
777 |
|
778 | if (!this._hasHint() || event.shiftKey) {
|
779 | return this.props.onKeyDown(event);
|
780 | }
|
781 |
|
782 | var handler = this.eventMap()[event.keyCode];
|
783 |
|
784 | if (handler) {
|
785 | handler(event);
|
786 | } else {
|
787 | return this.props.onKeyDown(event);
|
788 | }
|
789 |
|
790 | event.preventDefault();
|
791 | },
|
792 |
|
793 | componentWillReceiveProps: function (nextProps) {
|
794 | this.setState({
|
795 | visible: this.getOptionsForValue(this.state.entryValue, nextProps.options)
|
796 | });
|
797 | },
|
798 |
|
799 | render: function () {
|
800 | var inputClasses = {};
|
801 | inputClasses[this.props.customClasses.input] = !!this.props.customClasses.input;
|
802 | var inputClassList = classNames(inputClasses);
|
803 |
|
804 | var classes = {
|
805 | typeahead: this.props.defaultClassNames
|
806 | };
|
807 | classes[this.props.className] = !!this.props.className;
|
808 | var classList = classNames(classes);
|
809 |
|
810 | var InputElement = this.props.textarea ? 'textarea' : 'input';
|
811 | return React.createElement(
|
812 | 'div',
|
813 | { className: classList },
|
814 | this._renderHiddenInput(),
|
815 | React.createElement(InputElement, _extends({ ref: 'entry', type: 'text',
|
816 | disabled: this.props.disabled
|
817 | }, this.props.inputProps, {
|
818 | placeholder: this.props.placeholder,
|
819 | className: inputClassList,
|
820 | value: this.state.entryValue,
|
821 | onChange: this._onChange,
|
822 | onKeyDown: this._onKeyDown,
|
823 | onKeyPress: this.props.onKeyPress,
|
824 | onKeyUp: this.props.onKeyUp,
|
825 | onFocus: this.props.onFocus,
|
826 | onBlur: this.props.onBlur
|
827 | })),
|
828 | this._renderIncrementalSearchResults()
|
829 | );
|
830 | },
|
831 |
|
832 | _renderHiddenInput: function () {
|
833 | if (!this.props.name) {
|
834 | return null;
|
835 | }
|
836 |
|
837 | return React.createElement('input', {
|
838 | type: 'hidden',
|
839 | name: this.props.name,
|
840 | value: this.state.selection
|
841 | });
|
842 | },
|
843 |
|
844 | _generateFilterFunction: function () {
|
845 | var filterOptionProp = this.props.filterOption;
|
846 | if (typeof filterOptionProp === 'function') {
|
847 | return function (value, options) {
|
848 | return options.filter(function (o) {
|
849 | return filterOptionProp(value, o);
|
850 | });
|
851 | };
|
852 | } else {
|
853 | var mapper;
|
854 | if (typeof filterOptionProp === 'string') {
|
855 | mapper = Accessor.generateAccessor(filterOptionProp);
|
856 | } else {
|
857 | mapper = Accessor.IDENTITY_FN;
|
858 | }
|
859 | return function (value, options) {
|
860 | return fuzzy.filter(value, options, { extract: mapper }).map(function (res) {
|
861 | return options[res.index];
|
862 | });
|
863 | };
|
864 | }
|
865 | },
|
866 |
|
867 | _hasHint: function () {
|
868 | return this.state.visible.length > 0 || this._hasCustomValue();
|
869 | }
|
870 | });
|
871 |
|
872 | module.exports = Typeahead;
|
873 |
|
874 | },{"../accessor":3,"../keyevent":4,"./selector":10,"classnames":1,"fuzzy":2,"react":"react"}],9:[function(require,module,exports){
|
875 | var React = window.React || require('react');
|
876 | var classNames = require('classnames');
|
877 |
|
878 |
|
879 |
|
880 |
|
881 | var TypeaheadOption = React.createClass({
|
882 | displayName: 'TypeaheadOption',
|
883 |
|
884 | propTypes: {
|
885 | customClasses: React.PropTypes.object,
|
886 | customValue: React.PropTypes.string,
|
887 | onClick: React.PropTypes.func,
|
888 | children: React.PropTypes.string,
|
889 | hover: React.PropTypes.bool
|
890 | },
|
891 |
|
892 | getDefaultProps: function () {
|
893 | return {
|
894 | customClasses: {},
|
895 | onClick: function (event) {
|
896 | event.preventDefault();
|
897 | }
|
898 | };
|
899 | },
|
900 |
|
901 | render: function () {
|
902 | var classes = {};
|
903 | classes[this.props.customClasses.hover || "hover"] = !!this.props.hover;
|
904 | classes[this.props.customClasses.listItem] = !!this.props.customClasses.listItem;
|
905 |
|
906 | if (this.props.customValue) {
|
907 | classes[this.props.customClasses.customAdd] = !!this.props.customClasses.customAdd;
|
908 | }
|
909 |
|
910 | var classList = classNames(classes);
|
911 |
|
912 | return React.createElement(
|
913 | 'li',
|
914 | { className: classList, onClick: this._onClick },
|
915 | React.createElement(
|
916 | 'a',
|
917 | { href: 'javascript: void 0;', className: this._getClasses(), ref: 'anchor' },
|
918 | this.props.children
|
919 | )
|
920 | );
|
921 | },
|
922 |
|
923 | _getClasses: function () {
|
924 | var classes = {
|
925 | "typeahead-option": true
|
926 | };
|
927 | classes[this.props.customClasses.listAnchor] = !!this.props.customClasses.listAnchor;
|
928 |
|
929 | return classNames(classes);
|
930 | },
|
931 |
|
932 | _onClick: function (event) {
|
933 | event.preventDefault();
|
934 | return this.props.onClick(event);
|
935 | }
|
936 | });
|
937 |
|
938 | module.exports = TypeaheadOption;
|
939 |
|
940 | },{"classnames":1,"react":"react"}],10:[function(require,module,exports){
|
941 | var React = window.React || require('react');
|
942 | var TypeaheadOption = require('./option');
|
943 | var classNames = require('classnames');
|
944 |
|
945 |
|
946 |
|
947 |
|
948 |
|
949 | var TypeaheadSelector = React.createClass({
|
950 | displayName: 'TypeaheadSelector',
|
951 |
|
952 | propTypes: {
|
953 | options: React.PropTypes.array,
|
954 | allowCustomValues: React.PropTypes.number,
|
955 | customClasses: React.PropTypes.object,
|
956 | customValue: React.PropTypes.string,
|
957 | selectionIndex: React.PropTypes.number,
|
958 | onOptionSelected: React.PropTypes.func,
|
959 | displayOption: React.PropTypes.func.isRequired,
|
960 | defaultClassNames: React.PropTypes.bool
|
961 | },
|
962 |
|
963 | getDefaultProps: function () {
|
964 | return {
|
965 | selectionIndex: null,
|
966 | customClasses: {},
|
967 | allowCustomValues: 0,
|
968 | customValue: null,
|
969 | onOptionSelected: function (option) {},
|
970 | defaultClassNames: true
|
971 | };
|
972 | },
|
973 |
|
974 | render: function () {
|
975 |
|
976 | if (!this.props.options.length && this.props.allowCustomValues <= 0) {
|
977 | return false;
|
978 | }
|
979 |
|
980 | var classes = {
|
981 | "typeahead-selector": this.props.defaultClassNames
|
982 | };
|
983 | classes[this.props.customClasses.results] = this.props.customClasses.results;
|
984 | var classList = classNames(classes);
|
985 |
|
986 |
|
987 | var customValue = null;
|
988 | var customValueOffset = 0;
|
989 | if (this.props.customValue !== null) {
|
990 | customValueOffset++;
|
991 | customValue = React.createElement(
|
992 | TypeaheadOption,
|
993 | { ref: this.props.customValue, key: this.props.customValue,
|
994 | hover: this.props.selectionIndex === 0,
|
995 | customClasses: this.props.customClasses,
|
996 | customValue: this.props.customValue,
|
997 | onClick: this._onClick.bind(this, this.props.customValue) },
|
998 | this.props.customValue
|
999 | );
|
1000 | }
|
1001 |
|
1002 | var results = this.props.options.map(function (result, i) {
|
1003 | var displayString = this.props.displayOption(result, i);
|
1004 | var uniqueKey = displayString + '_' + i;
|
1005 | return React.createElement(
|
1006 | TypeaheadOption,
|
1007 | { ref: uniqueKey, key: uniqueKey,
|
1008 | hover: this.props.selectionIndex === i + customValueOffset,
|
1009 | customClasses: this.props.customClasses,
|
1010 | onClick: this._onClick.bind(this, result) },
|
1011 | displayString
|
1012 | );
|
1013 | }, this);
|
1014 |
|
1015 | return React.createElement(
|
1016 | 'ul',
|
1017 | { className: classList },
|
1018 | customValue,
|
1019 | results
|
1020 | );
|
1021 | },
|
1022 |
|
1023 | _onClick: function (result, event) {
|
1024 | return this.props.onOptionSelected(result, event);
|
1025 | }
|
1026 |
|
1027 | });
|
1028 |
|
1029 | module.exports = TypeaheadSelector;
|
1030 |
|
1031 | },{"./option":9,"classnames":1,"react":"react"}]},{},[5])(5)
|
1032 | }); |
\ | No newline at end of file |