summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarrison Healey <harrisonmhealey@gmail.com>2016-11-04 12:35:38 -0400
committerChristopher Speller <crspeller@gmail.com>2016-11-04 12:35:38 -0400
commite63e80dee012b22aca94c0095e184c6a6a80d4d7 (patch)
treef58b48a042cdefa6a7f65f4b3876322362bc0b98
parent7403bbce69baeabd7b4cd1ef316513a9fc6807c5 (diff)
downloadchat-e63e80dee012b22aca94c0095e184c6a6a80d4d7.tar.gz
chat-e63e80dee012b22aca94c0095e184c6a6a80d4d7.tar.bz2
chat-e63e80dee012b22aca94c0095e184c6a6a80d4d7.zip
PLT-4404/PLT-4578/PLT-4541/PLT-4542 Replaced third party autosizing textarea with a custom one (#4442)
* PLT-4578 Replaced third party autosizing textarea with a custom one * Fix Textbox.handleHeightChange not being called * Removed unused CSS * PLT-4541 Force EditPostModal to resize upon opening * Removed usage of jquery from AutosizeTextarea * Reverted changes made for PLT-4580 as they're no longer needed
-rw-r--r--NOTICE.txt31
-rw-r--r--webapp/components/autosize_textarea.jsx90
-rw-r--r--webapp/components/edit_post_modal.jsx2
-rw-r--r--webapp/components/suggestion/suggestion_box.jsx56
-rw-r--r--webapp/components/textbox.jsx17
-rw-r--r--webapp/package.json1
-rw-r--r--webapp/sass/components/_modal.scss2
-rw-r--r--webapp/sass/layout/_post.scss26
8 files changed, 138 insertions, 87 deletions
diff --git a/NOTICE.txt b/NOTICE.txt
index 092ce0cc8..7d0b16ff7 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1284,37 +1284,6 @@ limitations under the License.
---
-This product contains a modified portion of 'react-autosize-textarea', a light replacement for built-in textarea component which automaticaly adjusts its height to match the content.
-
-* HOMEPAGE:
- * https://github.com/buildo/react-autosize-textarea
-
-* LICENSE:
-
-The MIT License (MIT)
-
-Copyright (c) 2016 buildo s.r.l.s.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
----
-
This product contains a modified portion of 'compass-mixins', which pulls SASS style sheets on Bower, and enjoys the compass mixins by using libsass for faster compilation, by Christopher M. Eppstein.
* HOMEPAGE:
diff --git a/webapp/components/autosize_textarea.jsx b/webapp/components/autosize_textarea.jsx
new file mode 100644
index 000000000..45807fda0
--- /dev/null
+++ b/webapp/components/autosize_textarea.jsx
@@ -0,0 +1,90 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+
+export default class AutosizeTextarea extends React.Component {
+ static propTypes = {
+ value: React.PropTypes.string,
+ placeholder: React.PropTypes.string,
+ onHeightChange: React.PropTypes.func
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.height = 0;
+ }
+
+ get value() {
+ return this.refs.textarea.value;
+ }
+
+ set value(value) {
+ this.refs.textarea.value = value;
+ }
+
+ componentDidUpdate() {
+ this.recalculateSize();
+ }
+
+ recalculateSize() {
+ const height = this.refs.reference.scrollHeight;
+
+ if (height > 0 && height !== this.height) {
+ const textarea = this.refs.textarea;
+
+ const style = getComputedStyle(textarea);
+ const borderWidth = parseInt(style.borderTopWidth, 10) + parseInt(style.borderBottomWidth, 10);
+
+ // Directly change the height to avoid circular rerenders
+ textarea.style.height = String(height + borderWidth) + 'px';
+
+ this.height = height;
+
+ if (this.props.onHeightChange) {
+ this.props.onHeightChange(height, parseInt(style.maxHeight, 10));
+ }
+ }
+ }
+
+ getDOMNode() {
+ return this.refs.textarea;
+ }
+
+ render() {
+ window.forceUpdate = this.forceUpdate.bind(this);
+ const {
+ value,
+ placeholder,
+ ...otherProps
+ } = this.props;
+
+ const heightProps = {};
+ if (this.height <= 0) {
+ // Set an initial number of rows so that the textarea doesn't appear too large when its first rendered
+ heightProps.rows = 1;
+ } else {
+ heightProps.height = this.height;
+ }
+
+ return (
+ <div>
+ <textarea
+ ref='textarea'
+ {...heightProps}
+ {...this.props}
+ />
+ <div style={{height: 0, overflow: 'hidden'}}>
+ <textarea
+ ref='reference'
+ style={{height: 'auto', width: '100%'}}
+ value={value || placeholder}
+ rows='1'
+ {...otherProps}
+ />
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/webapp/components/edit_post_modal.jsx b/webapp/components/edit_post_modal.jsx
index cd33dd113..6ed2b81b2 100644
--- a/webapp/components/edit_post_modal.jsx
+++ b/webapp/components/edit_post_modal.jsx
@@ -156,6 +156,8 @@ export default class EditPostModal extends React.Component {
onModalShown() {
this.refs.editbox.focus();
+
+ this.refs.editbox.recalculateSize();
}
onModalHide() {
diff --git a/webapp/components/suggestion/suggestion_box.jsx b/webapp/components/suggestion/suggestion_box.jsx
index 590fdae04..21bfd3dc3 100644
--- a/webapp/components/suggestion/suggestion_box.jsx
+++ b/webapp/components/suggestion/suggestion_box.jsx
@@ -9,7 +9,7 @@ import * as GlobalActions from 'actions/global_actions.jsx';
import SuggestionStore from 'stores/suggestion_store.jsx';
import * as Utils from 'utils/utils.jsx';
-import TextareaAutosize from 'react-autosize-textarea';
+import AutosizeTextarea from 'components/autosize_textarea.jsx';
const KeyCodes = Constants.KeyCodes;
@@ -46,14 +46,17 @@ export default class SuggestionBox extends React.Component {
}
getTextbox() {
- // this is to support old code that looks at the input/textarea DOM nodes
- let textbox = this.refs.textbox;
-
- if (!(textbox instanceof HTMLElement)) {
- textbox = ReactDOM.findDOMNode(textbox);
+ if (this.props.type === 'textarea') {
+ return this.refs.textbox.getDOMNode();
}
- return textbox;
+ return this.refs.textbox;
+ }
+
+ recalculateSize() {
+ if (this.props.type === 'textarea') {
+ this.refs.textbox.recalculateSize();
+ }
}
handleDocumentClick(e) {
@@ -71,7 +74,7 @@ export default class SuggestionBox extends React.Component {
}
handleChange(e) {
- const textbox = ReactDOM.findDOMNode(this.refs.textbox);
+ const textbox = this.getTextbox();
const caret = Utils.getCaretPosition(textbox);
const pretext = textbox.value.substring(0, caret);
@@ -83,7 +86,7 @@ export default class SuggestionBox extends React.Component {
}
handleCompleteWord(term, matchedPretext) {
- const textbox = ReactDOM.findDOMNode(this.refs.textbox);
+ const textbox = this.getTextbox();
const caret = Utils.getCaretPosition(textbox);
const text = this.props.value;
const pretext = text.substring(0, caret);
@@ -150,48 +153,57 @@ export default class SuggestionBox extends React.Component {
}
render() {
+ const {
+ type,
+ listComponent,
+ listStyle,
+ renderDividers,
+ ...props
+ } = this.props;
+
let textbox = null;
- if (this.props.type === 'input') {
+ if (type === 'input') {
textbox = (
<input
ref='textbox'
type='text'
- {...this.props}
- onChange={this.handleChange}
+ {...props}
+ onInput={this.handleChange}
onKeyDown={this.handleKeyDown}
/>
);
- } else if (this.props.type === 'search') {
+ } else if (type === 'search') {
textbox = (
<input
ref='textbox'
type='search'
- {...this.props}
- onChange={this.handleChange}
+ {...props}
+ onInput={this.handleChange}
onKeyDown={this.handleKeyDown}
/>
);
- } else if (this.props.type === 'textarea') {
+ } else if (type === 'textarea') {
textbox = (
- <TextareaAutosize
+ <AutosizeTextarea
id={this.suggestionId}
ref='textbox'
- {...this.props}
- onChange={this.handleChange}
+ {...props}
+ onInput={this.handleChange}
onKeyDown={this.handleKeyDown}
/>
);
}
- const SuggestionListComponent = this.props.listComponent;
+ // This needs to be upper case so React doesn't think it's an html tag
+ const SuggestionListComponent = listComponent;
return (
<div>
{textbox}
<SuggestionListComponent
suggestionId={this.suggestionId}
- location={this.props.listStyle}
- renderDividers={this.props.renderDividers}
+ location={listStyle}
+ renderDividers={renderDividers}
/>
</div>
);
diff --git a/webapp/components/textbox.jsx b/webapp/components/textbox.jsx
index f11ef20ad..9192cd4f9 100644
--- a/webapp/components/textbox.jsx
+++ b/webapp/components/textbox.jsx
@@ -25,6 +25,7 @@ export default class Textbox extends React.Component {
super(props);
this.focus = this.focus.bind(this);
+ this.recalculateSize = this.recalculateSize.bind(this);
this.getStateFromStores = this.getStateFromStores.bind(this);
this.onRecievedError = this.onRecievedError.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
@@ -91,13 +92,10 @@ export default class Textbox extends React.Component {
}
}
- handleHeightChange(height) {
- const textbox = $(this.refs.message.getTextbox());
+ handleHeightChange(height, maxHeight) {
const wrapper = $(this.refs.wrapper);
- const maxHeight = parseInt(textbox.css('max-height'), 10);
-
- // move over attachment icon to compensate for the scrollbar
+ // Move over attachment icon to compensate for the scrollbar
if (height > maxHeight) {
wrapper.closest('.post-body__cell').addClass('scroll');
} else {
@@ -106,7 +104,14 @@ export default class Textbox extends React.Component {
}
focus() {
- this.refs.message.getTextbox().focus();
+ const textbox = this.refs.message.getTextbox();
+
+ textbox.focus();
+ Utils.placeCaretAtEnd(textbox);
+ }
+
+ recalculateSize() {
+ this.refs.message.recalculateSize();
}
showPreview(e) {
diff --git a/webapp/package.json b/webapp/package.json
index 6e4a7c17a..338829559 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -24,7 +24,6 @@
"perfect-scrollbar": "0.6.12",
"react": "15.3.2",
"react-addons-pure-render-mixin": "15.3.2",
- "react-autosize-textarea": "0.3.3",
"react-bootstrap": "0.30.3",
"react-custom-scrollbars": "4.0.0",
"react-dom": "15.3.2",
diff --git a/webapp/sass/components/_modal.scss b/webapp/sass/components/_modal.scss
index 7a44e3b96..3faf78bc6 100644
--- a/webapp/sass/components/_modal.scss
+++ b/webapp/sass/components/_modal.scss
@@ -21,7 +21,7 @@
.custom-textarea {
max-height: 60vh;
- min-height: 20em;
+ min-height: 8em;
}
.suggestion-list {
diff --git a/webapp/sass/layout/_post.scss b/webapp/sass/layout/_post.scss
index efba5b6f1..4a995a4d6 100644
--- a/webapp/sass/layout/_post.scss
+++ b/webapp/sass/layout/_post.scss
@@ -22,31 +22,6 @@
color: #d04444 !important;
}
-.textarea-div {
- border: 0;
- color: rgba(0,0,0,0);
- height: auto;
- left: 1px;
- line-height: 20px;
- min-height: 36px;
- position: absolute;
- top: 0px;
- white-space: pre-wrap;
- word-break: break-word;
- word-wrap: normal;
-}
-
-body.ios {
- .textarea-div {
- -webkit-overflow-scrolling: auto;
- padding: 7px 17px 7px 15px;
- }
-}
-
-.textarea-div::-webkit-scrollbar {
- display: none;
-}
-
.textarea-wrapper {
min-height: 36px;
position: relative;
@@ -390,7 +365,6 @@ body.ios {
.custom-textarea {
bottom: 0;
- line-height: 1.5;
max-height: 162px !important;
padding-right: 28px;
padding-top: 8px;