Add image loading indicator.

This commit is contained in:
Dessalines 2019-09-08 09:54:53 -07:00
parent a279cfad95
commit 461ae5d790
4 changed files with 46 additions and 9 deletions

View File

@ -1,7 +1,7 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { CommentNode as CommentNodeI, CommentForm as CommentFormI, SearchForm, SearchType, SortType, UserOperation, SearchResponse } from '../interfaces'; import { CommentNode as CommentNodeI, CommentForm as CommentFormI, SearchForm, SearchType, SortType, UserOperation, SearchResponse } from '../interfaces';
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { capitalizeFirstLetter, mentionDropdownFetchLimit, msgOp, mdToHtml, randomStr, imageUploadUrl, markdownHelpUrl } from '../utils'; import { capitalizeFirstLetter, mentionDropdownFetchLimit, msgOp, mdToHtml, randomStr, markdownHelpUrl } from '../utils';
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from '../services';
import * as autosize from 'autosize'; import * as autosize from 'autosize';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
@ -21,6 +21,7 @@ interface CommentFormState {
commentForm: CommentFormI; commentForm: CommentFormI;
buttonTitle: string; buttonTitle: string;
previewMode: boolean; previewMode: boolean;
imageLoading: boolean;
} }
export class CommentForm extends Component<CommentFormProps, CommentFormState> { export class CommentForm extends Component<CommentFormProps, CommentFormState> {
@ -38,6 +39,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('reply')), buttonTitle: !this.props.node ? capitalizeFirstLetter(i18n.t('post')) : this.props.edit ? capitalizeFirstLetter(i18n.t('edit')) : capitalizeFirstLetter(i18n.t('reply')),
previewMode: false, previewMode: false,
imageLoading: false,
} }
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -134,12 +136,15 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
{this.state.commentForm.content && {this.state.commentForm.content &&
<button className={`btn btn-sm mr-2 btn-secondary ${this.state.previewMode && 'active'}`} onClick={linkEvent(this, this.handlePreviewToggle)}><T i18nKey="preview">#</T></button> <button className={`btn btn-sm mr-2 btn-secondary ${this.state.previewMode && 'active'}`} onClick={linkEvent(this, this.handlePreviewToggle)}><T i18nKey="preview">#</T></button>
} }
{this.props.node && <button type="button" class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.handleReplyCancel)}><T i18nKey="cancel">#</T></button>} {this.props.node && <button type="button" class="btn btn-sm btn-secondary mr-2" onClick={linkEvent(this, this.handleReplyCancel)}><T i18nKey="cancel">#</T></button>}
<a href={markdownHelpUrl} target="_blank" class="d-inline-block float-right text-muted small font-weight-bold"><T i18nKey="formatting_help">#</T></a> <a href={markdownHelpUrl} target="_blank" class="d-inline-block float-right text-muted small font-weight-bold"><T i18nKey="formatting_help">#</T></a>
<form class="d-inline-block mr-2 float-right text-muted small font-weight-bold"> <form class="d-inline-block mr-2 float-right text-muted small font-weight-bold">
<label htmlFor={`file-upload-${this.id}`} class="pointer"><T i18nKey="upload_image">#</T></label> <label htmlFor={`file-upload-${this.id}`} class="pointer"><T i18nKey="upload_image">#</T></label>
<input id={`file-upload-${this.id}`} type="file" name="file" class="d-none" onChange={linkEvent(this, this.handleImageUpload)} /> <input id={`file-upload-${this.id}`} type="file" accept="image/*,video/*" name="file" class="d-none" onChange={linkEvent(this, this.handleImageUpload)} />
</form> </form>
{this.state.imageLoading &&
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg>
}
</div> </div>
</div> </div>
</form> </form>
@ -187,6 +192,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
const imageUploadUrl = `/pictshare/api/upload.php`; const imageUploadUrl = `/pictshare/api/upload.php`;
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
i.state.imageLoading = true;
i.setState(i.state);
fetch(imageUploadUrl, { fetch(imageUploadUrl, {
method: 'POST', method: 'POST',
body: formData, body: formData,
@ -198,9 +207,14 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
let content = i.state.commentForm.content; let content = i.state.commentForm.content;
content = (content) ? `${content} ${markdown}` : markdown; content = (content) ? `${content} ${markdown}` : markdown;
i.state.commentForm.content = content; i.state.commentForm.content = content;
i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
}) })
.catch((error) => alert(error)); .catch((error) => {
i.state.imageLoading = false;
i.setState(i.state);
alert(error);
})
} }
userSearch(text: string, cb: any) { userSearch(text: string, cb: any) {

View File

@ -4,7 +4,7 @@ import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators'; import { retryWhen, delay, take } from 'rxjs/operators';
import { PostForm as PostFormI, PostFormParams, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse, ListCommunitiesForm, SortType, SearchForm, SearchType, SearchResponse } from '../interfaces'; import { PostForm as PostFormI, PostFormParams, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse, ListCommunitiesForm, SortType, SearchForm, SearchType, SearchResponse } from '../interfaces';
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from '../services';
import { msgOp, getPageTitle, debounce, validURL, capitalizeFirstLetter, imageUploadUrl, markdownHelpUrl, mdToHtml } from '../utils'; import { msgOp, getPageTitle, debounce, validURL, capitalizeFirstLetter, markdownHelpUrl, mdToHtml } from '../utils';
import * as autosize from 'autosize'; import * as autosize from 'autosize';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { T } from 'inferno-i18next'; import { T } from 'inferno-i18next';
@ -21,6 +21,7 @@ interface PostFormState {
postForm: PostFormI; postForm: PostFormI;
communities: Array<Community>; communities: Array<Community>;
loading: boolean; loading: boolean;
imageLoading: boolean;
previewMode: boolean; previewMode: boolean;
suggestedTitle: string; suggestedTitle: string;
suggestedPosts: Array<Post>; suggestedPosts: Array<Post>;
@ -40,6 +41,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
}, },
communities: [], communities: [],
loading: false, loading: false,
imageLoading: false,
previewMode: false, previewMode: false,
suggestedTitle: undefined, suggestedTitle: undefined,
suggestedPosts: [], suggestedPosts: [],
@ -111,8 +113,11 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
} }
<form> <form>
<label htmlFor="file-upload" class="pointer d-inline-block mr-2 float-right text-muted small font-weight-bold"><T i18nKey="upload_image">#</T></label> <label htmlFor="file-upload" class="pointer d-inline-block mr-2 float-right text-muted small font-weight-bold"><T i18nKey="upload_image">#</T></label>
<input id="file-upload" type="file" name="file" class="d-none" onChange={linkEvent(this, this.handleImageUpload)} /> <input id="file-upload" type="file" accept="image/*,video/*" name="file" class="d-none" onChange={linkEvent(this, this.handleImageUpload)} />
</form> </form>
{this.state.imageLoading &&
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg>
}
{this.state.crossPosts.length > 0 && {this.state.crossPosts.length > 0 &&
<> <>
<div class="my-1 text-muted small font-weight-bold"><T i18nKey="cross_posts">#</T></div> <div class="my-1 text-muted small font-weight-bold"><T i18nKey="cross_posts">#</T></div>
@ -275,6 +280,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
const imageUploadUrl = `/pictshare/api/upload.php`; const imageUploadUrl = `/pictshare/api/upload.php`;
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
i.state.imageLoading = true;
i.setState(i.state);
fetch(imageUploadUrl, { fetch(imageUploadUrl, {
method: 'POST', method: 'POST',
body: formData, body: formData,
@ -285,11 +294,15 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
if (res.filetype == 'mp4') { if (res.filetype == 'mp4') {
url += '/raw'; url += '/raw';
} }
i.state.postForm.url = url; i.state.postForm.url = url;
i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
}) })
.catch((error) => alert(error)); .catch((error) => {
i.state.imageLoading = false;
i.setState(i.state);
alert(error);
})
} }
parseMessage(msg: any) { parseMessage(msg: any) {

1
ui/src/utils.ts vendored
View File

@ -15,7 +15,6 @@ import * as twemoji from 'twemoji';
import * as emojiShortName from 'emoji-short-name'; import * as emojiShortName from 'emoji-short-name';
export const repoUrl = 'https://github.com/dessalines/lemmy'; export const repoUrl = 'https://github.com/dessalines/lemmy';
export const imageUploadUrl = 'https://postimages.org/';
export const markdownHelpUrl = 'https://commonmark.org/help/'; export const markdownHelpUrl = 'https://commonmark.org/help/';
export const fetchLimit: number = 20; export const fetchLimit: number = 20;

11
ui/tmp vendored Normal file
View File

@ -0,0 +1,11 @@
lang | done | missing
--- | --- | ---
de | 86% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,settings,banned,subscribed,expires,recent_comments,nsfw,show_nsfw,crypto,monero,joined,by,to,transfer_community,transfer_site,are_you_sure,yes,no
eo | 95% | number_of_communities,preview,upload_image,formatting_help,banned,are_you_sure,yes,no
es | 95% | number_of_communities,preview,upload_image,formatting_help,banned,are_you_sure,yes,no
fr | 100% |
nl | 98% | preview,upload_image,formatting_help,banned
ru | 91% | cross_posts,cross_post,number_of_communities,preview,upload_image,formatting_help,banned,recent_comments,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
sv | 98% | preview,upload_image,formatting_help,banned
zh | 89% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,settings,banned,recent_comments,nsfw,show_nsfw,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no