DEV: Convert composer controller to native class syntax (#20723)

Actions are moved from actions: {} to top-level functions with @action decorator. Previously we had a save() action and a top-level function of the same name, so this commit renames the action to avoid a clash.
This commit is contained in:
David Taylor 2023-03-23 13:36:03 +00:00 committed by GitHub
parent b81767c1b1
commit bee61d4faf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 402 additions and 388 deletions

View File

@ -11,10 +11,8 @@ import {
cannotPostAgain,
durationTextFromSeconds,
} from "discourse/helpers/slow-mode";
import discourseComputed, {
observes,
on,
} from "discourse-common/utils/decorators";
import discourseComputed from "discourse-common/utils/decorators";
import { observes, on } from "@ember-decorators/object";
import DiscourseURL from "discourse/lib/url";
import Draft from "discourse/models/draft";
import I18n from "I18n";
@ -95,27 +93,33 @@ export function addComposerSaveErrorCallback(callback) {
_composerSaveErrorCallbacks.push(callback);
}
export default Controller.extend({
topicController: controller("topic"),
router: service(),
dialog: service(),
export default class ComposerController extends Controller {
@service router;
@service dialog;
@controller("topic") topicController;
checkedMessages: false,
messageCount: null,
showEditReason: false,
editReason: null,
scopedCategoryId: null,
prioritizedCategoryId: null,
lastValidatedAt: null,
isUploading: false,
isProcessingUpload: false,
topic: null,
linkLookup: null,
showPreview: true,
composerHeight: null,
forcePreview: and("site.mobileView", "showPreview"),
whisperOrUnlistTopic: or("isWhispering", "model.unlistTopic"),
categories: alias("site.categoriesList"),
checkedMessages = false;
messageCount = null;
showEditReason = false;
editReason = null;
scopedCategoryId = null;
prioritizedCategoryId = null;
lastValidatedAt = null;
isUploading = false;
isProcessingUpload = false;
topic = null;
linkLookup = null;
showPreview = true;
composerHeight = null;
@and("site.mobileView", "showPreview") forcePreview;
@or("isWhispering", "model.unlistTopic") whisperOrUnlistTopic;
@alias("site.categoriesList") categories;
@alias("topicController.model") topicModel;
@reads("currentUser.staff") isStaffUser;
@reads("currentUser.whisperer") whisperer;
@and("model.creatingTopic", "isStaffUser") canUnlistTopic;
@or("replyingToWhisper", "model.whisper") isWhispering;
@on("init")
_setupPreview() {
@ -123,7 +127,7 @@ export default Controller.extend({
? false
: this.keyValueStore.get("composer.showPreview") || "true";
this.set("showPreview", val === "true");
},
}
@computed(
"model.loading",
@ -138,18 +142,18 @@ export default Controller.extend({
this.isProcessingUpload ||
this._disableSubmit
);
},
}
set disableSubmit(value) {
return this.set("_disableSubmit", value);
},
}
@discourseComputed("showPreview")
toggleText(showPreview) {
return showPreview
? I18n.t("composer.hide_preview")
: I18n.t("composer.show_preview");
},
}
@observes("showPreview")
showPreviewChanged() {
@ -159,7 +163,7 @@ export default Controller.extend({
value: this.showPreview,
});
}
},
}
@discourseComputed(
"model.replyingToTopic",
@ -186,10 +190,10 @@ export default Controller.extend({
}
return "title";
},
}
showToolbar: computed({
get() {
@computed
get showToolbar() {
const keyValueStore = getOwner(this).lookup("service:key-value-store");
const storedVal = keyValueStore.get("toolbar-enabled");
if (this._toolbarEnabled === undefined && storedVal === undefined) {
@ -200,8 +204,9 @@ export default Controller.extend({
window.innerWidth > 370 && !this.capabilities.isAndroid;
}
return this._toolbarEnabled || storedVal === "true";
},
set(key, val) {
}
set showToolbar(val) {
const keyValueStore = getOwner(this).lookup("service:key-value-store");
this._toolbarEnabled = val;
keyValueStore.set({
@ -209,10 +214,7 @@ export default Controller.extend({
value: val ? "true" : "false",
});
return val;
},
}),
topicModel: alias("topicController.model"),
}
@discourseComputed("model.canEditTitle", "model.creatingPrivateMessage")
canEditTags(canEditTitle, creatingPrivateMessage) {
@ -228,36 +230,29 @@ export default Controller.extend({
this.site.can_tag_topics &&
(!isPrivateMessage || this.site.can_tag_pms)
);
},
}
@discourseComputed("model.editingPost", "model.topic.details.can_edit")
disableCategoryChooser(editingPost, canEditTopic) {
return editingPost && !canEditTopic;
},
}
@discourseComputed("model.editingPost", "model.topic.canEditTags")
disableTagsChooser(editingPost, canEditTags) {
return editingPost && !canEditTags;
},
isStaffUser: reads("currentUser.staff"),
whisperer: reads("currentUser.whisperer"),
canUnlistTopic: and("model.creatingTopic", "isStaffUser"),
}
@discourseComputed("canWhisper", "replyingToWhisper")
showWhisperToggle(canWhisper, replyingToWhisper) {
return canWhisper && !replyingToWhisper;
},
}
@discourseComputed("model.post")
replyingToWhisper(repliedToPost) {
return (
repliedToPost && repliedToPost.post_type === this.site.post_types.whisper
);
},
isWhispering: or("replyingToWhisper", "model.whisper"),
}
@discourseComputed("model.action", "isWhispering", "model.privateMessage")
saveIcon(modelAction, isWhispering, privateMessage) {
@ -269,7 +264,7 @@ export default Controller.extend({
}
return SAVE_ICONS[modelAction];
},
}
// Note we update when some other attributes like tag/category change to allow
// text customizations to use those.
@ -296,12 +291,12 @@ export default Controller.extend({
}
return SAVE_LABELS[modelAction];
},
}
@discourseComputed("whisperer", "model.action")
canWhisper(whisperer, modelAction) {
return whisperer && modelAction === Composer.REPLY;
},
}
_setupPopupMenuOption(callback) {
let option = callback(this);
@ -318,12 +313,12 @@ export default Controller.extend({
}
return option;
},
}
@discourseComputed("model.requiredCategoryMissing", "model.replyLength")
disableTextarea(requiredCategoryMissing, replyLength) {
return requiredCategoryMissing && replyLength === 0;
},
}
@discourseComputed("model.composeState", "model.creatingTopic", "model.post")
popupMenuOptions(composeState) {
@ -390,7 +385,7 @@ export default Controller.extend({
.filter((o) => o)
);
}
},
}
@discourseComputed("model.creatingPrivateMessage", "model.targetRecipients")
showWarning(creatingPrivateMessage, usernames) {
@ -410,12 +405,12 @@ export default Controller.extend({
}
return creatingPrivateMessage;
},
}
@discourseComputed("model.topic.title")
draftTitle(topicTitle) {
return emojiUnescape(escapeExpression(topicTitle));
},
}
@discourseComputed
allowUpload() {
@ -423,12 +418,12 @@ export default Controller.extend({
this.currentUser.staff,
this.siteSettings
);
},
}
@discourseComputed()
uploadIcon() {
return uploadIcon(this.currentUser.staff, this.siteSettings);
},
}
// Use this to open the composer when you are not sure whether it is
// already open and whether it already has a draft being worked on. Supports
@ -448,7 +443,7 @@ export default Controller.extend({
async focusComposer(opts = {}) {
await this._openComposerForFocus(opts);
this._focusAndInsertText(opts.insertText);
},
}
async _openComposerForFocus(opts) {
if (this.get("model.viewOpen")) {
@ -477,7 +472,7 @@ export default Controller.extend({
...(opts.openOpts || {}),
});
}
},
}
_focusAndInsertText(insertText) {
scheduleOnce("afterRender", () => {
@ -487,7 +482,7 @@ export default Controller.extend({
this.model.appendText(insertText, null, { new_line: true });
}
});
},
}
@action
openIfDraft(event) {
@ -510,30 +505,30 @@ export default Controller.extend({
);
return true;
},
}
@action
removeFullScreenExitPrompt() {
this.set("model.showFullScreenExitPrompt", false);
},
}
@action
async cancel(event) {
event?.preventDefault();
await this.cancelComposer();
},
}
@action
cancelUpload(event) {
event?.preventDefault();
this.set("model.uploadCancelled", true);
},
}
@action
togglePreview(event) {
event?.preventDefault();
this.toggleProperty("showPreview");
},
}
@action
viewNewReply(event) {
@ -543,13 +538,14 @@ export default Controller.extend({
event?.preventDefault();
DiscourseURL.routeTo(this.get("model.createdPost.url"));
this.close();
},
}
actions: {
@action
closeComposer() {
this.close();
},
}
@action
async openComposer(options, post, topic) {
await this.open(options);
@ -574,29 +570,35 @@ export default Controller.extend({
this.model.prependText(continueDiscussion, {
new_line: true,
});
},
}
@action
onPopupMenuAction(menuAction) {
this.send(menuAction);
},
}
@action
storeToolbarState(toolbarEvent) {
this.set("toolbarEvent", toolbarEvent);
},
}
@action
typed() {
this.checkReplyLength();
this.model.typing();
},
}
@action
cancelled() {
this.send("hitEsc");
},
}
@action
addLinkLookup(linkLookup) {
this.set("linkLookup", linkLookup);
},
}
@action
afterRefresh($preview) {
const topic = this.get("model.topic");
const linkLookup = this.linkLookup;
@ -673,21 +675,25 @@ export default Controller.extend({
}
return true;
});
},
}
@action
toggleWhisper() {
this.toggleProperty("model.whisper");
},
}
@action
toggleInvisible() {
this.toggleProperty("model.unlistTopic");
},
}
@action
toggleToolbar() {
this.toggleProperty("showToolbar");
},
}
// Toggle the reply view
@action
async toggle() {
this.closeAutocomplete();
@ -700,14 +706,16 @@ export default Controller.extend({
} else {
await this.cancelComposer();
}
},
}
@action
fullscreenComposer() {
this.toggleFullscreen();
return false;
},
}
// Import a quote from the post
@action
async importQuote(toolbarEvent) {
const postStream = this.get("topic.postStream");
let postId = this.get("model.post.id");
@ -743,24 +751,25 @@ export default Controller.extend({
toolbarEvent.addText(quote);
this.set("model.loading", false);
},
}
save(ignore, event) {
@action
saveAction(ignore, event) {
this.save(false, {
jump:
!(event?.shiftKey && this.get("model.replyingToTopic")) &&
!this.skipJumpOnSave,
});
},
}
@action
displayEditReason() {
this.set("showEditReason", true);
},
}
@action
hitEsc() {
if (
document.querySelectorAll(".emoji-picker-modal.fadeIn").length === 1
) {
if (document.querySelectorAll(".emoji-picker-modal.fadeIn").length === 1) {
this.appEvents.trigger("emoji-picker:close");
return;
}
@ -780,8 +789,9 @@ export default Controller.extend({
this.toggleFullscreen();
this.focusComposer();
}
},
}
@action
groupsMentioned({ name, userCount, maxMentions }) {
if (
this.get("model.creatingPrivateMessage") ||
@ -817,8 +827,9 @@ export default Controller.extend({
body,
});
}
},
}
@action
cannotSeeMention({ name, reason, notifiedCount, isGroup }) {
notifiedCount = parseInt(notifiedCount, 10);
@ -839,8 +850,9 @@ export default Controller.extend({
templateName: "education",
body,
});
},
}
@action
hereMention(count) {
this.appEvents.trigger("composer-messages:create", {
extraClass: "custom-body",
@ -850,23 +862,25 @@ export default Controller.extend({
count,
}),
});
},
}
@action
applyFormatCode() {
this.toolbarEvent.formatCode();
},
}
@action
applyUnorderedList() {
this.toolbarEvent.applyList("* ", "list_item");
},
}
@action
applyOrderedList() {
this.toolbarEvent.applyList(
(i) => (!i ? "1. " : `${parseInt(i, 10) + 1}. `),
"list_item"
);
},
},
}
save(force, options = {}) {
if (this.disableSubmit) {
@ -1125,7 +1139,7 @@ export default Controller.extend({
promise.finally(() => this.messageBus.resume());
return promise;
},
}
// Notify the composer messages controller that a reply has been typed. Some
// messages only appear after typing.
@ -1133,7 +1147,7 @@ export default Controller.extend({
if (!isEmpty("model.reply")) {
this.appEvents.trigger("composer:typed-reply");
}
},
}
/**
Open the composer view
@ -1270,7 +1284,7 @@ export default Controller.extend({
} finally {
this.skipAutoSave = false;
}
},
}
// Given a potential instance and options, set the model for this composer.
async _setModel(optionalComposerModel, opts) {
@ -1345,7 +1359,7 @@ export default Controller.extend({
"--composer-height",
defaultComposerHeight
);
},
}
_getDefaultComposerHeight() {
if (this.keyValueStore.getItem("composerHeight")) {
@ -1358,7 +1372,7 @@ export default Controller.extend({
} else {
return "var(--new-topic-composer-height, 400px)";
}
},
}
async destroyDraft(draftSequence = null) {
const key = this.get("model.draftKey");
@ -1378,7 +1392,7 @@ export default Controller.extend({
const sequence = draftSequence || this.get("model.draftSequence");
await Draft.clear(key, sequence);
this.appEvents.trigger("draft:destroyed", key);
},
}
confirmDraftAbandon(data) {
if (!data.draft) {
@ -1420,7 +1434,7 @@ export default Controller.extend({
],
});
});
},
}
cancelComposer() {
this.skipAutoSave = true;
@ -1472,7 +1486,7 @@ export default Controller.extend({
}).finally(() => {
this.skipAutoSave = false;
});
},
}
shrink() {
if (
@ -1483,7 +1497,7 @@ export default Controller.extend({
} else {
this.close();
}
},
}
_saveDraft() {
if (!this.model) {
@ -1500,7 +1514,7 @@ export default Controller.extend({
this._saveDraftPromise = null;
});
}
},
}
@observes("model.reply", "model.title")
_shouldSaveDraft() {
@ -1524,7 +1538,7 @@ export default Controller.extend({
);
}
}
},
}
@discourseComputed("model.categoryId", "lastValidatedAt")
categoryValidation(categoryId, lastValidatedAt) {
@ -1535,7 +1549,7 @@ export default Controller.extend({
lastShownAt: lastValidatedAt,
});
}
},
}
@discourseComputed("model.category", "model.tags", "lastValidatedAt")
tagValidation(category, tags, lastValidatedAt) {
@ -1552,13 +1566,13 @@ export default Controller.extend({
});
}
}
},
}
collapse() {
this._saveDraft();
this.set("model.composeState", Composer.DRAFT);
document.documentElement.style.setProperty("--composer-height", "40px");
},
}
toggleFullscreen() {
this._saveDraft();
@ -1571,12 +1585,12 @@ export default Controller.extend({
composer?.set("composeState", Composer.FULLSCREEN);
composer?.set("showFullScreenExitPrompt", true);
}
},
}
@discourseComputed("model.viewFullscreen", "model.showFullScreenExitPrompt")
showFullScreenPrompt(isFullscreen, showExitPrompt) {
return isFullscreen && showExitPrompt && !this.capabilities.touch;
},
}
close() {
// the 'fullscreen-composer' class is added to remove scrollbars from the
@ -1590,23 +1604,23 @@ export default Controller.extend({
document.activeElement?.blur();
document.documentElement.style.removeProperty("--composer-height");
this.setProperties({ model: null, lastValidatedAt: null });
},
}
closeAutocomplete() {
$(".d-editor-input").autocomplete({ cancel: true });
},
}
@discourseComputed("model.action")
canEdit(modelAction) {
return modelAction === "edit" && this.currentUser.can_edit;
},
}
@discourseComputed("model.composeState")
visible(state) {
return state && state !== "closed";
},
}
clearLastValidatedAt() {
this.set("lastValidatedAt", null);
},
});
}
}

View File

@ -4,7 +4,7 @@
@openIfDraft={{action "openIfDraft"}}
@typed={{action "typed"}}
@cancelled={{action "cancelled"}}
@save={{action "save"}}
@save={{this.saveAction}}
>
<div class="grippie"></div>
@ -234,7 +234,7 @@
<div class="save-or-cancel">
<ComposerSaveButton
@action={{action "save"}}
@action={{this.saveAction}}
@icon={{this.saveIcon}}
@label={{this.saveLabel}}
@forwardEvent={{true}}