This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/plugins/chat/assets/javascripts/discourse/components/chat-channel-selector-modal-inner.js
Roman Rizzi 0a5f548635
DEV: Move discourse-chat to the core repo. (#18776)
As part of this move, we are also renaming `discourse-chat` to `chat`.
2022-11-02 10:41:30 -03:00

182 lines
5.3 KiB
JavaScript

import Component from "@ember/component";
import { action } from "@ember/object";
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
import { ajax } from "discourse/lib/ajax";
import { bind } from "discourse-common/utils/decorators";
import { schedule } from "@ember/runloop";
import { inject as service } from "@ember/service";
import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseDebounce from "discourse-common/lib/debounce";
import { INPUT_DELAY } from "discourse-common/config/environment";
import { isPresent } from "@ember/utils";
export default Component.extend({
chat: service(),
tagName: "",
filter: "",
channels: null,
searchIndex: 0,
loading: false,
init() {
this._super(...arguments);
this.appEvents.on("chat-channel-selector-modal:close", this.close);
this.getInitialChannels();
},
didInsertElement() {
this._super(...arguments);
document.addEventListener("keyup", this.onKeyUp);
document
.getElementById("chat-channel-selector-modal-inner")
?.addEventListener("mouseover", this.mouseover);
document.getElementById("chat-channel-selector-input")?.focus();
},
willDestroyElement() {
this._super(...arguments);
this.appEvents.off("chat-channel-selector-modal:close", this.close);
document.removeEventListener("keyup", this.onKeyUp);
document
.getElementById("chat-channel-selector-modal-inner")
?.removeEventListener("mouseover", this.mouseover);
},
@bind
mouseover(e) {
if (e.target.classList.contains("chat-channel-selection-row")) {
let channel;
const id = parseInt(e.target.dataset.id, 10);
if (e.target.classList.contains("channel-row")) {
channel = this.channels.findBy("id", id);
} else {
channel = this.channels.find((c) => c.user && c.id === id);
}
channel?.set("focused", true);
this.channels.forEach((c) => {
if (c !== channel) {
c.set("focused", false);
}
});
}
},
@bind
onKeyUp(e) {
if (e.key === "Enter") {
let focusedChannel = this.channels.find((c) => c.focused);
this.switchChannel(focusedChannel);
e.preventDefault();
} else if (e.key === "ArrowDown") {
this.arrowNavigateChannels("down");
e.preventDefault();
} else if (e.key === "ArrowUp") {
this.arrowNavigateChannels("up");
e.preventDefault();
}
},
arrowNavigateChannels(direction) {
const indexOfFocused = this.channels.findIndex((c) => c.focused);
if (indexOfFocused > -1) {
const nextIndex = direction === "down" ? 1 : -1;
const nextChannel = this.channels[indexOfFocused + nextIndex];
if (nextChannel) {
this.channels[indexOfFocused].set("focused", false);
nextChannel.set("focused", true);
}
} else {
this.channels[0].set("focused", true);
}
schedule("afterRender", () => {
let focusedChannel = document.querySelector(
"#chat-channel-selector-modal-inner .chat-channel-selection-row.focused"
);
focusedChannel?.scrollIntoView({ block: "nearest", inline: "start" });
});
},
@action
switchChannel(channel) {
if (channel.user) {
return this.fetchOrCreateChannelForUser(channel).then((response) => {
this.chat
.startTrackingChannel(ChatChannel.create(response.chat_channel))
.then((newlyTracked) => {
this.chat.openChannel(newlyTracked);
this.close();
});
});
} else {
this.chat.openChannel(channel);
this.close();
}
},
@action
search(value) {
if (isPresent(value?.trim())) {
discourseDebounce(
this,
this.fetchChannelsFromServer,
value?.trim(),
INPUT_DELAY
);
} else {
discourseDebounce(this, this.getInitialChannels, INPUT_DELAY);
}
},
@action
fetchChannelsFromServer(filter) {
this.setProperties({
loading: true,
searchIndex: this.searchIndex + 1,
});
const thisSearchIndex = this.searchIndex;
ajax("/chat/chat_channels/search", { data: { filter } })
.then((searchModel) => {
if (this.searchIndex === thisSearchIndex) {
this.set("searchModel", searchModel);
const channels = searchModel.public_channels.concat(
searchModel.direct_message_channels,
searchModel.users
);
channels.forEach((c) => {
if (c.username) {
c.user = true; // This is used by the `chat-channel-selection-row` component
}
});
this.setProperties({
channels: channels.map((channel) => ChatChannel.create(channel)),
loading: false,
});
this.focusFirstChannel(this.channels);
}
})
.catch(popupAjaxError);
},
@action
getInitialChannels() {
return this.chat.getChannelsWithFilter(this.filter).then((channels) => {
this.focusFirstChannel(channels);
this.set("channels", channels);
});
},
@action
fetchOrCreateChannelForUser(user) {
return ajax("/chat/direct_messages/create.json", {
method: "POST",
data: { usernames: [user.username] },
}).catch(popupAjaxError);
},
focusFirstChannel(channels) {
channels.forEach((c) => c.set("focused", false));
channels[0]?.set("focused", true);
},
});