/lib/source/js/kendo.autocomplete.js

http://luckyloot.codeplex.com · JavaScript · 969 lines · 388 code · 108 blank · 473 comment · 66 complexity · 54156b1fa9786de0c59fa3e7c6304d07 MD5 · raw file

  1. /*
  2. * Kendo UI Web v2012.2.710 (http://kendoui.com)
  3. * Copyright 2012 Telerik AD. All rights reserved.
  4. *
  5. * Kendo UI Web commercial licenses may be obtained at http://kendoui.com/web-license
  6. * If you do not own a commercial license, this file shall be governed by the
  7. * GNU General Public License (GPL) version 3.
  8. * For GPL requirements, please review: http://www.gnu.org/copyleft/gpl.html
  9. */
  10. (function ($, undefined) {
  11. /**
  12. * @name kendo.ui.AutoComplete.Description
  13. *
  14. * @section
  15. * <p>
  16. * The <b>AutoComplete</b> provides suggestions depending on the typed
  17. * text. It also allows multiple value entries. The suggestions shown by
  18. * the <b>AutoComplete</b> can come from a local Array or from a remote
  19. * data service.
  20. * </p>
  21. * <h3>Getting Started</h3>
  22. *
  23. * @exampleTitle Create a HTML input element
  24. * @example
  25. * <input id="autoComplete" />
  26. *
  27. * @exampleTitle Initialize the AutoComplete using a jQuery selector
  28. * @example
  29. * $(document).ready(function() {
  30. * $("#autoComplete").kendoAutoComplete(["Item1", "Item2"]);
  31. * });
  32. *
  33. * @section <h3>AutoComplete Suggestions</h3>
  34. * <p>
  35. * There are two primary ways to provide the <b>AutoComplete</b>
  36. * suggestions:
  37. * </p>
  38. * <ol>
  39. * <li>From a local array</li>
  40. * <li>From a remote data service</li>
  41. * </ol>
  42. * <p>
  43. * Locally defined values are best for small, fixed sets of suggestions.
  44. * Remote suggestions should be used for larger data sets. When used
  45. * with the <strong>DataSource</strong> component,
  46. * filtering large remote data services can be pushed to the server as
  47. * well, maximizing client-side performance.
  48. * </p>
  49. * <h3>Local Suggestions</h3>
  50. * <p>
  51. * To configure and provide <b>AutoComplete</b> suggestions locally, you
  52. * can either pass an array directly to its constructor or you can set
  53. * the dataSource property to an local array.
  54. * </p>
  55. *
  56. * @exampleTitle Directly initialize suggestions in constructor
  57. * @example
  58. * $("#autoComplete").kendoAutoComplete(["Item1", "Item2", "Item3"]);
  59. *
  60. * @exampleTitle Using dataSource property to bind to local Array
  61. * @example
  62. * var data = ["Item1", "Item2", "Item3"];
  63. * $("#autoComplete").kendoAutoComplete({
  64. * dataSource: data
  65. * });
  66. *
  67. * @section
  68. * <h3>Remote Suggestions</h3>
  69. * <p>
  70. * The easiest way to bind an <b>AutoComplete</b> to remote
  71. * suggestions is to use the
  72. * <strong>DataSource</strong> component; an
  73. * abstraction for local and remote data. The <b>DataSource</b>
  74. * component can be used to serve data from a variety of data services,
  75. * such as
  76. * <a href="http://en.wikipedia.org/wiki/XML">XML</a>,
  77. * <a href="http://en.wikipedia.org/wiki/JSON">JSON</a>, and
  78. * <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a>.
  79. * </p>
  80. *
  81. * @exampleTitle Using the Kendo UI Web DataSource component to bind to
  82. * remote suggestions with OData
  83. * @example
  84. * $(document).ready(function(){
  85. * $("#autoComplete").kendoAutoComplete({
  86. * minLength: 3,
  87. * dataTextField: "Name", // JSON property name to use
  88. * dataSource: new kendo.data.DataSource({
  89. * type: "odata", // specifies data protocol
  90. * pageSize: 10, // limits result set
  91. * transport: {
  92. * read: "http://odata.netflix.com/Catalog/Titles"
  93. * }
  94. * })
  95. * })
  96. * });
  97. *
  98. * @exampleTitle Using the Kendo UI Web DataSource to bind to JSONP
  99. * suggestions
  100. * @example
  101. * $(document).ready(function(){
  102. * $("#autoComplete").kendoAutoComplete({
  103. * minLength:6,
  104. * dataTextField:"title",
  105. * filter: "contains",
  106. * dataSource: new kendo.data.DataSource({
  107. * transport: {
  108. * read: {
  109. * url: "http://api.geonames.org/wikipediaSearchJSON",
  110. * data: {
  111. * q: function(){
  112. * return $("#autoComplete").data("kendoAutoComplete").value();
  113. * },
  114. * maxRows: 10,
  115. * username: "demo"
  116. * }
  117. * }
  118. * },
  119. * schema: {
  120. * data:"geonames"
  121. * }
  122. * }),
  123. * change: function(){
  124. * this.dataSource.read();
  125. * }
  126. * })
  127. * });
  128. *
  129. * @section
  130. * <h3>Accessing an Existing AutoComplete</h3>
  131. * <p>
  132. * You can reference an existing <b>AutoComplete</b> instance via
  133. * <a href="http://api.jquery.com/jQuery.data/">jQuery.data()</a>.
  134. * Once a reference has been established, you can use the API to control
  135. * its behavior.
  136. * </p>
  137. *
  138. * @exampleTitle Accessing an existing AutoComplete instance
  139. * @example
  140. * var autoComplete = $("#autoComplete").data("kendoAutoComplete");
  141. *
  142. */
  143. var kendo = window.kendo,
  144. support = kendo.support,
  145. placeholderSupported = support.placeholder,
  146. ui = kendo.ui,
  147. keys = kendo.keys,
  148. DataSource = kendo.data.DataSource,
  149. List = ui.List,
  150. CHANGE = "change",
  151. DEFAULT = "k-state-default",
  152. DISABLED = "disabled",
  153. FOCUSED = "k-state-focused",
  154. SELECTED = "k-state-selected",
  155. STATEDISABLED = "k-state-disabled",
  156. HOVER = "k-state-hover",
  157. HOVEREVENTS = "mouseenter mouseleave",
  158. caretPosition = List.caret,
  159. selectText = List.selectText,
  160. proxy = $.proxy;
  161. function indexOfWordAtCaret(caret, text, separator) {
  162. return separator ? text.substring(0, caret).split(separator).length - 1 : 0;
  163. }
  164. function wordAtCaret(caret, text, separator) {
  165. return text.split(separator)[indexOfWordAtCaret(caret, text, separator)];
  166. }
  167. function replaceWordAtCaret(caret, text, word, separator) {
  168. var words = text.split(separator);
  169. words.splice(indexOfWordAtCaret(caret, text, separator), 1, word);
  170. if (separator && words[words.length - 1] !== "") {
  171. words.push("");
  172. }
  173. return words.join(separator);
  174. }
  175. function moveCaretAtEnd(element) {
  176. var length = element.value.length;
  177. selectText(element, length, length);
  178. }
  179. var AutoComplete = List.extend/** @lends kendo.ui.AutoComplete.prototype */({
  180. /**
  181. * @constructs
  182. * @extends kendo.ui.List
  183. * @param {Element} element DOM element
  184. * @param {Object} options Configuration options.
  185. * @option {Object | kendo.data.DataSource } [dataSource] The set of data that the AutoComplete will be bound to.
  186. * Either a local JavaScript object, or an instance of the Kendo UI DataSource.
  187. * _exampleTitle Bind to local array
  188. * _example
  189. * var items = [ { Name: "Item 1" }, { Name: "Item 2"} ];
  190. * $("#autoComplete").kendoAutoComplete({ dataSource: items });
  191. * _exampleTitle Bind to a remote URL
  192. * _example
  193. * $("#autocomplete").kendoAutoComplete({
  194. * dataSource: new kendo.data.DataSource({
  195. * transport: {
  196. * read: "Items/GetData" // url to server method which returns data
  197. * }
  198. * });
  199. * });
  200. * @option {Boolean} [enable] <true> Controls whether the AutoComplete should be initially enabled.
  201. * _example
  202. * // disable the autocomplete when it is created (enabled by default)
  203. * $("#autoComplete").kendoAutoComplete({
  204. * enable: false
  205. * });
  206. * @option {Boolean} [highlightFirst] <true> Controls whether the first item will be automatically highlighted.
  207. * _example
  208. * $("#autocomplete").kendoAutoComplete({
  209. * highlightFirst: false //no of the suggested items will be highlighted
  210. * });
  211. * @option {Boolean} [suggest] <false> Controls whether the AutoComplete should automatically auto-type the rest of text.
  212. * _example
  213. * // turn on auto-typing (off by default)
  214. * $("#autoComplete").kendoAutoComplete({
  215. * suggest: true
  216. * });
  217. * @option {Number} [delay] <200> Specifies the delay in ms after which the AutoComplete will start filtering the dataSource.
  218. * _example
  219. * // set the delay to 500 milliseconds
  220. * $("#autoComplete").kendoAutoComplete({
  221. * delay: 500
  222. * });
  223. * @option {Number} [minLength] <1> Specifies the minimum number of characters that should be typed before the AutoComplete queries
  224. * the dataSource.
  225. * _example
  226. * // wait until the user types 3 characters before querying the server
  227. * $("#autoComplete").kendoAutoComplete({
  228. * minLength: 3
  229. * });
  230. * @option {String} [dataTextField] <null> Sets the field of the data item that provides the text content of the list items.
  231. * _example
  232. * var items = [ { ID: 1, Name: "Item 1" }, { ID: 2, Name: "Item 2"} ];
  233. * $("#autoComplete").kendoAutoComplete({
  234. * dataSource: items,
  235. * dataTextField: "Name"
  236. * });
  237. * @option {String} [filter] <"startswith"> Defines the type of filtration. This value is handled by the remote data source.
  238. * _example
  239. * // send a filter value of 'contains' to the server
  240. * $("#autoComplete").kendoAutoComplete({
  241. * filter: 'contains'
  242. * });
  243. * @option {String} [ignoreCase] <true> Defines whether the filtration should be case sensitive.
  244. * _example
  245. * $("#autoComplete").kendoAutoComplete({
  246. * filter: 'contains',
  247. * ignoreCase: false //now filtration will be case sensitive
  248. * });
  249. * @option {Number} [height] <200> Sets the height of the drop-down list in pixels.
  250. * _example
  251. * // set the height of the drop-down list that appears when the autocomplete is activated to 500px
  252. * $("#autoComplete").kendoAutoComplete({
  253. * height: 500
  254. * });
  255. * @option {String} [separator] <""> Sets the separator for completion. Empty by default, allowing for only one completion.
  256. * _example
  257. * // set completion separator to ,
  258. * $("#autoComplete").kendoAutoComplete({
  259. * separator: ", "
  260. * });
  261. * @option {String} [template] Template to be used for rendering the items in the list.
  262. * _example
  263. * //template
  264. *
  265. * <script id="template" type="text/x-kendo-tmpl">
  266. * # if (data.BoxArt.SmallUrl) { #
  267. * <img src="${ data.BoxArt.SmallUrl }" alt="${ data.Name }" />Title:${ data.Name }, Year: ${ data.Name }
  268. * # } else { #
  269. * <img alt="${ data.Name }" />Title:${ data.Name }, Year: ${ data.Name }
  270. * # } #
  271. * </script>
  272. *
  273. * //autocomplete initialization
  274. * <script>
  275. * $("#autocomplete").kendoAutoComplete({
  276. * dataSource: dataSource,
  277. * dataTextField: "Name",
  278. * template: kendo.template($("#template").html())
  279. * });
  280. * </script>
  281. * @option {Object} [animation] <> Animations to be used for opening/closing the popup. Setting to false will turn of the animation.
  282. * @option {Object} [animation.open] <> Animation to be used for opening of the popup.
  283. * _example
  284. * //autocomplete initialization
  285. * <script>
  286. * $("#autocomplete").kendoAutoComplete({
  287. * dataSource: dataSource,
  288. * animation: {
  289. * open: {
  290. * effects: "fadeIn",
  291. * duration: 300,
  292. * show: true
  293. * }
  294. * }
  295. * });
  296. * </script>
  297. * @option {Object} [animation.close] <> Animation to be used for closing of the popup.
  298. * _example
  299. * //autocomplete initialization
  300. * <script>
  301. * $("#autocomplete").kendoAutoComplete({
  302. * dataSource: dataSource,
  303. * animation: {
  304. * close: {
  305. * effects: "fadeOut",
  306. * duration: 300,
  307. * hide: true
  308. * show: false
  309. * }
  310. * }
  311. * });
  312. * </script>
  313. * @option {String} [placeholder] <""> A string that appears in the textbox when it has no value.
  314. * _example
  315. * //autocomplete initialization
  316. * <script>
  317. * $("#autocomplete").kendoAutoComplete({
  318. * dataSource: dataSource,
  319. * placeholder: "Enter value..."
  320. * });
  321. * </script>
  322. * _example
  323. * <input id="autocomplete" placeholder="Enter value..." />
  324. *
  325. * //combobox initialization
  326. * <script>
  327. * $("#autocomplete").kendoAutoComplete({
  328. * dataSource: dataSource
  329. * });
  330. * </script>
  331. */
  332. init: function (element, options) {
  333. var that = this, wrapper;
  334. options = $.isArray(options) ? { dataSource: options} : options;
  335. List.fn.init.call(that, element, options);
  336. element = that.element;
  337. options = that.options;
  338. options.placeholder = options.placeholder || element.attr("placeholder");
  339. if (placeholderSupported) {
  340. element.attr("placeholder", options.placeholder);
  341. }
  342. that._wrapper();
  343. that._accessors();
  344. that._dataSource();
  345. element[0].type = "text";
  346. wrapper = that.wrapper;
  347. element
  348. .attr("autocomplete", "off")
  349. .addClass("k-input")
  350. .bind({
  351. keydown: proxy(that._keydown, that),
  352. paste: proxy(that._search, that),
  353. focus: function () {
  354. that._prev = that.value();
  355. that._placeholder(false);
  356. wrapper.addClass(FOCUSED);
  357. clearTimeout(that._bluring);
  358. },
  359. blur: function () {
  360. that._change();
  361. that._placeholder();
  362. wrapper.removeClass(FOCUSED);
  363. }
  364. });
  365. that._enable();
  366. that._popup();
  367. that._old = that.value();
  368. that._placeholder();
  369. kendo.notify(that);
  370. },
  371. options: {
  372. name: "AutoComplete",
  373. suggest: false,
  374. template: "",
  375. dataTextField: "",
  376. minLength: 1,
  377. delay: 200,
  378. height: 200,
  379. filter: "startswith",
  380. ignoreCase: true,
  381. highlightFirst: false,
  382. separator: null,
  383. placeholder: "",
  384. animation: {}
  385. },
  386. _dataSource: function() {
  387. var that = this;
  388. if (that.dataSource && that._refreshHandler) {
  389. that.dataSource.unbind(CHANGE, that._refreshHandler);
  390. } else {
  391. that._refreshHandler = proxy(that.refresh, that);
  392. }
  393. that.dataSource = DataSource.create(that.options.dataSource)
  394. .bind(CHANGE, that._refreshHandler);
  395. },
  396. setDataSource: function(dataSource) {
  397. this.options.dataSource = dataSource;
  398. this._dataSource();
  399. },
  400. events: [
  401. /**
  402. * Fires when the drop-down list is opened
  403. * @name kendo.ui.AutoComplete#open
  404. * @event
  405. * @param {Event} e
  406. * @example
  407. * $("#autoComplete").kendoAutoComplete({
  408. * open: function(e) {
  409. * // handle event
  410. * }
  411. * });
  412. * @example
  413. * var autoComplete = $("#autoComplete").data("kendoAutoComplete");
  414. * autoComplete.bind("open", function(e) {
  415. * // handle event
  416. * });
  417. */
  418. "open",
  419. /**
  420. * Fires when the drop-down list is closed
  421. * @name kendo.ui.AutoComplete#close
  422. * @event
  423. * @param {Event} e
  424. * @example
  425. * $("#autoComplete").kendoAutoComplete({
  426. * close: function(e) {
  427. * // handle event
  428. * }
  429. * });
  430. * @exampleTitle To set after initialization
  431. * @example
  432. * var autoComplete = $("#autoComplete").data("kendoAutoComplete");
  433. * autoComplete.bind("close", function(e) {
  434. * // handle event
  435. * });
  436. */
  437. "close",
  438. /**
  439. * Fires when the value has been changed.
  440. * @name kendo.ui.AutoComplete#change
  441. * @event
  442. * @param {Event} e
  443. * $("#autoComplete").kendoAutoComplete({
  444. * change: function(e) {
  445. * // handle event
  446. * }
  447. * });
  448. * @exampleTitle To set after initialization
  449. * @example
  450. * var autoComplete = $("#autoComplete").data("kendoAutoComplete");
  451. * $("#autoComplete").data("kendoAutoComplete").bind("change", function(e) {
  452. * // handle event
  453. * });
  454. */
  455. CHANGE,
  456. /**
  457. *
  458. * Triggered when a Li element is selected.
  459. *
  460. * @name kendo.ui.AutoComplete#select
  461. * @event
  462. *
  463. * @param {Event} e
  464. *
  465. * @param {jQuery} e.item
  466. * The selected item chosen by a user.
  467. *
  468. * @exampleTitle Attach select event handler during initialization; detach via unbind()
  469. * @example
  470. * // event handler for select
  471. * var onSelect = function(e) {
  472. * // access the selected item via e.item (jQuery object)
  473. * };
  474. *
  475. * // attach select event handler during initialization
  476. * var autocomplete = $("#autocomplete").kendoAutoComplete({
  477. * select: onSelect
  478. * });
  479. *
  480. * // detach select event handler via unbind()
  481. * autocomplete.data("kendoAutoComplete").unbind("select", onSelect);
  482. *
  483. * @exampleTitle Attach select event handler via bind(); detach via unbind()
  484. * @example
  485. * // event handler for select
  486. * var onSelect = function(e) {
  487. * // access the selected item via e.item (jQuery object)
  488. * };
  489. *
  490. * // attach select event handler via bind()
  491. * $("#autocomplete").data("kendoAutoComplete").bind("select", onSelect);
  492. *
  493. * // detach select event handler via unbind()
  494. * $("#autocomplete").data("kendoAutoComplete").unbind("select", onSelect);
  495. *
  496. */
  497. "select",
  498. "dataBinding",
  499. "dataBound"
  500. ],
  501. setOptions: function(options) {
  502. List.fn.setOptions.call(this, options);
  503. this._template();
  504. this._accessors();
  505. },
  506. /**
  507. * Returns the raw data record at the specified index
  508. * @name kendo.ui.AutoComplete#dataItem
  509. * @function
  510. * @param {Number} index The zero-based index of the data record
  511. * @returns {Object} The raw data record. Returns <i>undefined</i> if no data.
  512. * @example
  513. * var autocomplete = $("#autocomplete").data("kendoAutoComplete");
  514. *
  515. * // get the dataItem corresponding to the passed index.
  516. * var dataItem = autocomplete.dataItem(1);
  517. */
  518. /**
  519. * Enable/Disable the autocomplete widget.
  520. * @param {Boolean} enable The argument, which defines whether to enable/disable the autocomplete.
  521. * @example
  522. * // get a reference to the autocomplete widget
  523. * var autocomplete = $("autocomplete").data("kendoAutoComplete");
  524. *
  525. * // disables the autocomplete
  526. * autocomplete.enable(false);
  527. *
  528. * // enables the autocomplete
  529. * autocomplete.enable(true);
  530. */
  531. enable: function(enable) {
  532. var that = this,
  533. element = that.element,
  534. wrapper = that.wrapper;
  535. if (enable === false) {
  536. wrapper
  537. .removeClass(DEFAULT)
  538. .addClass(STATEDISABLED)
  539. .unbind(HOVEREVENTS);
  540. element.attr(DISABLED, DISABLED);
  541. } else {
  542. wrapper
  543. .removeClass(STATEDISABLED)
  544. .addClass(DEFAULT)
  545. .bind(HOVEREVENTS, that._toggleHover);
  546. element
  547. .removeAttr(DISABLED);
  548. }
  549. },
  550. /**
  551. * Closes the drop-down list.
  552. * @example
  553. * // get a reference to the autocomplete widget
  554. * var autocomplete = $("autocomplete").data("kendoAutoComplete");
  555. *
  556. * autocomplete.close();
  557. */
  558. close: function () {
  559. var that = this;
  560. that._current = null;
  561. that.popup.close();
  562. },
  563. /**
  564. * Re-render the items in drop-down list.
  565. * @name kendo.ui.AutoComplete#refresh
  566. * @function
  567. * @example
  568. * // get a referenence to the Kendo UI AutoComplete
  569. * var autocomplete = $("autocomplete").data("kendoAutoComplete");
  570. * // re-render the items in drop-down list.
  571. * autocomplete.refresh();
  572. */
  573. refresh: function () {
  574. var that = this,
  575. ul = that.ul[0],
  576. popup = that.popup,
  577. options = that.options,
  578. data = that._data(),
  579. length = data.length;
  580. that.trigger("dataBinding");
  581. ul.innerHTML = kendo.render(that.template, data);
  582. that._height(length);
  583. if (length) {
  584. if (options.highlightFirst) {
  585. that.current($(ul.firstChild));
  586. }
  587. if (options.suggest) {
  588. that.suggest($(ul.firstChild));
  589. }
  590. }
  591. if (that._open) {
  592. that._open = false;
  593. popup[length ? "open" : "close"]();
  594. }
  595. if (that._touchScroller) {
  596. that._touchScroller.reset();
  597. }
  598. that._makeUnselectable();
  599. that.trigger("dataBound");
  600. },
  601. /**
  602. * Selects drop-down list item and sets the text of the autocomplete.
  603. * @param {jQuery Object} li The LI element.
  604. * @example
  605. * // get a reference to the autocomplete widget
  606. * var autocomplete = $("autocomplete").data("kendoAutoComplete");
  607. *
  608. * // selects by jQuery object
  609. * autocomplete.select(autocomplete.ul.children().eq(0));
  610. */
  611. select: function (li) {
  612. this._select(li);
  613. },
  614. /**
  615. * Filters dataSource using the provided parameter and rebinds drop-down list.
  616. * @param {string} word The filter value.
  617. * @example
  618. * // get a reference to the autocomplete widget
  619. * var autocomplete = $("autocomplete").data("kendoAutoComplete");
  620. *
  621. * // Searches for item which has "Inception" in the name.
  622. * autocomplete.search("Inception");
  623. */
  624. search: function (word) {
  625. var that = this,
  626. options = that.options,
  627. ignoreCase = options.ignoreCase,
  628. separator = options.separator,
  629. length;
  630. word = word || that.value();
  631. that._current = null;
  632. clearTimeout(that._typing);
  633. if (separator) {
  634. word = wordAtCaret(caretPosition(that.element[0]), word, separator);
  635. }
  636. length = word.length;
  637. if (!length) {
  638. that.popup.close();
  639. } else if (length >= that.options.minLength) {
  640. that._open = true;
  641. that.dataSource.filter({
  642. value: ignoreCase ? word.toLowerCase() : word,
  643. operator: options.filter,
  644. field: options.dataTextField,
  645. ignoreCase: ignoreCase
  646. });
  647. }
  648. },
  649. /**
  650. * Forces a suggestion onto the text of the AutoComplete.
  651. * @param {string} value Characters to force a suggestion.
  652. * @example
  653. * // note that this suggest is not the same as the configuration method
  654. * // suggest which enables/disables auto suggesting for the AutoComplete
  655. * //
  656. * // get a referenence to the Kendo UI AutoComplete
  657. * var autoComplete = $("#autoComplete").data("kendoAutoComplete");
  658. *
  659. * // force a suggestion to the item with the name "Inception"
  660. * autoComplete.suggest("Inception");
  661. */
  662. suggest: function (word) {
  663. var that = this,
  664. key = that._last,
  665. value = that.value(),
  666. element = that.element[0],
  667. caret = caretPosition(element),
  668. separator = that.options.separator,
  669. words = value.split(separator),
  670. wordIndex = indexOfWordAtCaret(caret, value, separator),
  671. selectionEnd = caret,
  672. idx;
  673. if (key == keys.BACKSPACE || key == keys.DELETE) {
  674. that._last = undefined;
  675. return;
  676. }
  677. word = word || "";
  678. if (typeof word !== "string") {
  679. idx = List.inArray(word[0], that.ul[0]);
  680. if (idx > -1) {
  681. word = that._text(that._data()[idx]);
  682. } else {
  683. word = "";
  684. }
  685. }
  686. if (caret <= 0) {
  687. caret = value.toLowerCase().indexOf(word.toLowerCase()) + 1;
  688. }
  689. idx = value.substring(0, caret).lastIndexOf(separator);
  690. idx = idx > -1 ? caret - (idx + separator.length) : caret;
  691. value = words[wordIndex].substring(0, idx);
  692. if (word) {
  693. idx = word.toLowerCase().indexOf(value.toLowerCase());
  694. if (idx > -1) {
  695. word = word.substring(idx + value.length);
  696. selectionEnd = caret + word.length;
  697. value += word;
  698. }
  699. if (separator && words[words.length - 1] !== "") {
  700. words.push("");
  701. }
  702. }
  703. words[wordIndex] = value;
  704. that.value(words.join(separator || ""));
  705. selectText(element, caret, selectionEnd);
  706. },
  707. /**
  708. * Gets/Sets the value of the autocomplete.
  709. * @param {String} value The value to set.
  710. * @returns {String} The value of the autocomplete.
  711. * @example
  712. * // get a reference to the autocomplete widget
  713. * var autocomplete = $("autocomplete").data("kendoAutoComplete");
  714. *
  715. * // get the text of the autocomplete.
  716. * var value = autocomplete.value();
  717. */
  718. value: function (value) {
  719. var that = this,
  720. element = that.element[0];
  721. if (value !== undefined) {
  722. element.value = value;
  723. that._placeholder();
  724. } else {
  725. value = element.value;
  726. if (element.className.indexOf("k-readonly") > -1) {
  727. if (value === that.options.placeholder) {
  728. return "";
  729. } else {
  730. return value;
  731. }
  732. }
  733. return value;
  734. }
  735. },
  736. _accept: function (li) {
  737. var that = this;
  738. that._focus(li);
  739. moveCaretAtEnd(that.element[0]);
  740. },
  741. _keydown: function (e) {
  742. var that = this,
  743. ul = that.ul[0],
  744. key = e.keyCode,
  745. current = that._current,
  746. visible = that.popup.visible();
  747. that._last = key;
  748. if (key === keys.DOWN) {
  749. if (visible) {
  750. that._move(current ? current.next() : $(ul.firstChild));
  751. }
  752. e.preventDefault();
  753. } else if (key === keys.UP) {
  754. if (visible) {
  755. that._move(current ? current.prev() : $(ul.lastChild));
  756. }
  757. e.preventDefault();
  758. } else if (key === keys.ENTER || key === keys.TAB) {
  759. if (that.popup.visible()) {
  760. e.preventDefault();
  761. }
  762. that._accept(current);
  763. } else if (key === keys.ESC) {
  764. that.close();
  765. } else {
  766. that._search();
  767. }
  768. },
  769. _move: function (li) {
  770. var that = this;
  771. li = li[0] ? li : null;
  772. that.current(li);
  773. if (that.options.suggest) {
  774. that.suggest(li);
  775. }
  776. },
  777. _placeholder: function(show) {
  778. if (placeholderSupported) {
  779. return;
  780. }
  781. var that = this,
  782. element = that.element,
  783. placeholder = that.options.placeholder,
  784. value;
  785. if (placeholder) {
  786. value = element.val();
  787. if (show === undefined) {
  788. show = !value;
  789. }
  790. if (!show) {
  791. if (value !== placeholder) {
  792. placeholder = value;
  793. } else {
  794. placeholder = "";
  795. }
  796. }
  797. if (value === that._old && !show) {
  798. return;
  799. }
  800. element.toggleClass("k-readonly", show)
  801. .val(placeholder);
  802. }
  803. },
  804. _search: function () {
  805. var that = this;
  806. clearTimeout(that._typing);
  807. that._typing = setTimeout(function () {
  808. if (that._prev !== that.value()) {
  809. that._prev = that.value();
  810. that.search();
  811. }
  812. }, that.options.delay);
  813. },
  814. _select: function (li) {
  815. var that = this,
  816. separator = that.options.separator,
  817. data = that._data(),
  818. text,
  819. idx;
  820. li = $(li);
  821. if (li[0] && !li.hasClass(SELECTED)) {
  822. idx = List.inArray(li[0], that.ul[0]);
  823. if (idx > -1) {
  824. data = data[idx];
  825. text = that._text(data);
  826. if (separator) {
  827. text = replaceWordAtCaret(caretPosition(that.element[0]), that.value(), text, separator);
  828. }
  829. that.value(text);
  830. that.current(li.addClass(SELECTED));
  831. }
  832. }
  833. },
  834. _toggleHover: function(e) {
  835. if (!support.touch) {
  836. $(e.currentTarget).toggleClass(HOVER, e.type === "mouseenter");
  837. }
  838. },
  839. _wrapper: function () {
  840. var that = this,
  841. element = that.element,
  842. DOMelement = element[0],
  843. wrapper;
  844. wrapper = element.parent();
  845. if (!wrapper.is("span.k-widget")) {
  846. wrapper = element.wrap("<span />").parent();
  847. }
  848. wrapper[0].style.cssText = DOMelement.style.cssText;
  849. element.css({
  850. width: "100%",
  851. height: DOMelement.style.height
  852. });
  853. that._focused = that.element;
  854. that.wrapper = wrapper
  855. .addClass("k-widget k-autocomplete k-header")
  856. .addClass(DOMelement.className);
  857. }
  858. });
  859. ui.plugin(AutoComplete);
  860. })(jQuery);
  861. ;