DEV: Remove OpenComposer mixin and refactor related logic (#23015)
The OpenComposer mixin comes from a time before we had a composer service. As well as being a general cleanup/refactor, this commit aims to removes interlinking between composer APIs and the discovery-related controllers which are being removed as part of #22622. In summary, this commit: - Removes OpenComposer mixin - Adds and updates composer service APIs to support everything that `openComposer` did - Updates consumers to call the composer service directly, instead of relying on the mixin (either directly, or via a route-action which bubbled up to some parent) - Deprecates composer-related methods on `DiscourseRoute` and on the application route
This commit is contained in:
parent
31626ce85d
commit
6de4b3ac3f
|
@ -7,7 +7,6 @@
|
|||
@showUser={{this.showUser}}
|
||||
@filterPosts={{this.filterPosts}}
|
||||
@composePrivateMessage={{route-action "composePrivateMessage"}}
|
||||
@createNewMessageViaParams={{route-action "createNewMessageViaParams"}}
|
||||
role="dialog"
|
||||
/>
|
||||
|
||||
|
@ -15,5 +14,4 @@
|
|||
@topic={{this.topic.model}}
|
||||
@showUser={{this.showUser}}
|
||||
@showGroup={{this.showGroup}}
|
||||
@createNewMessageViaParams={{route-action "createNewMessageViaParams"}}
|
||||
/>
|
|
@ -2,8 +2,6 @@
|
|||
@composerModel={{this.model}}
|
||||
@replyOptions={{this.model.replyOptions}}
|
||||
@canWhisper={{this.canWhisper}}
|
||||
@openComposer={{this.openComposer}}
|
||||
@closeComposer={{this.closeComposer}}
|
||||
@action={{this.model.action}}
|
||||
@tabindex={{this.tabindex}}
|
||||
@topic={{this.model.topic}}
|
||||
|
|
|
@ -46,8 +46,6 @@
|
|||
<div class="reply-details">
|
||||
<ComposerActionTitle
|
||||
@model={{this.composer.model}}
|
||||
@openComposer={{this.composer.openComposer}}
|
||||
@closeComposer={{this.composer.closeComposer}}
|
||||
@canWhisper={{this.composer.canWhisper}}
|
||||
/>
|
||||
|
||||
|
|
|
@ -8,10 +8,12 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||
import { groupPath } from "discourse/lib/url";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import { modKeysPressed } from "discourse/lib/utilities";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
const maxMembersToDisplay = 10;
|
||||
|
||||
export default Component.extend(CardContentsBase, CleansUp, {
|
||||
composer: service(),
|
||||
elementId: "group-card",
|
||||
mentionSelector: "a.mention-group",
|
||||
classNames: ["no-bg", "group-card"],
|
||||
|
@ -105,7 +107,7 @@ export default Component.extend(CardContentsBase, CleansUp, {
|
|||
},
|
||||
|
||||
messageGroup() {
|
||||
this.createNewMessageViaParams({
|
||||
this.composer.openNewMessage({
|
||||
recipients: this.get("group.name"),
|
||||
hasGroups: true,
|
||||
});
|
||||
|
|
|
@ -18,10 +18,10 @@ export default class TopicsController extends DiscoveryController.extend(
|
|||
DismissTopics
|
||||
) {
|
||||
@service router;
|
||||
@service composer;
|
||||
@controller discovery;
|
||||
|
||||
period = null;
|
||||
canCreateTopicOnCategory = null;
|
||||
selected = null;
|
||||
expandGloballyPinned = false;
|
||||
expandAllPinned = false;
|
||||
|
|
|
@ -22,6 +22,7 @@ export default Controller.extend({
|
|||
dialog: service(),
|
||||
currentUser: service(),
|
||||
router: service(),
|
||||
composer: service(),
|
||||
|
||||
counts: null,
|
||||
showing: "members",
|
||||
|
@ -130,7 +131,7 @@ export default Controller.extend({
|
|||
|
||||
@action
|
||||
messageGroup() {
|
||||
this.send("createNewMessageViaParams", {
|
||||
this.composer.openNewMessage({
|
||||
recipients: this.get("model.name"),
|
||||
hasGroups: true,
|
||||
});
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import NavigationDefaultController from "discourse/controllers/navigation/default";
|
||||
import { inject as controller } from "@ember/controller";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class NavigationCategoriesController extends NavigationDefaultController {
|
||||
@service composer;
|
||||
@controller("discovery/categories") discoveryCategories;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,11 @@ import NavigationDefaultController from "discourse/controllers/navigation/defaul
|
|||
import { calculateFilterMode } from "discourse/lib/filter-mode";
|
||||
import { dependentKeyCompat } from "@ember/object/compat";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class NavigationCategoryController extends NavigationDefaultController {
|
||||
@service composer;
|
||||
|
||||
@tracked category;
|
||||
@tracked filterType;
|
||||
@tracked noSubcategories;
|
||||
|
@ -16,4 +19,22 @@ export default class NavigationCategoryController extends NavigationDefaultContr
|
|||
noSubcategories: this.noSubcategories,
|
||||
});
|
||||
}
|
||||
|
||||
get createTopicTargetCategory() {
|
||||
if (this.category?.canCreateTopic) {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
if (this.siteSettings.default_subcategory_on_read_only_category) {
|
||||
return this.category?.subcategoryWithCreateTopicPermission;
|
||||
}
|
||||
}
|
||||
|
||||
get enableCreateTopicButton() {
|
||||
return !!this.createTopicTargetCategory;
|
||||
}
|
||||
|
||||
get canCreateTopic() {
|
||||
return this.currentUser?.can_create_topic;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { tracked } from "@glimmer/tracking";
|
|||
|
||||
export default class NavigationDefaultController extends Controller {
|
||||
@service router;
|
||||
@service composer;
|
||||
@controller discovery;
|
||||
|
||||
@tracked category;
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
// This mixin allows a route to open the composer
|
||||
import Composer from "discourse/models/composer";
|
||||
import Mixin from "@ember/object/mixin";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
export default Mixin.create({
|
||||
openComposer(controller) {
|
||||
let categoryId = controller.get("category.id");
|
||||
|
||||
if (
|
||||
this.siteSettings.default_subcategory_on_read_only_category &&
|
||||
!controller.canCreateTopicOnCategory
|
||||
) {
|
||||
if (controller.canCreateTopicOnSubCategory) {
|
||||
categoryId = controller.get("defaultSubcategory.id");
|
||||
} else {
|
||||
categoryId = this.siteSettings.default_composer_category;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
categoryId &&
|
||||
!this.siteSettings.default_subcategory_on_read_only_category &&
|
||||
controller.category.isUncategorizedCategory &&
|
||||
!this.siteSettings.allow_uncategorized_topics
|
||||
) {
|
||||
categoryId = null;
|
||||
}
|
||||
|
||||
getOwner(this)
|
||||
.lookup("service:composer")
|
||||
.open({
|
||||
prioritizedCategoryId: categoryId,
|
||||
topicCategoryId: categoryId,
|
||||
action: Composer.CREATE_TOPIC,
|
||||
draftKey: controller.get("model.draft_key") || Composer.NEW_TOPIC_KEY,
|
||||
draftSequence: controller.get("model.draft_sequence") || 0,
|
||||
});
|
||||
},
|
||||
|
||||
openComposerWithTopicParams(
|
||||
controller,
|
||||
topicTitle,
|
||||
topicBody,
|
||||
topicCategoryId,
|
||||
topicTags
|
||||
) {
|
||||
getOwner(this)
|
||||
.lookup("service:composer")
|
||||
.open({
|
||||
action: Composer.CREATE_TOPIC,
|
||||
topicTitle,
|
||||
topicBody,
|
||||
topicCategoryId,
|
||||
topicTags,
|
||||
draftKey: controller.get("model.draft_key") || Composer.NEW_TOPIC_KEY,
|
||||
draftSequence: controller.get("model.draft_sequence"),
|
||||
});
|
||||
},
|
||||
|
||||
openComposerWithMessageParams({
|
||||
recipients = "",
|
||||
topicTitle = "",
|
||||
topicBody = "",
|
||||
hasGroups = false,
|
||||
} = {}) {
|
||||
getOwner(this).lookup("service:composer").open({
|
||||
action: Composer.PRIVATE_MESSAGE,
|
||||
recipients,
|
||||
topicTitle,
|
||||
topicBody,
|
||||
archetypeId: "private_message",
|
||||
draftKey: Composer.NEW_PRIVATE_MESSAGE_KEY,
|
||||
hasGroups,
|
||||
});
|
||||
},
|
||||
});
|
|
@ -345,6 +345,16 @@ const Category = RestModel.extend({
|
|||
isUncategorizedCategory(id) {
|
||||
return Category.isUncategorized(id);
|
||||
},
|
||||
|
||||
get canCreateTopic() {
|
||||
return this.permission === PermissionType.FULL;
|
||||
},
|
||||
|
||||
get subcategoryWithCreateTopicPermission() {
|
||||
return this.subcategories?.find(
|
||||
(subcategory) => subcategory.canCreateTopic
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
let _uncategorized;
|
||||
|
|
|
@ -3,7 +3,6 @@ import Category from "discourse/models/category";
|
|||
import Composer from "discourse/models/composer";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
import OpenComposer from "discourse/mixins/open-composer";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { findAll } from "discourse/models/login-method";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
@ -17,6 +16,7 @@ import { action } from "@ember/object";
|
|||
import KeyboardShortcutsHelp from "discourse/components/modal/keyboard-shortcuts-help";
|
||||
import NotActivatedModal from "../components/modal/not-activated";
|
||||
import ForgotPassword from "discourse/components/modal/forgot-password";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
function unlessReadOnly(method, message) {
|
||||
return function () {
|
||||
|
@ -38,7 +38,7 @@ function unlessStrictlyReadOnly(method, message) {
|
|||
};
|
||||
}
|
||||
|
||||
const ApplicationRoute = DiscourseRoute.extend(OpenComposer, {
|
||||
const ApplicationRoute = DiscourseRoute.extend({
|
||||
siteTitle: setting("title"),
|
||||
shortSiteDescription: setting("short_site_description"),
|
||||
documentTitle: service(),
|
||||
|
@ -190,14 +190,17 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, {
|
|||
user.checkEmail();
|
||||
},
|
||||
|
||||
createNewTopicViaParams(title, body, category_id, tags) {
|
||||
this.openComposerWithTopicParams(
|
||||
this.controllerFor("discovery/topics"),
|
||||
createNewTopicViaParams(title, body, categoryId, tags) {
|
||||
deprecated(
|
||||
"createNewTopicViaParam on the application route is deprecated. Use the composer service instead",
|
||||
{ id: "discourse.createNewTopicViaParams" }
|
||||
);
|
||||
getOwner(this).lookup("service:composer").openNewTopic({
|
||||
title,
|
||||
body,
|
||||
category_id,
|
||||
tags
|
||||
);
|
||||
categoryId,
|
||||
tags,
|
||||
});
|
||||
},
|
||||
|
||||
createNewMessageViaParams({
|
||||
|
@ -206,10 +209,14 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, {
|
|||
topicBody = "",
|
||||
hasGroups = false,
|
||||
} = {}) {
|
||||
this.openComposerWithMessageParams({
|
||||
deprecated(
|
||||
"createNewMessageViaParams on the application route is deprecated. Use the composer service instead",
|
||||
{ id: "discourse.createNewMessageViaParams" }
|
||||
);
|
||||
getOwner(this).lookup("service:composer").openNewMessage({
|
||||
recipients,
|
||||
topicTitle,
|
||||
topicBody,
|
||||
title: topicTitle,
|
||||
body: topicBody,
|
||||
hasGroups,
|
||||
});
|
||||
},
|
||||
|
|
|
@ -13,7 +13,6 @@ import Category from "discourse/models/category";
|
|||
import CategoryList from "discourse/models/category-list";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
import PermissionType from "discourse/models/permission-type";
|
||||
import TopicList from "discourse/models/topic-list";
|
||||
import { action } from "@ember/object";
|
||||
import PreloadStore from "discourse/lib/preload-store";
|
||||
|
@ -152,33 +151,7 @@ class AbstractCategoryRoute extends DiscourseRoute {
|
|||
|
||||
setupController(controller, model) {
|
||||
const topics = this.topics,
|
||||
category = model.category,
|
||||
canCreateTopic = topics.get("can_create_topic");
|
||||
|
||||
let canCreateTopicOnCategory =
|
||||
canCreateTopic && category.get("permission") === PermissionType.FULL;
|
||||
let cannotCreateTopicOnCategory = !canCreateTopicOnCategory;
|
||||
let defaultSubcategory;
|
||||
let canCreateTopicOnSubCategory;
|
||||
|
||||
if (this.siteSettings.default_subcategory_on_read_only_category) {
|
||||
cannotCreateTopicOnCategory = false;
|
||||
|
||||
if (!canCreateTopicOnCategory && category.subcategories) {
|
||||
defaultSubcategory = category.subcategories.find((subcategory) => {
|
||||
return subcategory.get("permission") === PermissionType.FULL;
|
||||
});
|
||||
canCreateTopicOnSubCategory = !!defaultSubcategory;
|
||||
}
|
||||
}
|
||||
|
||||
this.controllerFor("navigation/category").setProperties({
|
||||
canCreateTopicOnCategory,
|
||||
cannotCreateTopicOnCategory,
|
||||
canCreateTopic,
|
||||
canCreateTopicOnSubCategory,
|
||||
defaultSubcategory,
|
||||
});
|
||||
category = model.category;
|
||||
|
||||
let topicOpts = {
|
||||
model: topics,
|
||||
|
@ -189,10 +162,6 @@ class AbstractCategoryRoute extends DiscourseRoute {
|
|||
selected: [],
|
||||
noSubcategories: this.routeConfig && !!this.routeConfig.no_subcategories,
|
||||
expandAllPinned: true,
|
||||
canCreateTopic,
|
||||
canCreateTopicOnCategory,
|
||||
canCreateTopicOnSubCategory,
|
||||
defaultSubcategory,
|
||||
};
|
||||
|
||||
const p = category.get("params");
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import Composer from "discourse/models/composer";
|
||||
import Draft from "discourse/models/draft";
|
||||
import Route from "@ember/routing/route";
|
||||
import { once } from "@ember/runloop";
|
||||
import { seenUser } from "discourse/lib/user-presence";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
const DiscourseRoute = Route.extend({
|
||||
showFooter: false,
|
||||
|
@ -54,24 +53,14 @@ const DiscourseRoute = Route.extend({
|
|||
},
|
||||
|
||||
openTopicDraft() {
|
||||
const composer = getOwner(this).lookup("service:composer");
|
||||
|
||||
if (
|
||||
composer.get("model.action") === Composer.CREATE_TOPIC &&
|
||||
composer.get("model.draftKey") === Composer.NEW_TOPIC_KEY
|
||||
) {
|
||||
composer.set("model.composeState", Composer.OPEN);
|
||||
} else {
|
||||
Draft.get(Composer.NEW_TOPIC_KEY).then((data) => {
|
||||
if (data.draft) {
|
||||
composer.open({
|
||||
action: Composer.CREATE_TOPIC,
|
||||
draft: data.draft,
|
||||
draftKey: Composer.NEW_TOPIC_KEY,
|
||||
draftSequence: data.draft_sequence,
|
||||
});
|
||||
}
|
||||
});
|
||||
deprecated(
|
||||
"DiscourseRoute#openTopicDraft is deprecated. Inject the composer service and call openNewTopic instead",
|
||||
{ id: "discourse.open-topic-draft" }
|
||||
);
|
||||
if (this.currentUser?.has_topic_draft) {
|
||||
return getOwner(this)
|
||||
.lookup("service:composer")
|
||||
.openNewTopic({ preferDraft: true });
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import CategoryList from "discourse/models/category-list";
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import OpenComposer from "discourse/mixins/open-composer";
|
||||
import PreloadStore from "discourse/lib/preload-store";
|
||||
import TopicList from "discourse/models/topic-list";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
@ -13,9 +12,7 @@ import showModal from "discourse/lib/show-modal";
|
|||
import Session from "discourse/models/session";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class DiscoveryCategoriesRoute extends DiscourseRoute.extend(
|
||||
OpenComposer
|
||||
) {
|
||||
export default class DiscoveryCategoriesRoute extends DiscourseRoute {
|
||||
@service router;
|
||||
|
||||
renderTemplate() {
|
||||
|
@ -157,15 +154,6 @@ export default class DiscoveryCategoriesRoute extends DiscourseRoute.extend(
|
|||
showModal("reorder-categories");
|
||||
}
|
||||
|
||||
@action
|
||||
createTopic() {
|
||||
if (this.get("currentUser.has_topic_draft")) {
|
||||
this.openTopicDraft();
|
||||
} else {
|
||||
this.openComposer(this.controllerFor("discovery/categories"));
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
didTransition() {
|
||||
next(() => this.controllerFor("application").set("showFooter", true));
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import OpenComposer from "discourse/mixins/open-composer";
|
||||
import User from "discourse/models/user";
|
||||
import { setTopicList } from "discourse/lib/topic-list-tracker";
|
||||
import { action } from "@ember/object";
|
||||
|
@ -9,9 +8,7 @@ import { resetCachedTopicList } from "discourse/lib/cached-topic-list";
|
|||
The parent route for all discovery routes.
|
||||
Handles the logic for showing the loading spinners.
|
||||
**/
|
||||
export default class DiscoveryRoute extends DiscourseRoute.extend(
|
||||
OpenComposer
|
||||
) {
|
||||
export default class DiscoveryRoute extends DiscourseRoute {
|
||||
queryParams = {
|
||||
filter: { refreshModel: true },
|
||||
};
|
||||
|
@ -74,15 +71,6 @@ export default class DiscoveryRoute extends DiscourseRoute.extend(
|
|||
topic.clearPin();
|
||||
}
|
||||
|
||||
@action
|
||||
createTopic() {
|
||||
if (this.get("currentUser.has_topic_draft")) {
|
||||
this.openTopicDraft();
|
||||
} else {
|
||||
this.openComposer(this.controllerFor("discovery/topics"));
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
dismissReadTopics(dismissTopics) {
|
||||
const operationType = dismissTopics ? "topics" : "posts";
|
||||
|
|
|
@ -7,6 +7,7 @@ import { inject as service } from "@ember/service";
|
|||
|
||||
export default DiscourseRoute.extend({
|
||||
dialog: service(),
|
||||
composer: service(),
|
||||
|
||||
beforeModel(transition) {
|
||||
const params = transition.to.queryParams;
|
||||
|
@ -14,12 +15,12 @@ export default DiscourseRoute.extend({
|
|||
const groupName = params.groupname || params.group_name;
|
||||
|
||||
if (this.currentUser) {
|
||||
this.replaceWith("discovery.latest").then((e) => {
|
||||
this.replaceWith("discovery.latest").then(() => {
|
||||
if (params.username) {
|
||||
e.send("createNewMessageViaParams", {
|
||||
this.composer.openNewMessage({
|
||||
recipients: params.username,
|
||||
topicTitle: params.title,
|
||||
topicBody: params.body,
|
||||
title: params.title,
|
||||
body: params.body,
|
||||
});
|
||||
} else if (groupName) {
|
||||
// send a message to a group
|
||||
|
@ -27,10 +28,10 @@ export default DiscourseRoute.extend({
|
|||
.then((result) => {
|
||||
if (result.messageable) {
|
||||
next(() =>
|
||||
e.send("createNewMessageViaParams", {
|
||||
this.composer.openNewMessage({
|
||||
recipients: groupName,
|
||||
topicTitle: params.title,
|
||||
topicBody: params.body,
|
||||
title: params.title,
|
||||
body: params.body,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
|
@ -41,9 +42,9 @@ export default DiscourseRoute.extend({
|
|||
})
|
||||
.catch(() => this.dialog.alert(I18n.t("generic_error")));
|
||||
} else {
|
||||
e.send("createNewMessageViaParams", {
|
||||
topicTitle: params.title,
|
||||
topicBody: params.body,
|
||||
this.composer.openNewMessage({
|
||||
title: params.title,
|
||||
body: params.body,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,76 +2,78 @@ import Category from "discourse/models/category";
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import cookie from "discourse/lib/cookie";
|
||||
import { next } from "@ember/runloop";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class extends DiscourseRoute {
|
||||
@service composer;
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
beforeModel(transition) {
|
||||
if (this.currentUser) {
|
||||
let category, categoryId;
|
||||
|
||||
if (transition.to.queryParams.category_id) {
|
||||
categoryId = transition.to.queryParams.category_id;
|
||||
category = Category.findById(categoryId);
|
||||
} else if (transition.to.queryParams.category) {
|
||||
const splitCategory = transition.to.queryParams.category.split("/");
|
||||
|
||||
category = this._getCategory(
|
||||
splitCategory[0],
|
||||
splitCategory[1],
|
||||
"nameLower"
|
||||
);
|
||||
|
||||
if (!category) {
|
||||
category = this._getCategory(
|
||||
splitCategory[0],
|
||||
splitCategory[1],
|
||||
"slug"
|
||||
);
|
||||
}
|
||||
|
||||
if (category) {
|
||||
categoryId = category.id;
|
||||
}
|
||||
}
|
||||
const category = this.parseCategoryFromTransition(transition);
|
||||
|
||||
if (category) {
|
||||
let route = "discovery.category";
|
||||
let params = { category, id: category.id };
|
||||
|
||||
this.replaceWith(route, params).then((e) => {
|
||||
if (this.controllerFor("navigation/category").canCreateTopic) {
|
||||
this._sendTransition(e, transition, categoryId);
|
||||
this.replaceWith("discovery.category", {
|
||||
category,
|
||||
id: category.id,
|
||||
}).then(() => {
|
||||
if (this.currentUser.can_create_topic) {
|
||||
this.openComposer({ transition, category });
|
||||
}
|
||||
});
|
||||
} else if (transition.from) {
|
||||
// Navigation from another ember route
|
||||
transition.abort();
|
||||
this.openComposer({ transition });
|
||||
} else {
|
||||
if (transition.from) {
|
||||
transition.abort();
|
||||
this.send("createNewTopicViaParams");
|
||||
} else {
|
||||
this.replaceWith("discovery.latest").then((e) => {
|
||||
if (this.controllerFor("navigation/default").canCreateTopic) {
|
||||
this._sendTransition(e, transition);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.replaceWith("discovery.latest").then(() => {
|
||||
if (this.currentUser.can_create_topic) {
|
||||
this.openComposer({ transition });
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// User is not logged in
|
||||
cookie("destination_url", window.location.href);
|
||||
this.replaceWith("login");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_sendTransition(event, transition, categoryId) {
|
||||
openComposer({ transition, category }) {
|
||||
next(() => {
|
||||
event.send(
|
||||
"createNewTopicViaParams",
|
||||
transition.to.queryParams.title,
|
||||
transition.to.queryParams.body,
|
||||
categoryId,
|
||||
transition.to.queryParams.tags
|
||||
);
|
||||
this.composer.openNewTopic({
|
||||
title: transition.to.queryParams.title,
|
||||
body: transition.to.queryParams.body,
|
||||
category,
|
||||
tags: transition.to.queryParams.tags,
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
parseCategoryFromTransition(transition) {
|
||||
let category;
|
||||
|
||||
if (transition.to.queryParams.category_id) {
|
||||
const categoryId = transition.to.queryParams.category_id;
|
||||
category = Category.findById(categoryId);
|
||||
} else if (transition.to.queryParams.category) {
|
||||
const splitCategory = transition.to.queryParams.category.split("/");
|
||||
|
||||
category = this._getCategory(
|
||||
splitCategory[0],
|
||||
splitCategory[1],
|
||||
"nameLower"
|
||||
);
|
||||
|
||||
if (!category) {
|
||||
category = this._getCategory(
|
||||
splitCategory[0],
|
||||
splitCategory[1],
|
||||
"slug"
|
||||
);
|
||||
}
|
||||
}
|
||||
return category;
|
||||
}
|
||||
|
||||
_getCategory(mainCategory, subCategory, type) {
|
||||
let category;
|
||||
|
@ -92,5 +94,5 @@ export default DiscourseRoute.extend({
|
|||
}
|
||||
|
||||
return category;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import Composer, { SAVE_ICONS, SAVE_LABELS } from "discourse/models/composer";
|
||||
import Composer, {
|
||||
CREATE_TOPIC,
|
||||
NEW_TOPIC_KEY,
|
||||
SAVE_ICONS,
|
||||
SAVE_LABELS,
|
||||
} from "discourse/models/composer";
|
||||
import EmberObject, { action, computed } from "@ember/object";
|
||||
import { alias, and, or, reads } from "@ember/object/computed";
|
||||
import {
|
||||
|
@ -567,33 +572,6 @@ export default class ComposerService extends Service {
|
|||
this.close();
|
||||
}
|
||||
|
||||
@action
|
||||
async openComposer(options, post, topic) {
|
||||
await this.open(options);
|
||||
|
||||
let url = post?.url || topic?.url;
|
||||
const topicTitle = topic?.title;
|
||||
|
||||
if (!url || !topicTitle) {
|
||||
return;
|
||||
}
|
||||
|
||||
url = `${location.protocol}//${location.host}${url}`;
|
||||
const link = `[${escapeExpression(topicTitle)}](${url})`;
|
||||
const continueDiscussion = I18n.t("post.continue_discussion", {
|
||||
postLink: link,
|
||||
});
|
||||
|
||||
const reply = this.get("model.reply");
|
||||
if (reply?.includes(continueDiscussion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.prependText(continueDiscussion, {
|
||||
new_line: true,
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
onPopupMenuAction(menuAction) {
|
||||
return (
|
||||
|
@ -1339,6 +1317,62 @@ export default class ComposerService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
async #openNewTopicDraft() {
|
||||
if (
|
||||
this.model?.action === Composer.CREATE_TOPIC &&
|
||||
this.model?.draftKey === Composer.NEW_TOPIC_KEY
|
||||
) {
|
||||
this.set("model.composeState", Composer.OPEN);
|
||||
} else {
|
||||
const data = await Draft.get(Composer.NEW_TOPIC_KEY);
|
||||
if (data.draft) {
|
||||
return this.open({
|
||||
action: Composer.CREATE_TOPIC,
|
||||
draft: data.draft,
|
||||
draftKey: Composer.NEW_TOPIC_KEY,
|
||||
draftSequence: data.draft_sequence,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async openNewTopic({
|
||||
title,
|
||||
body,
|
||||
category,
|
||||
tags,
|
||||
preferDraft = false,
|
||||
} = {}) {
|
||||
if (preferDraft && this.currentUser.has_topic_draft) {
|
||||
return this.#openNewTopicDraft();
|
||||
} else {
|
||||
return this.open({
|
||||
prioritizedCategoryId: category?.id,
|
||||
topicCategoryId: category?.id,
|
||||
topicTitle: title,
|
||||
topicBody: body,
|
||||
topicTags: tags,
|
||||
action: CREATE_TOPIC,
|
||||
draftKey: NEW_TOPIC_KEY,
|
||||
draftSequence: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async openNewMessage({ title, body, recipients, hasGroups }) {
|
||||
return this.open({
|
||||
action: Composer.PRIVATE_MESSAGE,
|
||||
recipients,
|
||||
topicTitle: title,
|
||||
topicBody: body,
|
||||
archetypeId: "private_message",
|
||||
draftKey: Composer.NEW_PRIVATE_MESSAGE_KEY,
|
||||
hasGroups,
|
||||
});
|
||||
}
|
||||
|
||||
// Given a potential instance and options, set the model for this composer.
|
||||
async _setModel(optionalComposerModel, opts) {
|
||||
this.set("linkLookup", null);
|
||||
|
@ -1406,6 +1440,12 @@ export default class ComposerService extends Service {
|
|||
this.model.set("reply", opts.topicBody);
|
||||
}
|
||||
|
||||
if (opts.prependText && !this.model.reply?.includes(opts.prependText)) {
|
||||
this.model.prependText(opts.prependText, {
|
||||
new_line: true,
|
||||
});
|
||||
}
|
||||
|
||||
const defaultComposerHeight = this._getDefaultComposerHeight();
|
||||
|
||||
this.set("model.composerHeight", defaultComposerHeight);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{{#unless this.viewingCategoriesList}}
|
||||
<CategoryReadOnlyBanner
|
||||
@category={{this.category}}
|
||||
@readOnly={{this.navigationCategory.cannotCreateTopicOnCategory}}
|
||||
@readOnly={{not this.navigationCategory.enableCreateTopicButton}}
|
||||
/>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
|
|
@ -119,9 +119,12 @@
|
|||
@message={{this.footerMessage}}
|
||||
>
|
||||
{{#if this.latest}}
|
||||
{{#if this.canCreateTopicOnCategory}}
|
||||
{{#if this.category.canCreateTopic}}
|
||||
<DiscourseLinkedText
|
||||
@action={{route-action "createTopic"}}
|
||||
@action={{fn
|
||||
this.composer.openNewTopic
|
||||
(hash category=this.category preferDraft=true)
|
||||
}}
|
||||
@text="topic.suggest_create_topic"
|
||||
/>
|
||||
{{/if}}
|
||||
|
|
|
@ -76,9 +76,12 @@
|
|||
@message={{this.footerMessage}}
|
||||
>
|
||||
{{#if this.latest}}
|
||||
{{#if this.canCreateTopicOnCategory}}
|
||||
{{#if this.category.canCreateTopic}}
|
||||
<DiscourseLinkedText
|
||||
@action={{route-action "createTopic"}}
|
||||
@action={{fn
|
||||
this.composer.openNewTopic
|
||||
(hash category=this.category preferDraft=true)
|
||||
}}
|
||||
@text="topic.suggest_create_topic"
|
||||
/>
|
||||
{{/if}}
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
@reorderCategories={{route-action "reorderCategories"}}
|
||||
@canCreateTopic={{this.canCreateTopic}}
|
||||
@hasDraft={{this.currentUser.has_topic_draft}}
|
||||
@createTopic={{route-action "createTopic"}}
|
||||
@createTopic={{fn this.composer.openNewTopic (hash preferDraft=true)}}
|
||||
/>
|
||||
</DSection>
|
|
@ -23,8 +23,11 @@
|
|||
@filterMode={{this.filterMode}}
|
||||
@noSubcategories={{this.noSubcategories}}
|
||||
@canCreateTopic={{this.canCreateTopic}}
|
||||
@createTopic={{route-action "createTopic"}}
|
||||
@createTopicDisabled={{this.cannotCreateTopicOnCategory}}
|
||||
@createTopic={{fn
|
||||
this.composer.openNewTopic
|
||||
(hash category=this.createTopicTargetCategory preferDraft=true)
|
||||
}}
|
||||
@createTopicDisabled={{not this.enableCreateTopicButton}}
|
||||
@hasDraft={{this.currentUser.has_topic_draft}}
|
||||
@editCategory={{route-action "editCategory" this.category}}
|
||||
/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
@filterMode={{this.filterMode}}
|
||||
@canCreateTopic={{this.canCreateTopic}}
|
||||
@hasDraft={{this.currentUser.has_topic_draft}}
|
||||
@createTopic={{route-action "createTopic"}}
|
||||
@createTopic={{fn this.composer.openNewTopic (hash preferDraft=true)}}
|
||||
@skipCategoriesNavItem={{this.skipCategoriesNavItem}}
|
||||
/>
|
||||
</DSection>
|
|
@ -14,6 +14,7 @@ export default {
|
|||
moderator: true,
|
||||
staff: true,
|
||||
can_create_group: true,
|
||||
can_create_topic: true,
|
||||
title: "co-founder",
|
||||
reply_count: 859,
|
||||
topic_count: 36,
|
||||
|
|
|
@ -13,6 +13,7 @@ import { camelize } from "@ember/string";
|
|||
import { equal, gt } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
// Component can get destroyed and lose state
|
||||
let _topicSnapshot = null;
|
||||
|
@ -27,6 +28,7 @@ export function _clearSnapshots() {
|
|||
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
dialog: service(),
|
||||
composer: service(),
|
||||
seq: 0,
|
||||
pluginApiIdentifiers: ["composer-actions"],
|
||||
classNames: ["composer-actions"],
|
||||
|
@ -234,14 +236,32 @@ export default DropdownSelectBoxComponent.extend({
|
|||
return items;
|
||||
},
|
||||
|
||||
_continuedFromText(post, topic) {
|
||||
let url = post?.url || topic?.url;
|
||||
const topicTitle = topic?.title;
|
||||
|
||||
if (!url || !topicTitle) {
|
||||
return;
|
||||
}
|
||||
|
||||
url = `${location.protocol}//${location.host}${url}`;
|
||||
const link = `[${escapeExpression(topicTitle)}](${url})`;
|
||||
return I18n.t("post.continue_discussion", {
|
||||
postLink: link,
|
||||
});
|
||||
},
|
||||
|
||||
_replyFromExisting(options, post, topic) {
|
||||
this.closeComposer();
|
||||
this.openComposer(options, post, topic);
|
||||
this.composer.closeComposer();
|
||||
this.composer.open({
|
||||
...options,
|
||||
prependText: this._continuedFromText(post, topic),
|
||||
});
|
||||
},
|
||||
|
||||
_openComposer(options) {
|
||||
this.closeComposer();
|
||||
this.openComposer(options);
|
||||
this.composer.closeComposer();
|
||||
this.composer.open(options);
|
||||
},
|
||||
|
||||
toggleWhisperSelected(options, model) {
|
||||
|
|
|
@ -41,13 +41,9 @@ describe "Default to Subcategory when parent Category doesn't allow posting", ty
|
|||
end
|
||||
end
|
||||
describe "Category does not have subcategory" do
|
||||
it "should have the 'New Topic' button enabled and default Subcategory set to latest default subcategory" do
|
||||
it "should have the 'New Topic' button disabled" do
|
||||
category_page.visit(category_with_no_subcategory)
|
||||
expect(category_page).to have_button("New Topic", disabled: false)
|
||||
category_page.new_topic_button.click
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new("#reply-control.open .category-chooser")
|
||||
expect(select_kit).to have_selected_value(default_latest_category.id)
|
||||
expect(category_page).to have_button("New Topic", disabled: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -70,13 +66,9 @@ describe "Default to Subcategory when parent Category doesn't allow posting", ty
|
|||
end
|
||||
describe "Can't post on parent category" do
|
||||
describe "Category does not have subcategory" do
|
||||
it "should have the 'New Topic' button enabled and default Subcategory not set" do
|
||||
it "should have the 'New Topic' button disabled" do
|
||||
category_page.visit(category_with_no_subcategory)
|
||||
expect(category_page).to have_button("New Topic", disabled: false)
|
||||
category_page.new_topic_button.click
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new("#reply-control.open .category-chooser")
|
||||
expect(select_kit).to have_selected_name("category…")
|
||||
expect(category_page).to have_button("New Topic", disabled: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue