From c6cd3af5b54e124911389bf88cf0dad5aa916de6 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 6 Jul 2023 11:46:20 +0100 Subject: [PATCH] DEV: Convert share-topic modal to new component-based API (#22154) --- .../app/components/composer-messages.hbs | 8 +- .../app/components/composer-messages.js | 18 +-- .../modal/share-topic.hbs | 12 +- .../app/components/modal/share-topic.js | 121 +++++++++++++++++ .../discourse/app/controllers/share-topic.js | 126 ------------------ .../topic-footer-buttons.js | 22 +-- .../javascripts/discourse/app/widgets/post.js | 17 ++- 7 files changed, 169 insertions(+), 155 deletions(-) rename app/assets/javascripts/discourse/app/{templates => components}/modal/share-topic.hbs (91%) create mode 100644 app/assets/javascripts/discourse/app/components/modal/share-topic.js delete mode 100644 app/assets/javascripts/discourse/app/controllers/share-topic.js diff --git a/app/assets/javascripts/discourse/app/components/composer-messages.hbs b/app/assets/javascripts/discourse/app/components/composer-messages.hbs index ea42db24a83..202cbfc62e7 100644 --- a/app/assets/javascripts/discourse/app/components/composer-messages.hbs +++ b/app/assets/javascripts/discourse/app/components/composer-messages.hbs @@ -2,7 +2,13 @@ + {{#if this.showShareModal}} + + {{/if}} {{/each}} \ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/composer-messages.js b/app/assets/javascripts/discourse/app/components/composer-messages.js index 43e9d59ee7b..bc2527c1ecf 100644 --- a/app/assets/javascripts/discourse/app/components/composer-messages.js +++ b/app/assets/javascripts/discourse/app/components/composer-messages.js @@ -4,14 +4,18 @@ import EmberObject, { action } from "@ember/object"; import I18n from "I18n"; import LinkLookup from "discourse/lib/link-lookup"; import { not } from "@ember/object/computed"; -import showModal from "discourse/lib/show-modal"; import { ajax } from "discourse/lib/ajax"; +import { inject as service } from "@ember/service"; +import { tracked } from "@glimmer/tracking"; let _messagesCache = {}; let _recipient_names = []; @classNameBindings(":composer-popup-container", "hidden") export default class ComposerMessages extends Component { + @service modal; + @tracked showShareModal; + checkedMessages = false; messages = null; messagesByTemplate = null; @@ -309,19 +313,17 @@ export default class ComposerMessages extends Component { } } - @action - shareModal() { + get shareModalData() { const { topic } = this.composer; - const controller = showModal("share-topic", { model: topic.category }); - - controller.setProperties({ + return { + topic, + category: topic.category, allowInvites: topic.details.can_invite_to && !topic.archived && !topic.closed && !topic.deleted, - topic, - }); + }; } @action diff --git a/app/assets/javascripts/discourse/app/templates/modal/share-topic.hbs b/app/assets/javascripts/discourse/app/components/modal/share-topic.hbs similarity index 91% rename from app/assets/javascripts/discourse/app/templates/modal/share-topic.hbs rename to app/assets/javascripts/discourse/app/components/modal/share-topic.hbs index 1741bba57b2..b18a4b294bf 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/share-topic.hbs +++ b/app/assets/javascripts/discourse/app/components/modal/share-topic.hbs @@ -1,10 +1,14 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/modal/share-topic.js b/app/assets/javascripts/discourse/app/components/modal/share-topic.js new file mode 100644 index 00000000000..fa00bc6b543 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/modal/share-topic.js @@ -0,0 +1,121 @@ +import Component from "@ember/component"; +import { action } from "@ember/object"; +import { getAbsoluteURL } from "discourse-common/lib/get-url"; +import discourseComputed, { + afterRender, +} from "discourse-common/utils/decorators"; +import { readOnly } from "@ember/object/computed"; +import { longDateNoYear } from "discourse/lib/formatter"; +import Sharing from "discourse/lib/sharing"; +import showModal from "discourse/lib/show-modal"; +import { bufferedProperty } from "discourse/mixins/buffered-content"; +import I18n from "I18n"; +import Category from "discourse/models/category"; +import { getOwner } from "discourse-common/lib/get-owner"; + +const ShareTopicModal = Component.extend(bufferedProperty("invite"), { + topic: readOnly("model.topic"), + post: readOnly("model.post"), + category: readOnly("model.category"), + allowInvites: readOnly("model.allowInvites"), + + didInsertElement() { + this._showRestrictedGroupWarning(); + this._selectUrl(); + this._super(); + }, + + @afterRender + _showRestrictedGroupWarning() { + if (!this.category) { + return; + } + + Category.fetchVisibleGroups(this.category.id).then((result) => { + if (result.groups.length > 0) { + this.setProperties({ + flash: I18n.t("topic.share.restricted_groups", { + count: result.groups.length, + groupNames: result.groups.join(", "), + }), + flashType: "warning", + }); + } + }); + }, + + @afterRender + _selectUrl() { + const input = document.querySelector("input.invite-link"); + if (input && !this.site.mobileView) { + // if the input is auto-focused on mobile, iOS requires two taps of the copy button + input.setSelectionRange(0, this.url.length); + input.focus(); + } + }, + + @discourseComputed("post.shareUrl", "topic.shareUrl") + url(postUrl, topicUrl) { + if (postUrl) { + return getAbsoluteURL(postUrl); + } else if (topicUrl) { + return getAbsoluteURL(topicUrl); + } + }, + + @discourseComputed("post.created_at", "post.wiki", "post.last_wiki_edit") + displayDate(createdAt, wiki, lastWikiEdit) { + const date = wiki && lastWikiEdit ? lastWikiEdit : createdAt; + return longDateNoYear(new Date(date)); + }, + + @discourseComputed( + "topic.{isPrivateMessage,invisible,category.read_restricted}" + ) + sources(topic) { + const privateContext = + this.siteSettings.login_required || + topic?.isPrivateMessage || + topic?.invisible || + topic?.category?.read_restricted; + + return Sharing.activeSources(this.siteSettings.share_links, privateContext); + }, + + @action + share(source) { + Sharing.shareSource(source, { + title: this.topic.title, + url: this.url, + }); + }, + + @action + inviteUsers() { + const controller = showModal("create-invite"); + controller.setProperties({ + inviteToTopic: true, + topics: [this.topic], + }); + controller.buffered.setProperties({ + topicId: this.topic.id, + topicTitle: this.topic.title, + }); + }, + + @action + replyAsNewTopic() { + const postStream = this.topic.postStream; + const postId = this.post?.id || postStream.findPostIdForPostNumber(1); + const post = postStream.findLoadedPost(postId); + const topicController = getOwner(this).lookup("controller:topic"); + topicController.actions.replyAsNewTopic.call(topicController, post); + this.closeModal(); + }, +}); + +ShareTopicModal.reopenClass({ + modalClass: "share-topic-modal", +}); + +export default ShareTopicModal; diff --git a/app/assets/javascripts/discourse/app/controllers/share-topic.js b/app/assets/javascripts/discourse/app/controllers/share-topic.js deleted file mode 100644 index 5f9766af2c4..00000000000 --- a/app/assets/javascripts/discourse/app/controllers/share-topic.js +++ /dev/null @@ -1,126 +0,0 @@ -import Controller from "@ember/controller"; -import { action } from "@ember/object"; -import { getAbsoluteURL } from "discourse-common/lib/get-url"; -import discourseComputed, { - afterRender, -} from "discourse-common/utils/decorators"; -import { longDateNoYear } from "discourse/lib/formatter"; -import Sharing from "discourse/lib/sharing"; -import showModal from "discourse/lib/show-modal"; -import { bufferedProperty } from "discourse/mixins/buffered-content"; -import ModalFunctionality from "discourse/mixins/modal-functionality"; -import I18n from "I18n"; -import Category from "discourse/models/category"; -import { getOwner } from "discourse-common/lib/get-owner"; - -export default Controller.extend( - ModalFunctionality, - bufferedProperty("invite"), - { - topic: null, - post: null, - allowInvites: false, - - onShow() { - this.setProperties({ - topic: null, - post: null, - allowInvites: false, - }); - - this._showRestrictedGroupWarning(); - this._selectUrl(); - }, - - @afterRender - _showRestrictedGroupWarning() { - if (!this.model) { - return; - } - - Category.fetchVisibleGroups(this.model.id).then((result) => { - if (result.groups.length > 0) { - this.flash( - I18n.t("topic.share.restricted_groups", { - count: result.groups.length, - groupNames: result.groups.join(", "), - }), - "warning" - ); - } - }); - }, - - @afterRender - _selectUrl() { - const input = document.querySelector("input.invite-link"); - if (input && !this.site.mobileView) { - // if the input is auto-focused on mobile, iOS requires two taps of the copy button - input.setSelectionRange(0, this.url.length); - input.focus(); - } - }, - - @discourseComputed("post.shareUrl", "topic.shareUrl") - url(postUrl, topicUrl) { - if (postUrl) { - return getAbsoluteURL(postUrl); - } else if (topicUrl) { - return getAbsoluteURL(topicUrl); - } - }, - - @discourseComputed("post.created_at", "post.wiki", "post.last_wiki_edit") - displayDate(createdAt, wiki, lastWikiEdit) { - const date = wiki && lastWikiEdit ? lastWikiEdit : createdAt; - return longDateNoYear(new Date(date)); - }, - - @discourseComputed( - "topic.{isPrivateMessage,invisible,category.read_restricted}" - ) - sources(topic) { - const privateContext = - this.siteSettings.login_required || - topic?.isPrivateMessage || - topic?.invisible || - topic?.category?.read_restricted; - - return Sharing.activeSources( - this.siteSettings.share_links, - privateContext - ); - }, - - @action - share(source) { - Sharing.shareSource(source, { - title: this.topic.title, - url: this.url, - }); - }, - - @action - inviteUsers() { - const controller = showModal("create-invite"); - controller.setProperties({ - inviteToTopic: true, - topics: [this.topic], - }); - controller.buffered.setProperties({ - topicId: this.topic.id, - topicTitle: this.topic.title, - }); - }, - - @action - replyAsNewTopic() { - const postStream = this.topic.postStream; - const postId = this.post?.id || postStream.findPostIdForPostNumber(1); - const post = postStream.findLoadedPost(postId); - const topicController = getOwner(this).lookup("controller:topic"); - topicController.actions.replyAsNewTopic.call(topicController, post); - this.send("closeModal"); - }, - } -); diff --git a/app/assets/javascripts/discourse/app/instance-initializers/topic-footer-buttons.js b/app/assets/javascripts/discourse/app/instance-initializers/topic-footer-buttons.js index df290f09397..f1e3b651822 100644 --- a/app/assets/javascripts/discourse/app/instance-initializers/topic-footer-buttons.js +++ b/app/assets/javascripts/discourse/app/instance-initializers/topic-footer-buttons.js @@ -4,7 +4,7 @@ import { WITH_REMINDER_ICON, } from "discourse/models/bookmark"; import { registerTopicFooterButton } from "discourse/lib/register-topic-footer-button"; -import showModal from "discourse/lib/show-modal"; +import ShareTopicModal from "discourse/components/modal/share-topic"; const SHARE_PRIORITY = 1000; const BOOKMARK_PRIORITY = 900; @@ -13,7 +13,7 @@ const FLAG_PRIORITY = 700; const DEFER_PRIORITY = 500; export default { - initialize() { + initialize(owner) { registerTopicFooterButton({ id: "share-and-invite", icon: "d-topic-share", @@ -25,15 +25,15 @@ export default { }, title: "topic.share.help", action() { - const controller = showModal("share-topic", { - model: this.topic.category, - }); - controller.setProperties({ - allowInvites: - this.currentUser.can_invite_to_forum && - this.canInviteTo && - !this.inviteDisabled, - topic: this.topic, + owner.lookup("service:modal").show(ShareTopicModal, { + model: { + category: this.topic.category, + topic: this.topic, + allowInvites: + this.currentUser.can_invite_to_forum && + this.canInviteTo && + !this.inviteDisabled, + }, }); }, dropdown() { diff --git a/app/assets/javascripts/discourse/app/widgets/post.js b/app/assets/javascripts/discourse/app/widgets/post.js index ff04f2fbda7..f37656a822d 100644 --- a/app/assets/javascripts/discourse/app/widgets/post.js +++ b/app/assets/javascripts/discourse/app/widgets/post.js @@ -23,9 +23,10 @@ import { import { relativeAgeMediumSpan } from "discourse/lib/formatter"; import { transformBasicPost } from "discourse/lib/transform-post"; import autoGroupFlairForUser from "discourse/lib/avatar-flair"; -import showModal from "discourse/lib/show-modal"; import { nativeShare } from "discourse/lib/pwa-utils"; import { hideUserTip } from "discourse/lib/user-tips"; +import ShareTopicModal from "discourse/components/modal/share-topic"; +import { getOwner } from "@ember/application"; function transformWithCallbacks(post) { let transformed = transformBasicPost(post); @@ -410,8 +411,11 @@ createWidget("post-date", { showShareModal() { const post = this.findAncestorModel(); const topic = post.topic; - const controller = showModal("share-topic", { model: topic.category }); - controller.setProperties({ topic, post }); + getOwner(this) + .lookup("service:modal") + .show(ShareTopicModal, { + model: { category: topic.category, topic, post }, + }); }, }); @@ -627,8 +631,11 @@ createWidget("post-contents", { const post = this.findAncestorModel(); nativeShare(this.capabilities, { url: post.shareUrl }).catch(() => { const topic = post.topic; - const controller = showModal("share-topic", { model: topic.category }); - controller.setProperties({ topic, post }); + getOwner(this) + .lookup("service:modal") + .show(ShareTopicModal, { + model: { category: topic.category, topic, post }, + }); }); },