mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-01 18:37:41 +01:00
Add character group overlay including styles
This commit is contained in:
parent
45c6c61e8a
commit
91151cb3d6
13
public/css/character-group-overlay.css
Normal file
13
public/css/character-group-overlay.css
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
#rm_print_characters_block.group_overlay_mode_select .character_select {
|
||||
background-color: rgba(170, 170, 170, 0.2);
|
||||
}
|
||||
|
||||
#rm_print_characters_block.group_overlay_mode_select .character_select.character_selected {
|
||||
background-color: var(--SmartThemeQuoteColor);
|
||||
}
|
||||
|
||||
#rm_print_characters_block.group_overlay_mode_select .character_select .bulk_select_checkbox {
|
||||
visibility: hidden;
|
||||
height: 0 !important;
|
||||
}
|
172
public/scripts/CharacterGroupOverlay.js
Normal file
172
public/scripts/CharacterGroupOverlay.js
Normal file
@ -0,0 +1,172 @@
|
||||
"use strict";
|
||||
|
||||
import {event_types, eventSource} from "../script.js";
|
||||
|
||||
/**
|
||||
* Implement a SingletonPattern, allowing access to the group overlay instance
|
||||
* from everywhere via (new CharacterGroupOverlay())
|
||||
*
|
||||
* @type CharacterGroupOverlay
|
||||
*/
|
||||
let characterGroupOverlayInstance = null;
|
||||
|
||||
class State {
|
||||
static browse = 0;
|
||||
static select = 1;
|
||||
}
|
||||
|
||||
class CharacterGroupOverlay {
|
||||
static containerId = 'rm_print_characters_block';
|
||||
static selectModeClass = 'group_overlay_mode_select';
|
||||
static selectedClass = 'character_selected';
|
||||
|
||||
#state = State.browse;
|
||||
#longPress = false;
|
||||
#longPressEndCallbacks = [];
|
||||
#selectedCharacters = [];
|
||||
|
||||
/**
|
||||
* @type HTMLElement
|
||||
*/
|
||||
container = null;
|
||||
|
||||
get state() {
|
||||
return this.#state;
|
||||
}
|
||||
|
||||
set state(newState) {
|
||||
if (this.#state === newState) return;
|
||||
|
||||
eventSource.emit(event_types.CHARACTER_GROUP_OVERLAY_STATE_CHANGE_BEFORE, newState)
|
||||
.then(() => {
|
||||
this.#state = newState;
|
||||
eventSource.emit(event_types.CHARACTER_GROUP_OVERLAY_STATE_CHANGE_AFTER, this.state)
|
||||
});
|
||||
}
|
||||
|
||||
get isLongPress() {
|
||||
return this.#longPress;
|
||||
}
|
||||
|
||||
set isLongPress(longPress) {
|
||||
this.#longPress = longPress;
|
||||
}
|
||||
|
||||
get longPressEndCallbacks() {
|
||||
return this.#longPressEndCallbacks;
|
||||
}
|
||||
|
||||
get selectedCharacters() {
|
||||
return this.#selectedCharacters;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
if (characterGroupOverlayInstance instanceof CharacterGroupOverlay)
|
||||
return characterGroupOverlayInstance
|
||||
|
||||
this.container = document.getElementById(CharacterGroupOverlay.containerId);
|
||||
this.container.addEventListener('click', this.handleCancelClick);
|
||||
|
||||
eventSource.on(event_types.CHARACTER_GROUP_OVERLAY_STATE_CHANGE_AFTER, this.handleStateChange);
|
||||
characterGroupOverlayInstance = Object.freeze(this);
|
||||
}
|
||||
|
||||
browseState = () => this.state = State.browse;
|
||||
selectState = () => this.state = State.select;
|
||||
|
||||
/**
|
||||
* Set up a Sortable grid for the loaded page
|
||||
*/
|
||||
onPageLoad = () => {
|
||||
let touchState = false;
|
||||
const grid = document.getElementById('rm_print_characters_block');
|
||||
|
||||
const sortable = new Sortable(grid, {
|
||||
group: 'shared',
|
||||
animation: 150,
|
||||
sort:false,
|
||||
handle: '.character_select',
|
||||
onEnd: (evt) => {
|
||||
if (evt.from !== evt.to) {
|
||||
console.log('Folder creation request')
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const elements = [...document.getElementsByClassName('character_select')];
|
||||
|
||||
elements.forEach(element => element.addEventListener('touchstart', this.handleHold));
|
||||
elements.forEach(element => element.addEventListener('mousedown', this.handleHold));
|
||||
|
||||
elements.forEach(element => element.addEventListener('touchend', this._handleLongPressEnd));
|
||||
elements.forEach(element => element.addEventListener('mouseup', this._handleLongPressEnd));
|
||||
elements.forEach(element => element.addEventListener('dragend', this._handleLongPressEnd));
|
||||
|
||||
grid.addEventListener('click', this.handleCancelClick);
|
||||
}
|
||||
|
||||
handleHold = (event) => {
|
||||
this.isLongPress = true;
|
||||
setTimeout(() => {
|
||||
if (this.isLongPress) {
|
||||
this.state = State.select;
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
_handleLongPressEnd = () => {
|
||||
this.isLongPress = false;
|
||||
}
|
||||
|
||||
handleCancelClick = () => {
|
||||
this.state = State.browse;
|
||||
}
|
||||
|
||||
handleStateChange = () => {
|
||||
switch (this.state) {
|
||||
case State.browse:
|
||||
this.container.classList.remove(CharacterGroupOverlay.selectModeClass);
|
||||
[...this.container.getElementsByClassName('character_select')]
|
||||
.forEach(element => element.removeEventListener('click', this.toggleCharacterSelected));
|
||||
this.longPressEndCallbacks.forEach(callback => callback());
|
||||
this.clearSelectedCharacters();
|
||||
break;
|
||||
case State.select:
|
||||
this.container.classList.add(CharacterGroupOverlay.selectModeClass);
|
||||
[...this.container.getElementsByClassName('character_select')]
|
||||
.forEach(element => element.addEventListener('click', this.toggleCharacterSelected));
|
||||
this.clearSelectedCharacters();
|
||||
}
|
||||
}
|
||||
|
||||
toggleCharacterSelected = event => {
|
||||
event.stopPropagation();
|
||||
|
||||
const character = event.currentTarget;
|
||||
const characterId = character.getAttribute('chid');
|
||||
|
||||
const alreadySelected = this.selectedCharacters.includes(characterId)
|
||||
|
||||
if (alreadySelected) {
|
||||
character.classList.remove(CharacterGroupOverlay.selectedClass);
|
||||
this.dismissCharacter(characterId);
|
||||
} else {
|
||||
character.classList.add(CharacterGroupOverlay.selectedClass);
|
||||
this.selectCharacter(characterId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addLongPressEndCallback = callback => this.longPressEndCallbacks.push(callback);
|
||||
|
||||
selectCharacter = characterId => this.selectedCharacters.push(String(characterId));
|
||||
|
||||
dismissCharacter = characterId => this.#selectedCharacters = this.selectedCharacters.filter(item => String(characterId) !== item);
|
||||
|
||||
clearSelectedCharacters = () => {
|
||||
this.selectedCharacters.forEach(characterId => document.querySelector('.character_select[chid="'+characterId+'"]')?.classList.remove(CharacterGroupOverlay.selectedClass))
|
||||
this.selectedCharacters.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export {CharacterGroupOverlay};
|
@ -1,6 +1,7 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
@import url(css/promptmanager.css);
|
||||
@import url(css/character-group-overlay.css);
|
||||
|
||||
:root {
|
||||
--doc-height: 100%;
|
||||
|
Loading…
x
Reference in New Issue
Block a user