添加基础菜单
This commit is contained in:
@@ -5,6 +5,12 @@ import { EditorEvents } from "@tiptap/core";
|
||||
import { UAIEditorEventListener, UAIEditorOptions } from "../../../core/UAIEditor.ts";
|
||||
|
||||
import menuIcon from "../../../assets/icons/menu.svg";
|
||||
import { ScrollableDiv } from "./ScrollableDiv";
|
||||
|
||||
import { Redo } from "./base/Redo";
|
||||
import { Undo } from "./base/Undo";
|
||||
import { FormatPainter } from "./base/FormatPainter";
|
||||
import { ClearFormat } from "./base/ClearFormat";
|
||||
|
||||
/**
|
||||
* 传统菜单栏
|
||||
@@ -17,6 +23,16 @@ export class Classic extends HTMLElement implements UAIEditorEventListener {
|
||||
classicMenu!: HTMLElement;
|
||||
classicScrollableContainer!: HTMLElement;
|
||||
|
||||
// 基础菜单容器
|
||||
classicMenuBaseScrollable!: ScrollableDiv;
|
||||
classicMenuBaseGroup!: HTMLElement;
|
||||
|
||||
// 基础菜单
|
||||
baseMenuUndo!: Undo;
|
||||
baseMenuRedo!: Redo;
|
||||
baseMenuFormatPainter!: FormatPainter;
|
||||
baseMenuClearFormat!: ClearFormat;
|
||||
|
||||
constructor(defaultToolbarMenus: Record<string, any>[]) {
|
||||
super();
|
||||
this.defaultToolbarMenus = defaultToolbarMenus;
|
||||
@@ -57,6 +73,17 @@ export class Classic extends HTMLElement implements UAIEditorEventListener {
|
||||
option.value = menu.value;
|
||||
selectMuenus.options.add(option);
|
||||
});
|
||||
// 添加事件,处理菜单分组切换、界面元素切换
|
||||
selectMuenus.addEventListener("change", () => {
|
||||
const menu = selectMuenus.selectedOptions[0].value;
|
||||
this.classicMenuBaseScrollable.style.display = "none";
|
||||
if (menu === "base") {
|
||||
this.classicMenuBaseScrollable.style.display = "flex";
|
||||
}
|
||||
})
|
||||
// 创建分组菜单
|
||||
this.createBaseMenu(event, options);
|
||||
this.classicMenuBaseScrollable.style.display = "flex";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,5 +107,37 @@ export class Classic extends HTMLElement implements UAIEditorEventListener {
|
||||
* 初始化菜单
|
||||
*/
|
||||
initMenus() {
|
||||
this.baseMenuUndo = new Undo({ menuType: "button", enable: true, hideText: false });
|
||||
this.eventComponents.push(this.baseMenuUndo);
|
||||
|
||||
this.baseMenuRedo = new Redo({ menuType: "button", enable: true });
|
||||
this.eventComponents.push(this.baseMenuRedo);
|
||||
|
||||
this.baseMenuFormatPainter = new FormatPainter({ menuType: "button", enable: true });
|
||||
this.eventComponents.push(this.baseMenuFormatPainter);
|
||||
|
||||
this.baseMenuClearFormat = new ClearFormat({ menuType: "button", enable: true });
|
||||
this.eventComponents.push(this.baseMenuClearFormat);
|
||||
}
|
||||
/**
|
||||
* 创建基础菜单
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
createBaseMenu(event: EditorEvents["create"], options: UAIEditorOptions) {
|
||||
this.classicMenuBaseGroup = document.createElement("div");
|
||||
this.classicMenuBaseGroup.style.display = "flex";
|
||||
this.classicMenuBaseScrollable = new ScrollableDiv(this.classicMenuBaseGroup);
|
||||
this.classicMenuBaseScrollable.style.display = "none";
|
||||
this.classicMenu.appendChild(this.classicMenuBaseScrollable);
|
||||
this.classicMenuBaseScrollable.onCreate(event, options);
|
||||
|
||||
const group1 = document.createElement("div");
|
||||
group1.classList.add("uai-classic-virtual-group");
|
||||
this.classicMenuBaseGroup.appendChild(group1);
|
||||
group1.appendChild(this.baseMenuUndo);
|
||||
group1.appendChild(this.baseMenuRedo);
|
||||
group1.appendChild(this.baseMenuFormatPainter);
|
||||
group1.appendChild(this.baseMenuClearFormat);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,13 @@ import { EditorEvents } from "@tiptap/core";
|
||||
import { UAIEditorEventListener, UAIEditorOptions } from "../../../core/UAIEditor.ts";
|
||||
|
||||
import { t } from "i18next";
|
||||
import { ScrollableDiv } from "./ScrollableDiv";
|
||||
|
||||
import { Redo } from "./base/Redo";
|
||||
import { Undo } from "./base/Undo";
|
||||
|
||||
import { FormatPainter } from "./base/FormatPainter";
|
||||
import { ClearFormat } from "./base/ClearFormat";
|
||||
|
||||
/**
|
||||
* 经典菜单栏
|
||||
@@ -18,6 +25,17 @@ export class Ribbon extends HTMLElement implements UAIEditorEventListener {
|
||||
ribbonMenu!: HTMLElement;
|
||||
ribbonScrollableContainer!: HTMLElement;
|
||||
|
||||
// 基础菜单容器
|
||||
ribbonMenuBaseScrollable!: ScrollableDiv;
|
||||
ribbonMenuBaseGroup!: HTMLElement;
|
||||
|
||||
// 基础菜单
|
||||
baseMenuUndo!: Undo;
|
||||
baseMenuRedo!: Redo;
|
||||
|
||||
baseMenuFormatPainter!: FormatPainter;
|
||||
baseMenuClearFormat!: ClearFormat;
|
||||
|
||||
constructor(defaultToolbarMenus: Record<string, any>[]) {
|
||||
super();
|
||||
this.defaultToolbarMenus = defaultToolbarMenus;
|
||||
@@ -54,6 +72,10 @@ export class Ribbon extends HTMLElement implements UAIEditorEventListener {
|
||||
ribbonTabs.children[i].classList.remove("active");
|
||||
}
|
||||
tab.classList.add("active");
|
||||
this.ribbonMenuBaseScrollable.style.display = "none";
|
||||
if (menu.value === "base") {
|
||||
this.ribbonMenuBaseScrollable.style.display = "flex";
|
||||
}
|
||||
})
|
||||
ribbonTabs.appendChild(tab);
|
||||
});
|
||||
@@ -69,6 +91,10 @@ export class Ribbon extends HTMLElement implements UAIEditorEventListener {
|
||||
const level = i + 1
|
||||
this.headingOptions.push({ label: `${t('base.heading.text')}`.replace("{level}", `${level}`), desc: `h${level}`, value: level, element: document.createElement("div") })
|
||||
}
|
||||
|
||||
// 创建分组菜单
|
||||
this.createBaseMenu(event, options);
|
||||
this.ribbonMenuBaseScrollable.style.display = "flex";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,5 +130,46 @@ export class Ribbon extends HTMLElement implements UAIEditorEventListener {
|
||||
* 初始化菜单
|
||||
*/
|
||||
initMenus() {
|
||||
this.baseMenuUndo = new Undo({ menuType: "button", enable: true });
|
||||
this.eventComponents.push(this.baseMenuUndo);
|
||||
|
||||
this.baseMenuRedo = new Redo({ menuType: "button", enable: true });
|
||||
this.eventComponents.push(this.baseMenuRedo);
|
||||
|
||||
this.baseMenuFormatPainter = new FormatPainter({ menuType: "button", enable: true });
|
||||
this.eventComponents.push(this.baseMenuFormatPainter);
|
||||
|
||||
this.baseMenuClearFormat = new ClearFormat({ menuType: "button", enable: true });
|
||||
this.eventComponents.push(this.baseMenuClearFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建基础菜单
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
createBaseMenu(event: EditorEvents["create"], _options: UAIEditorOptions) {
|
||||
this.ribbonMenuBaseGroup = document.createElement("div");
|
||||
this.ribbonMenuBaseGroup.classList.add("uai-ribbon-container");
|
||||
this.ribbonMenuBaseGroup.style.display = "flex";
|
||||
this.ribbonMenuBaseScrollable = new ScrollableDiv(this.ribbonMenuBaseGroup);
|
||||
this.ribbonMenuBaseScrollable.style.display = "none";
|
||||
this.ribbonScrollableContainer.appendChild(this.ribbonMenuBaseScrollable);
|
||||
|
||||
const group1 = document.createElement("div");
|
||||
group1.classList.add("uai-ribbon-virtual-group");
|
||||
this.ribbonMenuBaseGroup.appendChild(group1);
|
||||
|
||||
const group1row1 = document.createElement("div");
|
||||
group1row1.classList.add("uai-ribbon-virtual-group-row");
|
||||
group1.appendChild(group1row1);
|
||||
group1row1.appendChild(this.baseMenuUndo);
|
||||
group1row1.appendChild(this.baseMenuRedo);
|
||||
|
||||
const group1row2 = document.createElement("div");
|
||||
group1row2.classList.add("uai-ribbon-virtual-group-row");
|
||||
group1.appendChild(group1row2);
|
||||
group1row2.appendChild(this.baseMenuFormatPainter);
|
||||
group1row2.appendChild(this.baseMenuClearFormat);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2024-present AI-Labs
|
||||
|
||||
// @ ts-nocheck
|
||||
import { EditorEvents } from "@tiptap/core";
|
||||
import { UAIEditorEventListener, UAIEditorOptions } from "../../../core/UAIEditor.ts";
|
||||
|
||||
/**
|
||||
* 可滚动容器
|
||||
*/
|
||||
export class ScrollableDiv extends HTMLElement implements UAIEditorEventListener {
|
||||
private container: HTMLElement;
|
||||
scrollLeftBtn: HTMLElement;
|
||||
content: HTMLElement;
|
||||
scrollRightBtn: HTMLElement;
|
||||
private scrollAmount: number = 50; // 每次滚动的像素数
|
||||
private transform: number = 0; // 当前transform值
|
||||
|
||||
constructor(content: HTMLElement) {
|
||||
super();
|
||||
this.content = content;
|
||||
|
||||
this.scrollLeftBtn = document.createElement("div");
|
||||
this.scrollLeftBtn.classList.add("uai-scrollable-control-button");
|
||||
this.scrollLeftBtn.innerHTML = "<strong><</strong>";
|
||||
this.scrollLeftBtn.style.display = "none";
|
||||
this.container = document.createElement("div");
|
||||
this.container.appendChild(this.content);
|
||||
// this.container.style.overflow = "hidden";
|
||||
// this.container.style.position = "relative";
|
||||
this.scrollRightBtn = document.createElement("div");
|
||||
this.scrollRightBtn.classList.add("uai-scrollable-control-button");
|
||||
this.scrollRightBtn.innerHTML = "<strong>></strong>";
|
||||
this.scrollRightBtn.style.display = "none";
|
||||
|
||||
this.scrollLeftBtn.addEventListener('click', () => {
|
||||
if (this.transform < 0) {
|
||||
this.transform += Math.min(this.scrollAmount, 0 - this.transform);
|
||||
}
|
||||
this.content.style.transform = `translateX(${this.transform}px)`;
|
||||
this.scrollButtonControl();
|
||||
});
|
||||
this.scrollRightBtn.addEventListener('click', () => {
|
||||
const scrollWidth = this.content.scrollWidth + this.transform - this.scrollRightBtn.clientWidth - this.container.clientWidth;
|
||||
if (scrollWidth > 0) {
|
||||
this.transform -= Math.min(this.scrollAmount, scrollWidth);
|
||||
}
|
||||
this.content.style.transform = `translateX(${this.transform}px)`;
|
||||
this.scrollButtonControl();
|
||||
});
|
||||
|
||||
this.classList.add("uai-classic-scrollable-menu")
|
||||
this.appendChild(this.scrollLeftBtn)
|
||||
this.appendChild(this.container)
|
||||
this.appendChild(this.scrollRightBtn)
|
||||
}
|
||||
|
||||
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
for (let entry of entries) {
|
||||
if (entry.target === this.parentElement) {
|
||||
this.scrollButtonControl();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
resizeObserver.observe(this.parentElement!);
|
||||
}
|
||||
|
||||
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
|
||||
}
|
||||
|
||||
onEditableChange(editable: boolean) {
|
||||
|
||||
}
|
||||
|
||||
scrollButtonControl() {
|
||||
if (this.transform < 0) {
|
||||
this.scrollLeftBtn.style.display = "flex";
|
||||
} else {
|
||||
this.scrollLeftBtn.style.display = "none";
|
||||
}
|
||||
if (this.parentElement!.scrollWidth + this.transform - this.scrollRightBtn.clientWidth < this.container.clientWidth) {
|
||||
this.scrollRightBtn.style.display = "flex";
|
||||
} else {
|
||||
this.scrollRightBtn.style.display = "none";
|
||||
}
|
||||
// 触发宽度变化事件
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2024-present AI-Labs
|
||||
|
||||
// @ ts-nocheck
|
||||
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
|
||||
import icon from "../../../../assets/icons/clear-format.svg";
|
||||
import { t } from "i18next";
|
||||
import { UAIEditorEventListener, UAIEditorOptions } from "../../../../core/UAIEditor.ts";
|
||||
import { EditorEvents } from "@tiptap/core";
|
||||
|
||||
/**
|
||||
* 基础菜单:清除格式
|
||||
*/
|
||||
export class ClearFormat extends HTMLElement implements UAIEditorEventListener {
|
||||
// 按钮选项
|
||||
menuButtonOptions: MenuButtonOptions = {
|
||||
menuType: "button",
|
||||
enable: true,
|
||||
icon: icon,
|
||||
hideText: true,
|
||||
text: t('base.clearFormat'),
|
||||
tooltip: t('base.clearFormat'),
|
||||
}
|
||||
|
||||
// 功能按钮
|
||||
menuButton: MenuButton;
|
||||
|
||||
constructor(options: MenuButtonOptions) {
|
||||
super();
|
||||
|
||||
// 初始化功能按钮选项
|
||||
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
|
||||
|
||||
// 创建功能按钮
|
||||
this.menuButton = new MenuButton(this.menuButtonOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义创建方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
|
||||
this.menuButton.onCreate(event, options);
|
||||
this.appendChild(this.menuButton);
|
||||
|
||||
// 定义按钮点击事件,清除文档格式
|
||||
this.addEventListener("click", () => {
|
||||
if (this.menuButtonOptions.enable) {
|
||||
event.editor.chain().unsetAllMarks().run();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义Transaction监听方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
|
||||
this.menuButton.onTransaction(event, options);
|
||||
}
|
||||
|
||||
onEditableChange(editable: boolean) {
|
||||
this.menuButtonOptions.enable = editable;
|
||||
this.menuButton.onEditableChange(editable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2024-present AI-Labs
|
||||
|
||||
// @ ts-nocheck
|
||||
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
|
||||
import icon from "../../../../assets/icons/format-painter.svg";
|
||||
import { t } from "i18next";
|
||||
import { UAIEditorEventListener, UAIEditorOptions } from "../../../../core/UAIEditor.ts";
|
||||
import { EditorEvents } from "@tiptap/core";
|
||||
|
||||
/**
|
||||
* 基础菜单:格式刷
|
||||
*/
|
||||
export class FormatPainter extends HTMLElement implements UAIEditorEventListener {
|
||||
// 按钮选项
|
||||
menuButtonOptions: MenuButtonOptions = {
|
||||
menuType: "button",
|
||||
enable: true,
|
||||
icon: icon,
|
||||
hideText: true,
|
||||
text: t('base.formatPainter.text'),
|
||||
tooltip: t('base.formatPainter.text'),
|
||||
}
|
||||
|
||||
// 功能按钮
|
||||
menuButton: MenuButton;
|
||||
|
||||
constructor(options: MenuButtonOptions) {
|
||||
super();
|
||||
|
||||
// 初始化功能按钮选项
|
||||
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
|
||||
|
||||
// 创建功能按钮
|
||||
this.menuButton = new MenuButton(this.menuButtonOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义创建方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
|
||||
this.menuButton.onCreate(event, options);
|
||||
this.appendChild(this.menuButton);
|
||||
|
||||
// 定义按钮点击事件,设置格式
|
||||
this.addEventListener("click", () => {
|
||||
if (this.menuButtonOptions.enable) {
|
||||
// TODO
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义Transaction监听方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
|
||||
this.menuButton.onTransaction(event, options);
|
||||
if (this.menuButton.menuButton) {
|
||||
var disable = !event.editor.state.selection.empty;
|
||||
this.onEditableChange(disable);
|
||||
}
|
||||
}
|
||||
|
||||
onEditableChange(editable: boolean) {
|
||||
this.menuButtonOptions.enable = editable;
|
||||
this.menuButton.onEditableChange(editable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2024-present AI-Labs
|
||||
|
||||
// @ ts-nocheck
|
||||
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
|
||||
import icon from "../../../../assets/icons/redo.svg";
|
||||
import { t } from "i18next";
|
||||
import { UAIEditorEventListener, UAIEditorOptions } from "../../../../core/UAIEditor.ts";
|
||||
import { EditorEvents } from "@tiptap/core";
|
||||
|
||||
/**
|
||||
* 基础菜单:重做
|
||||
*/
|
||||
export class Redo extends HTMLElement implements UAIEditorEventListener {
|
||||
// 按钮选项
|
||||
menuButtonOptions: MenuButtonOptions = {
|
||||
menuType: "button",
|
||||
enable: true,
|
||||
icon: icon,
|
||||
hideText: true,
|
||||
text: t('base.redo'),
|
||||
tooltip: t('base.redo'),
|
||||
shortcut: "Ctrl+Y / Ctrl+Shift+Z",
|
||||
}
|
||||
|
||||
// 功能按钮
|
||||
menuButton: MenuButton;
|
||||
|
||||
constructor(options: MenuButtonOptions) {
|
||||
super();
|
||||
|
||||
// 初始化功能按钮选项
|
||||
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
|
||||
|
||||
// 创建功能按钮
|
||||
this.menuButton = new MenuButton(this.menuButtonOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义创建方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onCreate(event: EditorEvents["create"], options: UAIEditorOptions){
|
||||
this.menuButton.onCreate(event, options);
|
||||
this.appendChild(this.menuButton);
|
||||
|
||||
// 定义按钮点击事件,重做
|
||||
this.addEventListener("click", ()=> {
|
||||
if(this.menuButtonOptions.enable) {
|
||||
event.editor.chain().redo().run();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义Transaction监听方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions){
|
||||
this.menuButton.onTransaction(event, options);
|
||||
if (this.menuButton.menuButton) {
|
||||
// 根据当前是否有可重做操作决定按钮是否可用
|
||||
var disable = event.editor.can().chain().redo().run();
|
||||
this.onEditableChange(disable);
|
||||
}
|
||||
}
|
||||
|
||||
onEditableChange(editable: boolean){
|
||||
this.menuButtonOptions.enable = editable;
|
||||
this.menuButton.onEditableChange(editable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2024-present AI-Labs
|
||||
|
||||
// @ ts-nocheck
|
||||
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
|
||||
import icon from "../../../../assets/icons/undo.svg";
|
||||
import { t } from "i18next";
|
||||
import { UAIEditorEventListener, UAIEditorOptions } from "../../../../core/UAIEditor.ts";
|
||||
import { EditorEvents } from "@tiptap/core";
|
||||
|
||||
/**
|
||||
* 基础菜单:撤销
|
||||
*/
|
||||
export class Undo extends HTMLElement implements UAIEditorEventListener {
|
||||
// 按钮选项
|
||||
menuButtonOptions: MenuButtonOptions = {
|
||||
menuType: "button",
|
||||
enable: true,
|
||||
icon: icon,
|
||||
hideText: true,
|
||||
text: t('base.undo'),
|
||||
tooltip: t('base.undo'),
|
||||
shortcut: "Ctrl+Z",
|
||||
}
|
||||
|
||||
// 功能按钮
|
||||
menuButton: MenuButton;
|
||||
|
||||
constructor(options: MenuButtonOptions) {
|
||||
super();
|
||||
|
||||
// 初始化功能按钮选项
|
||||
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
|
||||
|
||||
// 创建功能按钮
|
||||
this.menuButton = new MenuButton(this.menuButtonOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义创建方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onCreate(event: EditorEvents["create"], options: UAIEditorOptions){
|
||||
this.menuButton.onCreate(event, options);
|
||||
this.appendChild(this.menuButton);
|
||||
|
||||
// 定义按钮点击事件,撤销
|
||||
this.addEventListener("click", ()=> {
|
||||
if(this.menuButtonOptions.enable) {
|
||||
event.editor.chain().undo().run();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义Transaction监听方法
|
||||
* @param event
|
||||
* @param options
|
||||
*/
|
||||
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions){
|
||||
this.menuButton.onTransaction(event, options);
|
||||
if (this.menuButton.menuButton) {
|
||||
// 根据当前是否有可撤销操作决定按钮是否可用
|
||||
var disable = event.editor.can().chain().undo().run();
|
||||
this.onEditableChange(disable);
|
||||
}
|
||||
}
|
||||
|
||||
onEditableChange(editable: boolean){
|
||||
this.menuButtonOptions.enable = editable;
|
||||
this.menuButton.onEditableChange(editable);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user