]> Untitled Git - lemmy.git/blobdiff - ui/src/components/site-form.tsx
routes.api: fix get_captcha endpoint (#1135)
[lemmy.git] / ui / src / components / site-form.tsx
index 113e9c66433b42f63ccd8361ab2c09a3820bf572..9b572f57ecd0ed406dbf4498d3198c58e047e5fa 100644 (file)
@@ -1,9 +1,10 @@
 import { Component, linkEvent } from 'inferno';
-import { Site, SiteForm as SiteFormI } from '../interfaces';
+import { Prompt } from 'inferno-router';
+import { MarkdownTextArea } from './markdown-textarea';
+import { ImageUploadForm } from './image-upload-form';
+import { Site, SiteForm as SiteFormI } from 'lemmy-js-client';
 import { WebSocketService } from '../services';
-import { capitalizeFirstLetter, randomStr, setupTribute } from '../utils';
-import autosize from 'autosize';
-import Tribute from 'tributejs/src/Tribute.js';
+import { capitalizeFirstLetter, randomStr } from '../utils';
 import { i18n } from '../i18next';
 
 interface SiteFormProps {
@@ -18,13 +19,14 @@ interface SiteFormState {
 
 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   private id = `site-form-${randomStr()}`;
-  private tribute: Tribute;
   private emptyState: SiteFormState = {
     siteForm: {
       enable_downvotes: true,
       open_registration: true,
       enable_nsfw: true,
       name: null,
+      icon: null,
+      banner: null,
     },
     loading: false,
   };
@@ -32,8 +34,16 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   constructor(props: any, context: any) {
     super(props, context);
 
-    this.tribute = setupTribute();
     this.state = this.emptyState;
+    this.handleSiteDescriptionChange = this.handleSiteDescriptionChange.bind(
+      this
+    );
+
+    this.handleIconUpload = this.handleIconUpload.bind(this);
+    this.handleIconRemove = this.handleIconRemove.bind(this);
+
+    this.handleBannerUpload = this.handleBannerUpload.bind(this);
+    this.handleBannerRemove = this.handleBannerRemove.bind(this);
 
     if (this.props.site) {
       this.state.siteForm = {
@@ -42,140 +52,189 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
         enable_downvotes: this.props.site.enable_downvotes,
         open_registration: this.props.site.open_registration,
         enable_nsfw: this.props.site.enable_nsfw,
+        icon: this.props.site.icon,
+        banner: this.props.site.banner,
       };
     }
   }
 
-  componentDidMount() {
-    var textarea: any = document.getElementById(this.id);
-    autosize(textarea);
-    this.tribute.attach(textarea);
-    textarea.addEventListener('tribute-replaced', () => {
-      this.state.siteForm.description = textarea.value;
-      this.setState(this.state);
-      autosize.update(textarea);
-    });
+  // Necessary to stop the loading
+  componentWillReceiveProps() {
+    this.state.loading = false;
+    this.setState(this.state);
+  }
+
+  componentDidUpdate() {
+    if (
+      !this.state.loading &&
+      !this.props.site &&
+      (this.state.siteForm.name || this.state.siteForm.description)
+    ) {
+      window.onbeforeunload = () => true;
+    } else {
+      window.onbeforeunload = undefined;
+    }
+  }
+
+  componentWillUnmount() {
+    window.onbeforeunload = null;
   }
 
   render() {
     return (
-      <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
-        <h5>{`${
-          this.props.site
-            ? capitalizeFirstLetter(i18n.t('edit'))
-            : capitalizeFirstLetter(i18n.t('name'))
-        } ${i18n.t('your_site')}`}</h5>
-        <div class="form-group row">
-          <label class="col-12 col-form-label" htmlFor="create-site-name">
-            {i18n.t('name')}
-          </label>
-          <div class="col-12">
-            <input
-              type="text"
-              id="create-site-name"
-              class="form-control"
-              value={this.state.siteForm.name}
-              onInput={linkEvent(this, this.handleSiteNameChange)}
-              required
-              minLength={3}
-              maxLength={20}
+      <>
+        <Prompt
+          when={
+            !this.state.loading &&
+            !this.props.site &&
+            (this.state.siteForm.name || this.state.siteForm.description)
+          }
+          message={i18n.t('block_leaving')}
+        />
+        <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
+          <h5>{`${
+            this.props.site
+              ? capitalizeFirstLetter(i18n.t('save'))
+              : capitalizeFirstLetter(i18n.t('name'))
+          } ${i18n.t('your_site')}`}</h5>
+          <div class="form-group row">
+            <label class="col-12 col-form-label" htmlFor="create-site-name">
+              {i18n.t('name')}
+            </label>
+            <div class="col-12">
+              <input
+                type="text"
+                id="create-site-name"
+                class="form-control"
+                value={this.state.siteForm.name}
+                onInput={linkEvent(this, this.handleSiteNameChange)}
+                required
+                minLength={3}
+                maxLength={20}
+              />
+            </div>
+          </div>
+          <div class="form-group">
+            <label>{i18n.t('icon')}</label>
+            <ImageUploadForm
+              uploadTitle={i18n.t('upload_icon')}
+              imageSrc={this.state.siteForm.icon}
+              onUpload={this.handleIconUpload}
+              onRemove={this.handleIconRemove}
+              rounded
             />
           </div>
-        </div>
-        <div class="form-group row">
-          <label class="col-12 col-form-label" htmlFor={this.id}>
-            {i18n.t('sidebar')}
-          </label>
-          <div class="col-12">
-            <textarea
-              id={this.id}
-              value={this.state.siteForm.description}
-              onInput={linkEvent(this, this.handleSiteDescriptionChange)}
-              class="form-control"
-              rows={3}
-              maxLength={10000}
+          <div class="form-group">
+            <label>{i18n.t('banner')}</label>
+            <ImageUploadForm
+              uploadTitle={i18n.t('upload_banner')}
+              imageSrc={this.state.siteForm.banner}
+              onUpload={this.handleBannerUpload}
+              onRemove={this.handleBannerRemove}
             />
           </div>
-        </div>
-        <div class="form-group row">
-          <div class="col-12">
-            <div class="form-check">
-              <input
-                class="form-check-input"
-                id="create-site-downvotes"
-                type="checkbox"
-                checked={this.state.siteForm.enable_downvotes}
-                onChange={linkEvent(this, this.handleSiteEnableDownvotesChange)}
+          <div class="form-group row">
+            <label class="col-12 col-form-label" htmlFor={this.id}>
+              {i18n.t('sidebar')}
+            </label>
+            <div class="col-12">
+              <MarkdownTextArea
+                initialContent={this.state.siteForm.description}
+                onContentChange={this.handleSiteDescriptionChange}
+                hideNavigationWarnings
               />
-              <label class="form-check-label" htmlFor="create-site-downvotes">
-                {i18n.t('enable_downvotes')}
-              </label>
             </div>
           </div>
-        </div>
-        <div class="form-group row">
-          <div class="col-12">
-            <div class="form-check">
-              <input
-                class="form-check-input"
-                id="create-site-enable-nsfw"
-                type="checkbox"
-                checked={this.state.siteForm.enable_nsfw}
-                onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
-              />
-              <label class="form-check-label" htmlFor="create-site-enable-nsfw">
-                {i18n.t('enable_nsfw')}
-              </label>
+          <div class="form-group row">
+            <div class="col-12">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="create-site-downvotes"
+                  type="checkbox"
+                  checked={this.state.siteForm.enable_downvotes}
+                  onChange={linkEvent(
+                    this,
+                    this.handleSiteEnableDownvotesChange
+                  )}
+                />
+                <label class="form-check-label" htmlFor="create-site-downvotes">
+                  {i18n.t('enable_downvotes')}
+                </label>
+              </div>
             </div>
           </div>
-        </div>
-        <div class="form-group row">
-          <div class="col-12">
-            <div class="form-check">
-              <input
-                class="form-check-input"
-                id="create-site-open-registration"
-                type="checkbox"
-                checked={this.state.siteForm.open_registration}
-                onChange={linkEvent(
-                  this,
-                  this.handleSiteOpenRegistrationChange
-                )}
-              />
-              <label
-                class="form-check-label"
-                htmlFor="create-site-open-registration"
-              >
-                {i18n.t('open_registration')}
-              </label>
+          <div class="form-group row">
+            <div class="col-12">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="create-site-enable-nsfw"
+                  type="checkbox"
+                  checked={this.state.siteForm.enable_nsfw}
+                  onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
+                />
+                <label
+                  class="form-check-label"
+                  htmlFor="create-site-enable-nsfw"
+                >
+                  {i18n.t('enable_nsfw')}
+                </label>
+              </div>
             </div>
           </div>
-        </div>
-        <div class="form-group row">
-          <div class="col-12">
-            <button type="submit" class="btn btn-secondary mr-2">
-              {this.state.loading ? (
-                <svg class="icon icon-spinner spin">
-                  <use xlinkHref="#icon-spinner"></use>
-                </svg>
-              ) : this.props.site ? (
-                capitalizeFirstLetter(i18n.t('save'))
-              ) : (
-                capitalizeFirstLetter(i18n.t('create'))
-              )}
-            </button>
-            {this.props.site && (
+          <div class="form-group row">
+            <div class="col-12">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="create-site-open-registration"
+                  type="checkbox"
+                  checked={this.state.siteForm.open_registration}
+                  onChange={linkEvent(
+                    this,
+                    this.handleSiteOpenRegistrationChange
+                  )}
+                />
+                <label
+                  class="form-check-label"
+                  htmlFor="create-site-open-registration"
+                >
+                  {i18n.t('open_registration')}
+                </label>
+              </div>
+            </div>
+          </div>
+          <div class="form-group row">
+            <div class="col-12">
               <button
-                type="button"
-                class="btn btn-secondary"
-                onClick={linkEvent(this, this.handleCancel)}
+                type="submit"
+                class="btn btn-secondary mr-2"
+                disabled={this.state.loading}
               >
-                {i18n.t('cancel')}
+                {this.state.loading ? (
+                  <svg class="icon icon-spinner spin">
+                    <use xlinkHref="#icon-spinner"></use>
+                  </svg>
+                ) : this.props.site ? (
+                  capitalizeFirstLetter(i18n.t('save'))
+                ) : (
+                  capitalizeFirstLetter(i18n.t('create'))
+                )}
               </button>
-            )}
+              {this.props.site && (
+                <button
+                  type="button"
+                  class="btn btn-secondary"
+                  onClick={linkEvent(this, this.handleCancel)}
+                >
+                  {i18n.t('cancel')}
+                </button>
+              )}
+            </div>
           </div>
-        </div>
-      </form>
+        </form>
+      </>
     );
   }
 
@@ -195,9 +254,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
     i.setState(i.state);
   }
 
-  handleSiteDescriptionChange(i: SiteForm, event: any) {
-    i.state.siteForm.description = event.target.value;
-    i.setState(i.state);
+  handleSiteDescriptionChange(val: string) {
+    this.state.siteForm.description = val;
+    this.setState(this.state);
   }
 
   handleSiteEnableNsfwChange(i: SiteForm, event: any) {
@@ -218,4 +277,24 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   handleCancel(i: SiteForm) {
     i.props.onCancel();
   }
+
+  handleIconUpload(url: string) {
+    this.state.siteForm.icon = url;
+    this.setState(this.state);
+  }
+
+  handleIconRemove() {
+    this.state.siteForm.icon = '';
+    this.setState(this.state);
+  }
+
+  handleBannerUpload(url: string) {
+    this.state.siteForm.banner = url;
+    this.setState(this.state);
+  }
+
+  handleBannerRemove() {
+    this.state.siteForm.banner = '';
+    this.setState(this.state);
+  }
 }