Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

aui-input-text-control.js 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  1. AUI.add('aui-input-text-control', function(A) {
  2. var Lang = A.Lang,
  3. isArray = Lang.isArray,
  4. isFunction = Lang.isFunction,
  5. isString = Lang.isString,
  6. KeyMap = A.Event.KeyMap,
  7. ALERT = 'alert',
  8. BINDUI = 'bindUI',
  9. CONTENT = 'content',
  10. ICON = 'icon',
  11. LIST = 'list',
  12. LOADING = 'loading',
  13. RENDERUI = 'renderUI',
  14. ICON_DEFAULT = 'circle-triangle-b',
  15. ICON_ERROR = ALERT,
  16. ICON_LOADING = LOADING,
  17. BACKSPACE = 'BACKSPACE',
  18. TAB = 'TAB',
  19. ALT = 'ALT',
  20. WIN_IME = 'WIN_IME',
  21. OVERLAY_ALIGN = {
  22. node: null,
  23. points: ['tl', 'bl']
  24. },
  25. BOUNDING_BOX = 'boundingBox',
  26. CONTENT_BOX = 'contentBox';
  27. var InputTextControl = function() {
  28. var instance = this;
  29. instance.on(RENDERUI, instance._renderUIInputTextControl, instance);
  30. instance.on(BINDUI, instance._bindUIInputTextControl, instance);
  31. };
  32. /**
  33. * Static property used to define the default attribute
  34. * configuration for the AutoComplete.
  35. *
  36. * @property AutoComplete.ATTRS
  37. * @type Object
  38. * @static
  39. */
  40. InputTextControl.ATTRS = {
  41. /**
  42. * To use a button
  43. *
  44. * @attribute button
  45. * @default true
  46. * @type Boolean
  47. * @deprecated
  48. */
  49. button: {
  50. value: true
  51. },
  52. /**
  53. * The character used to indicate the beginning or ending of a new value. Most commonly used
  54. * is a ",".
  55. *
  56. * @attribute delimChar
  57. * @default null
  58. * @type String
  59. */
  60. delimChar: {
  61. value: null,
  62. setter: function(value) {
  63. if (isString(value) && (value.length > 0)) {
  64. value = [value];
  65. }
  66. else if (!isArray(value)) {
  67. value = A.Attribute.INVALID_VALUE;
  68. }
  69. return value;
  70. }
  71. },
  72. /**
  73. * If <a href="AutoComplete.html#config_typeAhead">typeAhead</a> is true, this
  74. * will clear a selection when the overlay closes unless a user explicitly selects an item.
  75. *
  76. * @attribute forceSelection
  77. * @default false
  78. * @type Boolean
  79. */
  80. forceSelection: {
  81. value: false
  82. },
  83. iconButton: {
  84. value: ICON_DEFAULT
  85. },
  86. /**
  87. * The input field which will recieve the users input.
  88. *
  89. * @attribute input
  90. * @default null
  91. * @type String | Node
  92. */
  93. input: {
  94. value: null
  95. },
  96. /**
  97. * The key or numeric index in the schema to match the result against.
  98. *
  99. * @attribute matchKey
  100. * @default 0
  101. * @type String | Number
  102. */
  103. matchKey: {
  104. value: 0
  105. },
  106. /**
  107. * The minimum number of characters required to query the data source.
  108. *
  109. * @attribute minQueryLength
  110. * @default 1
  111. * @type Number
  112. */
  113. minQueryLength: {
  114. value: 1
  115. },
  116. /**
  117. * The amount of time in seconds to delay before submitting the query.
  118. *
  119. * @attribute queryDelay
  120. * @default 0.2
  121. * @type Number
  122. */
  123. queryDelay: {
  124. value: 0.2,
  125. getter: function(value) {
  126. return value * 1000;
  127. }
  128. },
  129. /**
  130. * When IME usage is detected or interval detection is explicitly enabled,
  131. * AutoComplete will detect the input value at the given interval and send a
  132. * query if the value has changed.
  133. *
  134. * @attribute queryInterval
  135. * @default 0.5
  136. * @type Number
  137. */
  138. queryInterval: {
  139. value: 0.5,
  140. getter: function(value) {
  141. return value * 1000;
  142. }
  143. },
  144. /**
  145. * When <a href="AutoComplete.html#config_applyLocalFilter">applyLocalFilter</a> is true,
  146. * setting this to true will match only results with the same case.
  147. *
  148. * @attribute queryMatchCase
  149. * @default false
  150. * @type Boolean
  151. */
  152. queryMatchCase: {
  153. value: false
  154. },
  155. /**
  156. * When <a href="AutoComplete.html#config_applyLocalFilter">applyLocalFilter</a> is true,
  157. * setting this to true will match results which contain the query anywhere in the text,
  158. * instead of just matching just items that start with the query.
  159. *
  160. * @attribute queryMatchContains
  161. * @default false
  162. * @type Boolean
  163. */
  164. queryMatchContains: {
  165. value: false
  166. },
  167. /**
  168. * For IO DataSources, AutoComplete will automatically insert a "?" between the server URI and
  169. * the encoded query string. To prevent this behavior, you can
  170. * set this value to false. If you need to customize this even further, you
  171. * can override the <a href="AutoComplete.html#method_generateRequest">generateRequest</a> method.
  172. *
  173. * @attribute queryQuestionMark
  174. * @default true
  175. * @type Boolean
  176. */
  177. queryQuestionMark: {
  178. value: true
  179. },
  180. /**
  181. * Whether or not the input field should be updated with selections.
  182. *
  183. * @attribute suppressInputUpdate
  184. * @default false
  185. * @type Boolean
  186. */
  187. suppressInputUpdate: {
  188. value: false
  189. },
  190. /**
  191. * If <a href="AutoComplete.html#config_autoHighlight">autoHighlight</a> is enabled, whether or not the
  192. * input field should be automatically updated with the first result as the user types,
  193. * automatically selecting the portion of the text the user has not typed yet.
  194. *
  195. * @attribute typeAhead
  196. * @default false
  197. * @type Boolean
  198. */
  199. typeAhead: {
  200. value: false
  201. },
  202. /**
  203. * If <a href="AutoComplete.html#config_typeAhead">typeAhead</a> is true, number of seconds
  204. * to delay before updating the input. In order to prevent certain race conditions, this value must
  205. * always be greater than the <a href="AutoComplete.html#config_queryDelay">queryDelay</a>.
  206. *
  207. * @attribute typeAheadDelay
  208. * @default 0.2
  209. * @type Number
  210. */
  211. typeAheadDelay: {
  212. value: 0.2,
  213. getter: function(value) {
  214. return value * 1000;
  215. }
  216. },
  217. /**
  218. * The unique ID of the input element.
  219. *
  220. * @attribute uniqueName
  221. * @default null
  222. * @type String
  223. */
  224. uniqueName: {
  225. value: null
  226. }
  227. };
  228. InputTextControl.prototype = {
  229. /**
  230. * Construction logic executed during AutoComplete instantiation. Lifecycle.
  231. *
  232. * @method initializer
  233. * @protected
  234. */
  235. initializer: function(config) {
  236. var instance = this;
  237. instance._overlayAlign = A.mix({}, OVERLAY_ALIGN);
  238. },
  239. /**
  240. * Create the DOM structure for the InputTextControl. Lifecycle.
  241. *
  242. * @method _renderUIInputTextControl
  243. * @protected
  244. */
  245. _renderUIInputTextControl: function() {
  246. var instance = this;
  247. instance._renderInput();
  248. },
  249. /**
  250. * Bind the events on the InputTextControl UI. Lifecycle.
  251. *
  252. * @method _bindUIInputTextControl
  253. * @protected
  254. */
  255. _bindUIInputTextControl: function() {
  256. var instance = this;
  257. instance._bindDataSource();
  258. var button = instance.button;
  259. var inputNode = instance.inputNode;
  260. inputNode.on('blur', instance._onTextboxBlur, instance);
  261. inputNode.on('focus', instance._onTextboxFocus, instance);
  262. inputNode.on('keydown', instance._onTextboxKeyDown, instance);
  263. inputNode.on('keypress', instance._onTextboxKeyPress, instance);
  264. inputNode.on('keyup', instance._onTextboxKeyUp, instance);
  265. instance.publish('handleResponse');
  266. instance.publish('textboxKeyDown');
  267. instance.publish('textboxKeyPress');
  268. instance.publish('textboxKeyUp');
  269. instance.publish('invalidQueryLength');
  270. instance.publish('sendQueryDisabled');
  271. /**
  272. * Handles the containerCollapse event. Fired when the container is hidden.
  273. *
  274. * @event containerCollapse
  275. * @param {Event.Facade} event The containerCollapse event.
  276. */
  277. instance.publish('containerCollapse');
  278. /**
  279. * Handles the containerExpand event. Fired when the container is shown.
  280. *
  281. * @event containerExpand
  282. * @param {Event.Facade} event The containerExpand event.
  283. */
  284. instance.publish('containerExpand');
  285. /**
  286. * Handles the containerPopulate event. Fired when the container is populated.
  287. *
  288. * @event containerPopulate
  289. * @param {Event.Facade} event The containerPopulate event.
  290. */
  291. instance.publish('containerPopulate');
  292. /**
  293. * Handles the itemArrowFrom event. Fired when the user navigates via the keyboard away from
  294. * a selected item.
  295. *
  296. * @event itemArrowFrom
  297. * @param {Event.Facade} event The itemArrowFrom event.
  298. */
  299. instance.publish('itemArrowFrom');
  300. /**
  301. * Handles the itemArrowTo event. Fired when the user navigates via the keyboard to a selected item.
  302. *
  303. * @event itemArrowTo
  304. * @param {Event.Facade} event The itemArrowTo event.
  305. */
  306. instance.publish('itemArrowTo');
  307. /**
  308. * Handles the itemMouseOut event. Fired when the user mouses away from an item.
  309. *
  310. * @event itemMouseOut
  311. * @param {Event.Facade} event The itemMouseOut event.
  312. */
  313. instance.publish('itemMouseOut');
  314. /**
  315. * Handles the itemMouseOver event. Fired when the user mouses over an item.
  316. *
  317. * @event itemMouseOver
  318. * @param {Event.Facade} event The itemMouseOver event.
  319. */
  320. instance.publish('itemMouseOver');
  321. /**
  322. * Handles the itemSelect event. Fired when an item in the list is selected.
  323. *
  324. * @event itemSelect
  325. * @param {Event.Facade} event The itemSelect event.
  326. */
  327. instance.publish('itemSelect');
  328. /**
  329. * Handles the selectionEnforce event. Fired if <a href="Autocomplete.html#config_forceSelection">forceSelection</a>
  330. * is enabled and the users input element has been cleared because it did not match one of the results.
  331. *
  332. * @event selectionEnforce
  333. * @param {Event.Facade} event The selectionEnforce event.
  334. */
  335. instance.publish('selectionEnforce');
  336. /**
  337. * Handles the textboxBlur event. Fired when the user leaves the input element.
  338. *
  339. * @event textboxBlur
  340. * @param {Event.Facade} event The textboxBlur event.
  341. */
  342. instance.publish('textboxBlur');
  343. /**
  344. * Handles the textboxChange event. Fired when the value in the input element is changed.
  345. *
  346. * @event textboxChange
  347. * @param {Event.Facade} event The textboxChange event.
  348. */
  349. instance.publish('textboxChange');
  350. /**
  351. * Handles the textboxFocus event. Fired when user moves focus to the input element.
  352. *
  353. * @event textboxFocus
  354. * @param {Event.Facade} event The textboxFocus event.
  355. */
  356. instance.publish('textboxFocus');
  357. /**
  358. * Handles the textboxKey event. Fired when the input element receives key input.
  359. *
  360. * @event textboxKey
  361. * @param {Event.Facade} event The textboxKey event.
  362. */
  363. instance.publish('textboxKey');
  364. /**
  365. * Handles the typeAhead event. Fired when the input element has been pre-filled by the type-ahead feature.
  366. *
  367. * @event typeAhead
  368. * @param {Event.Facade} event The typeAhead event.
  369. */
  370. instance.publish('typeAhead');
  371. /**
  372. * Handles the unmatchedItemSelect event. Fired when a user selects something that does
  373. * not match any of the displayed results.
  374. *
  375. * @event unmatchedItemSelect
  376. * @param {Event.Facade} event The unmatchedItemSelect event.
  377. */
  378. instance.publish('unmatchedItemSelect');
  379. },
  380. /**
  381. * Sync the AutoComplete UI. Lifecycle.
  382. *
  383. * @method syncUI
  384. * @protected
  385. */
  386. syncUI: function() {
  387. var instance = this;
  388. instance.inputNode.setAttribute('autocomplete', 'off');
  389. },
  390. /**
  391. * An overridable method that is executed before the result overlay is loaded with results.
  392. *
  393. * @method doBeforeLoadData
  394. * @param {EventFacade} event
  395. * @return {Boolean}
  396. */
  397. doBeforeLoadData: function(event) {
  398. return true;
  399. },
  400. /**
  401. * An overridable method for formatting the result of the query before it's displayed in the overlay.
  402. *
  403. * @method formatResult
  404. * @param {Object} result The result data object
  405. * @param {String} request The current query string
  406. * @param {String} resultMatch The string from the results that matches the query
  407. * @return {String}
  408. */
  409. formatResult: function(result, request, resultMatch) {
  410. return resultMatch || '';
  411. },
  412. /**
  413. * An overridable method that creates an object to be passed to the sendRequest
  414. * method of the data source object. Useful to overwrite if you wish to create
  415. * a custom request object before it's sent.
  416. *
  417. * @method generateRequest
  418. * @param {String} query The string currently being entered
  419. * @return {Object}
  420. */
  421. generateRequest: function(query) {
  422. return {
  423. request: query
  424. };
  425. },
  426. /**
  427. * Handles the response for the display of the results. This is a callback method
  428. * that is fired by the sendRequest method so that results are ready to be accessed.
  429. *
  430. * @method handleResponse
  431. * @param {EventFacade} event
  432. */
  433. handleResponse: function(event) {
  434. var instance = this;
  435. instance.fire('handleResponse', event);
  436. var iconClass = instance.get('iconButton') || ICON_DEFAULT;
  437. if (event.error) {
  438. iconClass = ICON_ERROR;
  439. }
  440. instance.button.set(ICON, iconClass);
  441. },
  442. _bindDataSource: function() {
  443. var instance = this;
  444. var button = instance.button;
  445. var dataSource = instance.get('dataSource');
  446. var dataSourceType = instance.get('dataSourceType');
  447. dataSource.on('request', A.bind(button.set, button, ICON, ICON_LOADING));
  448. dataSource.on('error', instance.handleResponse, instance);
  449. dataSource.after('response', instance.handleResponse, instance);
  450. },
  451. /**
  452. * Clears the query interval
  453. *
  454. * @method _clearInterval
  455. * @private
  456. */
  457. _clearInterval: function() {
  458. var instance = this;
  459. if (instance._queryIntervalId) {
  460. clearInterval(instance._queryIntervalId);
  461. instance._queryIntervalId = null;
  462. }
  463. },
  464. /**
  465. * When <a href="Autocomplete.html#config_forceSelection">forceSelection</a> is true and
  466. * the user tries to leave the input element without selecting an item from the results,
  467. * the user selection is cleared.
  468. *
  469. * @method _clearSelection
  470. * @protected
  471. */
  472. _clearSelection: function() {
  473. var instance = this;
  474. var delimChar = instance.get('delimChar');
  475. var extraction = {
  476. previous: '',
  477. query: instance.inputNode.get('value')
  478. };
  479. if (delimChar) {
  480. extraction = instance._extractQuery(instance.inputNode.get('value'));
  481. }
  482. instance.fire('selectionEnforce', extraction.query);
  483. },
  484. /**
  485. * Enables query interval detection for IME support.
  486. *
  487. * @method _enableIntervalDetection
  488. * @protected
  489. */
  490. _enableIntervalDetection: function() {
  491. var instance = this;
  492. var queryInterval = instance.get('queryInterval');
  493. if (!instance._queryIntervalId && queryInterval) {
  494. instance._queryInterval = setInterval(A.bind(instance._onInterval, instance), queryInterval);
  495. }
  496. },
  497. /**
  498. * Extracts the right most query from the delimited string in the input.
  499. *
  500. * @method _extractQuery
  501. * @param {String} query String to parse
  502. * @protected
  503. * @return {String}
  504. */
  505. _extractQuery: function(query) {
  506. var instance = this;
  507. var delimChar = instance.get('delimChar');
  508. var delimIndex = -1;
  509. var i = delimChar.length - 1;
  510. var newIndex, queryStart, previous;
  511. for (; i >= 0; i--) {
  512. newIndex = query.lastIndexOf(delimChar[i]);
  513. if (newIndex > delimIndex) {
  514. delimIndex = newIndex;
  515. }
  516. }
  517. if (delimChar[i] == ' ') {
  518. for (var j = delimChar.length - 1; j >= 0; j--){
  519. if (query[delimIndex - 1] == delimChar[j]) {
  520. delimIndex--;
  521. break;
  522. }
  523. }
  524. }
  525. if (delimIndex > -1) {
  526. queryStart = delimIndex + 1;
  527. while (query.charAt(queryStart) == ' ') {
  528. queryStart += 1;
  529. }
  530. previous = query.substring(0, queryStart);
  531. query = query.substring(queryStart);
  532. }
  533. else {
  534. previous = '';
  535. }
  536. return {
  537. previous: previous,
  538. query: query
  539. };
  540. },
  541. /**
  542. * Focuses the input element.
  543. *
  544. * @method _focus
  545. * @protected
  546. */
  547. _focus: function() {
  548. var instance = this;
  549. setTimeout(
  550. function() {
  551. instance.inputNode.focus();
  552. },
  553. 1
  554. );
  555. },
  556. /**
  557. * Called when the user mouses down on the button element in the combobox.
  558. *
  559. * @method _onButtonMouseDown
  560. * @param {EventFacade} event
  561. * @protected
  562. */
  563. _onButtonMouseDown: function(event) {
  564. var instance = this;
  565. event.halt();
  566. instance._focus();
  567. instance._sendQuery(instance.inputNode.get('value') + '*');
  568. },
  569. /**
  570. * Enables the query to be triggered based on detecting text input via intervals instead of via
  571. * key events.
  572. *
  573. * @method _onInterval
  574. * @protected
  575. */
  576. _onInterval: function() {
  577. var instance = this;
  578. var curValue = instance.inputNode.get('value');
  579. var lastValue = instance._lastValue;
  580. if (curValue != lastValue) {
  581. instance._lastValue = curValue;
  582. instance._sendQuery(curValue);
  583. }
  584. },
  585. /**
  586. * Handles the input element losing focus.
  587. *
  588. * @method _onTextboxBlur
  589. * @param {EventFacade} event
  590. * @protected
  591. */
  592. _onTextboxBlur: function(event) {
  593. var instance = this;
  594. if (!instance._overContainer || KeyMap.isKey(instance._keyCode, TAB)) {
  595. instance.fire('textboxBlur');
  596. }
  597. else {
  598. instance._focus();
  599. }
  600. },
  601. /**
  602. * Handles the input element gaining focus.
  603. *
  604. * @method _onTextboxFocus
  605. * @param {EventFacade} event
  606. * @protected
  607. */
  608. _onTextboxFocus: function(event) {
  609. var instance = this;
  610. if (!instance.get('focused')) {
  611. instance.inputNode.setAttribute('autocomplete', 'off');
  612. instance.focus();
  613. instance._initInputValue = instance.inputNode.get('value');
  614. instance.fire('textboxFocus');
  615. }
  616. },
  617. /**
  618. * Handles the keydown events on the input element for functional keys.
  619. *
  620. * @method _onTextboxKeyDown
  621. * @param {EventFacade} event
  622. * @protected
  623. */
  624. _onTextboxKeyDown: function(event) {
  625. var instance = this;
  626. var keyCode = event.keyCode;
  627. if (instance._typeAheadDelayId != -1) {
  628. clearTimeout(instance._typeAheadDelayId);
  629. }
  630. instance.fire('textboxKeyDown', event);
  631. if (event.isKey(ALT)) {
  632. instance._enableIntervalDetection();
  633. }
  634. instance._keyCode = keyCode;
  635. },
  636. /**
  637. * Handles the key press events of the input element.
  638. *
  639. * @method _onTextboxKeyPress
  640. * @param {EventFacade} event
  641. * @protected
  642. */
  643. _onTextboxKeyPress: function(event) {
  644. var instance = this;
  645. instance.fire('textboxKeyPress', event);
  646. if (event.isKey(WIN_IME)) {
  647. instance._enableIntervalDetection();
  648. }
  649. },
  650. /**
  651. * Handles the keyup events of the input element.
  652. *
  653. * @method _onTextboxKeyUp
  654. * @param {EventFacade} event
  655. * @protected
  656. */
  657. _onTextboxKeyUp: function(event) {
  658. var instance = this;
  659. if (event.isSpecialKey() && !event.isKey(BACKSPACE)) {
  660. return;
  661. }
  662. instance.fire('textboxKeyUp', event);
  663. },
  664. /**
  665. * Handles the rendering of the input element.
  666. *
  667. * @method _renderInput
  668. * @protected
  669. */
  670. _renderInput: function() {
  671. var instance = this;
  672. var contentBox = instance.get(CONTENT_BOX);
  673. var input = instance.get('input');
  674. var iconButton = instance.get('iconButton') || ICON_DEFAULT;
  675. var comboConfig = {
  676. field: {
  677. labelText: false
  678. },
  679. icons: [
  680. {
  681. icon: iconButton,
  682. id: 'trigger',
  683. handler: {
  684. fn: instance._onButtonMouseDown,
  685. context: instance
  686. }
  687. }
  688. ]
  689. };
  690. var inputReference = null;
  691. var inputParent = null;
  692. if (input) {
  693. input = A.one(input);
  694. comboConfig.field.node = input;
  695. inputReference = input.next();
  696. inputParent = input.get('parentNode');
  697. }
  698. var comboBox = new A.Combobox(comboConfig).render(contentBox);
  699. if (inputParent) {
  700. var comboBoundingBox = comboBox.get('boundingBox');
  701. inputParent.insertBefore(comboBoundingBox, inputReference);
  702. }
  703. instance.inputNode = comboBox.get('node');
  704. instance.button = comboBox.icons.item('trigger');
  705. instance.comboBox = comboBox;
  706. instance.set('uniqueName', A.stamp(instance.inputNode));
  707. },
  708. /**
  709. * Makes a query request to the data source.
  710. *
  711. * @method _sendQuery
  712. * @param {String} query The query string
  713. * @protected
  714. */
  715. _sendQuery: function(query) {
  716. var instance = this;
  717. if (instance.get('disabled')) {
  718. instance.fire('sendQueryDisabled', query);
  719. return;
  720. }
  721. var delimChar = instance.get('delimChar');
  722. var minQueryLength = instance.get('minQueryLength');
  723. if (delimChar) {
  724. var extraction = instance._extractQuery(query);
  725. query = extraction.query;
  726. instance._pastSelections = extraction.previous;
  727. }
  728. if ((query && (query.length < minQueryLength)) || (!query && minQueryLength > 0)) {
  729. instance.fire('invalidQueryLength', query);
  730. return;
  731. }
  732. query = encodeURIComponent(query);
  733. var dataSource = instance.get('dataSource');
  734. var request = instance.generateRequest(query);
  735. instance.fire('dataRequest', request);
  736. dataSource.sendRequest(request);
  737. },
  738. /**
  739. * Updates in the input element with the first result as the user types,
  740. * selecting the text the user has not typed yet.
  741. *
  742. * @method _typeAhead
  743. * @param {Node} elListItem The selected list item
  744. * @param {String} query The query string
  745. * @protected
  746. */
  747. _typeAhead: function(elListItem, query) {
  748. var instance = this;
  749. if (!instance.get('typeAhead') || KeyMap.isKey(instance._keyCode, BACKSPACE)) {
  750. return;
  751. }
  752. var inputEl = A.Node.getDOMNode(instance.inputNode);
  753. if (inputEl.setSelectionRange || inputEl.createTextRange) {
  754. instance._typeAheadDelayId = setTimeout(
  755. function() {
  756. var value = inputEl.value;
  757. var start = value.length;
  758. instance._updateValue(elListItem);
  759. var end = inputEl.value.length;
  760. instance.inputNode.selectText(start, end);
  761. var prefill = inputEl.value.substr(start, end);
  762. instance.fire('typeAhead', query, prefill);
  763. },
  764. instance.get('typeAheadDelay')
  765. );
  766. }
  767. },
  768. _currentQuery: null,
  769. _initInputValue: null,
  770. _keyCode: null,
  771. _lastValue: null,
  772. _pastSelections: '',
  773. _typeAheadDelayId: -1
  774. };
  775. A.InputTextControl = InputTextControl;
  776. }, '@VERSION@' ,{requires:['aui-base','aui-datasource-control-base','aui-form-combobox']});