mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-25 00:39:27 +02:00
everything working properly
This commit is contained in:
parent
b48efdf883
commit
4bc465a964
62
src/data/emoji.ts
Normal file
62
src/data/emoji.ts
Normal file
File diff suppressed because one or more lines are too long
@ -84,7 +84,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
// for performance reasons, this limits how many options we can see at once. Without this, it would try to make text options for every single options
|
// for performance reasons, this limits how many options we can see at once. Without this, it would try to make text options for every single options
|
||||||
// which makes the performance take a hit. If there's not enough options to do this (set to 10 at the moment) and the ui mode !== Mode.AUTO_COMPLETE,
|
// which makes the performance take a hit. If there's not enough options to do this (set to 10 at the moment) and the ui mode !== Mode.AUTO_COMPLETE,
|
||||||
// this is ignored and the original code is untouched, with the options array being all the options from the config
|
// this is ignored and the original code is untouched, with the options array being all the options from the config
|
||||||
if (configOptions.length >= 10 && this.scene.ui.getMode() === Mode.AUTO_COMPLETE) {
|
if (configOptions.length >= 10 && this.mode === Mode.AUTO_COMPLETE) {
|
||||||
const optionsScrollTotal = configOptions.length;
|
const optionsScrollTotal = configOptions.length;
|
||||||
const optionStartIndex = this.scrollCursor;
|
const optionStartIndex = this.scrollCursor;
|
||||||
const optionEndIndex = Math.min(optionsScrollTotal, optionStartIndex + (!optionStartIndex || this.scrollCursor + (this.config?.maxOptions! - 1) >= optionsScrollTotal ? this.config?.maxOptions! - 1 : this.config?.maxOptions! - 2));
|
const optionEndIndex = Math.min(optionsScrollTotal, optionStartIndex + (!optionStartIndex || this.scrollCursor + (this.config?.maxOptions! - 1) >= optionsScrollTotal ? this.config?.maxOptions! - 1 : this.config?.maxOptions! - 2));
|
||||||
@ -101,7 +101,9 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
|
|||||||
this.optionSelectIcons.splice(0, this.optionSelectIcons.length);
|
this.optionSelectIcons.splice(0, this.optionSelectIcons.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.optionSelectText = addTextObject(this.scene, 0, 0, options.map(o => o.item ? ` ${o.label}` : o.label).join("\n"), TextStyle.WINDOW, { maxLines: options.length });
|
this.optionSelectText = addTextObject(this.scene, 0, 0, options.map(o => o.item ? ` ${o.label}` : o.label).join("\n"), TextStyle.WINDOW, {
|
||||||
|
maxLines: options.length + 1 // +1 because at the end of the options in autocomplete it hides the last option
|
||||||
|
});
|
||||||
this.optionSelectText.setLineSpacing(this.scale * 72);
|
this.optionSelectText.setLineSpacing(this.scale * 72);
|
||||||
this.optionSelectText.setName("text-option-select");
|
this.optionSelectText.setName("text-option-select");
|
||||||
this.optionSelectText.setLineSpacing(12);
|
this.optionSelectText.setLineSpacing(12);
|
||||||
|
@ -8,20 +8,21 @@ export interface OptionSelectConfigAC extends OptionSelectConfig {
|
|||||||
inputContainer: Phaser.GameObjects.Container;
|
inputContainer: Phaser.GameObjects.Container;
|
||||||
modalContainer: Phaser.GameObjects.Container;
|
modalContainer: Phaser.GameObjects.Container;
|
||||||
maxOptionsReverse?: number;
|
maxOptionsReverse?: number;
|
||||||
reverse?: true;
|
reverse?: true; // So that instead of showing the options looking below the input, they are shown above
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler {
|
export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler {
|
||||||
modalContainer: Phaser.GameObjects.Container;
|
modalContainer: Phaser.GameObjects.Container;
|
||||||
inputContainer: Phaser.GameObjects.Container;
|
inputContainer: Phaser.GameObjects.Container;
|
||||||
handlerKeyDown: (inputObject: InputText, evt: KeyboardEvent) => void;
|
handlerKeyDown: (inputObject: InputText, evt: KeyboardEvent) => void;
|
||||||
|
revertAutoCompleteMode: () => void;
|
||||||
reverse?: true;
|
reverse?: true;
|
||||||
|
|
||||||
constructor(scene: BattleScene, mode: Mode = Mode.AUTO_COMPLETE) {
|
constructor(scene: BattleScene, mode: Mode = Mode.AUTO_COMPLETE) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
|
|
||||||
this.handlerKeyDown = (inputObject, evt) => {
|
this.handlerKeyDown = (inputObject, evt) => {
|
||||||
// Don't move inputText cursor
|
// Don't move inputText cursor, cursor move fast for this
|
||||||
if (["arrowup"].some((key) => key === (evt.code || evt.key).toLowerCase())) {
|
if (["arrowup"].some((key) => key === (evt.code || evt.key).toLowerCase())) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
this.processInput(Button.UP);
|
this.processInput(Button.UP);
|
||||||
@ -30,9 +31,9 @@ export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler
|
|||||||
this.processInput(Button.DOWN);
|
this.processInput(Button.DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert Mode when not press...
|
// Revert Mode if not press...
|
||||||
if (!["enter", "arrowup", "arrowdown"].some((key) => (evt.code || evt.key).toLowerCase().includes(key))) {
|
if (!["enter", "arrowup", "arrowdown", "shift", "control", "alt"].some((key) => (evt.code || evt.key).toLowerCase().includes(key))) {
|
||||||
this.scene.ui.revertMode();
|
this.revertAutoCompleteMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recovery focus
|
// Recovery focus
|
||||||
@ -42,6 +43,13 @@ export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.revertAutoCompleteMode = () => {
|
||||||
|
const ui = this.getUi();
|
||||||
|
if (ui.getMode() === Mode.AUTO_COMPLETE) {
|
||||||
|
ui.revertMode();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getWindowWidth(): integer {
|
getWindowWidth(): integer {
|
||||||
@ -58,7 +66,7 @@ export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler
|
|||||||
const originalHandler = args[0].options[index].handler;
|
const originalHandler = args[0].options[index].handler;
|
||||||
opt.handler = () => {
|
opt.handler = () => {
|
||||||
if (originalHandler()) {
|
if (originalHandler()) {
|
||||||
ui.revertMode();
|
this.revertAutoCompleteMode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -67,35 +75,26 @@ export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler
|
|||||||
this.modalContainer = modalContainer;
|
this.modalContainer = modalContainer;
|
||||||
this.inputContainer = inputContainer;
|
this.inputContainer = inputContainer;
|
||||||
const input = args[0].inputContainer.list.find((el) => el instanceof InputText);
|
const input = args[0].inputContainer.list.find((el) => el instanceof InputText);
|
||||||
const ui = this.getUi();
|
|
||||||
|
|
||||||
const originalsEvents = input.listeners("keydown");
|
const originalsEvents = input.listeners("keydown");
|
||||||
|
// Remove the current keydown events from the input so that the one added in this mode is executed first
|
||||||
for (let i = 0; i < originalsEvents?.length; i++) {
|
for (let i = 0; i < originalsEvents?.length; i++) {
|
||||||
input.off("keydown", originalsEvents[i]);
|
input.off("keydown", originalsEvents[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlerBlur = () => {
|
input.on("blur", this.revertAutoCompleteMode);
|
||||||
ui.revertMode();
|
|
||||||
input.off("blur", handlerBlur);
|
|
||||||
};
|
|
||||||
const handlerPointerUp = () => {
|
|
||||||
ui.revertMode();
|
|
||||||
this.modalContainer.off("pointerup", handlerPointerUp);
|
|
||||||
};
|
|
||||||
|
|
||||||
input.on("blur", handlerBlur);
|
|
||||||
input.on("keydown", this.handlerKeyDown);
|
input.on("keydown", this.handlerKeyDown);
|
||||||
this.modalContainer.on("pointerup", handlerPointerUp);
|
this.modalContainer.on("pointerdown", this.revertAutoCompleteMode);
|
||||||
|
|
||||||
|
// After adding the event that will execute this mode first, return the ones it already had
|
||||||
for (let i = 0; i < originalsEvents?.length; i++) {
|
for (let i = 0; i < originalsEvents?.length; i++) {
|
||||||
input.on("keydown", originalsEvents[i]);
|
input.on("keydown", originalsEvents[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.reverse && newArgs[0].maxOptionsReverse) {
|
|
||||||
newArgs[0].maxOptions = newArgs[0].maxOptionsReverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.reverse) {
|
if (this.reverse) {
|
||||||
|
if (newArgs[0].maxOptionsReverse) {
|
||||||
|
newArgs[0].maxOptions = newArgs[0].maxOptionsReverse;
|
||||||
|
}
|
||||||
newArgs[0].options.reverse();
|
newArgs[0].options.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,18 +112,39 @@ export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler
|
|||||||
protected setupOptions() {
|
protected setupOptions() {
|
||||||
super.setupOptions();
|
super.setupOptions();
|
||||||
if (this.modalContainer) {
|
if (this.modalContainer) {
|
||||||
this.optionSelectContainer.setSize(this.optionSelectContainer.height, Math.max(this.optionSelectText.displayWidth + 24, this.getWindowWidth()));
|
// Adjust the width to the minimum of the visible options
|
||||||
|
this.optionSelectContainer.setSize(this.optionSelectContainer.height, Math.max(this.optionSelectText.displayWidth, this.getWindowWidth()));
|
||||||
if (this.reverse) {
|
if (this.reverse) {
|
||||||
|
// Position above the input
|
||||||
this.optionSelectContainer.setPositionRelative(this.modalContainer, this.optionSelectBg.width + this.inputContainer.x, this.inputContainer.y);
|
this.optionSelectContainer.setPositionRelative(this.modalContainer, this.optionSelectBg.width + this.inputContainer.x, this.inputContainer.y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Position below the input
|
||||||
this.optionSelectContainer.setPositionRelative(this.modalContainer, this.optionSelectBg.width + this.inputContainer.x, this.optionSelectBg.height + this.inputContainer.y + (this.inputContainer.list.find((el) => el instanceof Phaser.GameObjects.NineSlice)?.height ?? 0));
|
this.optionSelectContainer.setPositionRelative(this.modalContainer, this.optionSelectBg.width + this.inputContainer.x, this.optionSelectBg.height + this.inputContainer.y + (this.inputContainer.list.find((el) => el instanceof Phaser.GameObjects.NineSlice)?.height ?? 0));
|
||||||
|
|
||||||
|
// If the modal goes off screen, center it
|
||||||
|
// if ((this.optionSelectContainer.getBounds().width + this.optionSelectContainer.getBounds().x) > this.scene.game.canvas.width) {
|
||||||
|
// this.optionSelectContainer.setX(this.optionSelectContainer.getBounds().x - ((this.optionSelectContainer.getBounds().width + this.optionSelectContainer.getBounds().x) - this.scene.game.canvas.width));
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processInput(button: Button): boolean {
|
||||||
|
// the cancel and action button are here because if you're typing, x and z are used for cancel/action. This means you could be typing something and accidentally cancel/select when you don't mean to
|
||||||
|
// the submit button is therefore used to select a choice (the enter button), though this does not work on my local dev testing for phones, as for my phone/keyboard combo, the enter and z key are both
|
||||||
|
// bound to Button.ACTION, which makes this not work on mobile
|
||||||
|
if (button !== Button.CANCEL && button !== Button.ACTION) {
|
||||||
|
return super.processInput(button);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
clear(): void {
|
clear(): void {
|
||||||
super.clear();
|
super.clear();
|
||||||
const input = this.inputContainer.list.find((el) => el instanceof InputText);
|
const input = this.inputContainer.list.find((el) => el instanceof InputText);
|
||||||
input?.off("keydown", this.handlerKeyDown);
|
input?.off("keydown", this.handlerKeyDown);
|
||||||
|
input?.off("blur", this.revertAutoCompleteMode);
|
||||||
|
this.modalContainer.off("pointerdown", this.revertAutoCompleteMode);
|
||||||
|
this.scrollCursor = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,30 @@ import { OptionSelectItem } from "./abstact-option-select-ui-handler";
|
|||||||
import { addWindow } from "./ui-theme";
|
import { addWindow } from "./ui-theme";
|
||||||
import { addTextObject, getTextStyleOptions, TextStyle } from "./text";
|
import { addTextObject, getTextStyleOptions, TextStyle } from "./text";
|
||||||
import InputText from "phaser3-rex-plugins/plugins/inputtext";
|
import InputText from "phaser3-rex-plugins/plugins/inputtext";
|
||||||
import BattleScene from "#app/battle-scene.js";
|
import BattleScene from "#app/battle-scene";
|
||||||
import AutoCompleteUiHandler, { OptionSelectConfigAC } from "./autocomplete-ui-handler";
|
import AutoCompleteUiHandler, { OptionSelectConfigAC } from "./autocomplete-ui-handler";
|
||||||
|
import emojisAvailable from "#app/data/emoji";
|
||||||
|
import { emojiRegex } from "#app/data/emoji";
|
||||||
|
|
||||||
const emojiAvailable = ["♪", "★", "♥", "♣", "☻", "ª", "☼", "►", "♫", "←", "→", "↩", "↪"];
|
function textArrayWithEmojis(str: string): string[] {
|
||||||
|
const result: string[] = [];
|
||||||
|
let match;
|
||||||
|
let lastIndex = 0;
|
||||||
|
|
||||||
|
while ((match = emojiRegex.exec(str)) !== null) {
|
||||||
|
if (match.index > lastIndex) {
|
||||||
|
result.push(...str.slice(lastIndex, match.index).split(""));
|
||||||
|
}
|
||||||
|
result.push(match[0]);
|
||||||
|
lastIndex = emojiRegex.lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastIndex < str.length) {
|
||||||
|
result.push(...str.slice(lastIndex).split(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
export default class RenameFormUiHandler extends FormModalUiHandler {
|
export default class RenameFormUiHandler extends FormModalUiHandler {
|
||||||
protected autocomplete: AutoCompleteUiHandler;
|
protected autocomplete: AutoCompleteUiHandler;
|
||||||
@ -94,7 +114,7 @@ export default class RenameFormUiHandler extends FormModalUiHandler {
|
|||||||
const maxEmojis = 6;
|
const maxEmojis = 6;
|
||||||
|
|
||||||
const modalOptions: OptionSelectConfigAC = {
|
const modalOptions: OptionSelectConfigAC = {
|
||||||
options: emojiAvailable.map((emoji, index): OptionSelectItem => {
|
options: emojisAvailable.map((emoji, index): OptionSelectItem => {
|
||||||
return {
|
return {
|
||||||
label: `${emoji} /${index + 1}`,
|
label: `${emoji} /${index + 1}`,
|
||||||
handler: ()=> {
|
handler: ()=> {
|
||||||
@ -125,62 +145,81 @@ export default class RenameFormUiHandler extends FormModalUiHandler {
|
|||||||
// If deleting and currently positioned at "/", display the list of emojis
|
// If deleting and currently positioned at "/", display the list of emojis
|
||||||
if (
|
if (
|
||||||
!evt.data &&
|
!evt.data &&
|
||||||
input.text.split("").filter((char) => emojiAvailable.some((em) => em === char)).length < maxEmojis &&
|
input.text.split("").filter((char) => emojisAvailable.some((em) => em === char)).length < maxEmojis &&
|
||||||
input.text.split("").some((char, i) => char === "/" && i + 1 === input.cursorPosition)
|
input.text.split("").some((char, i) => char === "/" && i + 1 === input.cursorPosition)
|
||||||
) {
|
) {
|
||||||
ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOptions);
|
ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDisallowedEmojis = (text) => {
|
|
||||||
return text.split("").filter((char) => {
|
|
||||||
const isEmoji = !char.match(/[\u0000-\u00ff]/);
|
|
||||||
const isAllowedEmoji = emojiAvailable.includes(char);
|
|
||||||
return isEmoji && !isAllowedEmoji;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove disallowed emojis.
|
// Remove disallowed emojis.
|
||||||
while (getDisallowedEmojis(input.text).length > 0) {
|
if (textArrayWithEmojis(input.text).filter((char) => {
|
||||||
const disallowedEmojis = getDisallowedEmojis(input.text);
|
// const isEmoji = !char.match(/[\u0000-\u00ff]/); // Emojis, special characters and kaomojis
|
||||||
const lastDisallowedEmojiIndex = input.text.lastIndexOf(disallowedEmojis[0]);
|
const isEmoji = char.match(emojiRegex); // Only Emojis
|
||||||
|
const isAllowedEmoji = emojisAvailable.includes(char);
|
||||||
if (lastDisallowedEmojiIndex !== -1) {
|
return isEmoji && !isAllowedEmoji;
|
||||||
const textBeforeCursor = input.text.substring(0, lastDisallowedEmojiIndex);
|
}).length) {
|
||||||
const textAfterCursor = input.text.substring(lastDisallowedEmojiIndex + 1);
|
const regex = emojiRegex;
|
||||||
const newText = textBeforeCursor + textAfterCursor;
|
let totalLength: number = 0;
|
||||||
|
const newText = input.text.replace(regex, (match) => {
|
||||||
if (newText !== input.text) {
|
if (emojisAvailable.includes(match)) {
|
||||||
input.setText(newText);
|
return match;
|
||||||
input.setCursorPosition(lastDisallowedEmojiIndex);
|
|
||||||
}
|
}
|
||||||
}
|
totalLength += match.length;
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
const cursorPosition = input.cursorPosition;
|
||||||
|
input.setText(newText);
|
||||||
|
input.setCursorPosition(cursorPosition - totalLength);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If the number of available emojis exceeds the maximum allowed number of emojis..
|
// If the number of available emojis exceeds the maximum allowed number of emojis..
|
||||||
//.. Delete any attempt to insert another one.
|
//.. Delete any attempt to insert another one.
|
||||||
if (evt.data && input.text.split("").filter((char) => emojiAvailable.some((em) => em === char)).length > maxEmojis) {
|
while (textArrayWithEmojis(input.text).filter((char) => emojisAvailable.includes(char)).length > maxEmojis) {
|
||||||
const texto = input.text;
|
const charactersWithEmojis = textArrayWithEmojis(input.text);
|
||||||
const textBeforeCursor = texto.substring(0, input.cursorPosition);
|
const emojis = charactersWithEmojis.filter((char, i, arr) => {
|
||||||
const textAfterCursor = texto.substring(input.cursorPosition);
|
if (emojisAvailable.includes(char)) {
|
||||||
|
let totalLength = 0;
|
||||||
|
for (let j = 0; j <= i; j++) {
|
||||||
|
totalLength += arr[j].length;
|
||||||
|
}
|
||||||
|
return totalLength < input.cursorPosition + 1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
const cursorPosition = input.cursorPosition;
|
||||||
|
const lastEmoji = emojis[emojis.length - 1];
|
||||||
|
const lastEmojiIndex = charactersWithEmojis.filter((char, i, arr) => {
|
||||||
|
let totalLength = 0;
|
||||||
|
for (let j = 0; j <= i; j++) {
|
||||||
|
totalLength += arr[j].length;
|
||||||
|
}
|
||||||
|
return totalLength < input.cursorPosition + 1;
|
||||||
|
}).lastIndexOf(lastEmoji);
|
||||||
|
|
||||||
const exactlyEmoji = textBeforeCursor.lastIndexOf(evt.data);
|
if (lastEmojiIndex !== -1) {
|
||||||
if (exactlyEmoji !== -1) {
|
const textBeforeCursor = charactersWithEmojis.slice(0, lastEmojiIndex).join("");
|
||||||
const textReplace = textBeforeCursor.substring(0, exactlyEmoji) + textAfterCursor;
|
const textAfterCursor = charactersWithEmojis.slice(lastEmojiIndex + 1).join("");
|
||||||
if (textReplace !== input.text) {
|
const newText = textBeforeCursor + textAfterCursor;
|
||||||
input.setText(textReplace);
|
|
||||||
input.setCursorPosition(exactlyEmoji);
|
if (newText !== input.text) {
|
||||||
|
input.setText(newText);
|
||||||
|
input.setCursorPosition(cursorPosition - lastEmoji.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the number of available emojis has been reached, do not display the list of emojis
|
// If the number of available emojis has been reached, do not display the list of emojis
|
||||||
if (evt.data && input.text.split("").filter((char) => emojiAvailable.some((em) => em === char)).length < maxEmojis) {
|
if (evt.data && input.text.split("").filter((char) => emojisAvailable.some((em) => em === char)).length < maxEmojis) {
|
||||||
|
|
||||||
// Retrieve the exact command, as it can be either "/", or "/n"
|
// Retrieve the exact command, as it can be either "/", or "/n"
|
||||||
const command = input.text.split("").filter((_, i, arr) => arr.includes("/") && i >= (input.text.split("").filter((_, i) => i < input.cursorPosition).lastIndexOf("/")) && i < input.cursorPosition).join("");
|
const command = input.text.split("").filter((_, i, arr) => i >= (input.text.split("").filter((_, i) => i < input.cursorPosition).lastIndexOf("/")) && i < input.cursorPosition).join("");
|
||||||
|
|
||||||
if (modalOptions.options.some((opt) => opt.label.includes(command))) {
|
if (evt.data === "/") {
|
||||||
|
ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOptions);
|
||||||
|
} else if (command.includes("/") && modalOptions.options.some((opt) => opt.label.includes(command))) {
|
||||||
const filterOptions = {
|
const filterOptions = {
|
||||||
...modalOptions,
|
...modalOptions,
|
||||||
options: modalOptions.options.filter((opt) => opt.label.includes(command))
|
options: modalOptions.options.filter((opt) => opt.label.includes(command))
|
||||||
|
@ -5,6 +5,8 @@ import { PlayerPokemon } from "#app/field/pokemon";
|
|||||||
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
|
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils";
|
||||||
import { Mode } from "./ui";
|
import { Mode } from "./ui";
|
||||||
|
import { OptionSelectConfigAC } from "./autocomplete-ui-handler";
|
||||||
|
import InputText from "phaser3-rex-plugins/plugins/inputtext";
|
||||||
|
|
||||||
export default class TestDialogueUiHandler extends FormModalUiHandler {
|
export default class TestDialogueUiHandler extends FormModalUiHandler {
|
||||||
|
|
||||||
@ -23,7 +25,6 @@ export default class TestDialogueUiHandler extends FormModalUiHandler {
|
|||||||
|
|
||||||
if (typeof value === "object" && !isNullOrUndefined(value)) { // we check for not null or undefined here because if the language json file has a null key, the typeof will still be an object, but that object will be null, causing issues
|
if (typeof value === "object" && !isNullOrUndefined(value)) { // we check for not null or undefined here because if the language json file has a null key, the typeof will still be an object, but that object will be null, causing issues
|
||||||
// If the value is an object, execute the same process
|
// If the value is an object, execute the same process
|
||||||
// si el valor es un objeto ejecuta el mismo proceso
|
|
||||||
|
|
||||||
return flattenKeys(value, topKey ?? t, topKey ? midleKey ? [...midleKey, t] : [t] : undefined).filter((t) => t.length > 0);
|
return flattenKeys(value, topKey ?? t, topKey ? midleKey ? [...midleKey, t] : [t] : undefined).filter((t) => t.length > 0);
|
||||||
} else if (typeof value === "string" || isNullOrUndefined(value)) { // we check for null or undefined here as per above - the typeof is still an object but the value is null so we need to exit out of this and pass the null key
|
} else if (typeof value === "string" || isNullOrUndefined(value)) { // we check for null or undefined here as per above - the typeof is still an object but the value is null so we need to exit out of this and pass the null key
|
||||||
@ -73,37 +74,33 @@ export default class TestDialogueUiHandler extends FormModalUiHandler {
|
|||||||
const input = this.inputs[0];
|
const input = this.inputs[0];
|
||||||
input.setMaxLength(255);
|
input.setMaxLength(255);
|
||||||
|
|
||||||
input.on("keydown", (inputObject, evt: KeyboardEvent) => {
|
input.on("textchange", (inputObject: InputText, evt: InputEvent) => {
|
||||||
if (["escape", "space"].some((v) => v === evt.key.toLowerCase() || v === evt.code.toLowerCase()) && ui.getMode() === Mode.AUTO_COMPLETE) {
|
|
||||||
// Delete autocomplete list and recovery focus.
|
|
||||||
inputObject.on("blur", () => inputObject.node.focus(), { once: true });
|
|
||||||
ui.revertMode();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
input.on("textchange", (inputObject, evt: InputEvent) => {
|
|
||||||
// Delete autocomplete.
|
|
||||||
if (ui.getMode() === Mode.AUTO_COMPLETE) {
|
|
||||||
ui.revertMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
let options: OptionSelectItem[] = [];
|
let options: OptionSelectItem[] = [];
|
||||||
const splitArr = inputObject.text.split(" ");
|
const splitArr = inputObject.text.split(" ");
|
||||||
const filteredKeys = this.keys.filter((command) => command.toLowerCase().includes(splitArr[splitArr.length - 1].toLowerCase()));
|
|
||||||
|
// At what index of splitArr is the input cursor located
|
||||||
|
let indexInOriginalArray = 0;
|
||||||
|
let cumulativeLength = 0;
|
||||||
|
for (let i = 0; i < splitArr.length; i++) {
|
||||||
|
const spaceAndWordLength = splitArr[i] === "" ? 2 : 1;
|
||||||
|
cumulativeLength += (splitArr[i].length + spaceAndWordLength);
|
||||||
|
if (cumulativeLength > input.cursorPosition) {
|
||||||
|
indexInOriginalArray = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredKeys = this.keys.filter((command) => command.toLowerCase().includes(splitArr[indexInOriginalArray].toLowerCase()));
|
||||||
if (inputObject.text !== "" && filteredKeys.length > 0) {
|
if (inputObject.text !== "" && filteredKeys.length > 0) {
|
||||||
// if performance is required, you could reduce the number of total results by changing the slice below to not have all ~8000 inputs going
|
options = filteredKeys.map((value) => {
|
||||||
options = filteredKeys.slice(0).map((value) => {
|
|
||||||
return {
|
return {
|
||||||
label: value,
|
label: value,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
// this is here to make sure that if you try to backspace then enter, the last known evt.data (backspace) is picked up
|
const separatedArray = inputObject.text.split(" ");
|
||||||
// this is because evt.data is null for backspace, so without this, the autocomplete windows just closes
|
separatedArray[indexInOriginalArray] = value;
|
||||||
if (!isNullOrUndefined(evt.data) || evt.inputType?.toLowerCase() === "deletecontentbackward") {
|
const cursorPosition = inputObject.cursorPosition - splitArr[indexInOriginalArray].length + separatedArray[indexInOriginalArray].length;
|
||||||
const separatedArray = inputObject.text.split(" ");
|
inputObject.setText(separatedArray.join(" "));
|
||||||
separatedArray[separatedArray.length - 1] = value;
|
inputObject.setCursorPosition(cursorPosition);
|
||||||
inputObject.setText(separatedArray.join(" "));
|
|
||||||
}
|
|
||||||
ui.revertMode();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -111,10 +108,11 @@ export default class TestDialogueUiHandler extends FormModalUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.length > 0) {
|
if (options.length > 0) {
|
||||||
const modalOpts = {
|
const modalOpts: OptionSelectConfigAC = {
|
||||||
options: options,
|
options: options,
|
||||||
maxOptions: 5,
|
maxOptions: 5,
|
||||||
modalContainer: this.modalContainer
|
modalContainer: this.modalContainer,
|
||||||
|
inputContainer: this.inputContainers[0]
|
||||||
};
|
};
|
||||||
ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOpts);
|
ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOpts);
|
||||||
}
|
}
|
||||||
@ -140,6 +138,12 @@ export default class TestDialogueUiHandler extends FormModalUiHandler {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
const originalCancel = config.buttonActions[1];
|
||||||
|
config.buttonActions[1] = ()=>{
|
||||||
|
if (ui.getMode() === Mode.TEST_DIALOGUE) {
|
||||||
|
originalCancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user