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/direct-message-creator.js
Joffrey JAFFEUX f12724b5a5
DEV: routable chat part 2 (#20232)
This commit is expanding on previous work making everything chat working through an URL.

Improves drawer templates to be all URLs
Implements some kind of router for the drawer
Removes few remaining actions for opening channels
2023-02-14 11:27:07 +01:00

316 lines
7.6 KiB
JavaScript

import { caretPosition } from "discourse/lib/utilities";
import { isEmpty } from "@ember/utils";
import Component from "@ember/component";
import { action } from "@ember/object";
import discourseDebounce from "discourse-common/lib/debounce";
import discourseComputed, { bind } from "discourse-common/utils/decorators";
import { INPUT_DELAY } from "discourse-common/config/environment";
import { inject as service } from "@ember/service";
import { schedule } from "@ember/runloop";
import { gt, not } from "@ember/object/computed";
import { createDirectMessageChannelDraft } from "discourse/plugins/chat/discourse/models/chat-channel";
export default Component.extend({
tagName: "",
users: null,
selectedUsers: null,
term: null,
isFiltering: false,
isFilterFocused: false,
highlightedSelectedUser: null,
focusedUser: null,
chat: service(),
router: service(),
chatStateManager: service(),
isLoading: false,
init() {
this._super(...arguments);
this.set("users", []);
this.set("selectedUsers", []);
this.set("channel", createDirectMessageChannelDraft());
},
didInsertElement() {
this._super(...arguments);
this.filterUsernames();
},
didReceiveAttrs() {
this._super(...arguments);
this.set("term", null);
this.focusFilter();
if (!this.hasSelection) {
this.filterUsernames();
}
},
hasSelection: gt("channel.chatable.users.length", 0),
@discourseComputed
chatProgressBarContainer() {
return document.querySelector("#chat-progress-bar-container");
},
@bind
filterUsernames(term = null) {
this.set("isFiltering", true);
this.chat
.searchPossibleDirectMessageUsers({
term,
limit: 6,
exclude: this.channel.chatable?.users?.mapBy("username") || [],
lastSeenUsers: isEmpty(term) ? true : false,
})
.then((r) => {
if (this.isDestroying || this.isDestroyed) {
return;
}
if (r !== "__CANCELLED") {
this.set("users", r.users || []);
this.set("focusedUser", this.users.firstObject);
}
})
.finally(() => {
if (this.isDestroying || this.isDestroyed) {
return;
}
this.set("isFiltering", false);
});
},
shouldRenderResults: not("isFiltering"),
@action
selectUser(user) {
this.selectedUsers.pushObject(user);
this.users.removeObject(user);
this.set("users", []);
this.set("focusedUser", null);
this.set("highlightedSelectedUser", null);
this.set("term", null);
this.focusFilter();
this.onChangeSelectedUsers?.(this.selectedUsers);
},
@action
deselectUser(user) {
this.users.removeObject(user);
this.selectedUsers.removeObject(user);
this.set("focusedUser", this.users.firstObject);
this.set("highlightedSelectedUser", null);
this.set("term", null);
if (isEmpty(this.selectedUsers)) {
this.filterUsernames();
}
this.focusFilter();
this.onChangeSelectedUsers?.(this.selectedUsers);
},
@action
focusFilter() {
this.set("isFilterFocused", true);
schedule("afterRender", () => {
document.querySelector(".filter-usernames")?.focus();
});
},
@action
onFilterInput(term) {
this.set("term", term);
this.set("users", []);
if (!term?.length) {
return;
}
this.set("isFiltering", true);
discourseDebounce(this, this.filterUsernames, term, INPUT_DELAY);
},
@action
handleUserKeyUp(user, event) {
if (event.key === "Enter") {
event.stopPropagation();
event.preventDefault();
this.selectUser(user);
}
},
@action
onFilterInputFocusOut() {
this.set("isFilterFocused", false);
this.set("highlightedSelectedUser", null);
},
@action
leaveChannel() {
this.router.transitionTo("chat.index");
},
@action
handleFilterKeyUp(event) {
if (event.key === "Tab") {
const enabledComposer = document.querySelector(".chat-composer-input");
if (enabledComposer && !enabledComposer.disabled) {
event.preventDefault();
event.stopPropagation();
enabledComposer.focus();
}
}
if (
(event.key === "Enter" || event.key === "Backspace") &&
this.highlightedSelectedUser
) {
event.preventDefault();
event.stopPropagation();
this.deselectUser(this.highlightedSelectedUser);
return;
}
if (event.key === "Backspace" && isEmpty(this.term) && this.hasSelection) {
event.preventDefault();
event.stopPropagation();
this.deselectUser(this.channel.chatable.users.lastObject);
}
if (event.key === "Enter" && this.focusedUser) {
event.preventDefault();
event.stopPropagation();
this.selectUser(this.focusedUser);
}
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
this._handleVerticalArrowKeys(event);
}
if (event.key === "Escape" && this.highlightedSelectedUser) {
this.set("highlightedSelectedUser", null);
}
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
this._handleHorizontalArrowKeys(event);
}
},
_firstSelectWithArrows(event) {
if (event.key === "ArrowRight") {
return;
}
if (event.key === "ArrowLeft") {
const position = caretPosition(
document.querySelector(".filter-usernames")
);
if (position > 0) {
return;
} else {
event.preventDefault();
event.stopPropagation();
this.set(
"highlightedSelectedUser",
this.channel.chatable.users.lastObject
);
}
}
},
_changeSelectionWithArrows(event) {
if (event.key === "ArrowRight") {
if (
this.highlightedSelectedUser === this.channel.chatable.users.lastObject
) {
this.set("highlightedSelectedUser", null);
return;
}
if (this.channel.chatable.users.length === 1) {
return;
}
this._highlightNextSelectedUser(event.key === "ArrowLeft" ? -1 : 1);
}
if (event.key === "ArrowLeft") {
if (this.channel.chatable.users.length === 1) {
return;
}
this._highlightNextSelectedUser(event.key === "ArrowLeft" ? -1 : 1);
}
},
_highlightNextSelectedUser(modifier) {
const newIndex =
this.channel.chatable.users.indexOf(this.highlightedSelectedUser) +
modifier;
if (this.channel.chatable.users.objectAt(newIndex)) {
this.set(
"highlightedSelectedUser",
this.channel.chatable.users.objectAt(newIndex)
);
} else {
this.set(
"highlightedSelectedUser",
event.key === "ArrowLeft"
? this.channel.chatable.users.lastObject
: this.channel.chatable.users.firstObject
);
}
},
_handleHorizontalArrowKeys(event) {
const position = caretPosition(document.querySelector(".filter-usernames"));
if (position > 0) {
return;
}
if (!this.highlightedSelectedUser) {
this._firstSelectWithArrows(event);
} else {
this._changeSelectionWithArrows(event);
}
},
_handleVerticalArrowKeys(event) {
if (isEmpty(this.users)) {
return;
}
event.preventDefault();
event.stopPropagation();
if (!this.focusedUser) {
this.set("focusedUser", this.users.firstObject);
return;
}
const modifier = event.key === "ArrowUp" ? -1 : 1;
const newIndex = this.users.indexOf(this.focusedUser) + modifier;
if (this.users.objectAt(newIndex)) {
this.set("focusedUser", this.users.objectAt(newIndex));
} else {
this.set(
"focusedUser",
event.key === "ArrowUp" ? this.users.lastObject : this.users.firstObject
);
}
},
});