searchbar.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. var __extends = (this && this.__extends) || (function () {
  2. var extendStatics = Object.setPrototypeOf ||
  3. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  4. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  5. return function (d, b) {
  6. extendStatics(d, b);
  7. function __() { this.constructor = d; }
  8. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  9. };
  10. })();
  11. (function (factory) {
  12. if (typeof module === "object" && typeof module.exports === "object") {
  13. var v = factory(require, exports);
  14. if (v !== undefined) module.exports = v;
  15. }
  16. else if (typeof define === "function" && define.amd) {
  17. define(["require", "exports", "@angular/core", "@angular/forms", "../../config/config", "../../util/base-input", "../../util/util", "../../util/debouncer", "../../platform/platform"], factory);
  18. }
  19. })(function (require, exports) {
  20. "use strict";
  21. Object.defineProperty(exports, "__esModule", { value: true });
  22. var core_1 = require("@angular/core");
  23. var forms_1 = require("@angular/forms");
  24. var config_1 = require("../../config/config");
  25. var base_input_1 = require("../../util/base-input");
  26. var util_1 = require("../../util/util");
  27. var debouncer_1 = require("../../util/debouncer");
  28. var platform_1 = require("../../platform/platform");
  29. /**
  30. * @name Searchbar
  31. * @module ionic
  32. * @description
  33. * Manages the display of a Searchbar which can be used to search or filter items.
  34. *
  35. * @usage
  36. * ```html
  37. * <ion-searchbar
  38. * [(ngModel)]="myInput"
  39. * [showCancelButton]="shouldShowCancel"
  40. * (ionInput)="onInput($event)"
  41. * (ionCancel)="onCancel($event)">
  42. * </ion-searchbar>
  43. * ```
  44. *
  45. * @demo /docs/demos/src/searchbar/
  46. * @see {@link /docs/components#searchbar Searchbar Component Docs}
  47. */
  48. var Searchbar = (function (_super) {
  49. __extends(Searchbar, _super);
  50. function Searchbar(config, _plt, elementRef, renderer, ngControl) {
  51. var _this = _super.call(this, config, elementRef, renderer, 'searchbar', '', null, null, ngControl) || this;
  52. _this._plt = _plt;
  53. _this._shouldBlur = true;
  54. _this._shouldAlignLeft = true;
  55. _this._isCancelVisible = false;
  56. _this._spellcheck = false;
  57. _this._autocomplete = 'off';
  58. _this._autocorrect = 'off';
  59. _this._isActive = false;
  60. _this._showCancelButton = false;
  61. _this._animated = false;
  62. _this._inputDebouncer = new debouncer_1.TimeoutDebouncer(0);
  63. /**
  64. * @input {string} Set the the cancel button text. Default: `"Cancel"`.
  65. */
  66. _this.cancelButtonText = 'Cancel';
  67. /**
  68. * @input {string} Set the input's placeholder. Default `"Search"`.
  69. */
  70. _this.placeholder = 'Search';
  71. /**
  72. * @input {string} Set the type of the input. Values: `"text"`, `"password"`, `"email"`, `"number"`, `"search"`, `"tel"`, `"url"`. Default `"search"`.
  73. */
  74. _this.type = 'search';
  75. /**
  76. * @output {event} Emitted when the Searchbar input has changed, including when it's cleared.
  77. */
  78. _this.ionInput = new core_1.EventEmitter();
  79. /**
  80. * @output {event} Emitted when the cancel button is clicked.
  81. */
  82. _this.ionCancel = new core_1.EventEmitter();
  83. /**
  84. * @output {event} Emitted when the clear input button is clicked.
  85. */
  86. _this.ionClear = new core_1.EventEmitter();
  87. _this.debounce = 250;
  88. return _this;
  89. }
  90. Object.defineProperty(Searchbar.prototype, "showCancelButton", {
  91. /**
  92. * @input {boolean} If true, show the cancel button. Default `false`.
  93. */
  94. get: function () {
  95. return this._showCancelButton;
  96. },
  97. set: function (val) {
  98. this._showCancelButton = util_1.isTrueProperty(val);
  99. },
  100. enumerable: true,
  101. configurable: true
  102. });
  103. Object.defineProperty(Searchbar.prototype, "debounce", {
  104. /**
  105. * @input {number} How long, in milliseconds, to wait to trigger the `ionInput` event after each keystroke. Default `250`.
  106. */
  107. get: function () {
  108. return this._debouncer.wait;
  109. },
  110. set: function (val) {
  111. this._debouncer.wait = val;
  112. this._inputDebouncer.wait = val;
  113. },
  114. enumerable: true,
  115. configurable: true
  116. });
  117. Object.defineProperty(Searchbar.prototype, "autocomplete", {
  118. /**
  119. * @input {string} Set the input's autocomplete property. Values: `"on"`, `"off"`. Default `"off"`.
  120. */
  121. set: function (val) {
  122. this._autocomplete = (val === '' || val === 'on') ? 'on' : this._config.get('autocomplete', 'off');
  123. },
  124. enumerable: true,
  125. configurable: true
  126. });
  127. Object.defineProperty(Searchbar.prototype, "autocorrect", {
  128. /**
  129. * @input {string} Set the input's autocorrect property. Values: `"on"`, `"off"`. Default `"off"`.
  130. */
  131. set: function (val) {
  132. this._autocorrect = (val === '' || val === 'on') ? 'on' : this._config.get('autocorrect', 'off');
  133. },
  134. enumerable: true,
  135. configurable: true
  136. });
  137. Object.defineProperty(Searchbar.prototype, "spellcheck", {
  138. /**
  139. * @input {string|boolean} Set the input's spellcheck property. Values: `true`, `false`. Default `false`.
  140. */
  141. set: function (val) {
  142. this._spellcheck = (val === '' || val === 'true' || val === true) ? true : this._config.getBoolean('spellcheck', false);
  143. },
  144. enumerable: true,
  145. configurable: true
  146. });
  147. Object.defineProperty(Searchbar.prototype, "animated", {
  148. /**
  149. * @input {boolean} If true, enable searchbar animation. Default `false`.
  150. */
  151. get: function () {
  152. return this._animated;
  153. },
  154. set: function (val) {
  155. this._animated = util_1.isTrueProperty(val);
  156. },
  157. enumerable: true,
  158. configurable: true
  159. });
  160. /**
  161. * @hidden
  162. * On Initialization check for attributes
  163. */
  164. Searchbar.prototype.ngOnInit = function () {
  165. var showCancelButton = this.showCancelButton;
  166. if (typeof showCancelButton === 'string') {
  167. this.showCancelButton = (showCancelButton === '' || showCancelButton === 'true');
  168. }
  169. };
  170. /**
  171. * @hidden
  172. */
  173. Searchbar.prototype._inputUpdated = function () {
  174. var ele = this._searchbarInput.nativeElement;
  175. var value = this._value;
  176. // It is important not to re-assign the value if it is the same, because,
  177. // otherwise, the caret is moved to the end of the input
  178. if (ele.value !== value) {
  179. ele.value = value;
  180. }
  181. this.positionElements();
  182. };
  183. /**
  184. * @hidden
  185. * Positions the input search icon, placeholder, and the cancel button
  186. * based on the input value and if it is focused. (ios only)
  187. */
  188. Searchbar.prototype.positionElements = function () {
  189. var isAnimated = this._animated;
  190. var prevAlignLeft = this._shouldAlignLeft;
  191. var shouldAlignLeft = (!isAnimated || (this._value && this._value.toString().trim() !== '') || this._isFocus === true);
  192. this._shouldAlignLeft = shouldAlignLeft;
  193. if (this._mode !== 'ios') {
  194. return;
  195. }
  196. if (prevAlignLeft !== shouldAlignLeft) {
  197. this.positionPlaceholder();
  198. }
  199. if (isAnimated) {
  200. this.positionCancelButton();
  201. }
  202. };
  203. Searchbar.prototype.positionPlaceholder = function () {
  204. var inputEle = this._searchbarInput.nativeElement;
  205. var iconEle = this._searchbarIcon.nativeElement;
  206. if (this._shouldAlignLeft) {
  207. inputEle.removeAttribute('style');
  208. iconEle.removeAttribute('style');
  209. }
  210. else {
  211. // Create a dummy span to get the placeholder width
  212. var doc = this._plt.doc();
  213. var tempSpan = doc.createElement('span');
  214. tempSpan.innerHTML = this.placeholder;
  215. doc.body.appendChild(tempSpan);
  216. // Get the width of the span then remove it
  217. var textWidth = tempSpan.offsetWidth;
  218. doc.body.removeChild(tempSpan);
  219. // Set the input padding start
  220. var inputLeft = 'calc(50% - ' + (textWidth / 2) + 'px)';
  221. if (this._plt.isRTL) {
  222. inputEle.style.paddingRight = inputLeft;
  223. }
  224. else {
  225. inputEle.style.paddingLeft = inputLeft;
  226. }
  227. // Set the icon margin start
  228. var iconLeft = 'calc(50% - ' + ((textWidth / 2) + 30) + 'px)';
  229. if (this._plt.isRTL) {
  230. iconEle.style.marginRight = iconLeft;
  231. }
  232. else {
  233. iconEle.style.marginLeft = iconLeft;
  234. }
  235. }
  236. };
  237. /**
  238. * @hidden
  239. * Show the iOS Cancel button on focus, hide it offscreen otherwise
  240. */
  241. Searchbar.prototype.positionCancelButton = function () {
  242. var showShowCancel = this._isFocus;
  243. if (showShowCancel !== this._isCancelVisible) {
  244. var cancelStyleEle = this._cancelButton.nativeElement;
  245. var cancelStyle = cancelStyleEle.style;
  246. this._isCancelVisible = showShowCancel;
  247. if (showShowCancel) {
  248. if (this._plt.isRTL) {
  249. cancelStyle.marginLeft = '0';
  250. }
  251. else {
  252. cancelStyle.marginRight = '0';
  253. }
  254. }
  255. else {
  256. var offset = cancelStyleEle.offsetWidth;
  257. if (offset > 0) {
  258. if (this._plt.isRTL) {
  259. cancelStyle.marginLeft = -offset + 'px';
  260. }
  261. else {
  262. cancelStyle.marginRight = -offset + 'px';
  263. }
  264. }
  265. }
  266. }
  267. };
  268. /**
  269. * @hidden
  270. * Update the Searchbar input value when the input changes
  271. */
  272. Searchbar.prototype.inputChanged = function (ev) {
  273. var _this = this;
  274. this.value = ev.target.value;
  275. this._inputDebouncer.debounce(function () {
  276. _this.ionInput.emit(ev);
  277. });
  278. };
  279. /**
  280. * @hidden
  281. * Sets the Searchbar to focused and active on input focus.
  282. */
  283. Searchbar.prototype.inputFocused = function () {
  284. this._isActive = true;
  285. this._fireFocus();
  286. this.positionElements();
  287. };
  288. /**
  289. * @hidden
  290. * Sets the Searchbar to not focused and checks if it should align left
  291. * based on whether there is a value in the searchbar or not.
  292. */
  293. Searchbar.prototype.inputBlurred = function () {
  294. // _shouldBlur determines if it should blur
  295. // if we are clearing the input we still want to stay focused in the input
  296. if (this._shouldBlur === false) {
  297. this._searchbarInput.nativeElement.focus();
  298. this._shouldBlur = true;
  299. return;
  300. }
  301. this._fireBlur();
  302. this.positionElements();
  303. };
  304. /**
  305. * @hidden
  306. * Clears the input field and triggers the control change.
  307. */
  308. Searchbar.prototype.clearInput = function (ev) {
  309. var _this = this;
  310. this.ionClear.emit(ev);
  311. // setTimeout() fixes https://github.com/ionic-team/ionic/issues/7527
  312. // wait for 4 frames
  313. setTimeout(function () {
  314. var value = _this._value;
  315. if (util_1.isPresent(value) && value !== '') {
  316. _this.value = ''; // DOM WRITE
  317. _this.ionInput.emit(ev);
  318. }
  319. }, 16 * 4);
  320. this._shouldBlur = false;
  321. };
  322. /**
  323. * @hidden
  324. * Clears the input field and tells the input to blur since
  325. * the clearInput function doesn't want the input to blur
  326. * then calls the custom cancel function if the user passed one in.
  327. */
  328. Searchbar.prototype.cancelSearchbar = function (ev) {
  329. this.ionCancel.emit(ev);
  330. this.clearInput(ev);
  331. this._shouldBlur = true;
  332. this._isActive = false;
  333. };
  334. Searchbar.prototype.setFocus = function () {
  335. this._renderer.invokeElementMethod(this._searchbarInput.nativeElement, 'focus');
  336. };
  337. Searchbar.decorators = [
  338. { type: core_1.Component, args: [{
  339. selector: 'ion-searchbar',
  340. template: '<div class="searchbar-input-container">' +
  341. '<button ion-button mode="md" (click)="cancelSearchbar($event)" (mousedown)="cancelSearchbar($event)" clear color="dark" class="searchbar-md-cancel" type="button">' +
  342. '<ion-icon name="md-arrow-back"></ion-icon>' +
  343. '</button>' +
  344. '<div #searchbarIcon class="searchbar-search-icon"></div>' +
  345. '<input #searchbarInput class="searchbar-input" (input)="inputChanged($event)" (blur)="inputBlurred()" (focus)="inputFocused()" ' +
  346. 'dir="auto" ' +
  347. '[attr.placeholder]="placeholder" ' +
  348. '[attr.type]="type" ' +
  349. '[attr.autocomplete]="_autocomplete" ' +
  350. '[attr.autocorrect]="_autocorrect" ' +
  351. '[attr.spellcheck]="_spellcheck">' +
  352. '<button ion-button clear class="searchbar-clear-icon" [mode]="_mode" (click)="clearInput($event)" (mousedown)="clearInput($event)" type="button"></button>' +
  353. '</div>' +
  354. '<button ion-button #cancelButton mode="ios" [tabindex]="_isActive ? 1 : -1" clear (click)="cancelSearchbar($event)" (mousedown)="cancelSearchbar($event)" class="searchbar-ios-cancel" type="button">{{cancelButtonText}}</button>',
  355. host: {
  356. '[class.searchbar-animated]': '_animated',
  357. '[class.searchbar-has-value]': '_value',
  358. '[class.searchbar-active]': '_isActive',
  359. '[class.searchbar-show-cancel]': '_showCancelButton',
  360. '[class.searchbar-left-aligned]': '_shouldAlignLeft',
  361. '[class.searchbar-has-focus]': '_isFocus'
  362. },
  363. encapsulation: core_1.ViewEncapsulation.None
  364. },] },
  365. ];
  366. /** @nocollapse */
  367. Searchbar.ctorParameters = function () { return [
  368. { type: config_1.Config, },
  369. { type: platform_1.Platform, },
  370. { type: core_1.ElementRef, },
  371. { type: core_1.Renderer, },
  372. { type: forms_1.NgControl, decorators: [{ type: core_1.Optional },] },
  373. ]; };
  374. Searchbar.propDecorators = {
  375. 'cancelButtonText': [{ type: core_1.Input },],
  376. 'showCancelButton': [{ type: core_1.Input },],
  377. 'debounce': [{ type: core_1.Input },],
  378. 'placeholder': [{ type: core_1.Input },],
  379. 'autocomplete': [{ type: core_1.Input },],
  380. 'autocorrect': [{ type: core_1.Input },],
  381. 'spellcheck': [{ type: core_1.Input },],
  382. 'type': [{ type: core_1.Input },],
  383. 'animated': [{ type: core_1.Input },],
  384. 'ionInput': [{ type: core_1.Output },],
  385. 'ionCancel': [{ type: core_1.Output },],
  386. 'ionClear': [{ type: core_1.Output },],
  387. '_searchbarInput': [{ type: core_1.ViewChild, args: ['searchbarInput',] },],
  388. '_searchbarIcon': [{ type: core_1.ViewChild, args: ['searchbarIcon',] },],
  389. '_cancelButton': [{ type: core_1.ViewChild, args: ['cancelButton', { read: core_1.ElementRef },] },],
  390. };
  391. return Searchbar;
  392. }(base_input_1.BaseInput));
  393. exports.Searchbar = Searchbar;
  394. });
  395. //# sourceMappingURL=searchbar.js.map