OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE | |
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS | |
5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS | |
6 Code distributed by Google as part of the polymer project is also | |
7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS | |
8 --> | |
9 | |
10 <!-- | |
11 /** | |
12 * core-input is an unstyled single- or multi-line text field where user can | |
13 * enter input. | |
14 * | |
15 * Example: | |
16 * | |
17 * <core-input placeholder="Placeholder text here"></core-input> | |
18 * | |
19 * <core-input multiline placeholder="Enter multiple lines here"></core-inpu
t> | |
20 * | |
21 * The text input's value is considered "committed" if the user hits the "enter" | |
22 * key or blurs the input after changing the value. The `change` event is fired | |
23 * when the value becomes committed, and the committed value is stored in the | |
24 * `value` property. The current value of the input is stored in the `inputValue
` | |
25 * property. | |
26 * | |
27 * Validation | |
28 * ---------- | |
29 * | |
30 * core-input can optionally validate the value using the HTML5 constraints API, | |
31 * similar to native inputs. There are two methods to configure input validation
: | |
32 * | |
33 * 1. By setting the `type` attribute. For example, setting it to `email` will | |
34 * check the value is a valid email, and setting it to `number` will check | |
35 * the input is a number. | |
36 * | |
37 * 2. By setting attributes related to validation. The attributes are `pattern`, | |
38 * `min`, `max`, `step` and `required`. | |
39 * | |
40 * Only `required` is supported for multiline inputs currently. | |
41 * | |
42 * Example: | |
43 * | |
44 * <core-input type="email" placeholder="enter your email"></core-input> | |
45 * | |
46 * <core-input type="number" min="5" placeholder="enter a number greater tha
n or equal to 5"></core-input> | |
47 * | |
48 * <core-input pattern=".*abc.*" placeholder="enter something containing 'ab
c'"></core-input> | |
49 * | |
50 * See https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_
validation | |
51 * for more info on validation. | |
52 * | |
53 * @group Polymer Core Elements | |
54 * @element core-input | |
55 * @homepage github.io | |
56 */ | |
57 --> | |
58 | |
59 <!-- | |
60 Fired when the inputValue of is changed. This is the same event as the DOM | |
61 "input" event. | |
62 | |
63 @event input | |
64 --> | |
65 | |
66 <!-- | |
67 Fired when the user commits the value of the input, either by the hitting the | |
68 `enter` key or blurring the input after the changing the inputValue. Also see th
e | |
69 DOM "change" event. | |
70 | |
71 @event change | |
72 --> | |
73 | |
74 <!-- | |
75 Fired when the inputValue of this text input changes and fails validation. | |
76 | |
77 @event input-invalid | |
78 @param {Object} detail | |
79 @param {string} value The text input's inputValue. | |
80 --> | |
81 | |
82 <!-- | |
83 Fired when the inputValue of this text input changes and passes validation. | |
84 | |
85 @event input-valid | |
86 @param {Object} detail | |
87 @param {string} value The text input's inputValue. | |
88 --> | |
89 <link href="../polymer/polymer.html" rel="import"> | |
90 | |
91 <polymer-element name="core-input" on-focus="{{focusAction}}"> | |
92 | |
93 <template> | |
94 | |
95 <link href="core-input.css" rel="stylesheet"> | |
96 | |
97 <template if="{{multiline}}"> | |
98 <textarea id="input" value="{{inputValue}}" rows="{{rows}}" disabled?="{{d
isabled}}" placeholder="{{placeholder}}" autofocus?="{{autofocus}}" required?="{
{required}}" readonly?="{{readonly}}" maxlength="{{maxlength}}" aria-label="{{la
bel || placeholder}}" aria-invalid="{{invalid}}" on-change="{{inputChangeAction}
}" on-focus="{{inputFocusAction}}" on-blur="{{inputBlurAction}}"></textarea> | |
99 </template> | |
100 | |
101 <template if="{{!multiline}}"> | |
102 <input id="input" value="{{inputValue}}" disabled?="{{disabled}}" type="{{
type}}" placeholder="{{placeholder}}" autofocus?="{{autofocus}}" required?="{{re
quired}}" readonly?="{{readonly}}" pattern="{{pattern}}" min="{{min}}" max="{{ma
x}}" step="{{step}}" maxlength="{{maxlength}}" aria-label="{{label || placeholde
r}}" aria-invalid="{{invalid}}" on-keypress="{{keypressAction}}" on-change="{{in
putChangeAction}}" on-focus="{{inputFocusAction}}" on-blur="{{inputBlurAction}}"
> | |
103 </template> | |
104 | |
105 </template> | |
106 | |
107 <script> | |
108 | |
109 Polymer('core-input', { | |
110 publish: { | |
111 /** | |
112 * Placeholder text that hints to the user what can be entered in | |
113 * the input. | |
114 * | |
115 * @attribute placeholder | |
116 * @type string | |
117 * @default '' | |
118 */ | |
119 placeholder: '', | |
120 | |
121 /** | |
122 * If true, this input cannot be focused and the user cannot change | |
123 * its value. | |
124 * | |
125 * @attribute disabled | |
126 * @type boolean | |
127 * @default false | |
128 */ | |
129 disabled: false, | |
130 | |
131 /** | |
132 * If true, the user cannot modify the value of the input. | |
133 * | |
134 * @attribute readonly | |
135 * @type boolean | |
136 * @default false | |
137 */ | |
138 readonly: false, | |
139 | |
140 /** | |
141 * If true, this input will automatically gain focus on page load. | |
142 * | |
143 * @attribute autofocus | |
144 * @type boolean | |
145 * @default false | |
146 */ | |
147 autofocus: false, | |
148 | |
149 /** | |
150 * If true, this input accepts multi-line input like a `<textarea>` | |
151 * | |
152 * @attribute multiline | |
153 * @type boolean | |
154 * @default false | |
155 */ | |
156 multiline: false, | |
157 | |
158 /** | |
159 * (multiline only) The height of this text input in rows. The input | |
160 * will scroll internally if more input is entered beyond the size | |
161 * of the component. This property is meaningless if multiline is | |
162 * false. You can also set this property to "fit" and size the | |
163 * component with CSS to make the input fit the CSS size. | |
164 * | |
165 * @attribute rows | |
166 * @type number|'fit' | |
167 * @default 'fit' | |
168 */ | |
169 rows: 'fit', | |
170 | |
171 /** | |
172 * The current value of this input. Changing inputValue programmatically | |
173 * will cause value to be out of sync. Instead, change value directly | |
174 * or call commit() after changing inputValue. | |
175 * | |
176 * @attribute inputValue | |
177 * @type string | |
178 * @default '' | |
179 */ | |
180 inputValue: '', | |
181 | |
182 /** | |
183 * The value of the input committed by the user, either by changing the | |
184 * inputValue and blurring the input, or by hitting the `enter` key. | |
185 * | |
186 * @attribute value | |
187 * @type string | |
188 * @default '' | |
189 */ | |
190 value: '', | |
191 | |
192 /** | |
193 * Set the input type. Not supported for `multiline`. | |
194 * | |
195 * @attribute type | |
196 * @type string | |
197 * @default text | |
198 */ | |
199 type: 'text', | |
200 | |
201 /** | |
202 * If true, the input is invalid if its value is null. | |
203 * | |
204 * @attribute required | |
205 * @type boolean | |
206 * @default false | |
207 */ | |
208 required: false, | |
209 | |
210 /** | |
211 * A regular expression to validate the input value against. See | |
212 * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constra
int_validation#Validation-related_attributes | |
213 * for more info. Not supported if `multiline` is true. | |
214 * | |
215 * @attribute pattern | |
216 * @type string | |
217 * @default '.*' | |
218 */ | |
219 // FIXME(yvonne): The default is set to .* because we can't bind to patt
ern such | |
220 // that the attribute is unset if pattern is null. | |
221 pattern: '.*', | |
222 | |
223 /** | |
224 * If set, the input is invalid if the value is less than this property.
See | |
225 * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constra
int_validation#Validation-related_attributes | |
226 * for more info. Not supported if `multiline` is true. | |
227 * | |
228 * @attribute min | |
229 */ | |
230 min: null, | |
231 | |
232 /** | |
233 * If set, the input is invalid if the value is greater than this proper
ty. See | |
234 * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constra
int_validation#Validation-related_attributes | |
235 * for more info. Not supported if `multiline` is true. | |
236 * | |
237 * @attribute max | |
238 */ | |
239 max: null, | |
240 | |
241 /** | |
242 * If set, the input is invalid if the value is not `min` plus an integr
al multiple | |
243 * of this property. See | |
244 * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constra
int_validation#Validation-related_attributes | |
245 * for more info. Not supported if `multiline` is true. | |
246 * | |
247 * @attribute step | |
248 */ | |
249 step: null, | |
250 | |
251 /** | |
252 * The maximum length of the input value. | |
253 * | |
254 * @attribute maxlength | |
255 * @type number | |
256 */ | |
257 maxlength: null, | |
258 | |
259 /** | |
260 * If this property is true, the text input's inputValue failed validati
on. | |
261 * | |
262 * @attribute invalid | |
263 * @type boolean | |
264 * @default false | |
265 */ | |
266 invalid: false, | |
267 | |
268 /** | |
269 * If this property is true, validate the input as they are entered. | |
270 * | |
271 * @attribute validateImmediately | |
272 * @type boolean | |
273 * @default true | |
274 */ | |
275 validateImmediately: true | |
276 }, | |
277 | |
278 ready: function() { | |
279 this.handleTabindex(this.getAttribute('tabindex')); | |
280 }, | |
281 | |
282 disabledChanged: function() { | |
283 if (this.disabled) { | |
284 this.setAttribute('aria-disabled', true); | |
285 } else { | |
286 this.removeAttribute('aria-disabled'); | |
287 } | |
288 }, | |
289 | |
290 invalidChanged: function() { | |
291 this.classList.toggle('invalid', this.invalid); | |
292 this.fire('input-'+ (this.invalid ? 'invalid' : 'valid'), {value: this.i
nputValue}); | |
293 }, | |
294 | |
295 inputValueChanged: function() { | |
296 if (this.validateImmediately) { | |
297 this.updateValidity_(); | |
298 } | |
299 }, | |
300 | |
301 valueChanged: function() { | |
302 this.inputValue = this.value; | |
303 }, | |
304 | |
305 requiredChanged: function() { | |
306 if (this.validateImmediately) { | |
307 this.updateValidity_(); | |
308 } | |
309 }, | |
310 | |
311 attributeChanged: function(attr, oldVal, curVal) { | |
312 if (attr === 'tabindex') { | |
313 this.handleTabindex(curVal); | |
314 } | |
315 }, | |
316 | |
317 handleTabindex: function(tabindex) { | |
318 if (tabindex > 0) { | |
319 this.$.input.setAttribute('tabindex', -1); | |
320 } else { | |
321 this.$.input.removeAttribute('tabindex'); | |
322 } | |
323 }, | |
324 | |
325 /** | |
326 * Commits the inputValue to value. | |
327 * | |
328 * @method commit | |
329 */ | |
330 commit: function() { | |
331 this.value = this.inputValue; | |
332 }, | |
333 | |
334 updateValidity_: function() { | |
335 if (this.$.input.willValidate) { | |
336 this.invalid = !this.$.input.validity.valid; | |
337 } | |
338 }, | |
339 | |
340 keypressAction: function(e) { | |
341 // disallow non-numeric input if type = number | |
342 if (this.type !== 'number') { | |
343 return; | |
344 } | |
345 var c = String.fromCharCode(e.charCode); | |
346 if (e.charCode !== 0 && !c.match(/[\d-\.e]/)) { | |
347 e.preventDefault(); | |
348 } | |
349 }, | |
350 | |
351 inputChangeAction: function() { | |
352 this.commit(); | |
353 if (!window.ShadowDOMPolyfill) { | |
354 // re-fire event that does not bubble across shadow roots | |
355 this.fire('change', null, this); | |
356 } | |
357 }, | |
358 | |
359 focusAction: function(e) { | |
360 if (this.getAttribute('tabindex') > 0) { | |
361 // Forward focus to the inner input if tabindex is set on the element | |
362 // This will not cause an infinite loop because focus will not fire on
the <input> | |
363 // again if it's already focused. | |
364 this.$.input.focus(); | |
365 } | |
366 }, | |
367 | |
368 inputFocusAction: function(e) { | |
369 if (window.ShadowDOMPolyfill) { | |
370 // re-fire non-bubbling event if polyfill | |
371 this.fire('focus', null, this, false); | |
372 } | |
373 }, | |
374 | |
375 inputBlurAction: function() { | |
376 if (window.ShadowDOMPolyfill) { | |
377 // re-fire non-bubbling event | |
378 this.fire('blur', null, this, false); | |
379 } | |
380 }, | |
381 | |
382 /** | |
383 * Forwards to the internal input / textarea element. | |
384 * | |
385 * @method blur | |
386 */ | |
387 blur: function() { | |
388 this.$.input.blur(); | |
389 }, | |
390 | |
391 /** | |
392 * Forwards to the internal input / textarea element. | |
393 * | |
394 * @method click | |
395 */ | |
396 click: function() { | |
397 this.$.input.click(); | |
398 }, | |
399 | |
400 /** | |
401 * Forwards to the internal input / textarea element. | |
402 * | |
403 * @method focus | |
404 */ | |
405 focus: function() { | |
406 this.$.input.focus(); | |
407 }, | |
408 | |
409 /** | |
410 * Forwards to the internal input / textarea element. | |
411 * | |
412 * @method select | |
413 */ | |
414 select: function() { | |
415 this.$.input.select(); | |
416 }, | |
417 | |
418 /** | |
419 * Forwards to the internal input / textarea element. | |
420 * | |
421 * @method setSelectionRange | |
422 * @param {number} selectionStart | |
423 * @param {number} selectionEnd | |
424 * @param {String} selectionDirection (optional) | |
425 */ | |
426 setSelectionRange: function(selectionStart, selectionEnd, selectionDirecti
on) { | |
427 this.$.input.setSelectionRange(selectionStart, selectionEnd, selectionDi
rection); | |
428 }, | |
429 | |
430 /** | |
431 * Forwards to the internal input element, not implemented for multiline. | |
432 * | |
433 * @method setRangeText | |
434 * @param {String} replacement | |
435 * @param {number} start (optional) | |
436 * @param {number} end (optional) | |
437 * @param {String} selectMode (optional) | |
438 */ | |
439 setRangeText: function(replacement, start, end, selectMode) { | |
440 if (!this.multiline) { | |
441 this.$.input.setRangeText(replacement, start, end, selectMode); | |
442 } | |
443 }, | |
444 | |
445 /** | |
446 * Forwards to the internal input, not implemented for multiline. | |
447 * | |
448 * @method stepDown | |
449 * @param {number} n (optional) | |
450 */ | |
451 stepDown: function(n) { | |
452 if (!this.multiline) { | |
453 this.$.input.stepDown(n); | |
454 } | |
455 }, | |
456 | |
457 /** | |
458 * Forwards to the internal input, not implemented for multiline. | |
459 * | |
460 * @method stepUp | |
461 * @param {number} n (optional) | |
462 */ | |
463 stepUp: function(n) { | |
464 if (!this.multiline) { | |
465 this.$.input.stepUp(n); | |
466 } | |
467 }, | |
468 | |
469 get willValidate() { | |
470 return this.$.input.willValidate; | |
471 }, | |
472 | |
473 get validity() { | |
474 return this.$.input.validity; | |
475 }, | |
476 | |
477 get validationMessage() { | |
478 return this.$.input.validationMessage; | |
479 }, | |
480 | |
481 /** | |
482 * Forwards to the internal input / textarea element and updates state. | |
483 * | |
484 * @method checkValidity | |
485 * @return {boolean} | |
486 */ | |
487 checkValidity: function() { | |
488 var r = this.$.input.checkValidity(); | |
489 this.updateValidity_(); | |
490 return r; | |
491 }, | |
492 | |
493 /** | |
494 * Forwards to the internal input / textarea element and updates state. | |
495 * | |
496 * @method setCustomValidity | |
497 * @param {String} message | |
498 */ | |
499 setCustomValidity: function(message) { | |
500 this.$.input.setCustomValidity(message); | |
501 this.updateValidity_(); | |
502 } | |
503 | |
504 }); | |
505 </script> | |
506 | |
507 </polymer-element> | |
OLD | NEW |