Merge pull request #2494 from hmhealey/plt2190

PLT-2190 Switched Textbox to use a TextareaAutosize and removed custom resizing code
Этот коммит содержится в:
Christopher Speller
2016-03-23 16:21:27 -04:00
родитель 826529f048 f134df04b0
Коммит 6285ec44bb
6 изменённых файлов: 56 добавлений и 69 удалений

Просмотреть файл

@@ -27,8 +27,8 @@ const holders = defineMessages({
import React from 'react'; import React from 'react';
class EditPostModal extends React.Component { class EditPostModal extends React.Component {
constructor() { constructor(props) {
super(); super(props);
this.handleEdit = this.handleEdit.bind(this); this.handleEdit = this.handleEdit.bind(this);
this.handleEditInput = this.handleEditInput.bind(this); this.handleEditInput = this.handleEditInput.bind(this);
@@ -56,12 +56,13 @@ class EditPostModal extends React.Component {
updatedPost.id = this.state.post_id; updatedPost.id = this.state.post_id;
updatedPost.channel_id = this.state.channel_id; updatedPost.channel_id = this.state.channel_id;
Client.updatePost(updatedPost, Client.updatePost(
function success() { updatedPost,
() => {
AsyncClient.getPosts(updatedPost.channel_id); AsyncClient.getPosts(updatedPost.channel_id);
window.scrollTo(0, 0); window.scrollTo(0, 0);
}, },
function error(err) { (err) => {
AsyncClient.dispatchError(err, 'updatePost'); AsyncClient.dispatchError(err, 'updatePost');
} }
); );
@@ -106,11 +107,11 @@ class EditPostModal extends React.Component {
componentDidMount() { componentDidMount() {
var self = this; var self = this;
$(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', function onHidden() { $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', () => {
self.setState({editText: '', title: '', channel_id: '', post_id: '', comments: 0, refocusId: '', error: ''}); self.setState({editText: '', title: '', channel_id: '', post_id: '', comments: 0, refocusId: '', error: ''});
}); });
$(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', function onShow(e) { $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', (e) => {
var button = e.relatedTarget; var button = e.relatedTarget;
if (!button) { if (!button) {
return; return;
@@ -118,12 +119,11 @@ class EditPostModal extends React.Component {
self.setState({editText: $(button).attr('data-message'), title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid'), post_id: $(button).attr('data-postid'), comments: $(button).attr('data-comments'), refocusId: $(button).attr('data-refocusid')}); self.setState({editText: $(button).attr('data-message'), title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid'), post_id: $(button).attr('data-postid'), comments: $(button).attr('data-comments'), refocusId: $(button).attr('data-refocusid')});
}); });
$(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', function onShown() { $(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', () => {
self.refs.editbox.resize(); self.refs.editbox.focus();
$('#edit_textbox').get(0).focus();
}); });
$(ReactDOM.findDOMNode(this.refs.modal)).on('hide.bs.modal', function onShown() { $(ReactDOM.findDOMNode(this.refs.modal)).on('hide.bs.modal', () => {
if (self.state.refocusId !== '') { if (self.state.refocusId !== '') {
setTimeout(() => { setTimeout(() => {
$(self.state.refocusId).get(0).focus(); $(self.state.refocusId).get(0).focus();
@@ -221,4 +221,4 @@ EditPostModal.propTypes = {
intl: intlShape.isRequired intl: intlShape.isRequired
}; };
export default injectIntl(EditPostModal); export default injectIntl(EditPostModal);

Просмотреть файл

@@ -3,11 +3,14 @@
import $ from 'jquery'; import $ from 'jquery';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import Constants from 'utils/constants.jsx'; import Constants from 'utils/constants.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx'; import * as GlobalActions from 'action_creators/global_actions.jsx';
import SuggestionStore from 'stores/suggestion_store.jsx'; import SuggestionStore from 'stores/suggestion_store.jsx';
import * as Utils from 'utils/utils.jsx'; import * as Utils from 'utils/utils.jsx';
import TextareaAutosize from 'react-textarea-autosize';
const KeyCodes = Constants.KeyCodes; const KeyCodes = Constants.KeyCodes;
import React from 'react'; import React from 'react';
@@ -44,7 +47,13 @@ export default class SuggestionBox extends React.Component {
getTextbox() { getTextbox() {
// this is to support old code that looks at the input/textarea DOM nodes // this is to support old code that looks at the input/textarea DOM nodes
return ReactDOM.findDOMNode(this.refs.textbox); let textbox = this.refs.textbox;
if (!(textbox instanceof HTMLElement)) {
textbox = ReactDOM.findDOMNode(textbox);
}
return textbox;
} }
handleDocumentClick(e) { handleDocumentClick(e) {
@@ -132,7 +141,8 @@ export default class SuggestionBox extends React.Component {
); );
} else if (this.props.type === 'textarea') { } else if (this.props.type === 'textarea') {
textbox = ( textbox = (
<textarea <TextareaAutosize
id={this.suggestionId}
ref='textbox' ref='textbox'
{...newProps} {...newProps}
/> />
@@ -163,5 +173,6 @@ SuggestionBox.propTypes = {
// explicitly name any input event handlers we override and need to manually call // explicitly name any input event handlers we override and need to manually call
onChange: React.PropTypes.func, onChange: React.PropTypes.func,
onKeyDown: React.PropTypes.func onKeyDown: React.PropTypes.func,
onHeightChange: React.PropTypes.func
}; };

Просмотреть файл

@@ -2,7 +2,6 @@
// See License.txt for license information. // See License.txt for license information.
import $ from 'jquery'; import $ from 'jquery';
import ReactDOM from 'react-dom';
import AtMentionProvider from './suggestion/at_mention_provider.jsx'; import AtMentionProvider from './suggestion/at_mention_provider.jsx';
import CommandProvider from './suggestion/command_provider.jsx'; import CommandProvider from './suggestion/command_provider.jsx';
import EmoticonProvider from './suggestion/emoticon_provider.jsx'; import EmoticonProvider from './suggestion/emoticon_provider.jsx';
@@ -29,7 +28,7 @@ export default class Textbox extends React.Component {
this.onRecievedError = this.onRecievedError.bind(this); this.onRecievedError = this.onRecievedError.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this);
this.resize = this.resize.bind(this); this.handleHeightChange = this.handleHeightChange.bind(this);
this.showPreview = this.showPreview.bind(this); this.showPreview = this.showPreview.bind(this);
this.state = { this.state = {
@@ -54,8 +53,6 @@ export default class Textbox extends React.Component {
componentDidMount() { componentDidMount() {
ErrorStore.addChangeListener(this.onRecievedError); ErrorStore.addChangeListener(this.onRecievedError);
this.resize();
} }
componentWillUnmount() { componentWillUnmount() {
@@ -72,10 +69,6 @@ export default class Textbox extends React.Component {
} }
} }
componentDidUpdate() {
this.resize();
}
handleKeyPress(e) { handleKeyPress(e) {
this.props.onKeyPress(e); this.props.onKeyPress(e);
} }
@@ -86,50 +79,28 @@ export default class Textbox extends React.Component {
} }
} }
focus() { handleHeightChange(height) {
this.refs.message.getTextbox().focus(); const textbox = $(this.refs.message.getTextbox());
const wrapper = $(this.refs.wrapper);
const maxHeight = parseInt(textbox.css('max-height'), 10);
// move over attachment icon to compensate for the scrollbar
if (height > maxHeight) {
wrapper.closest('.post-body__cell').addClass('scroll');
} else {
wrapper.closest('.post-body__cell').removeClass('scroll');
}
} }
resize() { focus() {
const textbox = this.refs.message.getTextbox(); this.refs.message.getTextbox().focus();
const $textbox = $(textbox);
const $wrapper = $(ReactDOM.findDOMNode(this.refs.wrapper));
const padding = parseInt($textbox.css('padding-bottom'), 10) + parseInt($textbox.css('padding-top'), 10);
const borders = parseInt($textbox.css('border-bottom-width'), 10) + parseInt($textbox.css('border-top-width'), 10);
const maxHeight = parseInt($textbox.css('max-height'), 10) - borders;
// set the height to auto and remove the scrollbar so we can get the actual size of the contents
$textbox.css('height', 'auto').css('overflow-y', 'hidden');
let height = textbox.scrollHeight - padding;
if (height + padding > maxHeight) {
height = maxHeight - padding;
// turn scrollbar on and move over attachment icon to compensate for that
$textbox.css('overflow-y', 'scroll');
$wrapper.closest('.post-body__cell').addClass('scroll');
} else {
$wrapper.closest('.post-body__cell').removeClass('scroll');
}
// set the textarea to be the proper height
$textbox.height(height);
// set the wrapper height to match the height of the textbox including padding and borders
$wrapper.height(height + padding + borders);
if (this.state.preview) {
$(ReactDOM.findDOMNode(this.refs.preview)).height(height + borders);
}
} }
showPreview(e) { showPreview(e) {
e.preventDefault(); e.preventDefault();
e.target.blur(); e.target.blur();
this.setState({preview: !this.state.preview}); this.setState({preview: !this.state.preview});
this.resize();
} }
render() { render() {
@@ -157,7 +128,7 @@ export default class Textbox extends React.Component {
); );
} }
let helpText = ( const helpText = (
<div <div
style={{visibility: hasText ? 'visible' : 'hidden', opacity: hasText ? '0.5' : '0'}} style={{visibility: hasText ? 'visible' : 'hidden', opacity: hasText ? '0.5' : '0'}}
className='help_format_text' className='help_format_text'
@@ -174,12 +145,16 @@ export default class Textbox extends React.Component {
defaultMessage='_italic_' defaultMessage='_italic_'
/> />
</i> </i>
<span>~~<strike> <span>
<FormattedMessage {'~~'}
id='textbox.strike' <strike>
defaultMessage='strike' <FormattedMessage
/> id='textbox.strike'
</strike>~~ </span> defaultMessage='strike'
/>
</strike>
{'~~ '}
</span>
<code> <code>
<FormattedMessage <FormattedMessage
id='textbox.inlinecode' id='textbox.inlinecode'
@@ -214,16 +189,17 @@ export default class Textbox extends React.Component {
spellCheck='true' spellCheck='true'
autoComplete='off' autoComplete='off'
autoCorrect='off' autoCorrect='off'
rows='1'
maxLength={Constants.MAX_POST_LEN} maxLength={Constants.MAX_POST_LEN}
placeholder={this.props.createMessage} placeholder={this.props.createMessage}
value={this.props.messageText} value={this.props.messageText}
onUserInput={this.props.onUserInput} onUserInput={this.props.onUserInput}
onKeyPress={this.handleKeyPress} onKeyPress={this.handleKeyPress}
onKeyDown={this.handleKeyDown} onKeyDown={this.handleKeyDown}
onHeightChange={this.handleHeightChange}
style={{visibility: this.state.preview ? 'hidden' : 'visible'}} style={{visibility: this.state.preview ? 'hidden' : 'visible'}}
listComponent={SuggestionList} listComponent={SuggestionList}
providers={this.suggestionProviders} providers={this.suggestionProviders}
channelId={this.props.channelId}
/> />
<div <div
ref='preview' ref='preview'

Просмотреть файл

@@ -24,6 +24,7 @@
"react-dom": "0.14.7", "react-dom": "0.14.7",
"react-intl": "2.0.0-rc-1", "react-intl": "2.0.0-rc-1",
"react-router": "2.0.1", "react-router": "2.0.1",
"react-textarea-autosize": "3.3.0",
"twemoji": "1.4.1", "twemoji": "1.4.1",
"velocity-animate": "1.2.3" "velocity-animate": "1.2.3"
}, },

Просмотреть файл

@@ -8,6 +8,7 @@
.suggestion-list--top { .suggestion-list--top {
position: absolute; position: absolute;
bottom: 100%;
} }
.suggestion-list__content { .suggestion-list__content {

Просмотреть файл

@@ -7,9 +7,7 @@
line-height: 20px; line-height: 20px;
min-height: 36px; min-height: 36px;
overflow-x: hidden; overflow-x: hidden;
position: absolute;
resize: none; resize: none;
top: 0px;
white-space: pre-wrap; white-space: pre-wrap;
word-wrap: break-word; word-wrap: break-word;