Update Polymer and pull in iron-list
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / iron-autogrow-textarea / iron-autogrow-textarea-extracted.js
blob4ab09882fb4c70483f19b9e78592560f2d467626
3   Polymer({
5     is: 'iron-autogrow-textarea',
7     behaviors: [
8       Polymer.IronFormElementBehavior,
9       Polymer.IronValidatableBehavior,
10       Polymer.IronControlState
11     ],
13     properties: {
15       /**
16        * Use this property instead of `value` for two-way data binding.
17        */
18       bindValue: {
19         observer: '_bindValueChanged',
20         type: String
21       },
23       /**
24        * The initial number of rows.
25        *
26        * @attribute rows
27        * @type number
28        * @default 1
29        */
30       rows: {
31         type: Number,
32         value: 1,
33         observer: '_updateCached'
34       },
36       /**
37        * The maximum number of rows this element can grow to until it
38        * scrolls. 0 means no maximum.
39        *
40        * @attribute maxRows
41        * @type number
42        * @default 0
43        */
44       maxRows: {
45        type: Number,
46        value: 0,
47        observer: '_updateCached'
48       },
50       /**
51        * Bound to the textarea's `autocomplete` attribute.
52        */
53       autocomplete: {
54         type: String,
55         value: 'off'
56       },
58       /**
59        * Bound to the textarea's `autofocus` attribute.
60        */
61       autofocus: {
62         type: Boolean,
63         value: false
64       },
66       /**
67        * Bound to the textarea's `inputmode` attribute.
68        */
69       inputmode: {
70         type: String
71       },
73       /**
74        * Bound to the textarea's `name` attribute.
75        */
76       name: {
77         type: String
78       },
80       /**
81        * The value for this input, same as `bindValue`
82        */
83       value: {
84         notify: true,
85         type: String,
86         computed: '_computeValue(bindValue)'
87       },
89       /**
90        * Bound to the textarea's `placeholder` attribute.
91        */
92       placeholder: {
93         type: String
94       },
96       /**
97        * Bound to the textarea's `readonly` attribute.
98        */
99       readonly: {
100         type: String
101       },
103       /**
104        * Set to true to mark the textarea as required.
105        */
106       required: {
107         type: Boolean
108       },
110       /**
111        * The maximum length of the input value.
112        */
113       maxlength: {
114         type: Number
115       }
117     },
119     listeners: {
120       'input': '_onInput'
121     },
123     /**
124      * Returns the underlying textarea.
125      * @type HTMLTextAreaElement
126      */
127     get textarea() {
128       return this.$.textarea;
129     },
131     /**
132      * Returns true if `value` is valid. The validator provided in `validator`
133      * will be used first, if it exists; otherwise, the `textarea`'s validity
134      * is used.
135      * @return {boolean} True if the value is valid.
136      */
137     validate: function() {
138       // Empty, non-required input is valid.
139       if (!this.required && this.value == '') {
140         this.invalid = false;
141         return true;
142       }
144       var valid;
145       if (this.hasValidator()) {
146         valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
147       } else {
148         valid = this.$.textarea.validity.valid;
149         this.invalid = !valid;
150       }
151       this.fire('iron-input-validate');
152       return valid;
153     },
155     _bindValueChanged: function() {
156       var textarea = this.textarea;
157       if (!textarea) {
158         return;
159       }
161       textarea.value = this.bindValue;
162       this.$.mirror.innerHTML = this._valueForMirror();
163       // manually notify because we don't want to notify until after setting value
164       this.fire('bind-value-changed', {value: this.bindValue});
165     },
167     _onInput: function(event) {
168       this.bindValue = event.path ? event.path[0].value : event.target.value;
169     },
171     _constrain: function(tokens) {
172       var _tokens;
173       tokens = tokens || [''];
174       // Enforce the min and max heights for a multiline input to avoid measurement
175       if (this.maxRows > 0 && tokens.length > this.maxRows) {
176         _tokens = tokens.slice(0, this.maxRows);
177       } else {
178         _tokens = tokens.slice(0);
179       }
180       while (this.rows > 0 && _tokens.length < this.rows) {
181         _tokens.push('');
182       }
183       return _tokens.join('<br>') + '&nbsp;';
184     },
186     _valueForMirror: function() {
187       var input = this.textarea;
188       if (!input) {
189         return;
190       }
191       this.tokens = (input && input.value) ? input.value.replace(/&/gm, '&amp;').replace(/"/gm, '&quot;').replace(/'/gm, '&#39;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;').split('\n') : [''];
192       return this._constrain(this.tokens);
193     },
195     _updateCached: function() {
196       this.$.mirror.innerHTML = this._constrain(this.tokens);
197     },
199     _computeValue: function() {
200       return this.bindValue;
201     }
202   });