mirror of
https://github.com/wassname/talk.git
synced 2026-06-30 04:37:04 +08:00
Implement DraftArea
This commit is contained in:
@@ -17,7 +17,7 @@ import pluginsConfig from 'pluginsConfig';
|
||||
// TODO: move init code into `bootstrap` service after auth has been refactored.
|
||||
function preInit({ store, pym, inIframe }) {
|
||||
// TODO: This is popup specific code and needs to be refactored.
|
||||
if (!inIframe()) {
|
||||
if (!inIframe) {
|
||||
store.dispatch(addExternalConfig({}));
|
||||
store.dispatch(checkLogin());
|
||||
return;
|
||||
|
||||
@@ -2,13 +2,13 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from 'coral-ui';
|
||||
import cn from 'classnames';
|
||||
import Slot from 'coral-framework/components/Slot';
|
||||
|
||||
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
|
||||
import { name } from '../containers/CommentBox';
|
||||
import styles from './CommentForm.css';
|
||||
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import DraftArea from '../containers/DraftArea';
|
||||
|
||||
/**
|
||||
* Common UI for Creating or Editing a Comment
|
||||
@@ -61,10 +61,6 @@ export class CommentForm extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
onBodyChange = e => {
|
||||
this.props.onBodyChange(e.target.value);
|
||||
};
|
||||
|
||||
onClickSubmit = () => {
|
||||
this.props.onSubmit();
|
||||
};
|
||||
@@ -107,37 +103,16 @@ export class CommentForm extends React.Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`${name}-container`}>
|
||||
<label
|
||||
htmlFor={this.props.bodyInputId}
|
||||
className="screen-reader-text"
|
||||
aria-hidden={true}
|
||||
>
|
||||
{this.props.bodyLabel}
|
||||
</label>
|
||||
<textarea
|
||||
className={`${name}-textarea`}
|
||||
value={body}
|
||||
placeholder={this.props.bodyPlaceholder}
|
||||
id={this.props.bodyInputId}
|
||||
onChange={this.onBodyChange}
|
||||
rows={3}
|
||||
disabled={disableTextArea}
|
||||
/>
|
||||
<Slot fill="commentInputArea" />
|
||||
</div>
|
||||
{this.props.charCountEnable && (
|
||||
<div
|
||||
className={`${name}-char-count ${
|
||||
length > maxCharCount ? `${name}-char-max` : ''
|
||||
}`}
|
||||
>
|
||||
{maxCharCount &&
|
||||
`${maxCharCount - length} ${t(
|
||||
'comment_box.characters_remaining'
|
||||
)}`}
|
||||
</div>
|
||||
)}
|
||||
<DraftArea
|
||||
id={this.props.bodyInputId}
|
||||
label={this.props.bodyLabel}
|
||||
value={body}
|
||||
placeholder={this.props.bodyPlaceholder}
|
||||
onChange={this.props.onBodyChange}
|
||||
disabled={disableTextArea}
|
||||
charCountEnable={this.props.charCountEnable}
|
||||
maxCharCount={this.props.maxCharCount}
|
||||
/>
|
||||
<div className={`${name}-button-container`}>
|
||||
{this.props.buttonContainerStart}
|
||||
{typeof this.props.onCancel === 'function' && (
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import Slot from 'coral-framework/components/Slot';
|
||||
|
||||
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
|
||||
|
||||
/**
|
||||
* An enhanced textarea to make comment drafts.
|
||||
*/
|
||||
export default class DraftArea extends React.Component {
|
||||
renderCharCount() {
|
||||
const { value, maxCharCount } = this.props;
|
||||
const className = cn('talk-plugin-commentbox-char-count', {
|
||||
['talk-plugin-commentbox-char-max']: value.length > maxCharCount,
|
||||
});
|
||||
const remaining = maxCharCount - value.length;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{remaining} {t('comment_box.characters_remaining')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
placeholder,
|
||||
id,
|
||||
disabled,
|
||||
rows,
|
||||
label,
|
||||
charCountEnable,
|
||||
maxCharCount,
|
||||
onChange,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={'talk-plugin-commentbox-container'}>
|
||||
<label htmlFor={id} className="screen-reader-text" aria-hidden={true}>
|
||||
{label}
|
||||
</label>
|
||||
<textarea
|
||||
className={'talk-plugin-commentbox-textarea'}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
id={id}
|
||||
onChange={onChange}
|
||||
rows={rows}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Slot fill="commentInputArea" />
|
||||
</div>
|
||||
{charCountEnable && maxCharCount > 0 && this.renderCharCount()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DraftArea.defaultProps = {
|
||||
rows: 3,
|
||||
};
|
||||
|
||||
DraftArea.propTypes = {
|
||||
charCountEnable: PropTypes.bool,
|
||||
maxCharCount: PropTypes.number,
|
||||
id: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
rows: PropTypes.number,
|
||||
};
|
||||
@@ -21,6 +21,7 @@ export class EditableCommentContent extends React.Component {
|
||||
|
||||
// comment that is being edited
|
||||
comment: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
body: PropTypes.string,
|
||||
editing: PropTypes.shape({
|
||||
edited: PropTypes.bool,
|
||||
@@ -120,10 +121,12 @@ export class EditableCommentContent extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const id = `edit-draft_${this.props.comment.id}`;
|
||||
return (
|
||||
<div className={styles.editCommentForm}>
|
||||
<CommentForm
|
||||
defaultValue={this.props.comment.body}
|
||||
bodyInputId={id}
|
||||
charCountEnable={this.props.charCountEnable}
|
||||
maxCharCount={this.props.maxCharCount}
|
||||
submitEnabled={this.isSubmitEnabled}
|
||||
|
||||
@@ -7,7 +7,8 @@ const name = 'talk-plugin-replies';
|
||||
|
||||
class ReplyBox extends Component {
|
||||
componentDidMount() {
|
||||
document.getElementById('replyText').focus();
|
||||
// TODO: (kiwi) This does not follow best practices, better to move this logic into the component.
|
||||
document.getElementById(`comment-draft_${this.props.parentId}`).focus();
|
||||
}
|
||||
|
||||
cancelReply = () => {
|
||||
@@ -54,6 +55,8 @@ ReplyBox.propTypes = {
|
||||
notify: PropTypes.func.isRequired,
|
||||
postComment: PropTypes.func.isRequired,
|
||||
assetId: PropTypes.string.isRequired,
|
||||
currentUser: PropTypes.object,
|
||||
styles: PropTypes.object,
|
||||
};
|
||||
|
||||
export default ReplyBox;
|
||||
|
||||
@@ -20,7 +20,6 @@ class CommentBox extends React.Component {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
username: '',
|
||||
body: '',
|
||||
loadingState: '',
|
||||
|
||||
@@ -129,7 +128,7 @@ class CommentBox extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isReply, maxCharCount } = this.props;
|
||||
const { isReply, maxCharCount, assetId, parentId } = this.props;
|
||||
let { onCancel } = this.props;
|
||||
|
||||
if (isReply && typeof onCancel !== 'function') {
|
||||
@@ -139,6 +138,11 @@ class CommentBox extends React.Component {
|
||||
onCancel = () => {};
|
||||
}
|
||||
|
||||
// Generate id for the DraftArea.
|
||||
const id = parentId
|
||||
? `comment-draft_${parentId}`
|
||||
: `comment-draft_${assetId}`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CommentForm
|
||||
@@ -147,7 +151,7 @@ class CommentBox extends React.Component {
|
||||
maxCharCount={maxCharCount}
|
||||
charCountEnable={this.props.charCountEnable}
|
||||
bodyPlaceholder={t('comment.comment')}
|
||||
bodyInputId={isReply ? 'replyText' : 'commentText'}
|
||||
bodyInputId={id}
|
||||
body={this.state.body}
|
||||
buttonContainerStart={
|
||||
<Slot
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import DraftArea from '../components/DraftArea';
|
||||
|
||||
const STORAGE_PATH = 'DraftArea';
|
||||
|
||||
/**
|
||||
* An enhanced textarea to make comment drafts.
|
||||
*/
|
||||
export default class DraftAreaContainer extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.initValue();
|
||||
}
|
||||
|
||||
async initValue() {
|
||||
const value = await this.context.pymSessionStorage.getItem(this.getPath());
|
||||
if (value && this.props.onChange) {
|
||||
this.props.onChange(value);
|
||||
}
|
||||
}
|
||||
|
||||
getPath = () => {
|
||||
return `${STORAGE_PATH}_${this.props.id}`;
|
||||
};
|
||||
|
||||
onChange = e => {
|
||||
this.context.pymSessionStorage.setItem(this.getPath(), e.target.value);
|
||||
this.props.onChange && this.props.onChange(e.target.value);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DraftArea
|
||||
value={this.props.value}
|
||||
placeholder={this.props.placeholder}
|
||||
id={this.props.id}
|
||||
onChange={this.onChange}
|
||||
rows={this.props.rows}
|
||||
disabled={this.props.disabled}
|
||||
charCountEnable={this.props.charCountEnable}
|
||||
maxCharCount={this.props.maxCharCount}
|
||||
label={this.props.label}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DraftAreaContainer.contextTypes = {
|
||||
pymSessionStorage: PropTypes.object,
|
||||
};
|
||||
|
||||
DraftAreaContainer.propTypes = {
|
||||
charCountEnable: PropTypes.bool,
|
||||
maxCharCount: PropTypes.number,
|
||||
id: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
rows: PropTypes.number,
|
||||
label: PropTypes.string,
|
||||
};
|
||||
+1
-1
@@ -80,7 +80,7 @@ export async function createContext({
|
||||
: localStorage;
|
||||
const pymSessionStorage = inIframe
|
||||
? createPymStorage(pym, 'sessionStorage')
|
||||
: localStorage;
|
||||
: sessionStorage;
|
||||
const history = createHistory(BASE_PATH);
|
||||
const introspection = createIntrospection(introspectionData);
|
||||
let store = null;
|
||||
|
||||
Reference in New Issue
Block a user