Add ICU message format support
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / iron-autogrow-textarea / iron-autogrow-textarea-extracted.js
blobd69ffdb59b030c86b67e948366bb4037ea35206a
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: String,
63         value: 'off'
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     _update: function() {
156       this.$.mirror.innerHTML = this._valueForMirror();
158       var textarea = this.textarea;
159       // If the value of the textarea was updated imperatively, then we
160       // need to manually update bindValue as well.
161       if (textarea && this.bindValue != textarea.value) {
162         this.bindValue = textarea.value;
163       }
164     },
166     _bindValueChanged: function() {
167       var textarea = this.textarea;
168       if (!textarea) {
169         return;
170       }
172       textarea.value = this.bindValue;
173       this._update();
174       // manually notify because we don't want to notify until after setting value
175       this.fire('bind-value-changed', {value: this.bindValue});
176     },
178     _onInput: function(event) {
179       this.bindValue = event.path ? event.path[0].value : event.target.value;
180       this._update();
181     },
183     _constrain: function(tokens) {
184       var _tokens;
185       tokens = tokens || [''];
186       // Enforce the min and max heights for a multiline input to avoid measurement
187       if (this.maxRows > 0 && tokens.length > this.maxRows) {
188         _tokens = tokens.slice(0, this.maxRows);
189       } else {
190         _tokens = tokens.slice(0);
191       }
192       while (this.rows > 0 && _tokens.length < this.rows) {
193         _tokens.push('');
194       }
195       return _tokens.join('<br>') + '&nbsp;';
196     },
198     _valueForMirror: function() {
199       var input = this.textarea;
200       if (!input) {
201         return;
202       }
203       this.tokens = (input && input.value) ? input.value.replace(/&/gm, '&amp;').replace(/"/gm, '&quot;').replace(/'/gm, '&#39;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;').split('\n') : [''];
204       return this._constrain(this.tokens);
205     },
207     _updateCached: function() {
208       this.$.mirror.innerHTML = this._constrain(this.tokens);
209     },
211     _computeValue: function() {
212       return this.bindValue;
213     }
214   })