Files
discourse/plugins/chat/assets/javascripts/discourse/initializers/chat-setup.js
David Taylor 583c932173 DEV: Refactor complex initializers into classes (#28661)
We're working to remove all decorators from object-literal-properties. This commit refactors all initializers which were using these decorators into classes, where decorators are allowed. Also adds cleanup logic to the local-dates initializer, which was previously missing.
2024-09-02 10:08:07 +01:00

227 lines
6.3 KiB
JavaScript

import { setOwner } from "@ember/owner";
import { service } from "@ember/service";
import { number } from "discourse/lib/formatter";
import { withPluginApi } from "discourse/lib/plugin-api";
import { getOwnerWithFallback } from "discourse-common/lib/get-owner";
import { replaceIcon } from "discourse-common/lib/icon-library";
import { bind } from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
import { clearChatComposerButtons } from "discourse/plugins/chat/discourse/lib/chat-composer-buttons";
import ChannelHashtagType from "discourse/plugins/chat/discourse/lib/hashtag-types/channel";
import ChatHeaderIcon from "../components/chat/header/icon";
import chatStyleguide from "../components/styleguide/organisms/chat";
let _lastForcedRefreshAt;
const MIN_REFRESH_DURATION_MS = 180000; // 3 minutes
replaceIcon("d-chat", "comment");
class ChatSetupInit {
@service router;
@service("chat") chatService;
@service chatHistory;
@service site;
@service siteSettings;
@service currentUser;
@service appEvents;
constructor(owner) {
setOwner(this, owner);
this.appEvents.on("discourse:focus-changed", this, "_handleFocusChanged");
if (!this.chatService.userCanChat) {
return;
}
withPluginApi("0.12.1", (api) => {
api.onPageChange((path) => {
const route = this.router.recognize(path);
if (route.name.startsWith("chat.")) {
this.chatHistory.visit(route);
}
});
api.registerHashtagType("channel", new ChannelHashtagType(owner));
api.registerChatComposerButton({
id: "chat-upload-btn",
icon: "far-image",
label: "chat.upload",
position: "dropdown",
action: "uploadClicked",
dependentKeys: ["canAttachUploads"],
displayed() {
return this.canAttachUploads;
},
});
if (this.siteSettings.discourse_local_dates_enabled) {
api.registerChatComposerButton({
label: "discourse_local_dates.title",
id: "local-dates",
class: "chat-local-dates-btn",
icon: "calendar-alt",
position: "dropdown",
action() {
this.insertDiscourseLocalDate();
},
});
}
api.registerChatComposerButton({
label: "chat.emoji",
id: "emoji",
class: "chat-emoji-btn",
icon: "far-smile",
position: this.site.desktopView ? "inline" : "dropdown",
context: "channel",
action() {
const chatEmojiPickerManager = owner.lookup(
"service:chat-emoji-picker-manager"
);
chatEmojiPickerManager.open({ context: "channel" });
},
});
api.registerChatComposerButton({
label: "chat.emoji",
id: "channel-emoji",
class: "chat-emoji-btn",
icon: "discourse-emojis",
position: "dropdown",
context: "thread",
action() {
const chatEmojiPickerManager = owner.lookup(
"service:chat-emoji-picker-manager"
);
chatEmojiPickerManager.open({ context: "thread" });
},
});
// we want to decorate the chat quote dates regardless
// of whether the current user has chat enabled
api.decorateCookedElement((elem) => {
const currentUser = getOwnerWithFallback(this).lookup(
"service:current-user"
);
const currentUserTimezone = currentUser?.user_option?.timezone;
const chatTranscriptElements =
elem.querySelectorAll(".chat-transcript");
chatTranscriptElements.forEach((el) => {
const dateTimeRaw = el.dataset["datetime"];
const dateTimeEl = el.querySelector(
".chat-transcript-datetime a, .chat-transcript-datetime span"
);
if (currentUserTimezone) {
dateTimeEl.innerText = moment
.tz(dateTimeRaw, currentUserTimezone)
.format(I18n.t("dates.long_no_year"));
} else {
dateTimeEl.innerText = moment(dateTimeRaw).format(
I18n.t("dates.long_no_year")
);
}
dateTimeEl.dataset.dateFormatted = true;
});
});
if (!this.chatService.userCanChat) {
return;
}
document.body.classList.add("chat-enabled");
this.chatService.loadChannels();
const chatNotificationManager = owner.lookup(
"service:chat-notification-manager"
);
chatNotificationManager.start();
if (!this._registeredDocumentTitleCountCallback) {
api.addDocumentTitleCounter(this.documentTitleCountCallback);
this._registeredDocumentTitleCountCallback = true;
}
api.addCardClickListenerSelector(".chat-drawer-outlet");
if (this.chatService.userCanChat) {
api.headerIcons.add("chat", ChatHeaderIcon);
}
api.addStyleguideSection?.({
component: chatStyleguide,
category: "organisms",
id: "chat",
});
api.addAboutPageActivity("chat_messages", (periods) => {
const count = periods["7_days"];
if (count) {
return {
icon: "comment-dots",
class: "chat-messages",
activityText: I18n.t("about.activities.chat_messages", {
count,
formatted_number: number(count),
}),
period: I18n.t("about.activities.periods.last_7_days"),
};
}
});
});
}
@bind
documentTitleCountCallback() {
return this.chatService.getDocumentTitleCount();
}
teardown() {
this.appEvents.off("discourse:focus-changed", this, "_handleFocusChanged");
if (!this.chatService.userCanChat) {
return;
}
_lastForcedRefreshAt = null;
clearChatComposerButtons();
}
@bind
_handleFocusChanged(hasFocus) {
if (!this.chatService.userCanChat) {
return;
}
if (!hasFocus) {
_lastForcedRefreshAt = Date.now();
return;
}
_lastForcedRefreshAt = _lastForcedRefreshAt || Date.now();
const duration = Date.now() - _lastForcedRefreshAt;
if (duration <= MIN_REFRESH_DURATION_MS) {
return;
}
_lastForcedRefreshAt = Date.now();
}
}
export default {
name: "chat-setup",
before: "hashtag-css-generator",
initialize(owner) {
this.instance = new ChatSetupInit(owner);
},
teardown() {
this.instance.teardown();
this.instance = null;
},
};