jellyfin-web/dashboard-ui/bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html

354 lines
8.9 KiB
HTML
Raw Normal View History

2015-06-26 20:27:38 -07:00
<!--
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-behaviors/iron-control-state.html">
2015-12-14 08:43:03 -07:00
<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
2015-06-26 20:27:38 -07:00
<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html">
2015-07-13 14:26:11 -07:00
<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
2015-06-26 20:27:38 -07:00
<!--
`iron-autogrow-textarea` is an element containing a textarea that grows in height as more
lines of input are entered. Unless an explicit height or the `maxRows` property is set, it will
never scroll.
Example:
2015-08-05 18:21:18 -07:00
<iron-autogrow-textarea></iron-autogrow-textarea>
2015-06-26 20:27:38 -07:00
2015-10-07 18:49:40 -07:00
### Styling
2015-12-14 08:43:03 -07:00
2015-10-07 18:49:40 -07:00
The following custom properties and mixins are available for styling:
2015-12-14 08:43:03 -07:00
2015-10-07 18:49:40 -07:00
Custom property | Description | Default
----------------|-------------|----------
`--iron-autogrow-textarea` | Mixin applied to the textarea | `{}`
2016-02-18 11:20:10 -07:00
`--iron-autogrow-textarea-placeholder` | Mixin applied to the textarea placeholder | `{}`
2015-10-07 18:49:40 -07:00
2015-06-26 20:27:38 -07:00
@group Iron Elements
@hero hero.svg
@demo demo/index.html
-->
<dom-module id="iron-autogrow-textarea">
<style>
:host {
display: inline-block;
position: relative;
width: 400px;
border: 1px solid;
padding: 2px;
-moz-appearance: textarea;
-webkit-appearance: textarea;
2016-02-18 11:20:10 -07:00
overflow: hidden;
2015-06-26 20:27:38 -07:00
}
.mirror-text {
visibility: hidden;
word-wrap: break-word;
}
2015-12-14 08:43:03 -07:00
.fit {
@apply(--layout-fit);
}
2015-06-26 20:27:38 -07:00
textarea {
position: relative;
outline: none;
border: none;
resize: none;
background: inherit;
2015-07-13 14:26:11 -07:00
color: inherit;
2015-06-26 20:27:38 -07:00
/* see comments in template */
width: 100%;
height: 100%;
font-size: inherit;
font-family: inherit;
2015-08-05 18:21:18 -07:00
line-height: inherit;
2015-12-14 08:43:03 -07:00
text-align: inherit;
2015-10-07 18:49:40 -07:00
@apply(--iron-autogrow-textarea);
2015-06-26 20:27:38 -07:00
}
::content textarea:invalid {
box-shadow: none;
}
2016-02-18 11:20:10 -07:00
textarea::-webkit-input-placeholder {
@apply(--iron-autogrow-textarea-placeholder);
}
textarea:-moz-placeholder {
@apply(--iron-autogrow-textarea-placeholder);
}
textarea::-moz-placeholder {
@apply(--iron-autogrow-textarea-placeholder);
}
textarea:-ms-input-placeholder {
@apply(--iron-autogrow-textarea-placeholder);
}
2015-06-26 20:27:38 -07:00
</style>
<template>
<!-- the mirror sizes the input/textarea so it grows with typing -->
2015-12-14 08:43:03 -07:00
<!-- use &#160; instead &nbsp; of to allow this element to be used in XHTML -->
<div id="mirror" class="mirror-text" aria-hidden="true">&#160;</div>
2015-06-26 20:27:38 -07:00
<!-- size the input/textarea with a div, because the textarea has intrinsic size in ff -->
<div class="textarea-container fit">
<textarea id="textarea"
2016-02-23 22:36:48 -07:00
name$="[[name]]"
2015-06-26 20:27:38 -07:00
autocomplete$="[[autocomplete]]"
autofocus$="[[autofocus]]"
inputmode$="[[inputmode]]"
placeholder$="[[placeholder]]"
readonly$="[[readonly]]"
required$="[[required]]"
2015-10-07 18:49:40 -07:00
disabled$="[[disabled]]"
2015-06-26 20:27:38 -07:00
rows$="[[rows]]"
maxlength$="[[maxlength]]"></textarea>
</div>
</template>
</dom-module>
<script>
Polymer({
is: 'iron-autogrow-textarea',
behaviors: [
2015-07-13 14:26:11 -07:00
Polymer.IronFormElementBehavior,
2015-06-26 20:27:38 -07:00
Polymer.IronValidatableBehavior,
Polymer.IronControlState
],
properties: {
/**
* Use this property instead of `value` for two-way data binding.
2016-02-23 22:36:48 -07:00
* This property will be deprecated in the future. Use `value` instead.
* @type {string|number}
2015-06-26 20:27:38 -07:00
*/
bindValue: {
observer: '_bindValueChanged',
type: String
},
/**
* The initial number of rows.
*
* @attribute rows
* @type number
* @default 1
*/
rows: {
type: Number,
value: 1,
observer: '_updateCached'
},
/**
* The maximum number of rows this element can grow to until it
* scrolls. 0 means no maximum.
*
* @attribute maxRows
* @type number
* @default 0
*/
maxRows: {
type: Number,
value: 0,
observer: '_updateCached'
},
/**
* Bound to the textarea's `autocomplete` attribute.
*/
autocomplete: {
type: String,
value: 'off'
},
/**
* Bound to the textarea's `autofocus` attribute.
*/
autofocus: {
2015-08-05 18:21:18 -07:00
type: Boolean,
value: false
2015-06-26 20:27:38 -07:00
},
/**
* Bound to the textarea's `inputmode` attribute.
*/
inputmode: {
type: String
},
/**
* Bound to the textarea's `placeholder` attribute.
*/
placeholder: {
type: String
},
/**
* Bound to the textarea's `readonly` attribute.
*/
readonly: {
type: String
},
/**
* Set to true to mark the textarea as required.
*/
required: {
type: Boolean
},
/**
* The maximum length of the input value.
*/
maxlength: {
type: Number
}
},
listeners: {
'input': '_onInput'
},
2016-02-23 22:36:48 -07:00
observers: [
'_onValueChanged(value)'
],
2015-06-26 20:27:38 -07:00
/**
* Returns the underlying textarea.
2015-07-13 14:26:11 -07:00
* @type HTMLTextAreaElement
2015-06-26 20:27:38 -07:00
*/
get textarea() {
return this.$.textarea;
},
2015-09-24 10:08:10 -07:00
/**
* Returns textarea's selection start.
* @type Number
*/
get selectionStart() {
return this.$.textarea.selectionStart;
},
/**
* Returns textarea's selection end.
* @type Number
*/
get selectionEnd() {
return this.$.textarea.selectionEnd;
},
/**
* Sets the textarea's selection start.
*/
set selectionStart(value) {
this.$.textarea.selectionStart = value;
},
/**
* Sets the textarea's selection end.
*/
set selectionEnd(value) {
this.$.textarea.selectionEnd = value;
},
2015-07-13 14:26:11 -07:00
/**
* Returns true if `value` is valid. The validator provided in `validator`
* will be used first, if it exists; otherwise, the `textarea`'s validity
* is used.
* @return {boolean} True if the value is valid.
*/
validate: function() {
// Empty, non-required input is valid.
if (!this.required && this.value == '') {
this.invalid = false;
return true;
}
var valid;
if (this.hasValidator()) {
valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
} else {
valid = this.$.textarea.validity.valid;
this.invalid = !valid;
}
this.fire('iron-input-validate');
return valid;
},
2015-06-26 20:27:38 -07:00
_bindValueChanged: function() {
var textarea = this.textarea;
if (!textarea) {
return;
}
2015-10-07 18:49:40 -07:00
// If the bindValue changed manually, then we need to also update
// the underlying textarea's value. Otherwise this change was probably
// generated from the _onInput handler, and the two values are already
// the same.
if (textarea.value !== this.bindValue) {
textarea.value = !(this.bindValue || this.bindValue === 0) ? '' : this.bindValue;
}
2016-02-23 22:36:48 -07:00
this.value = this.bindValue;
2015-09-03 21:33:31 -07:00
this.$.mirror.innerHTML = this._valueForMirror();
2015-06-26 20:27:38 -07:00
// manually notify because we don't want to notify until after setting value
this.fire('bind-value-changed', {value: this.bindValue});
},
_onInput: function(event) {
this.bindValue = event.path ? event.path[0].value : event.target.value;
},
_constrain: function(tokens) {
var _tokens;
tokens = tokens || [''];
// Enforce the min and max heights for a multiline input to avoid measurement
if (this.maxRows > 0 && tokens.length > this.maxRows) {
_tokens = tokens.slice(0, this.maxRows);
} else {
_tokens = tokens.slice(0);
}
while (this.rows > 0 && _tokens.length < this.rows) {
_tokens.push('');
}
2015-12-14 08:43:03 -07:00
// Use &#160; instead &nbsp; of to allow this element to be used in XHTML.
return _tokens.join('<br/>') + '&#160;';
2015-06-26 20:27:38 -07:00
},
_valueForMirror: function() {
var input = this.textarea;
if (!input) {
return;
}
this.tokens = (input && input.value) ? input.value.replace(/&/gm, '&amp;').replace(/"/gm, '&quot;').replace(/'/gm, '&#39;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;').split('\n') : [''];
return this._constrain(this.tokens);
},
_updateCached: function() {
this.$.mirror.innerHTML = this._constrain(this.tokens);
2015-07-13 14:26:11 -07:00
},
2016-02-23 22:36:48 -07:00
_onValueChanged: function() {
this.bindValue = this.value;
2015-06-26 20:27:38 -07:00
}
2015-08-05 18:21:18 -07:00
});
2015-06-26 20:27:38 -07:00
</script>