DEV: Convert share-topic modal to new component-based API (#22154)

This commit is contained in:
David Taylor 2023-07-06 11:46:20 +01:00 committed by GitHub
parent 5134b28d83
commit c6cd3af5b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 169 additions and 155 deletions

View File

@ -2,7 +2,13 @@
<ComposerMessage <ComposerMessage
@message={{message}} @message={{message}}
@closeMessage={{action "closeMessage"}} @closeMessage={{action "closeMessage"}}
@shareModal={{action "shareModal"}} @shareModal={{fn (mut this.showShareModal) true}}
@switchPM={{action "switchPM"}} @switchPM={{action "switchPM"}}
/> />
{{#if this.showShareModal}}
<Modal::ShareTopic
@closeModal={{fn (mut this.showShareModal) false}}
@model={{this.shareModalData}}
/>
{{/if}}
{{/each}} {{/each}}

View File

@ -4,14 +4,18 @@ import EmberObject, { action } from "@ember/object";
import I18n from "I18n"; import I18n from "I18n";
import LinkLookup from "discourse/lib/link-lookup"; import LinkLookup from "discourse/lib/link-lookup";
import { not } from "@ember/object/computed"; import { not } from "@ember/object/computed";
import showModal from "discourse/lib/show-modal";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { inject as service } from "@ember/service";
import { tracked } from "@glimmer/tracking";
let _messagesCache = {}; let _messagesCache = {};
let _recipient_names = []; let _recipient_names = [];
@classNameBindings(":composer-popup-container", "hidden") @classNameBindings(":composer-popup-container", "hidden")
export default class ComposerMessages extends Component { export default class ComposerMessages extends Component {
@service modal;
@tracked showShareModal;
checkedMessages = false; checkedMessages = false;
messages = null; messages = null;
messagesByTemplate = null; messagesByTemplate = null;
@ -309,19 +313,17 @@ export default class ComposerMessages extends Component {
} }
} }
@action get shareModalData() {
shareModal() {
const { topic } = this.composer; const { topic } = this.composer;
const controller = showModal("share-topic", { model: topic.category }); return {
topic,
controller.setProperties({ category: topic.category,
allowInvites: allowInvites:
topic.details.can_invite_to && topic.details.can_invite_to &&
!topic.archived && !topic.archived &&
!topic.closed && !topic.closed &&
!topic.deleted, !topic.deleted,
topic, };
});
} }
@action @action

View File

@ -1,10 +1,14 @@
<DModalBody <DModal
@rawTitle={{if @title={{if
this.post this.post
(i18n "post.share.title" post_number=this.post.post_number) (i18n "post.share.title" post_number=this.post.post_number)
(i18n "topic.share.title") (i18n "topic.share.title")
}} }}
@rawSubtitle={{if this.post this.displayDate}} @subtitle={{if this.post this.displayDate}}
@closeModal={{@closeModal}}
@flash={{this.flash}}
@flashType={{this.flashType}}
class="share-topic-modal"
> >
<form> <form>
<div class="input-group invite-link"> <div class="input-group invite-link">
@ -74,4 +78,4 @@
</div> </div>
</div> </div>
</form> </form>
</DModalBody> </DModal>

View File

@ -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;

View File

@ -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");
},
}
);

View File

@ -4,7 +4,7 @@ import {
WITH_REMINDER_ICON, WITH_REMINDER_ICON,
} from "discourse/models/bookmark"; } from "discourse/models/bookmark";
import { registerTopicFooterButton } from "discourse/lib/register-topic-footer-button"; 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 SHARE_PRIORITY = 1000;
const BOOKMARK_PRIORITY = 900; const BOOKMARK_PRIORITY = 900;
@ -13,7 +13,7 @@ const FLAG_PRIORITY = 700;
const DEFER_PRIORITY = 500; const DEFER_PRIORITY = 500;
export default { export default {
initialize() { initialize(owner) {
registerTopicFooterButton({ registerTopicFooterButton({
id: "share-and-invite", id: "share-and-invite",
icon: "d-topic-share", icon: "d-topic-share",
@ -25,15 +25,15 @@ export default {
}, },
title: "topic.share.help", title: "topic.share.help",
action() { action() {
const controller = showModal("share-topic", { owner.lookup("service:modal").show(ShareTopicModal, {
model: this.topic.category, model: {
}); category: this.topic.category,
controller.setProperties({ topic: this.topic,
allowInvites: allowInvites:
this.currentUser.can_invite_to_forum && this.currentUser.can_invite_to_forum &&
this.canInviteTo && this.canInviteTo &&
!this.inviteDisabled, !this.inviteDisabled,
topic: this.topic, },
}); });
}, },
dropdown() { dropdown() {

View File

@ -23,9 +23,10 @@ import {
import { relativeAgeMediumSpan } from "discourse/lib/formatter"; import { relativeAgeMediumSpan } from "discourse/lib/formatter";
import { transformBasicPost } from "discourse/lib/transform-post"; import { transformBasicPost } from "discourse/lib/transform-post";
import autoGroupFlairForUser from "discourse/lib/avatar-flair"; import autoGroupFlairForUser from "discourse/lib/avatar-flair";
import showModal from "discourse/lib/show-modal";
import { nativeShare } from "discourse/lib/pwa-utils"; import { nativeShare } from "discourse/lib/pwa-utils";
import { hideUserTip } from "discourse/lib/user-tips"; import { hideUserTip } from "discourse/lib/user-tips";
import ShareTopicModal from "discourse/components/modal/share-topic";
import { getOwner } from "@ember/application";
function transformWithCallbacks(post) { function transformWithCallbacks(post) {
let transformed = transformBasicPost(post); let transformed = transformBasicPost(post);
@ -410,8 +411,11 @@ createWidget("post-date", {
showShareModal() { showShareModal() {
const post = this.findAncestorModel(); const post = this.findAncestorModel();
const topic = post.topic; const topic = post.topic;
const controller = showModal("share-topic", { model: topic.category }); getOwner(this)
controller.setProperties({ topic, post }); .lookup("service:modal")
.show(ShareTopicModal, {
model: { category: topic.category, topic, post },
});
}, },
}); });
@ -627,8 +631,11 @@ createWidget("post-contents", {
const post = this.findAncestorModel(); const post = this.findAncestorModel();
nativeShare(this.capabilities, { url: post.shareUrl }).catch(() => { nativeShare(this.capabilities, { url: post.shareUrl }).catch(() => {
const topic = post.topic; const topic = post.topic;
const controller = showModal("share-topic", { model: topic.category }); getOwner(this)
controller.setProperties({ topic, post }); .lookup("service:modal")
.show(ShareTopicModal, {
model: { category: topic.category, topic, post },
});
}); });
}, },