import { Component, linkEvent } from 'inferno'; import { Prompt } from 'inferno-router'; import { PostListings } from './post-listings'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; import { PostForm as PostFormI, PostFormParams, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse, ListCommunitiesForm, SortType, SearchForm, SearchType, SearchResponse, WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, getPageTitle, validURL, capitalizeFirstLetter, markdownHelpUrl, archiveUrl, mdToHtml, debounce, isImage, toast, randomStr, setupTribute, setupTippy, hostname, pictrsDeleteToast, validTitle, } from '../utils'; import autosize from 'autosize'; import Tribute from 'tributejs/src/Tribute.js'; import emojiShortName from 'emoji-short-name'; import Choices from 'choices.js'; import { i18n } from '../i18next'; const MAX_POST_TITLE_LENGTH = 200; interface PostFormProps { post?: Post; // If a post is given, that means this is an edit params?: PostFormParams; onCancel?(): any; onCreate?(id: number): any; onEdit?(post: Post): any; enableNsfw: boolean; enableDownvotes: boolean; } interface PostFormState { postForm: PostFormI; communities: Array; loading: boolean; imageLoading: boolean; previewMode: boolean; suggestedTitle: string; suggestedPosts: Array; crossPosts: Array; } export class PostForm extends Component { private id = `post-form-${randomStr()}`; private tribute: Tribute; private subscription: Subscription; private choices: Choices; private emptyState: PostFormState = { postForm: { name: null, nsfw: false, auth: null, community_id: null, creator_id: UserService.Instance.user ? UserService.Instance.user.id : null, }, communities: [], loading: false, imageLoading: false, previewMode: false, suggestedTitle: undefined, suggestedPosts: [], crossPosts: [], }; constructor(props: any, context: any) { super(props, context); this.fetchSimilarPosts = debounce(this.fetchSimilarPosts).bind(this); this.fetchPageTitle = debounce(this.fetchPageTitle).bind(this); this.tribute = setupTribute(); this.state = this.emptyState; if (this.props.post) { this.state.postForm = { body: this.props.post.body, // NOTE: debouncing breaks both these for some reason, unless you use defaultValue name: this.props.post.name, community_id: this.props.post.community_id, edit_id: this.props.post.id, creator_id: this.props.post.creator_id, url: this.props.post.url, nsfw: this.props.post.nsfw, auth: null, }; } if (this.props.params) { this.state.postForm.name = this.props.params.name; if (this.props.params.url) { this.state.postForm.url = this.props.params.url; } if (this.props.params.body) { this.state.postForm.body = this.props.params.body; } } this.subscription = WebSocketService.Instance.subject .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) .subscribe( msg => this.parseMessage(msg), err => console.error(err), () => console.log('complete') ); let listCommunitiesForm: ListCommunitiesForm = { sort: SortType[SortType.TopAll], limit: 9999, }; WebSocketService.Instance.listCommunities(listCommunitiesForm); } componentDidMount() { var textarea: any = document.getElementById(this.id); autosize(textarea); this.tribute.attach(textarea); textarea.addEventListener('tribute-replaced', () => { this.state.postForm.body = textarea.value; this.setState(this.state); autosize.update(textarea); }); setupTippy(); } componentDidUpdate() { if ( !this.state.loading && (this.state.postForm.name || this.state.postForm.url || this.state.postForm.body) ) { window.onbeforeunload = () => true; } else { window.onbeforeunload = undefined; } } componentWillUnmount() { this.subscription.unsubscribe(); this.choices && this.choices.destroy(); window.onbeforeunload = null; } render() { return (
{this.state.suggestedTitle && (
{i18n.t('copy_suggested_title', { title: this.state.suggestedTitle, })}
)} {validURL(this.state.postForm.url) && ( {i18n.t('archive_link')} )} {this.state.imageLoading && ( )} {isImage(this.state.postForm.url) && ( )} {this.state.crossPosts.length > 0 && ( <>
{i18n.t('cross_posts')}
)}