sforkowany z mirror/soapbox
Porównaj commity
4 Commity
develop
...
chat_texta
Autor | SHA1 | Data |
---|---|---|
crockwave | 8b349ffb4b | |
crockwave | 244f205869 | |
crockwave | 51031b9f99 | |
crockwave | 241e4ea177 |
|
@ -6,6 +6,7 @@ import DisplayName from '../../../components/display_name';
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
import emojify from 'soapbox/features/emoji/emoji';
|
||||
import { unescapeHTML } from 'soapbox/utils/html';
|
||||
|
||||
export default class Chat extends ImmutablePureComponent {
|
||||
|
||||
|
@ -27,7 +28,7 @@ export default class Chat extends ImmutablePureComponent {
|
|||
const parsedContent = content ? emojify(content) : '';
|
||||
|
||||
return (
|
||||
<div className='account'>
|
||||
<div className='account' title={unescapeHTML(parsedContent)}>
|
||||
<button className='floating-link' onClick={this.handleClick} />
|
||||
<div className='account__wrapper'>
|
||||
<div key={account.get('id')} className='account__display-name'>
|
||||
|
@ -37,7 +38,7 @@ export default class Chat extends ImmutablePureComponent {
|
|||
<DisplayName account={account} />
|
||||
<span
|
||||
className='chat__last-message'
|
||||
dangerouslySetInnerHTML={{ __html: parsedContent }}
|
||||
dangerouslySetInnerHTML={{ __html: unescapeHTML(parsedContent) }}
|
||||
/>
|
||||
{unreadCount > 0 && <i className='icon-with-badge__badge'>{shortNumberFormat(unreadCount)}</i>}
|
||||
</div>
|
||||
|
|
|
@ -15,6 +15,7 @@ import { uploadMedia } from 'soapbox/actions/media';
|
|||
import UploadProgress from 'soapbox/features/compose/components/upload_progress';
|
||||
import { truncateFilename } from 'soapbox/utils/media';
|
||||
import IconButton from 'soapbox/components/icon_button';
|
||||
import TextareaAutosize from 'react-textarea-autosize';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'chat_box.input.placeholder', defaultMessage: 'Send a message…' },
|
||||
|
@ -40,6 +41,7 @@ class ChatBox extends ImmutablePureComponent {
|
|||
chat: ImmutablePropTypes.map,
|
||||
onSetInputRef: PropTypes.func,
|
||||
me: PropTypes.node,
|
||||
onAttachment: PropTypes.func,
|
||||
}
|
||||
|
||||
initialState = () => ({
|
||||
|
@ -108,6 +110,14 @@ class ChatBox extends ImmutablePureComponent {
|
|||
this.setState({ content: e.target.value });
|
||||
}
|
||||
|
||||
handleHeightChange = (e, el) => {
|
||||
if (e >= el.state.maxHeight) {
|
||||
// can use this to implement appearance of vertical scrollbar
|
||||
// setting showScroll true would allow render to change div className so that scss can set overflow-y: scroll on the TextareaAutosize
|
||||
// this.setState({ showScroll: true });
|
||||
}
|
||||
}
|
||||
|
||||
markRead = () => {
|
||||
const { dispatch, chatId } = this.props;
|
||||
dispatch(markChatRead(chatId));
|
||||
|
@ -119,10 +129,14 @@ class ChatBox extends ImmutablePureComponent {
|
|||
|
||||
setInputRef = (el) => {
|
||||
const { onSetInputRef } = this.props;
|
||||
this.inputElem = el;
|
||||
onSetInputRef(el);
|
||||
};
|
||||
|
||||
handleAttachment = () => {
|
||||
const { onAttachment } = this.props;
|
||||
onAttachment(true);
|
||||
}
|
||||
|
||||
handleRemoveFile = (e) => {
|
||||
this.setState({ attachment: undefined, resetFileKey: fileKeyGen() });
|
||||
}
|
||||
|
@ -142,6 +156,7 @@ class ChatBox extends ImmutablePureComponent {
|
|||
|
||||
dispatch(uploadMedia(data, this.onUploadProgress)).then(response => {
|
||||
this.setState({ attachment: response.data, isUploading: false });
|
||||
this.handleAttachment();
|
||||
}).catch(() => {
|
||||
this.setState({ isUploading: false });
|
||||
});
|
||||
|
@ -156,7 +171,7 @@ class ChatBox extends ImmutablePureComponent {
|
|||
<div className='chat-box__filename'>
|
||||
{truncateFilename(attachment.preview_url, 20)}
|
||||
</div>
|
||||
<div class='chat-box__remove-attachment'>
|
||||
<div className='chat-box__remove-attachment'>
|
||||
<IconButton icon='remove' onClick={this.handleRemoveFile} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -187,11 +202,14 @@ class ChatBox extends ImmutablePureComponent {
|
|||
<UploadProgress active={isUploading} progress={uploadProgress*100} />
|
||||
<div className='chat-box__actions simple_form'>
|
||||
{this.renderActionButton()}
|
||||
<textarea
|
||||
rows={1}
|
||||
<TextareaAutosize
|
||||
maxRows={4}
|
||||
minRows={1}
|
||||
autoFocus
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onChange={this.handleContentChange}
|
||||
onHeightChange={this.handleHeightChange}
|
||||
value={content}
|
||||
ref={this.setInputRef}
|
||||
/>
|
||||
|
|
|
@ -55,8 +55,10 @@ class ChatWindow extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
handleInputRef = (el) => {
|
||||
this.inputElem = el;
|
||||
this.focusInput();
|
||||
if (el) {
|
||||
this.inputElem = el._ref;
|
||||
this.focusInput();
|
||||
}
|
||||
};
|
||||
|
||||
focusInput = () => {
|
||||
|
@ -109,6 +111,7 @@ class ChatWindow extends ImmutablePureComponent {
|
|||
<ChatBox
|
||||
chatId={chat.get('id')}
|
||||
onSetInputRef={this.handleInputRef}
|
||||
onAttachment={this.focusInput}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// NB: This function can still return unsafe HTML
|
||||
export const unescapeHTML = (html) => {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = html.replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n').replace(/<[^>]*>/g, '');
|
||||
return wrapper.textContent;
|
||||
if (html !== null) {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = html.replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n').replace(/<[^>]*>/g, '');
|
||||
return wrapper.textContent;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -286,6 +286,7 @@
|
|||
border-radius: 6px;
|
||||
color: var(--primary-text-color);
|
||||
font-size: 15px;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -123,7 +123,7 @@
|
|||
"react-select": "^2.4.4",
|
||||
"react-sparklines": "^1.7.0",
|
||||
"react-swipeable-views": "^0.13.0",
|
||||
"react-textarea-autosize": "^7.1.0",
|
||||
"react-textarea-autosize": "^7.1.2",
|
||||
"react-toggle": "^4.0.1",
|
||||
"redis": "^2.7.1",
|
||||
"redux": "^4.0.5",
|
||||
|
|
|
@ -9764,10 +9764,10 @@ react-test-renderer@^16.13.1:
|
|||
react-is "^16.8.6"
|
||||
scheduler "^0.19.1"
|
||||
|
||||
react-textarea-autosize@^7.1.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.0.tgz#3132cb77e65d94417558d37c0bfe415a5afd3445"
|
||||
integrity sha512-c2FlR/fP0qbxmlrW96SdrbgP/v0XZMTupqB90zybvmDVDutytUgPl7beU35klwcTeMepUIQEpQUn3P3bdshGPg==
|
||||
react-textarea-autosize@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.2.tgz#70fdb333ef86bcca72717e25e623e90c336e2cda"
|
||||
integrity sha512-uH3ORCsCa3C6LHxExExhF4jHoXYCQwE5oECmrRsunlspaDAbS4mGKNlWZqjLfInWtFQcf0o1n1jC/NGXFdUBCg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
prop-types "^15.6.0"
|
||||
|
|
Ładowanie…
Reference in New Issue