3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
11 <link rel=
"import" href=
"../polymer/polymer.html">
12 <link rel=
"import" href=
"../iron-behaviors/iron-control-state.html">
13 <link rel=
"import" href=
"../iron-flex-layout/classes/iron-flex-layout.html">
14 <link rel=
"import" href=
"../iron-validatable-behavior/iron-validatable-behavior.html">
15 <link rel=
"import" href=
"../iron-form-element-behavior/iron-form-element-behavior.html">
18 `iron-autogrow-textarea` is an element containing a textarea that grows in height as more
19 lines of input are entered. Unless an explicit height or the `maxRows` property is set, it will
24 <iron-autogrow-textarea id="a1">
25 <textarea id="t1"></textarea>
26 </iron-autogrow-textarea>
28 Because the `textarea`'s `value` property is not observable, you should use
29 this element's `bind-value` instead for imperative updates.
36 <dom-module id=
"iron-autogrow-textarea">
40 display: inline-block;
45 -moz-appearance: textarea;
46 -webkit-appearance: textarea;
51 word-wrap: break-word;
61 /* see comments in template */
68 ::content textarea:invalid {
74 <!-- the mirror sizes the input/textarea so it grows with typing -->
75 <div id=
"mirror" class=
"mirror-text" aria-hidden=
"true"> </div>
77 <!-- size the input/textarea with a div, because the textarea has intrinsic size in ff -->
78 <div class=
"textarea-container fit">
79 <textarea id=
"textarea"
80 autocomplete$=
"[[autocomplete]]"
81 autofocus$=
"[[autofocus]]"
82 inputmode$=
"[[inputmode]]"
83 placeholder$=
"[[placeholder]]"
84 readonly$=
"[[readonly]]"
85 required$=
"[[required]]"
87 maxlength$=
"[[maxlength]]"></textarea>
96 is
: 'iron-autogrow-textarea',
99 Polymer
.IronFormElementBehavior
,
100 Polymer
.IronValidatableBehavior
,
101 Polymer
.IronControlState
107 * Use this property instead of `value` for two-way data binding.
110 observer
: '_bindValueChanged',
115 * The initial number of rows.
124 observer
: '_updateCached'
128 * The maximum number of rows this element can grow to until it
129 * scrolls. 0 means no maximum.
138 observer
: '_updateCached'
142 * Bound to the textarea's `autocomplete` attribute.
150 * Bound to the textarea's `autofocus` attribute.
158 * Bound to the textarea's `inputmode` attribute.
165 * Bound to the textarea's `name` attribute.
172 * The value for this input, same as `bindValue`
177 computed
: '_computeValue(bindValue)'
181 * Bound to the textarea's `placeholder` attribute.
188 * Bound to the textarea's `readonly` attribute.
195 * Set to true to mark the textarea as required.
202 * The maximum length of the input value.
215 * Returns the underlying textarea.
216 * @type HTMLTextAreaElement
219 return this.$.textarea
;
223 * Returns true if `value` is valid. The validator provided in `validator`
224 * will be used first, if it exists; otherwise, the `textarea`'s validity
226 * @return {boolean} True if the value is valid.
228 validate: function() {
229 // Empty, non-required input is valid.
230 if (!this.required
&& this.value
== '') {
231 this.invalid
= false;
236 if (this.hasValidator()) {
237 valid
= Polymer
.IronValidatableBehavior
.validate
.call(this, this.value
);
239 valid
= this.$.textarea
.validity
.valid
;
240 this.invalid
= !valid
;
242 this.fire('iron-input-validate');
246 _update: function() {
247 this.$.mirror
.innerHTML
= this._valueForMirror();
249 var textarea
= this.textarea
;
250 // If the value of the textarea was updated imperatively, then we
251 // need to manually update bindValue as well.
252 if (textarea
&& this.bindValue
!= textarea
.value
) {
253 this.bindValue
= textarea
.value
;
257 _bindValueChanged: function() {
258 var textarea
= this.textarea
;
263 textarea
.value
= this.bindValue
;
265 // manually notify because we don't want to notify until after setting value
266 this.fire('bind-value-changed', {value
: this.bindValue
});
269 _onInput: function(event
) {
270 this.bindValue
= event
.path
? event
.path
[0].value
: event
.target
.value
;
274 _constrain: function(tokens
) {
276 tokens
= tokens
|| [''];
277 // Enforce the min and max heights for a multiline input to avoid measurement
278 if (this.maxRows
> 0 && tokens
.length
> this.maxRows
) {
279 _tokens
= tokens
.slice(0, this.maxRows
);
281 _tokens
= tokens
.slice(0);
283 while (this.rows
> 0 && _tokens
.length
< this.rows
) {
286 return _tokens
.join('<br>') + ' ';
289 _valueForMirror: function() {
290 var input
= this.textarea
;
294 this.tokens
= (input
&& input
.value
) ? input
.value
.replace(/&/gm, '&').replace(/"/gm, '"').replace(/'/gm, ''').replace(/</gm, '<').replace(/>/gm, '>').split('\n') : [''];
295 return this._constrain(this.tokens);
298 _updateCached: function() {
299 this.$.mirror.innerHTML = this._constrain(this.tokens);
302 _computeValue: function() {
303 return this.bindValue;