]> Untitled Git - lemmy.git/commitdiff
Ask for confirmation on leaving pages with incomplete forms. Fixes #529
authorDessalines <tyhou13@gmx.com>
Fri, 6 Mar 2020 19:57:52 +0000 (14:57 -0500)
committerDessalines <tyhou13@gmx.com>
Fri, 6 Mar 2020 19:57:52 +0000 (14:57 -0500)
ui/src/components/comment-form.tsx
ui/src/components/community-form.tsx
ui/src/components/post-form.tsx
ui/src/components/private-message-form.tsx
ui/src/components/site-form.tsx
ui/translations/en.json

index aa8e651de30a69a49779c81588dd72ba0a7d58df..f3009d341a8293acac27ea1beb0b3de268feb02b 100644 (file)
@@ -1,4 +1,5 @@
 import { Component, linkEvent } from 'inferno';
+import { Prompt } from 'inferno-router';
 import {
   CommentNode as CommentNodeI,
   CommentForm as CommentFormI,
@@ -87,6 +88,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
   render() {
     return (
       <div class="mb-3">
+        <Prompt
+          when={this.state.commentForm.content}
+          message={i18n.t('block_leaving')}
+        />
         <form onSubmit={linkEvent(this, this.handleCommentSubmit)}>
           <div class="form-group row">
             <div className={`col-sm-12`}>
index aaa3e6c41161c841e1b0281a382acf3513fd5f14..eedc2003808533a8af6727a8795a2fa3ff6b0226 100644 (file)
@@ -1,4 +1,5 @@
 import { Component, linkEvent } from 'inferno';
+import { Prompt } from 'inferno-router';
 import { Subscription } from 'rxjs';
 import { retryWhen, delay, take } from 'rxjs/operators';
 import {
@@ -105,120 +106,131 @@ export class CommunityForm extends Component<
 
   render() {
     return (
-      <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
-        <div class="form-group row">
-          <label class="col-12 col-form-label" htmlFor="community-name">
-            {i18n.t('name')}
-          </label>
-          <div class="col-12">
-            <input
-              type="text"
-              id="community-name"
-              class="form-control"
-              value={this.state.communityForm.name}
-              onInput={linkEvent(this, this.handleCommunityNameChange)}
-              required
-              minLength={3}
-              maxLength={20}
-              pattern="[a-z0-9_]+"
-              title={i18n.t('community_reqs')}
-            />
+      <>
+        <Prompt
+          when={
+            !this.state.loading &&
+            (this.state.communityForm.name ||
+              this.state.communityForm.title ||
+              this.state.communityForm.description)
+          }
+          message={i18n.t('block_leaving')}
+        />
+        <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
+          <div class="form-group row">
+            <label class="col-12 col-form-label" htmlFor="community-name">
+              {i18n.t('name')}
+            </label>
+            <div class="col-12">
+              <input
+                type="text"
+                id="community-name"
+                class="form-control"
+                value={this.state.communityForm.name}
+                onInput={linkEvent(this, this.handleCommunityNameChange)}
+                required
+                minLength={3}
+                maxLength={20}
+                pattern="[a-z0-9_]+"
+                title={i18n.t('community_reqs')}
+              />
+            </div>
           </div>
-        </div>
 
-        <div class="form-group row">
-          <label class="col-12 col-form-label" htmlFor="community-title">
-            {i18n.t('title')}
-          </label>
-          <div class="col-12">
-            <input
-              type="text"
-              id="community-title"
-              value={this.state.communityForm.title}
-              onInput={linkEvent(this, this.handleCommunityTitleChange)}
-              class="form-control"
-              required
-              minLength={3}
-              maxLength={100}
-            />
-          </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.communityForm.description}
-              onInput={linkEvent(this, this.handleCommunityDescriptionChange)}
-              class="form-control"
-              rows={3}
-              maxLength={10000}
-            />
-          </div>
-        </div>
-        <div class="form-group row">
-          <label class="col-12 col-form-label" htmlFor="community-category">
-            {i18n.t('category')}
-          </label>
-          <div class="col-12">
-            <select
-              class="form-control"
-              id="community-category"
-              value={this.state.communityForm.category_id}
-              onInput={linkEvent(this, this.handleCommunityCategoryChange)}
-            >
-              {this.state.categories.map(category => (
-                <option value={category.id}>{category.name}</option>
-              ))}
-            </select>
+          <div class="form-group row">
+            <label class="col-12 col-form-label" htmlFor="community-title">
+              {i18n.t('title')}
+            </label>
+            <div class="col-12">
+              <input
+                type="text"
+                id="community-title"
+                value={this.state.communityForm.title}
+                onInput={linkEvent(this, this.handleCommunityTitleChange)}
+                class="form-control"
+                required
+                minLength={3}
+                maxLength={100}
+              />
+            </div>
           </div>
-        </div>
-
-        {this.state.enable_nsfw && (
           <div class="form-group row">
+            <label class="col-12 col-form-label" htmlFor={this.id}>
+              {i18n.t('sidebar')}
+            </label>
             <div class="col-12">
-              <div class="form-check">
-                <input
-                  class="form-check-input"
-                  id="community-nsfw"
-                  type="checkbox"
-                  checked={this.state.communityForm.nsfw}
-                  onChange={linkEvent(this, this.handleCommunityNsfwChange)}
-                />
-                <label class="form-check-label" htmlFor="community-nsfw">
-                  {i18n.t('nsfw')}
-                </label>
-              </div>
+              <textarea
+                id={this.id}
+                value={this.state.communityForm.description}
+                onInput={linkEvent(this, this.handleCommunityDescriptionChange)}
+                class="form-control"
+                rows={3}
+                maxLength={10000}
+              />
             </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.community ? (
-                capitalizeFirstLetter(i18n.t('save'))
-              ) : (
-                capitalizeFirstLetter(i18n.t('create'))
-              )}
-            </button>
-            {this.props.community && (
-              <button
-                type="button"
-                class="btn btn-secondary"
-                onClick={linkEvent(this, this.handleCancel)}
+          <div class="form-group row">
+            <label class="col-12 col-form-label" htmlFor="community-category">
+              {i18n.t('category')}
+            </label>
+            <div class="col-12">
+              <select
+                class="form-control"
+                id="community-category"
+                value={this.state.communityForm.category_id}
+                onInput={linkEvent(this, this.handleCommunityCategoryChange)}
               >
-                {i18n.t('cancel')}
+                {this.state.categories.map(category => (
+                  <option value={category.id}>{category.name}</option>
+                ))}
+              </select>
+            </div>
+          </div>
+
+          {this.state.enable_nsfw && (
+            <div class="form-group row">
+              <div class="col-12">
+                <div class="form-check">
+                  <input
+                    class="form-check-input"
+                    id="community-nsfw"
+                    type="checkbox"
+                    checked={this.state.communityForm.nsfw}
+                    onChange={linkEvent(this, this.handleCommunityNsfwChange)}
+                  />
+                  <label class="form-check-label" htmlFor="community-nsfw">
+                    {i18n.t('nsfw')}
+                  </label>
+                </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.community ? (
+                  capitalizeFirstLetter(i18n.t('save'))
+                ) : (
+                  capitalizeFirstLetter(i18n.t('create'))
+                )}
               </button>
-            )}
+              {this.props.community && (
+                <button
+                  type="button"
+                  class="btn btn-secondary"
+                  onClick={linkEvent(this, this.handleCancel)}
+                >
+                  {i18n.t('cancel')}
+                </button>
+              )}
+            </div>
           </div>
-        </div>
-      </form>
+        </form>
+      </>
     );
   }
 
index ef25a546bd949bbb65db25f592ff096fd17e0a41..5f05bd588acc70f998208470460879942d7a967a 100644 (file)
@@ -1,4 +1,5 @@
 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';
@@ -153,6 +154,15 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
   render() {
     return (
       <div>
+        <Prompt
+          when={
+            !this.state.loading &&
+            (this.state.postForm.name ||
+              this.state.postForm.url ||
+              this.state.postForm.body)
+          }
+          message={i18n.t('block_leaving')}
+        />
         <form onSubmit={linkEvent(this, this.handlePostSubmit)}>
           <div class="form-group row">
             <label class="col-sm-2 col-form-label" htmlFor="post-url">
index 90b3b6e165eb5ed6d534476f33ee56c4eb2d7961..f5f0cc756d04476f4b12c43b04f4e11e1da8afdb 100644 (file)
@@ -1,4 +1,5 @@
 import { Component, linkEvent } from 'inferno';
+import { Prompt } from 'inferno-router';
 import { Link } from 'inferno-router';
 import { Subscription } from 'rxjs';
 import { retryWhen, delay, take } from 'rxjs/operators';
@@ -116,6 +117,10 @@ export class PrivateMessageForm extends Component<
   render() {
     return (
       <div>
+        <Prompt
+          when={!this.state.loading && this.state.privateMessageForm.content}
+          message={i18n.t('block_leaving')}
+        />
         <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
           {!this.props.privateMessage && (
             <div class="form-group row">
index 113e9c66433b42f63ccd8361ab2c09a3820bf572..df913043ea5324ef387af2715e223f8126b241f3 100644 (file)
@@ -1,4 +1,5 @@
 import { Component, linkEvent } from 'inferno';
+import { Prompt } from 'inferno-router';
 import { Site, SiteForm as SiteFormI } from '../interfaces';
 import { WebSocketService } from '../services';
 import { capitalizeFirstLetter, randomStr, setupTribute } from '../utils';
@@ -59,123 +60,138 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
 
   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}
-            />
-          </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>
-        </div>
-        <div class="form-group row">
-          <div class="col-12">
-            <div class="form-check">
+      <>
+        <Prompt
+          when={
+            !this.state.loading &&
+            (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('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
-                class="form-check-input"
-                id="create-site-downvotes"
-                type="checkbox"
-                checked={this.state.siteForm.enable_downvotes}
-                onChange={linkEvent(this, this.handleSiteEnableDownvotesChange)}
+                type="text"
+                id="create-site-name"
+                class="form-control"
+                value={this.state.siteForm.name}
+                onInput={linkEvent(this, this.handleSiteNameChange)}
+                required
+                minLength={3}
+                maxLength={20}
               />
-              <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)}
+          <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}
               />
-              <label class="form-check-label" htmlFor="create-site-enable-nsfw">
-                {i18n.t('enable_nsfw')}
-              </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-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-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">
-            <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 && (
-              <button
-                type="button"
-                class="btn btn-secondary"
-                onClick={linkEvent(this, this.handleCancel)}
-              >
-                {i18n.t('cancel')}
+          <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 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="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 && (
+                <button
+                  type="button"
+                  class="btn btn-secondary"
+                  onClick={linkEvent(this, this.handleCancel)}
+                >
+                  {i18n.t('cancel')}
+                </button>
+              )}
+            </div>
           </div>
-        </div>
-      </form>
+        </form>
+      </>
     );
   }
 
index ea063fcaf82ac04163cfe2f7a4ec8bb38bccbb05..afee21bbed0cd924f430d8b58cfa1ccea407c9aa 100644 (file)
     "no_private_message_edit_allowed": "Not allowed to edit private message.",
     "couldnt_update_private_message": "Couldn't update private message.",
     "time": "Time",
-    "action": "Action"
+    "action": "Action",
+    "block_leaving": "Are you sure you want to leave?"
 }