From 2efe167f6d5f5cb65a2b749ba2fcee0934b247a3 Mon Sep 17 00:00:00 2001 From: Dessalines <dessalines@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:59:19 -0400 Subject: [PATCH] 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> --- src/shared/components/person/settings.tsx | 26 +++++++++++++++++++++ src/shared/components/post/post-listing.tsx | 20 +++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) 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} -- 2.44.1