Update Polymer and pull in iron-list
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / paper-input / paper-input-behavior-extracted.js
blob94a0515af3bc84d47cd4a03015b51d418d66a790
3   /**
4    * Use `Polymer.PaperInputBehavior` to implement inputs with `<paper-input-container>`. This
5    * behavior is implemented by `<paper-input>`. It exposes a number of properties from
6    * `<paper-input-container>` and `<input is="iron-input">` and they should be bound in your
7    * template.
8    *
9    * The input element can be accessed by the `inputElement` property if you need to access
10    * properties or methods that are not exposed.
11    * @polymerBehavior Polymer.PaperInputBehavior
12    */
13   Polymer.PaperInputBehaviorImpl = {
15     properties: {
16       /**
17        * Fired when the input changes due to user interaction.
18        *
19        * @event change
20        */
22       /**
23        * The label for this input. Bind this to `<paper-input-container>`'s `label` property.
24        */
25       label: {
26         type: String
27       },
29       /**
30        * The value for this input. Bind this to the `<input is="iron-input">`'s `bindValue`
31        * property, or the value property of your input that is `notify:true`.
32        */
33       value: {
34         notify: true,
35         type: String
36       },
38       /**
39        * Set to true to disable this input. Bind this to both the `<paper-input-container>`'s
40        * and the input's `disabled` property.
41        */
42       disabled: {
43         type: Boolean,
44         value: false
45       },
47       /**
48        * Returns true if the value is invalid. Bind this to both the `<paper-input-container>`'s
49        * and the input's `invalid` property.
50        */
51       invalid: {
52         type: Boolean,
53         value: false,
54         notify: true
55       },
57       /**
58        * Set to true to prevent the user from entering invalid input. Bind this to the
59        * `<input is="iron-input">`'s `preventInvalidInput` property.
60        */
61       preventInvalidInput: {
62         type: Boolean
63       },
65       /**
66        * Set this to specify the pattern allowed by `preventInvalidInput`. Bind this to the
67        * `<input is="iron-input">`'s `allowedPattern` property.
68        */
69       allowedPattern: {
70         type: String
71       },
73       /**
74        * The type of the input. The supported types are `text`, `number` and `password`. Bind this
75        * to the `<input is="iron-input">`'s `type` property.
76        */
77       type: {
78         type: String
79       },
81       /**
82        * The datalist of the input (if any). This should match the id of an existing <datalist>. Bind this
83        * to the `<input is="iron-input">`'s `list` property.
84        */
85       list: {
86         type: String
87       },
89       /**
90        * A pattern to validate the `input` with. Bind this to the `<input is="iron-input">`'s
91        * `pattern` property.
92        */
93       pattern: {
94         type: String
95       },
97       /**
98        * Set to true to mark the input as required. Bind this to the `<input is="iron-input">`'s
99        * `required` property.
100        */
101       required: {
102         type: Boolean,
103         value: false
104       },
106       /**
107        * The error message to display when the input is invalid. Bind this to the
108        * `<paper-input-error>`'s content, if using.
109        */
110       errorMessage: {
111         type: String
112       },
114       /**
115        * Set to true to show a character counter.
116        */
117       charCounter: {
118         type: Boolean,
119         value: false
120       },
122       /**
123        * Set to true to disable the floating label. Bind this to the `<paper-input-container>`'s
124        * `noLabelFloat` property.
125        */
126       noLabelFloat: {
127         type: Boolean,
128         value: false
129       },
131       /**
132        * Set to true to always float the label. Bind this to the `<paper-input-container>`'s
133        * `alwaysFloatLabel` property.
134        */
135       alwaysFloatLabel: {
136         type: Boolean,
137         value: false
138       },
140       /**
141        * Set to true to auto-validate the input value. Bind this to the `<paper-input-container>`'s
142        * `autoValidate` property.
143        */
144       autoValidate: {
145         type: Boolean,
146         value: false
147       },
149       /**
150        * Name of the validator to use. Bind this to the `<input is="iron-input">`'s `validator`
151        * property.
152        */
153       validator: {
154         type: String
155       },
157       // HTMLInputElement attributes for binding if needed
159       /**
160        * Bind this to the `<input is="iron-input">`'s `autocomplete` property.
161        */
162       autocomplete: {
163         type: String,
164         value: 'off'
165       },
167       /**
168        * Bind this to the `<input is="iron-input">`'s `autofocus` property.
169        */
170       autofocus: {
171         type: Boolean
172       },
174       /**
175        * Bind this to the `<input is="iron-input">`'s `inputmode` property.
176        */
177       inputmode: {
178         type: String
179       },
181       /**
182        * Bind this to the `<input is="iron-input">`'s `minlength` property.
183        */
184       minlength: {
185         type: Number
186       },
188       /**
189        * The maximum length of the input value. Bind this to the `<input is="iron-input">`'s
190        * `maxlength` property.
191        */
192       maxlength: {
193         type: Number
194       },
196       /**
197        * The minimum (numeric or date-time) input value.
198        * Bind this to the `<input is="iron-input">`'s `min` property.
199        */
200       min: {
201         type: String
202       },
204       /**
205        * The maximum (numeric or date-time) input value.
206        * Can be a String (e.g. `"2000-1-1"`) or a Number (e.g. `2`).
207        * Bind this to the `<input is="iron-input">`'s `max` property.
208        */
209       max: {
210         type: String
211       },
213       /**
214        * Limits the numeric or date-time increments.
215        * Bind this to the `<input is="iron-input">`'s `step` property.
216        */
217       step: {
218         type: String
219       },
221       /**
222        * Bind this to the `<input is="iron-input">`'s `name` property.
223        */
224       name: {
225         type: String
226       },
228       /**
229        * A placeholder string in addition to the label. If this is set, the label will always float.
230        */
231       placeholder: {
232         type: String,
233         // need to set a default so _computeAlwaysFloatLabel is run
234         value: ''
235       },
237       /**
238        * Bind this to the `<input is="iron-input">`'s `readonly` property.
239        */
240       readonly: {
241         type: Boolean,
242         value: false
243       },
245       /**
246        * Bind this to the `<input is="iron-input">`'s `size` property.
247        */
248       size: {
249         type: Number
250       },
252       // Nonstandard attributes for binding if needed
254       /**
255        * Bind this to the `<input is="iron-input">`'s `autocapitalize` property.
256        */
257       autocapitalize: {
258         type: String,
259         value: 'none'
260       },
262       /**
263        * Bind this to the `<input is="iron-input">`'s `autocorrect` property.
264        */
265       autocorrect: {
266         type: String,
267         value: 'off'
268       },
270       _ariaDescribedBy: {
271         type: String,
272         value: ''
273       }
275     },
277     listeners: {
278       'addon-attached': '_onAddonAttached'
279     },
281     observers: [
282       '_focusedControlStateChanged(focused)'
283     ],
285     /**
286      * Returns a reference to the input element.
287      */
288     get inputElement() {
289       return this.$.input;
290     },
292     attached: function() {
293       this._updateAriaLabelledBy();
294     },
296     _appendStringWithSpace: function(str, more) {
297       if (str) {
298         str = str + ' ' + more;
299       } else {
300         str = more;
301       }
302       return str;
303     },
305     _onAddonAttached: function(event) {
306       var target = event.path ? event.path[0] : event.target;
307       if (target.id) {
308         this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, target.id);
309       } else {
310         var id = 'paper-input-add-on-' + Math.floor((Math.random() * 100000));
311         target.id = id;
312         this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, id);
313       }
314     },
316     /**
317      * Validates the input element and sets an error style if needed.
318      *
319      * @return {boolean}
320      */
321     validate: function() {
322       return this.inputElement.validate();
323     },
325     /**
326      * If `autoValidate` is true, then validates the element.
327      */
328     _handleAutoValidate: function() {
329       if (this.autoValidate)
330         this.validate();
331     },
333     /**
334      * Restores the cursor to its original position after updating the value.
335      * @param {string} newValue The value that should be saved.
336      */
337     updateValueAndPreserveCaret: function(newValue) {
338       // Not all elements might have selection, and even if they have the
339       // right properties, accessing them might throw an exception (like for
340       // <input type=number>)
341       try {
342         var start = this.inputElement.selectionStart;
343         this.value = newValue;
345         // The cursor automatically jumps to the end after re-setting the value,
346         // so restore it to its original position.
347         this.inputElement.selectionStart = start;
348         this.inputElement.selectionEnd = start;
349       } catch (e) {
350         // Just set the value and give up on the caret.
351         this.value = newValue;
352       }
353     },
355     _computeAlwaysFloatLabel: function(alwaysFloatLabel, placeholder) {
356       return placeholder || alwaysFloatLabel;
357     },
359     _focusedControlStateChanged: function(focused) {
360       // IronControlState stops the focus and blur events in order to redispatch them on the host
361       // element, but paper-input-container listens to those events. Since there are more
362       // pending work on focus/blur in IronControlState, I'm putting in this hack to get the
363       // input focus state working for now.
364       if (!this.$.container) {
365         this.$.container = Polymer.dom(this.root).querySelector('paper-input-container');
366         if (!this.$.container) {
367           return;
368         }
369       }
370       if (focused) {
371         this.$.container._onFocus();
372       } else {
373         this.$.container._onBlur();
374       }
375     },
377     _updateAriaLabelledBy: function() {
378       var label = Polymer.dom(this.root).querySelector('label');
379       if (!label) {
380         this._ariaLabelledBy = '';
381         return;
382       }
383       var labelledBy;
384       if (label.id) {
385         labelledBy = label.id;
386       } else {
387         labelledBy = 'paper-input-label-' + new Date().getUTCMilliseconds();
388         label.id = labelledBy;
389       }
390       this._ariaLabelledBy = labelledBy;
391     },
393     _onChange:function(event) {
394       // In the Shadow DOM, the `change` event is not leaked into the
395       // ancestor tree, so we must do this manually.
396       // See https://w3c.github.io/webcomponents/spec/shadow/#events-that-are-not-leaked-into-ancestor-trees.
397       if (this.shadowRoot) {
398         this.fire(event.type, {sourceEvent: event}, {
399           node: this,
400           bubbles: event.bubbles,
401           cancelable: event.cancelable
402         });
403       }
404     }
406   };
408   /** @polymerBehavior */
409   Polymer.PaperInputBehavior = [Polymer.IronControlState, Polymer.PaperInputBehaviorImpl];