mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	add qr context menus
This commit is contained in:
		
							
								
								
									
										46
									
								
								public/scripts/extensions/quick-reply/src/ContextMenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								public/scripts/extensions/quick-reply/src/ContextMenu.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| import { MenuItem } from "./MenuItem.js"; | ||||
|  | ||||
| export class ContextMenu { | ||||
| 	/**@type {HTMLElement}*/ root; | ||||
| 	/**@type {HTMLElement}*/ menu; | ||||
|  | ||||
| 	/**@type {MenuItem[]}*/ itemList = []; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 	constructor(/**@type {MenuItem[]}*/items) { | ||||
| 		this.itemList = items; | ||||
| 	} | ||||
|  | ||||
| 	render() { | ||||
| 		if (!this.root) { | ||||
| 			const blocker = document.createElement('div'); { | ||||
| 				this.root = blocker; | ||||
| 				blocker.classList.add('ctx-blocker'); | ||||
| 				blocker.addEventListener('click', ()=>this.hide()); | ||||
| 				const menu = document.createElement('ul'); { | ||||
| 					this.menu = menu; | ||||
| 					menu.classList.add('list-group'); | ||||
| 					menu.classList.add('ctx-menu'); | ||||
| 					this.itemList.forEach(it=>menu.append(it.render())); | ||||
| 					blocker.append(menu); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return this.root; | ||||
| 	} | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 	show({screenX, screenY}) { | ||||
| 		this.render(); | ||||
| 		this.menu.style.bottom = `${window.innerHeight - screenY}px`; | ||||
| 		this.menu.style.left = `${screenX}px`; | ||||
| 		document.body.append(this.root); | ||||
| 	} | ||||
| 	hide() { | ||||
| 		this.root.remove(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										27
									
								
								public/scripts/extensions/quick-reply/src/MenuHeader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								public/scripts/extensions/quick-reply/src/MenuHeader.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| import { SubMenu } from "./SubMenu.js"; | ||||
|  | ||||
| export class MenuHeader { | ||||
| 	/**@type {String}*/ label; | ||||
|  | ||||
| 	/**@type {HTMLElement}*/ root; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 	constructor(/**@type {String}*/label) { | ||||
| 		this.label = label; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	render() { | ||||
| 		if (!this.root) { | ||||
| 			const item = document.createElement('li'); { | ||||
| 				this.root = item; | ||||
| 				item.classList.add('list-group-item'); | ||||
| 				item.classList.add('ctx-header'); | ||||
| 				item.append(this.label); | ||||
| 			} | ||||
| 		} | ||||
| 		return this.root; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										43
									
								
								public/scripts/extensions/quick-reply/src/MenuItem.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								public/scripts/extensions/quick-reply/src/MenuItem.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| import { SubMenu } from "./SubMenu.js"; | ||||
|  | ||||
| export class MenuItem { | ||||
| 	/**@type {String}*/ label; | ||||
| 	/**@type {Object}*/ value; | ||||
| 	/**@type {Function}*/ callback; | ||||
| 	/**@type {MenuItem[]}*/ childList = []; | ||||
|  | ||||
| 	/**@type {HTMLElement}*/ root; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 	constructor(/**@type {String}*/label, /**@type {Object}*/value, /**@type {function}*/callback, /**@type {MenuItem[]}*/children=[]) { | ||||
| 		this.label = label; | ||||
| 		this.value = value; | ||||
| 		this.callback = callback; | ||||
| 		this.childList = children; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	render() { | ||||
| 		if (!this.root) { | ||||
| 			const item = document.createElement('li'); { | ||||
| 				this.root = item; | ||||
| 				item.classList.add('list-group-item'); | ||||
| 				item.classList.add('ctx-item'); | ||||
| 				item.title = this.value; | ||||
| 				if (this.callback) { | ||||
| 					item.addEventListener('click', (evt)=>this.callback(evt, this)); | ||||
| 				} | ||||
| 				if (this.childList.length > 0) { | ||||
| 					item.classList.add('ctx-has-children'); | ||||
| 					const sub = new SubMenu(this.childList); | ||||
| 					item.addEventListener('pointerover', ()=>sub.show(item)); | ||||
| 					item.addEventListener('pointerleave', ()=>sub.hide()); | ||||
| 				} | ||||
| 				item.append(this.label); | ||||
| 			} | ||||
| 		} | ||||
| 		return this.root; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										55
									
								
								public/scripts/extensions/quick-reply/src/SubMenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								public/scripts/extensions/quick-reply/src/SubMenu.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| import { MenuItem } from "./MenuItem.js"; | ||||
|  | ||||
| export class SubMenu { | ||||
| 	/**@type {MenuItem[]}*/ itemList = []; | ||||
| 	/**@type {Boolean}*/ isActive = false; | ||||
| 	 | ||||
| 	/**@type {HTMLElement}*/ root; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 	constructor(/**@type {MenuItem[]}*/items) { | ||||
| 		this.itemList = items; | ||||
| 	} | ||||
|  | ||||
| 	render() { | ||||
| 		if (!this.root) { | ||||
| 			const menu = document.createElement('ul'); { | ||||
| 				this.root = menu; | ||||
| 				menu.classList.add('list-group'); | ||||
| 				menu.classList.add('ctx-menu'); | ||||
| 				menu.classList.add('ctx-sub-menu'); | ||||
| 				this.itemList.forEach(it=>menu.append(it.render())); | ||||
| 			} | ||||
| 		} | ||||
| 		return this.root; | ||||
| 	} | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 	show(/**@type {HTMLElement}*/parent) { | ||||
| 		if (this.isActive) return; | ||||
| 		this.isActive = true; | ||||
| 		this.render(); | ||||
| 		parent.append(this.root); | ||||
| 		requestAnimationFrame(()=>{ | ||||
| 			const rect = this.root.getBoundingClientRect(); | ||||
| 			console.log(window.innerHeight, rect); | ||||
| 			if (rect.bottom > window.innerHeight - 5) { | ||||
| 				this.root.style.top = `${window.innerHeight - 5 - rect.bottom}px`; | ||||
| 			} | ||||
| 			if (rect.right > window.innerWidth - 5) { | ||||
| 				this.root.style.left = 'unset'; | ||||
| 				this.root.style.right = '100%'; | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 	hide() { | ||||
| 		this.root.remove(); | ||||
| 		this.root.style.top = ''; | ||||
| 		this.root.style.left = ''; | ||||
| 		this.isActive = false; | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user