From: Dessalines <dessalines@users.noreply.github.com>
Date: Mon, 7 Aug 2023 16:59:19 +0000 (-0400)
Subject: Add open links in new tab (#2032)
X-Git-Url: http://these/git/%7B%60%24%7BarchiveTodayUrl%7D/%24%7B%60data:application/static/git-favicon.png?a=commitdiff_plain;h=2efe167f6d5f5cb65a2b749ba2fcee0934b247a3;p=lemmy-ui.git

Add open links in new tab (#2032)

* Open links in a new tab setting in UI

* fixes according to review

* also open external links when setting is enabled

* oopsie

* oopsie 2

* pull translations

* Fixing PR comments.

* Fix prettier.

---------

Co-authored-by: Dogeek <simon.bordeyne@gmail.com>
Co-authored-by: Simon Bordeyne <Dogeek@users.noreply.github.com>
Co-authored-by: SleeplessOne1917 <abias1122@gmail.com>
---

diff --git a/src/shared/components/person/settings.tsx b/src/shared/components/person/settings.tsx
index d045047..659c77c 100644
--- a/src/shared/components/person/settings.tsx
+++ b/src/shared/components/person/settings.tsx
@@ -73,6 +73,7 @@ interface SettingsState {
     show_new_post_notifs?: boolean;
     discussion_languages?: number[];
     generate_totp_2fa?: boolean;
+    open_links_in_new_tab?: boolean;
   };
   changePasswordForm: {
     new_password?: string;
@@ -780,6 +781,23 @@ export class Settings extends Component<any, SettingsState> {
               </label>
             </div>
           </div>
+          <div className="input-group mb-3">
+            <div className="form-check">
+              <input
+                className="form-check-input"
+                id="user-open-links-in-new-tab"
+                type="checkbox"
+                checked={this.state.saveUserSettingsForm.open_links_in_new_tab}
+                onChange={linkEvent(this, this.handleOpenInNewTab)}
+              />
+              <label
+                className="form-check-label"
+                htmlFor="user-open-links-in-new-tab"
+              >
+                {I18NextService.i18n.t("open_links_in_new_tab")}
+              </label>
+            </div>
+          </div>
           {this.totpSection()}
           <div className="input-group mb-3">
             <button type="submit" className="btn d-block btn-secondary me-4">
@@ -1029,6 +1047,14 @@ export class Settings extends Component<any, SettingsState> {
     );
   }
 
+  handleOpenInNewTab(i: Settings, event: any) {
+    i.setState(
+      s => (
+        (s.saveUserSettingsForm.open_links_in_new_tab = event.target.checked), s
+      ),
+    );
+  }
+
   handleShowScoresChange(i: Settings, event: any) {
     const mui = UserService.Instance.myUserInfo;
     if (mui) {
diff --git a/src/shared/components/post/post-listing.tsx b/src/shared/components/post/post-listing.tsx
index afd5daa..c926635 100644
--- a/src/shared/components/post/post-listing.tsx
+++ b/src/shared/components/post/post-listing.tsx
@@ -349,6 +349,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
           href={url}
           rel={relTags}
           title={url}
+          target={this.linkTarget}
         >
           {this.imgThumb(this.imageSrc)}
           <Icon
@@ -368,6 +369,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
             data-tippy-content={I18NextService.i18n.t("expand_here")}
             onClick={linkEvent(this, this.handleImageExpandClick)}
             aria-label={I18NextService.i18n.t("expand_here")}
+            target={this.linkTarget}
           >
             <div className="thumbnail rounded bg-light d-flex justify-content-center">
               <Icon icon="play" classes="d-flex align-items-center" />
@@ -376,7 +378,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
         );
       } else {
         return (
-          <a className="text-body" href={url} title={url} rel={relTags}>
+          <a
+            className="text-body"
+            href={url}
+            title={url}
+            rel={relTags}
+            target={this.linkTarget}
+          >
             <div className="thumbnail rounded bg-light d-flex justify-content-center">
               <Icon icon="external-link" classes="d-flex align-items-center" />
             </div>
@@ -389,6 +397,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
           className="text-body"
           to={`/post/${post.id}`}
           title={I18NextService.i18n.t("comments")}
+          target={this.linkTarget}
         >
           <div className="thumbnail rounded bg-light d-flex justify-content-center">
             <Icon icon="message-square" classes="d-flex align-items-center" />
@@ -737,6 +746,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     );
   }
 
+  public get linkTarget(): string {
+    return UserService.Instance.myUserInfo?.local_user_view.local_user
+      .open_links_in_new_tab
+      ? "_blank"
+      : // _self is the default target on links when the field is not specified
+        "_self";
+  }
+
   get commentsButton() {
     const post_view = this.postView;
     const title = I18NextService.i18n.t("number_of_comments", {
@@ -750,6 +767,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
         title={title}
         to={`/post/${post_view.post.id}?scrollToComments=true`}
         data-tippy-content={title}
+        target={this.linkTarget}
       >
         <Icon icon="message-square" classes="me-1" inline />
         {post_view.counts.comments}