]> Untitled Git - lemmy-ui.git/commitdiff
Create community, Create post, and instances pages done.
authorDessalines <tyhou13@gmx.com>
Mon, 7 Sep 2020 22:24:48 +0000 (17:24 -0500)
committerDessalines <tyhou13@gmx.com>
Mon, 7 Sep 2020 22:24:48 +0000 (17:24 -0500)
src/shared/components/communities.tsx
src/shared/components/community-form.tsx
src/shared/components/create-community.tsx
src/shared/components/create-post.tsx
src/shared/components/instances.tsx
src/shared/components/markdown-textarea.tsx
src/shared/components/post-form.tsx
src/shared/routes.ts
src/shared/utils.ts

index a6b972646db5ef41a0b89190118169b8059f7924..d04020d498b3fc9f6dd88d0b5501aea51d127c4e 100644 (file)
@@ -52,13 +52,16 @@ export class Communities extends Component<any, CommunitiesState> {
   constructor(props: any, context: any) {
     super(props, context);
     this.state = this.emptyState;
-    this.parseMessage = this.parseMessage.bind(this);
 
+    this.parseMessage = this.parseMessage.bind(this);
     this.subscription = wsSubscribe(this.parseMessage);
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
       this.state.communities = this.isoData.routeData[0].communities;
+      this.state.communities.sort(
+        (a, b) => b.number_of_subscribers - a.number_of_subscribers
+      );
       this.state.loading = false;
     } else {
       this.refetch();
index 6fa72ec1b7ef646e6742940817da4d48c7f65162..301a9eb1ce3dbca4aa39d4e403aea5972086f75d 100644 (file)
@@ -6,7 +6,6 @@ import {
   CommunityForm as CommunityFormI,
   UserOperation,
   Category,
-  ListCategoriesResponse,
   CommunityResponse,
   WebSocketJsonResponse,
   Community,
@@ -20,6 +19,7 @@ import { ImageUploadForm } from './image-upload-form';
 
 interface CommunityFormProps {
   community?: Community; // If a community is given, that means this is an edit
+  categories: Category[];
   onCancel?(): any;
   onCreate?(community: Community): any;
   onEdit?(community: Community): any;
@@ -28,7 +28,6 @@ interface CommunityFormProps {
 
 interface CommunityFormState {
   communityForm: CommunityFormI;
-  categories: Category[];
   loading: boolean;
 }
 
@@ -43,12 +42,11 @@ export class CommunityForm extends Component<
     communityForm: {
       name: null,
       title: null,
-      category_id: null,
+      category_id: this.props.categories[0].id,
       nsfw: false,
       icon: null,
       banner: null,
     },
-    categories: [],
     loading: false,
   };
 
@@ -88,8 +86,6 @@ export class CommunityForm extends Component<
         err => console.error(err),
         () => console.log('complete')
       );
-
-    WebSocketService.Instance.listCategories();
   }
 
   componentDidUpdate() {
@@ -218,7 +214,7 @@ export class CommunityForm extends Component<
                 value={this.state.communityForm.category_id}
                 onInput={linkEvent(this, this.handleCommunityCategoryChange)}
               >
-                {this.state.categories.map(category => (
+                {this.props.categories.map(category => (
                   <option value={category.id}>{category.name}</option>
                 ))}
               </select>
@@ -344,13 +340,6 @@ export class CommunityForm extends Component<
       this.state.loading = false;
       this.setState(this.state);
       return;
-    } else if (res.op == UserOperation.ListCategories) {
-      let data = res.data as ListCategoriesResponse;
-      this.state.categories = data.categories;
-      if (!this.props.community) {
-        this.state.communityForm.category_id = data.categories[0].id;
-      }
-      this.setState(this.state);
     } else if (res.op == UserOperation.CreateCommunity) {
       let data = res.data as CommunityResponse;
       this.state.loading = false;
index 6f156211d34be49fb5bc1c80b30ef781f8f14410..07680b5d8c5d22edcbc55efd086febb233d2126a 100644 (file)
@@ -1,87 +1,95 @@
 import { Component } from 'inferno';
 import { Helmet } from 'inferno-helmet';
 import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
 import { CommunityForm } from './community-form';
 import {
   Community,
   UserOperation,
   WebSocketJsonResponse,
-  GetSiteResponse,
   Site,
+  ListCategoriesResponse,
+  Category,
 } from 'lemmy-js-client';
-import { toast, wsJsonToRes } from '../utils';
+import {
+  setIsoData,
+  toast,
+  wsJsonToRes,
+  wsSubscribe,
+  isBrowser,
+  lemmyHttp,
+} from '../utils';
 import { WebSocketService, UserService } from '../services';
 import { i18n } from '../i18next';
 
 interface CreateCommunityState {
   site: Site;
+  categories: Category[];
+  loading: boolean;
 }
 
 export class CreateCommunity extends Component<any, CreateCommunityState> {
+  private isoData = setIsoData(this.context);
   private subscription: Subscription;
   private emptyState: CreateCommunityState = {
-    site: {
-      id: undefined,
-      name: undefined,
-      creator_id: undefined,
-      published: undefined,
-      creator_name: undefined,
-      number_of_users: undefined,
-      number_of_posts: undefined,
-      number_of_comments: undefined,
-      number_of_communities: undefined,
-      enable_downvotes: undefined,
-      open_registration: undefined,
-      enable_nsfw: undefined,
-    },
+    site: this.isoData.site.site,
+    categories: [],
+    loading: true,
   };
   constructor(props: any, context: any) {
     super(props, context);
     this.handleCommunityCreate = this.handleCommunityCreate.bind(this);
     this.state = this.emptyState;
 
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
+    // TODO not sure if this works
     if (!UserService.Instance.user) {
       toast(i18n.t('not_logged_in'), 'danger');
       this.context.router.history.push(`/login`);
     }
 
-    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')
-      );
-
-    WebSocketService.Instance.getSite();
+    // Only fetch the data if coming from another route
+    if (this.isoData.path == this.context.router.route.match.url) {
+      this.state.categories = this.isoData.routeData[0].categories;
+      this.state.loading = false;
+    } else {
+      WebSocketService.Instance.listCategories();
+    }
   }
 
   componentWillUnmount() {
-    this.subscription.unsubscribe();
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
   }
 
   get documentTitle(): string {
-    if (this.state.site.name) {
-      return `${i18n.t('create_community')} - ${this.state.site.name}`;
-    } else {
-      return 'Lemmy';
-    }
+    return `${i18n.t('create_community')} - ${this.state.site.name}`;
   }
 
   render() {
     return (
       <div class="container">
         <Helmet title={this.documentTitle} />
-        <div class="row">
-          <div class="col-12 col-lg-6 offset-lg-3 mb-4">
-            <h5>{i18n.t('create_community')}</h5>
-            <CommunityForm
-              onCreate={this.handleCommunityCreate}
-              enableNsfw={this.state.site.enable_nsfw}
-            />
+        {this.state.loading ? (
+          <h5>
+            <svg class="icon icon-spinner spin">
+              <use xlinkHref="#icon-spinner"></use>
+            </svg>
+          </h5>
+        ) : (
+          <div class="row">
+            <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+              <h5>{i18n.t('create_community')}</h5>
+              <CommunityForm
+                categories={this.state.categories}
+                onCreate={this.handleCommunityCreate}
+                enableNsfw={this.state.site.enable_nsfw}
+              />
+            </div>
           </div>
-        </div>
+        )}
       </div>
     );
   }
@@ -90,15 +98,20 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
     this.props.history.push(`/c/${community.name}`);
   }
 
+  static fetchInitialData(_auth: string, _path: string): Promise<any>[] {
+    return [lemmyHttp.listCategories()];
+  }
+
   parseMessage(msg: WebSocketJsonResponse) {
     console.log(msg);
     let res = wsJsonToRes(msg);
     if (msg.error) {
       // Toast errors are already handled by community-form
       return;
-    } else if (res.op == UserOperation.GetSite) {
-      let data = res.data as GetSiteResponse;
-      this.state.site = data.site;
+    } else if (res.op == UserOperation.ListCategories) {
+      let data = res.data as ListCategoriesResponse;
+      this.state.categories = data.categories;
+      this.state.loading = false;
       this.setState(this.state);
     }
   }
index f4c03b653ecd72659137a86fe03b8398f5381e14..fc759d0f08b67948db9d769dd2cb4649daae9640 100644 (file)
@@ -1,40 +1,41 @@
 import { Component } from 'inferno';
 import { Helmet } from 'inferno-helmet';
 import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
 import { PostForm } from './post-form';
-import { toast, wsJsonToRes } from '../utils';
-import { WebSocketService, UserService } from '../services';
+import {
+  lemmyHttp,
+  setAuth,
+  setIsoData,
+  toast,
+  wsJsonToRes,
+  wsSubscribe,
+} from '../utils';
+import { UserService, WebSocketService } from '../services';
 import {
   UserOperation,
   PostFormParams,
   WebSocketJsonResponse,
-  GetSiteResponse,
+  ListCommunitiesResponse,
+  Community,
   Site,
+  ListCommunitiesForm,
+  SortType,
 } from 'lemmy-js-client';
 import { i18n } from '../i18next';
 
 interface CreatePostState {
   site: Site;
+  communities: Community[];
+  loading: boolean;
 }
 
 export class CreatePost extends Component<any, CreatePostState> {
+  private isoData = setIsoData(this.context);
   private subscription: Subscription;
   private emptyState: CreatePostState = {
-    site: {
-      id: undefined,
-      name: undefined,
-      creator_id: undefined,
-      published: undefined,
-      creator_name: undefined,
-      number_of_users: undefined,
-      number_of_posts: undefined,
-      number_of_comments: undefined,
-      number_of_communities: undefined,
-      enable_downvotes: undefined,
-      open_registration: undefined,
-      enable_nsfw: undefined,
-    },
+    site: this.isoData.site.site,
+    communities: [],
+    loading: true,
   };
 
   constructor(props: any, context: any) {
@@ -47,15 +48,24 @@ export class CreatePost extends Component<any, CreatePostState> {
       this.context.router.history.push(`/login`);
     }
 
-    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')
-      );
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
+    // Only fetch the data if coming from another route
+    if (this.isoData.path == this.context.router.route.match.url) {
+      this.state.communities = this.isoData.routeData[0].communities;
+      this.state.loading = false;
+    } else {
+      this.refetch();
+    }
+  }
 
-    WebSocketService.Instance.getSite();
+  refetch() {
+    let listCommunitiesForm: ListCommunitiesForm = {
+      sort: SortType.TopAll,
+      limit: 9999,
+    };
+    WebSocketService.Instance.listCommunities(listCommunitiesForm);
   }
 
   componentWillUnmount() {
@@ -63,28 +73,33 @@ export class CreatePost extends Component<any, CreatePostState> {
   }
 
   get documentTitle(): string {
-    if (this.state.site.name) {
-      return `${i18n.t('create_post')} - ${this.state.site.name}`;
-    } else {
-      return 'Lemmy';
-    }
+    return `${i18n.t('create_post')} - ${this.state.site.name}`;
   }
 
   render() {
     return (
       <div class="container">
         <Helmet title={this.documentTitle} />
-        <div class="row">
-          <div class="col-12 col-lg-6 offset-lg-3 mb-4">
-            <h5>{i18n.t('create_post')}</h5>
-            <PostForm
-              onCreate={this.handlePostCreate}
-              params={this.params}
-              enableDownvotes={this.state.site.enable_downvotes}
-              enableNsfw={this.state.site.enable_nsfw}
-            />
+        {this.state.loading ? (
+          <h5>
+            <svg class="icon icon-spinner spin">
+              <use xlinkHref="#icon-spinner"></use>
+            </svg>
+          </h5>
+        ) : (
+          <div class="row">
+            <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+              <h5>{i18n.t('create_post')}</h5>
+              <PostForm
+                communities={this.state.communities}
+                onCreate={this.handlePostCreate}
+                params={this.params}
+                enableDownvotes={this.state.site.enable_downvotes}
+                enableNsfw={this.state.site.enable_nsfw}
+              />
+            </div>
           </div>
-        </div>
+        )}
       </div>
     );
   }
@@ -110,22 +125,32 @@ export class CreatePost extends Component<any, CreatePostState> {
         return lastLocation.split('/c/')[1];
       }
     }
-    return;
+    return null;
   }
 
   handlePostCreate(id: number) {
     this.props.history.push(`/post/${id}`);
   }
 
+  static fetchInitialData(auth: string, _path: string): Promise<any>[] {
+    let listCommunitiesForm: ListCommunitiesForm = {
+      sort: SortType.TopAll,
+      limit: 9999,
+    };
+    setAuth(listCommunitiesForm, auth);
+    return [lemmyHttp.listCommunities(listCommunitiesForm)];
+  }
+
   parseMessage(msg: WebSocketJsonResponse) {
     console.log(msg);
     let res = wsJsonToRes(msg);
     if (msg.error) {
       toast(i18n.t(msg.error), 'danger');
       return;
-    } else if (res.op == UserOperation.GetSite) {
-      let data = res.data as GetSiteResponse;
-      this.state.site = data.site;
+    } else if (res.op == UserOperation.ListCommunities) {
+      let data = res.data as ListCommunitiesResponse;
+      this.state.communities = data.communities;
+      this.state.loading = false;
       this.setState(this.state);
     }
   }
index c54b3718910d7a5d638bb6d6d774a71a15087e17..0929761d260383a03badf40aeec9816a6c8a6311 100644 (file)
 import { Component } from 'inferno';
 import { Helmet } from 'inferno-helmet';
-import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
-import {
-  UserOperation,
-  WebSocketJsonResponse,
-  GetSiteResponse,
-} from 'lemmy-js-client';
-import { WebSocketService } from '../services';
-import { wsJsonToRes, toast, isBrowser } from '../utils';
+import { GetSiteResponse } from 'lemmy-js-client';
+import { setIsoData } from '../utils';
 import { i18n } from '../i18next';
 
 interface InstancesState {
-  loading: boolean;
   siteRes: GetSiteResponse;
 }
 
 export class Instances extends Component<any, InstancesState> {
-  private subscription: Subscription;
+  private isoData = setIsoData(this.context);
   private emptyState: InstancesState = {
-    loading: true,
-    siteRes: undefined,
+    siteRes: this.isoData.site,
   };
 
   constructor(props: any, context: any) {
     super(props, context);
     this.state = this.emptyState;
-
-    if (isBrowser()) {
-      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')
-        );
-
-      WebSocketService.Instance.getSite();
-    }
-  }
-
-  componentWillUnmount() {
-    this.subscription.unsubscribe();
   }
 
   get documentTitle(): string {
-    if (this.state.siteRes) {
-      return `${i18n.t('instances')} - ${this.state.siteRes.site.name}`;
-    } else {
-      return 'Lemmy';
-    }
+    return `${i18n.t('instances')} - ${this.state.siteRes.site.name}`;
   }
 
   render() {
     return (
       <div class="container">
         <Helmet title={this.documentTitle} />
-        {this.state.loading ? (
-          <h5 class="">
-            <svg class="icon icon-spinner spin">
-              <use xlinkHref="#icon-spinner"></use>
-            </svg>
-          </h5>
-        ) : (
-          <div>
-            <h5>{i18n.t('linked_instances')}</h5>
-            {this.state.siteRes &&
-            this.state.siteRes.federated_instances.length ? (
-              <ul>
-                {this.state.siteRes.federated_instances.map(i => (
-                  <li>
-                    <a href={`https://${i}`} target="_blank" rel="noopener">
-                      {i}
-                    </a>
-                  </li>
-                ))}
-              </ul>
-            ) : (
-              <div>{i18n.t('none_found')}</div>
-            )}
-          </div>
-        )}
+        <div>
+          <h5>{i18n.t('linked_instances')}</h5>
+          {this.state.siteRes &&
+          this.state.siteRes.federated_instances.length ? (
+            <ul>
+              {this.state.siteRes.federated_instances.map(i => (
+                <li>
+                  <a href={`https://${i}`} target="_blank" rel="noopener">
+                    {i}
+                  </a>
+                </li>
+              ))}
+            </ul>
+          ) : (
+            <div>{i18n.t('none_found')}</div>
+          )}
+        </div>
       </div>
     );
   }
-
-  parseMessage(msg: WebSocketJsonResponse) {
-    console.log(msg);
-    let res = wsJsonToRes(msg);
-    if (msg.error) {
-      toast(i18n.t(msg.error), 'danger');
-      return;
-    } else if (res.op == UserOperation.GetSite) {
-      let data = res.data as GetSiteResponse;
-      this.state.siteRes = data;
-      this.state.loading = false;
-      this.setState(this.state);
-    }
-  }
 }
index 1faa8a9d745f25425c8e7755c19d434077dc594b..c566c2ef8839b07e1fe3e6ce4abe5e60cb2f7f04 100644 (file)
@@ -8,10 +8,10 @@ import {
   setupTribute,
   pictrsDeleteToast,
   setupTippy,
+  isBrowser,
 } from '../utils';
 import { UserService } from '../services';
 import autosize from 'autosize';
-import Tribute from 'tributejs/src/Tribute.js';
 import { i18n } from '../i18next';
 
 interface MarkdownTextAreaProps {
@@ -41,7 +41,7 @@ export class MarkdownTextArea extends Component<
 > {
   private id = `comment-textarea-${randomStr()}`;
   private formId = `comment-form-${randomStr()}`;
-  private tribute: Tribute;
+  private tribute: any;
   private emptyState: MarkdownTextAreaState = {
     content: this.props.initialContent,
     previewMode: false,
@@ -52,8 +52,9 @@ export class MarkdownTextArea extends Component<
   constructor(props: any, context: any) {
     super(props, context);
 
-    // TODO
-    /* this.tribute = setupTribute(); */
+    if (isBrowser()) {
+      this.tribute = setupTribute();
+    }
     this.state = this.emptyState;
   }
 
index 8e34c6d86c646b4b279c40914c9a0e1efb1a7fb0..ac6ad3b020c2e0bc7b725a39a7dbdaac696ce6ab 100644 (file)
@@ -3,7 +3,6 @@ import { Prompt } from 'inferno-router';
 import { PostListings } from './post-listings';
 import { MarkdownTextArea } from './markdown-textarea';
 import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
 import {
   PostForm as PostFormI,
   PostFormParams,
@@ -11,8 +10,6 @@ import {
   PostResponse,
   UserOperation,
   Community,
-  ListCommunitiesResponse,
-  ListCommunitiesForm,
   SortType,
   SearchForm,
   SearchType,
@@ -34,14 +31,22 @@ import {
   hostname,
   pictrsDeleteToast,
   validTitle,
+  wsSubscribe,
+  isBrowser,
 } from '../utils';
-import Choices from 'choices.js';
+
+var Choices;
+if (isBrowser()) {
+  Choices = require('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
+  communities: Community[];
   params?: PostFormParams;
   onCancel?(): any;
   onCreate?(id: number): any;
@@ -52,7 +57,6 @@ interface PostFormProps {
 
 interface PostFormState {
   postForm: PostFormI;
-  communities: Community[];
   loading: boolean;
   imageLoading: boolean;
   previewMode: boolean;
@@ -64,7 +68,7 @@ interface PostFormState {
 export class PostForm extends Component<PostFormProps, PostFormState> {
   private id = `post-form-${randomStr()}`;
   private subscription: Subscription;
-  private choices: Choices;
+  private choices: any;
   private emptyState: PostFormState = {
     postForm: {
       name: null,
@@ -72,7 +76,6 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
       auth: null,
       community_id: null,
     },
-    communities: [],
     loading: false,
     imageLoading: false,
     previewMode: false,
@@ -112,24 +115,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
       }
     }
 
-    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.TopAll,
-      limit: 9999,
-    };
-
-    WebSocketService.Instance.listCommunities(listCommunitiesForm);
+    this.subscription = wsSubscribe(this.parseMessage);
   }
 
   componentDidMount() {
     setupTippy();
+    this.setupCommunities();
   }
 
   componentDidUpdate() {
@@ -209,7 +200,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
                   onChange={linkEvent(this, this.handleImageUpload)}
                 />
               </form>
-              {validURL(this.state.postForm.url) && (
+              {this.state.postForm.url && validURL(this.state.postForm.url) && (
                 <a
                   href={`${archiveUrl}/?run=1&url=${encodeURIComponent(
                     this.state.postForm.url
@@ -305,7 +296,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
                   onInput={linkEvent(this, this.handlePostCommunityChange)}
                 >
                   <option>{i18n.t('select_a_community')}</option>
-                  {this.state.communities.map(community => (
+                  {this.props.communities.map(community => (
                     <option value={community.id}>
                       {community.local
                         ? community.name
@@ -531,63 +522,53 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
       });
   }
 
-  parseMessage(msg: WebSocketJsonResponse) {
-    let res = wsJsonToRes(msg);
-    if (msg.error) {
-      toast(i18n.t(msg.error), 'danger');
-      this.state.loading = false;
-      this.setState(this.state);
-      return;
-    } else if (res.op == UserOperation.ListCommunities) {
-      let data = res.data as ListCommunitiesResponse;
-      this.state.communities = data.communities;
-      if (this.props.post) {
-        this.state.postForm.community_id = this.props.post.community_id;
-      } else if (this.props.params && this.props.params.community) {
-        let foundCommunityId = data.communities.find(
-          r => r.name == this.props.params.community
-        ).id;
-        this.state.postForm.community_id = foundCommunityId;
-      } else {
-        // By default, the null valued 'Select a Community'
-      }
-      this.setState(this.state);
+  setupCommunities() {
+    if (this.props.post) {
+      this.state.postForm.community_id = this.props.post.community_id;
+    } else if (this.props.params && this.props.params.community) {
+      let foundCommunityId = this.props.communities.find(
+        r => r.name == this.props.params.community
+      ).id;
+      this.state.postForm.community_id = foundCommunityId;
+    } else {
+      // By default, the null valued 'Select a Community'
+    }
 
-      // Set up select searching
+    // Set up select searching
+    if (isBrowser()) {
       let selectId: any = document.getElementById('post-community');
       if (selectId) {
-        // TODO
-        /* this.choices = new Choices(selectId, { */
-        /*   shouldSort: false, */
-        /*   classNames: { */
-        /*     containerOuter: 'choices', */
-        /*     containerInner: 'choices__inner bg-secondary border-0', */
-        /*     input: 'form-control', */
-        /*     inputCloned: 'choices__input--cloned', */
-        /*     list: 'choices__list', */
-        /*     listItems: 'choices__list--multiple', */
-        /*     listSingle: 'choices__list--single', */
-        /*     listDropdown: 'choices__list--dropdown', */
-        /*     item: 'choices__item bg-secondary', */
-        /*     itemSelectable: 'choices__item--selectable', */
-        /*     itemDisabled: 'choices__item--disabled', */
-        /*     itemChoice: 'choices__item--choice', */
-        /*     placeholder: 'choices__placeholder', */
-        /*     group: 'choices__group', */
-        /*     groupHeading: 'choices__heading', */
-        /*     button: 'choices__button', */
-        /*     activeState: 'is-active', */
-        /*     focusState: 'is-focused', */
-        /*     openState: 'is-open', */
-        /*     disabledState: 'is-disabled', */
-        /*     highlightedState: 'text-info', */
-        /*     selectedState: 'text-info', */
-        /*     flippedState: 'is-flipped', */
-        /*     loadingState: 'is-loading', */
-        /*     noResults: 'has-no-results', */
-        /*     noChoices: 'has-no-choices', */
-        /*   }, */
-        /* }); */
+        this.choices = new Choices(selectId, {
+          shouldSort: false,
+          classNames: {
+            containerOuter: 'choices',
+            containerInner: 'choices__inner bg-secondary border-0',
+            input: 'form-control',
+            inputCloned: 'choices__input--cloned',
+            list: 'choices__list',
+            listItems: 'choices__list--multiple',
+            listSingle: 'choices__list--single',
+            listDropdown: 'choices__list--dropdown',
+            item: 'choices__item bg-secondary',
+            itemSelectable: 'choices__item--selectable',
+            itemDisabled: 'choices__item--disabled',
+            itemChoice: 'choices__item--choice',
+            placeholder: 'choices__placeholder',
+            group: 'choices__group',
+            groupHeading: 'choices__heading',
+            button: 'choices__button',
+            activeState: 'is-active',
+            focusState: 'is-focused',
+            openState: 'is-open',
+            disabledState: 'is-disabled',
+            highlightedState: 'text-info',
+            selectedState: 'text-info',
+            flippedState: 'is-flipped',
+            loadingState: 'is-loading',
+            noResults: 'has-no-results',
+            noChoices: 'has-no-choices',
+          },
+        });
         this.choices.passedElement.element.addEventListener(
           'choice',
           (e: any) => {
@@ -597,6 +578,16 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
           false
         );
       }
+    }
+  }
+
+  parseMessage(msg: WebSocketJsonResponse) {
+    let res = wsJsonToRes(msg);
+    if (msg.error) {
+      toast(i18n.t(msg.error), 'danger');
+      this.state.loading = false;
+      this.setState(this.state);
+      return;
     } else if (res.op == UserOperation.CreatePost) {
       let data = res.data as PostResponse;
       if (data.post.creator_id == UserService.Instance.user.id) {
index 778d0ff5ffb15c484f3fb34b3de10866c213ca51..2b3eb757f9806ae863367ab99242791c0f9f826f 100644 (file)
@@ -28,8 +28,17 @@ export const routes: IRoutePropsWithFetch[] = [
     component: Main,
   },
   { path: `/login`, component: Login },
-  { path: `/create_post`, component: CreatePost },
-  { path: `/create_community`, component: CreateCommunity },
+  {
+    path: `/create_post`,
+    component: CreatePost,
+    fetchInitialData: (auth, path) => CreatePost.fetchInitialData(auth, path),
+  },
+  {
+    path: `/create_community`,
+    component: CreateCommunity,
+    fetchInitialData: (auth, path) =>
+      CreateCommunity.fetchInitialData(auth, path),
+  },
   {
     path: `/create_private_message`,
     component: CreatePrivateMessage,
index e93c2f8c3bc84f351d54d5aee5853c324d5fdce8..315b0e98de66448c731976e57bc8afab2b407d33 100644 (file)
@@ -50,7 +50,10 @@ import { httpUri } from './env';
 import { CommentSortType, DataType, IsoData } from './interfaces';
 import { UserService, WebSocketService } from './services';
 
-// import Tribute from 'tributejs';
+var Tribute;
+if (isBrowser()) {
+  Tribute = require('tributejs');
+}
 import markdown_it from 'markdown-it';
 import markdown_it_sub from 'markdown-it-sub';
 import markdown_it_sup from 'markdown-it-sup';
@@ -266,6 +269,7 @@ export function isVideo(url: string) {
 
 // TODO this broke
 export function validURL(str: string) {
+  console.log(str);
   // try {
   return !!new URL(str);
   // } catch {
@@ -648,71 +652,71 @@ function notify(info: NotifyInfo, router: any) {
   }
 }
 
-// export function setupTribute(): Tribute<{}> {
-//   return new Tribute({
-//     noMatchTemplate: function () {
-//       return '';
-//     },
-//     collection: [
-//       // Emojis
-//       {
-//         trigger: ':',
-//         menuItemTemplate: (item: any) => {
-//           let shortName = `:${item.original.key}:`;
-//           return `${item.original.val} ${shortName}`;
-//         },
-//         selectTemplate: (item: any) => {
-//           return `:${item.original.key}:`;
-//         },
-//         values: Object.entries(emojiShortName).map(e => {
-//           return { key: e[1], val: e[0] };
-//         }),
-//         allowSpaces: false,
-//         autocompleteMode: true,
-//         // TODO
-//         // menuItemLimit: mentionDropdownFetchLimit,
-//         menuShowMinLength: 2,
-//       },
-//       // Users
-//       {
-//         trigger: '@',
-//         selectTemplate: (item: any) => {
-//           let link = item.original.local
-//             ? `[${item.original.key}](/u/${item.original.name})`
-//             : `[${item.original.key}](/user/${item.original.id})`;
-//           return link;
-//         },
-//         values: (text: string, cb: any) => {
-//           userSearch(text, (users: any) => cb(users));
-//         },
-//         allowSpaces: false,
-//         autocompleteMode: true,
-//         // TODO
-//         // menuItemLimit: mentionDropdownFetchLimit,
-//         menuShowMinLength: 2,
-//       },
-
-//       // Communities
-//       {
-//         trigger: '!',
-//         selectTemplate: (item: any) => {
-//           let link = item.original.local
-//             ? `[${item.original.key}](/c/${item.original.name})`
-//             : `[${item.original.key}](/community/${item.original.id})`;
-//           return link;
-//         },
-//         values: (text: string, cb: any) => {
-//           communitySearch(text, (communities: any) => cb(communities));
-//         },
-//         allowSpaces: false,
-//         autocompleteMode: true,
-//         // TODO
-//         // menuItemLimit: mentionDropdownFetchLimit,
-//         menuShowMinLength: 2,
-//       },
-//     ],
-//   });
-// }
+export function setupTribute() {
+  return new Tribute({
+    noMatchTemplate: function () {
+      return '';
+    },
+    collection: [
+      // Emojis
+      {
+        trigger: ':',
+        menuItemTemplate: (item: any) => {
+          let shortName = `:${item.original.key}:`;
+          return `${item.original.val} ${shortName}`;
+        },
+        selectTemplate: (item: any) => {
+          return `:${item.original.key}:`;
+        },
+        values: Object.entries(emojiShortName).map(e => {
+          return { key: e[1], val: e[0] };
+        }),
+        allowSpaces: false,
+        autocompleteMode: true,
+        // TODO
+        // menuItemLimit: mentionDropdownFetchLimit,
+        menuShowMinLength: 2,
+      },
+      // Users
+      {
+        trigger: '@',
+        selectTemplate: (item: any) => {
+          let link = item.original.local
+            ? `[${item.original.key}](/u/${item.original.name})`
+            : `[${item.original.key}](/user/${item.original.id})`;
+          return link;
+        },
+        values: (text: string, cb: any) => {
+          userSearch(text, (users: any) => cb(users));
+        },
+        allowSpaces: false,
+        autocompleteMode: true,
+        // TODO
+        // menuItemLimit: mentionDropdownFetchLimit,
+        menuShowMinLength: 2,
+      },
+
+      // Communities
+      {
+        trigger: '!',
+        selectTemplate: (item: any) => {
+          let link = item.original.local
+            ? `[${item.original.key}](/c/${item.original.name})`
+            : `[${item.original.key}](/community/${item.original.id})`;
+          return link;
+        },
+        values: (text: string, cb: any) => {
+          communitySearch(text, (communities: any) => cb(communities));
+        },
+        allowSpaces: false,
+        autocompleteMode: true,
+        // TODO
+        // menuItemLimit: mentionDropdownFetchLimit,
+        menuShowMinLength: 2,
+      },
+    ],
+  });
+}
 
 // TODO
 // let tippyInstance = tippy('[data-tippy-content]');