diff options
author | Dessalines <tyhou13@gmx.com> | 2020-06-23 21:11:38 -0400 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2020-06-23 21:11:38 -0400 |
commit | dc94e58cbf7e7de10d97331a3056380a3416e0b0 (patch) | |
tree | 85ed25783b0470ead3012a9718aea50b39c940dd /ui/src/components | |
parent | fd6a040568239d2e6949394fdc0ce0f7ac70275c (diff) | |
parent | 790b944031f9433be765936763d848ffa6e1b496 (diff) |
Merge branch 'master' into federation_merge_from_master_2
Diffstat (limited to 'ui/src/components')
-rw-r--r-- | ui/src/components/comment-form.tsx | 90 | ||||
-rw-r--r-- | ui/src/components/comment-node.tsx | 47 | ||||
-rw-r--r-- | ui/src/components/community-form.tsx | 6 | ||||
-rw-r--r-- | ui/src/components/inbox.tsx | 20 | ||||
-rw-r--r-- | ui/src/components/login.tsx | 1 | ||||
-rw-r--r-- | ui/src/components/navbar.tsx | 4 | ||||
-rw-r--r-- | ui/src/components/post-form.tsx | 42 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 10 | ||||
-rw-r--r-- | ui/src/components/private-message-form.tsx | 8 | ||||
-rw-r--r-- | ui/src/components/private-message.tsx | 9 | ||||
-rw-r--r-- | ui/src/components/site-form.tsx | 8 | ||||
-rw-r--r-- | ui/src/components/user-listing.tsx | 4 | ||||
-rw-r--r-- | ui/src/components/user.tsx | 25 |
13 files changed, 172 insertions, 102 deletions
diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index b3c1a9a1..0fb7824e 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -18,6 +18,7 @@ import { setupTribute, wsJsonToRes, emojiPicker, + pictrsDeleteToast, } from '../utils'; import { WebSocketService, UserService } from '../services'; import autosize from 'autosize'; @@ -60,7 +61,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { buttonTitle: !this.props.node ? capitalizeFirstLetter(i18n.t('post')) : this.props.edit - ? capitalizeFirstLetter(i18n.t('edit')) + ? capitalizeFirstLetter(i18n.t('save')) : capitalizeFirstLetter(i18n.t('reply')), previewMode: false, loading: false, @@ -137,7 +138,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { /> {this.state.previewMode && ( <div - className="md-div" + className="card card-body md-div" dangerouslySetInnerHTML={mdToHtml( this.state.commentForm.content )} @@ -150,7 +151,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { <button type="submit" class="btn btn-sm btn-secondary mr-2" - disabled={this.props.disabled} + disabled={this.props.disabled || this.state.loading} > {this.state.loading ? ( <svg class="icon icon-spinner spin"> @@ -244,18 +245,32 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { }); } - handleFinished() { - this.state.previewMode = false; - this.state.loading = false; - this.state.commentForm.content = ''; - this.setState(this.state); - let form: any = document.getElementById(this.formId); - form.reset(); - if (this.props.node) { - this.props.onReplyCancel(); + handleFinished(data: CommentResponse) { + let isReply = + this.props.node !== undefined && data.comment.parent_id !== null; + let xor = + +!(data.comment.parent_id !== null) ^ +(this.props.node !== undefined); + + if ( + (data.comment.creator_id == UserService.Instance.user.id && + // If its a reply, make sure parent child match + isReply && + data.comment.parent_id == this.props.node.comment.id) || + // Otherwise, check the XOR of the two + (!isReply && xor) + ) { + this.state.previewMode = false; + this.state.loading = false; + this.state.commentForm.content = ''; + this.setState(this.state); + let form: any = document.getElementById(this.formId); + form.reset(); + if (this.props.node) { + this.props.onReplyCancel(); + } + autosize.update(form); + this.setState(this.state); } - autosize.update(document.querySelector('textarea')); - this.setState(this.state); } handleCommentSubmit(i: CommentForm, event: any) { @@ -305,9 +320,9 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { file = event; } - const imageUploadUrl = `/pictshare/api/upload.php`; + const imageUploadUrl = `/pictrs/image`; const formData = new FormData(); - formData.append('file', file); + formData.append('images[]', file); i.state.imageLoading = true; i.setState(i.state); @@ -318,16 +333,31 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { }) .then(res => res.json()) .then(res => { - let url = `${window.location.origin}/pictshare/${res.url}`; - let imageMarkdown = - res.filetype == 'mp4' ? `[vid](${url}/raw)` : `![](${url})`; - let content = i.state.commentForm.content; - content = content ? `${content}\n${imageMarkdown}` : imageMarkdown; - i.state.commentForm.content = content; - i.state.imageLoading = false; - i.setState(i.state); - let textarea: any = document.getElementById(i.id); - autosize.update(textarea); + console.log('pictrs upload:'); + console.log(res); + if (res.msg == 'ok') { + let hash = res.files[0].file; + let url = `${window.location.origin}/pictrs/image/${hash}`; + let deleteToken = res.files[0].delete_token; + let deleteUrl = `${window.location.origin}/pictrs/image/delete/${deleteToken}/${hash}`; + let imageMarkdown = `![](${url})`; + let content = i.state.commentForm.content; + content = content ? `${content}\n${imageMarkdown}` : imageMarkdown; + i.state.commentForm.content = content; + i.state.imageLoading = false; + i.setState(i.state); + let textarea: any = document.getElementById(i.id); + autosize.update(textarea); + pictrsDeleteToast( + i18n.t('click_to_delete_picture'), + i18n.t('picture_deleted'), + deleteUrl + ); + } else { + i.state.imageLoading = false; + i.setState(i.state); + toast(JSON.stringify(res), 'danger'); + } }) .catch(error => { i.state.imageLoading = false; @@ -343,14 +373,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { if (UserService.Instance.user) { if (res.op == UserOperation.CreateComment) { let data = res.data as CommentResponse; - if (data.comment.creator_id == UserService.Instance.user.id) { - this.handleFinished(); - } + this.handleFinished(data); } else if (res.op == UserOperation.EditComment) { let data = res.data as CommentResponse; - if (data.comment.creator_id == UserService.Instance.user.id) { - this.handleFinished(); - } + this.handleFinished(data); } } } diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index ca828a45..155efe8e 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -132,7 +132,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { > <div id={`comment-${node.comment.id}`} - className={`details comment-node border-top border-light ${ + className={`details comment-node border-top border-light py-2 ${ this.isCommentNew ? 'mark' : '' }`} style={ @@ -148,7 +148,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { 'ml-2' }`} > - <div class="d-flex flex-wrap align-items-center mb-1 mt-1 text-muted small"> + <div class="d-flex flex-wrap align-items-center text-muted small"> <span class="mr-2"> <UserListing user={{ @@ -299,25 +299,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { )} <button class="btn btn-link btn-animate text-muted" - onClick={linkEvent(this, this.handleSaveCommentClick)} - data-tippy-content={ - node.comment.saved ? i18n.t('unsave') : i18n.t('save') - } - > - {this.state.saveLoading ? ( - this.loadingIcon - ) : ( - <svg - class={`icon icon-inline ${ - node.comment.saved && 'text-warning' - }`} - > - <use xlinkHref="#icon-star"></use> - </svg> - )} - </button> - <button - class="btn btn-link btn-animate text-muted" onClick={linkEvent(this, this.handleReplyClick)} data-tippy-content={i18n.t('reply')} > @@ -352,6 +333,30 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { )} {!this.props.showContext && this.linkBtn} <button + class="btn btn-link btn-animate text-muted" + onClick={linkEvent( + this, + this.handleSaveCommentClick + )} + data-tippy-content={ + node.comment.saved + ? i18n.t('unsave') + : i18n.t('save') + } + > + {this.state.saveLoading ? ( + this.loadingIcon + ) : ( + <svg + class={`icon icon-inline ${ + node.comment.saved && 'text-warning' + }`} + > + <use xlinkHref="#icon-star"></use> + </svg> + )} + </button> + <button className="btn btn-link btn-animate text-muted" onClick={linkEvent(this, this.handleViewSource)} data-tippy-content={i18n.t('view_source')} diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index eedc2003..90e12738 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -207,7 +207,11 @@ export class CommunityForm extends Component< )} <div class="form-group row"> <div class="col-12"> - <button type="submit" class="btn btn-secondary mr-2"> + <button + type="submit" + class="btn btn-secondary mr-2" + disabled={this.state.loading} + > {this.state.loading ? ( <svg class="icon icon-spinner spin"> <use xlinkHref="#icon-spinner"></use> diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx index 4fa1498a..edbacd51 100644 --- a/ui/src/components/inbox.tsx +++ b/ui/src/components/inbox.tsx @@ -123,7 +123,10 @@ export class Inbox extends Component<any, InboxState> { this.state.unreadOrAll == UnreadOrAll.Unread && ( <ul class="list-inline mb-1 text-muted small font-weight-bold"> <li className="list-inline-item"> - <span class="pointer" onClick={this.markAllAsRead}> + <span + class="pointer" + onClick={linkEvent(this, this.markAllAsRead)} + > {i18n.t('mark_all_as_read')} </span> </li> @@ -392,8 +395,14 @@ export class Inbox extends Component<any, InboxState> { this.refetch(); } - markAllAsRead() { + markAllAsRead(i: Inbox) { WebSocketService.Instance.markAllAsRead(); + i.state.replies = []; + i.state.mentions = []; + i.state.messages = []; + i.sendUnreadCount(); + window.scrollTo(0, 0); + i.setState(i.state); } parseMessage(msg: WebSocketJsonResponse) { @@ -447,12 +456,7 @@ export class Inbox extends Component<any, InboxState> { this.setState(this.state); setupTippy(); } else if (res.op == UserOperation.MarkAllAsRead) { - this.state.replies = []; - this.state.mentions = []; - this.state.messages = []; - this.sendUnreadCount(); - window.scrollTo(0, 0); - this.setState(this.state); + // Moved to be instant } else if (res.op == UserOperation.EditComment) { let data = res.data as CommentResponse; editCommentRes(data, this.state.replies); diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx index 84014f68..ce04d0d4 100644 --- a/ui/src/components/login.tsx +++ b/ui/src/components/login.tsx @@ -111,6 +111,7 @@ export class Login extends Component<any, State> { required /> <button + type="button" disabled={!validEmail(this.state.loginForm.username_or_email)} onClick={linkEvent(this, this.handlePasswordReset)} className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold" diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index f1936be1..4cb74391 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -22,7 +22,7 @@ import { } from '../interfaces'; import { wsJsonToRes, - pictshareAvatarThumbnail, + pictrsAvatarThumbnail, showAvatars, fetchLimit, isCommentType, @@ -218,7 +218,7 @@ export class Navbar extends Component<any, NavbarState> { <span> {UserService.Instance.user.avatar && showAvatars() && ( <img - src={pictshareAvatarThumbnail( + src={pictrsAvatarThumbnail( UserService.Instance.user.avatar )} height="32" diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index 22224c34..9f5aa363 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -36,6 +36,7 @@ import { setupTippy, emojiPicker, hostname, + pictrsDeleteToast, } from '../utils'; import autosize from 'autosize'; import Tribute from 'tributejs/src/Tribute.js'; @@ -284,7 +285,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> { /> {this.state.previewMode && ( <div - className="md-div" + className="card card-body md-div" dangerouslySetInnerHTML={mdToHtml(this.state.postForm.body)} /> )} @@ -364,7 +365,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> { <div class="form-group row"> <div class="col-sm-10"> <button - disabled={!this.state.postForm.community_id} + disabled={ + !this.state.postForm.community_id || this.state.loading + } type="submit" class="btn btn-secondary mr-2" > @@ -410,6 +413,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> { handlePostSubmit(i: PostForm, event: any) { event.preventDefault(); + + // Coerce empty url string to undefined + if (i.state.postForm.url && i.state.postForm.url === '') { + i.state.postForm.url = undefined; + } + if (i.props.post) { WebSocketService.Instance.editPost(i.state.postForm); } else { @@ -523,9 +532,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> { file = event; } - const imageUploadUrl = `/pictshare/api/upload.php`; + const imageUploadUrl = `/pictrs/image`; const formData = new FormData(); - formData.append('file', file); + formData.append('images[]', file); i.state.imageLoading = true; i.setState(i.state); @@ -536,13 +545,26 @@ export class PostForm extends Component<PostFormProps, PostFormState> { }) .then(res => res.json()) .then(res => { - let url = `${window.location.origin}/pictshare/${encodeURI(res.url)}`; - if (res.filetype == 'mp4') { - url += '/raw'; + console.log('pictrs upload:'); + console.log(res); + if (res.msg == 'ok') { + let hash = res.files[0].file; + let url = `${window.location.origin}/pictrs/image/${hash}`; + let deleteToken = res.files[0].delete_token; + let deleteUrl = `${window.location.origin}/pictrs/image/delete/${deleteToken}/${hash}`; + i.state.postForm.url = url; + i.state.imageLoading = false; + i.setState(i.state); + pictrsDeleteToast( + i18n.t('click_to_delete_picture'), + i18n.t('picture_deleted'), + deleteUrl + ); + } else { + i.state.imageLoading = false; + i.setState(i.state); + toast(JSON.stringify(res), 'danger'); } - i.state.postForm.url = url; - i.state.imageLoading = false; - i.setState(i.state); }) .catch(error => { i.state.imageLoading = false; diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index def42e3c..b4cc4f92 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -29,7 +29,7 @@ import { isImage, isVideo, getUnixTime, - pictshareImage, + pictrsImage, setupTippy, hostname, previewLines, @@ -163,15 +163,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> { getImage(thumbnail: boolean = false) { let post = this.props.post; if (isImage(post.url)) { - if (post.url.includes('pictshare')) { - return pictshareImage(post.url, thumbnail); + if (post.url.includes('pictrs')) { + return pictrsImage(post.url, thumbnail); } else if (post.thumbnail_url) { - return pictshareImage(post.thumbnail_url, thumbnail); + return pictrsImage(post.thumbnail_url, thumbnail); } else { return post.url; } } else if (post.thumbnail_url) { - return pictshareImage(post.thumbnail_url, thumbnail); + return pictrsImage(post.thumbnail_url, thumbnail); } } diff --git a/ui/src/components/private-message-form.tsx b/ui/src/components/private-message-form.tsx index 64e22d61..8cb7590e 100644 --- a/ui/src/components/private-message-form.tsx +++ b/ui/src/components/private-message-form.tsx @@ -157,7 +157,7 @@ export class PrivateMessageForm extends Component< /> {this.state.previewMode && ( <div - className="md-div" + className="card card-body md-div" dangerouslySetInnerHTML={mdToHtml( this.state.privateMessageForm.content )} @@ -186,7 +186,11 @@ export class PrivateMessageForm extends Component< )} <div class="form-group row"> <div class="offset-sm-2 col-sm-10"> - <button type="submit" class="btn btn-secondary mr-2"> + <button + type="submit" + class="btn btn-secondary mr-2" + disabled={this.state.loading} + > {this.state.loading ? ( <svg class="icon icon-spinner spin"> <use xlinkHref="#icon-spinner"></use> diff --git a/ui/src/components/private-message.tsx b/ui/src/components/private-message.tsx index 3acd6e19..71924f0c 100644 --- a/ui/src/components/private-message.tsx +++ b/ui/src/components/private-message.tsx @@ -5,12 +5,7 @@ import { EditPrivateMessageForm, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { - mdToHtml, - pictshareAvatarThumbnail, - showAvatars, - toast, -} from '../utils'; +import { mdToHtml, pictrsAvatarThumbnail, showAvatars, toast } from '../utils'; import { MomentTime } from './moment-time'; import { PrivateMessageForm } from './private-message-form'; import { i18n } from '../i18next'; @@ -78,7 +73,7 @@ export class PrivateMessage extends Component< <img height="32" width="32" - src={pictshareAvatarThumbnail( + src={pictrsAvatarThumbnail( this.mine ? message.recipient_avatar : message.creator_avatar diff --git a/ui/src/components/site-form.tsx b/ui/src/components/site-form.tsx index f0c80585..a51286c8 100644 --- a/ui/src/components/site-form.tsx +++ b/ui/src/components/site-form.tsx @@ -78,7 +78,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> { <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}> <h5>{`${ this.props.site - ? capitalizeFirstLetter(i18n.t('edit')) + ? capitalizeFirstLetter(i18n.t('save')) : capitalizeFirstLetter(i18n.t('name')) } ${i18n.t('your_site')}`}</h5> <div class="form-group row"> @@ -175,7 +175,11 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> { </div> <div class="form-group row"> <div class="col-12"> - <button type="submit" class="btn btn-secondary mr-2"> + <button + type="submit" + class="btn btn-secondary mr-2" + disabled={this.state.loading} + > {this.state.loading ? ( <svg class="icon icon-spinner spin"> <use xlinkHref="#icon-spinner"></use> diff --git a/ui/src/components/user-listing.tsx b/ui/src/components/user-listing.tsx index 903aa1a7..0e150b94 100644 --- a/ui/src/components/user-listing.tsx +++ b/ui/src/components/user-listing.tsx @@ -1,7 +1,7 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; import { UserView } from '../interfaces'; -import { pictshareAvatarThumbnail, showAvatars, hostname } from '../utils'; +import { pictrsAvatarThumbnail, showAvatars, hostname } from '../utils'; interface UserOther { name: string; @@ -40,7 +40,7 @@ export class UserListing extends Component<UserListingProps, any> { <img height="32" width="32" - src={pictshareAvatarThumbnail(user.avatar)} + src={pictrsAvatarThumbnail(user.avatar)} class="rounded-circle mr-2" /> )} diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index 78807153..f635a1cd 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.tsx @@ -927,7 +927,7 @@ export class User extends Component<any, UserState> { handleUserSettingsThemeChange(i: User, event: any) { i.state.userSettingsForm.theme = event.target.value; - setTheme(event.target.value); + setTheme(event.target.value, true); i.setState(i.state); } @@ -993,9 +993,9 @@ export class User extends Component<any, UserState> { handleImageUpload(i: User, event: any) { event.preventDefault(); let file = event.target.files[0]; - const imageUploadUrl = `/pictshare/api/upload.php`; + const imageUploadUrl = `/pictrs/image`; const formData = new FormData(); - formData.append('file', file); + formData.append('images[]', file); i.state.avatarLoading = true; i.setState(i.state); @@ -1006,14 +1006,19 @@ export class User extends Component<any, UserState> { }) .then(res => res.json()) .then(res => { - let url = `${window.location.origin}/pictshare/${res.url}`; - if (res.filetype == 'mp4') { - url += '/raw'; + console.log('pictrs upload:'); + console.log(res); + if (res.msg == 'ok') { + let hash = res.files[0].file; + let url = `${window.location.origin}/pictrs/image/${hash}`; + i.state.userSettingsForm.avatar = url; + i.state.avatarLoading = false; + i.setState(i.state); + } else { + i.state.avatarLoading = false; + i.setState(i.state); + toast(JSON.stringify(res), 'danger'); } - i.state.userSettingsForm.avatar = url; - console.log(url); - i.state.avatarLoading = false; - i.setState(i.state); }) .catch(error => { i.state.avatarLoading = false; |