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
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
13 Polymer.PaperInputBehaviorImpl = {
17 * Fired when the input changes due to user interaction.
23 * The label for this input. Bind this to `<paper-input-container>`'s `label` property.
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`.
39 * Set to true to disable this input. Bind this to both the `<paper-input-container>`'s
40 * and the input's `disabled` property.
48 * Returns true if the value is invalid. Bind this to both the `<paper-input-container>`'s
49 * and the input's `invalid` property.
58 * Set to true to prevent the user from entering invalid input. Bind this to the
59 * `<input is="iron-input">`'s `preventInvalidInput` property.
61 preventInvalidInput: {
66 * Set this to specify the pattern allowed by `preventInvalidInput`. Bind this to the
67 * `<input is="iron-input">`'s `allowedPattern` property.
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.
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.
90 * A pattern to validate the `input` with. Bind this to the `<input is="iron-input">`'s
98 * Set to true to mark the input as required. Bind this to the `<input is="iron-input">`'s
99 * `required` property.
107 * The error message to display when the input is invalid. Bind this to the
108 * `<paper-input-error>`'s content, if using.
115 * Set to true to show a character counter.
123 * Set to true to disable the floating label. Bind this to the `<paper-input-container>`'s
124 * `noLabelFloat` property.
132 * Set to true to always float the label. Bind this to the `<paper-input-container>`'s
133 * `alwaysFloatLabel` property.
141 * Set to true to auto-validate the input value. Bind this to the `<paper-input-container>`'s
142 * `autoValidate` property.
150 * Name of the validator to use. Bind this to the `<input is="iron-input">`'s `validator`
157 // HTMLInputElement attributes for binding if needed
160 * Bind this to the `<input is="iron-input">`'s `autocomplete` property.
168 * Bind this to the `<input is="iron-input">`'s `autofocus` property.
175 * Bind this to the `<input is="iron-input">`'s `inputmode` property.
182 * Bind this to the `<input is="iron-input">`'s `minlength` property.
189 * The maximum length of the input value. Bind this to the `<input is="iron-input">`'s
190 * `maxlength` property.
197 * The minimum (numeric or date-time) input value.
198 * Bind this to the `<input is="iron-input">`'s `min` property.
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.
214 * Limits the numeric or date-time increments.
215 * Bind this to the `<input is="iron-input">`'s `step` property.
222 * Bind this to the `<input is="iron-input">`'s `name` property.
229 * A placeholder string in addition to the label. If this is set, the label will always float.
233 // need to set a default so _computeAlwaysFloatLabel is run
238 * Bind this to the `<input is="iron-input">`'s `readonly` property.
246 * Bind this to the `<input is="iron-input">`'s `size` property.
252 // Nonstandard attributes for binding if needed
255 * Bind this to the `<input is="iron-input">`'s `autocapitalize` property.
263 * Bind this to the `<input is="iron-input">`'s `autocorrect` property.
278 'addon-attached': '_onAddonAttached'
282 '_focusedControlStateChanged(focused)'
286 * Returns a reference to the input element.
292 attached: function() {
293 this._updateAriaLabelledBy();
296 _appendStringWithSpace: function(str, more) {
298 str = str + ' ' + more;
305 _onAddonAttached: function(event) {
306 var target = event.path ? event.path[0] : event.target;
308 this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, target.id);
310 var id = 'paper-input-add-on-' + Math.floor((Math.random() * 100000));
312 this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, id);
317 * Validates the input element and sets an error style if needed.
321 validate: function() {
322 return this.inputElement.validate();
326 * If `autoValidate` is true, then validates the element.
328 _handleAutoValidate: function() {
329 if (this.autoValidate)
334 * Restores the cursor to its original position after updating the value.
335 * @param {string} newValue The value that should be saved.
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>)
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;
350 // Just set the value and give up on the caret.
351 this.value = newValue;
355 _computeAlwaysFloatLabel: function(alwaysFloatLabel, placeholder) {
356 return placeholder || alwaysFloatLabel;
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) {
371 this.$.container._onFocus();
373 this.$.container._onBlur();
377 _updateAriaLabelledBy: function() {
378 var label = Polymer.dom(this.root).querySelector('label');
380 this._ariaLabelledBy = '';
385 labelledBy = label.id;
387 labelledBy = 'paper-input-label-' + new Date().getUTCMilliseconds();
388 label.id = labelledBy;
390 this._ariaLabelledBy = labelledBy;
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}, {
400 bubbles: event.bubbles,
401 cancelable: event.cancelable
408 /** @polymerBehavior */
409 Polymer.PaperInputBehavior = [Polymer.IronControlState, Polymer.PaperInputBehaviorImpl];