import { Editor, Node } from '@tiptap/core';
import Bold from '@tiptap/extension-bold';
import Italic from '@tiptap/extension-italic';
import Underline from '@tiptap/extension-underline';
import Strike from '@tiptap/extension-strike';
import Code from '@tiptap/extension-code';
import CodeBlock from '@tiptap/extension-code-block';
import Blockquote from '@tiptap/extension-blockquote';
import Heading from '@tiptap/extension-heading';
import Paragraph from '@tiptap/extension-paragraph';
import Text from '@tiptap/extension-text';
import ListItem from '@tiptap/extension-list-item';
import BulletList from '@tiptap/extension-bullet-list';
import OrderedList from '@tiptap/extension-ordered-list';
import TaskList from '@tiptap/extension-task-list';
import TaskItem from '@tiptap/extension-task-item';
import Link from '@tiptap/extension-link';
import Image from '@tiptap/extension-image';
import Table from '@tiptap/extension-table';
import TableRow from '@tiptap/extension-table-row';
import TableCell from '@tiptap/extension-table-cell';
import TableHeader from '@tiptap/extension-table-header';
import HorizontalRule from '@tiptap/extension-horizontal-rule';
import Dropcursor from '@tiptap/extension-dropcursor';
import Gapcursor from '@tiptap/extension-gapcursor';
import History from '@tiptap/extension-history';
import Highlight from '@tiptap/extension-highlight';
import Color from '@tiptap/extension-color';
import TextStyle from '@tiptap/extension-text-style';
import FontFamily from '@tiptap/extension-font-family';
import FontSize from './font-size';
import CharacterCount from '@tiptap/extension-character-count';
import Placeholder from '@tiptap/extension-placeholder';
import Subscript from '@tiptap/extension-subscript';
import Superscript from '@tiptap/extension-superscript';
import TextAlign from '@tiptap/extension-text-align';
import Typography from '@tiptap/extension-typography';
import Document from '@tiptap/extension-document';
import ImageResizable from './image-resize';

// 1. 只使用在线字体，简化方案
if (!document.getElementById('material-symbols-font')) {
  const link = document.createElement('link');
  link.id = 'material-symbols-font';
  link.rel = 'stylesheet';
  link.href = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined';
  document.head.appendChild(link);
}

// 2. Material Symbols 字体图标（官方名称，风格完全统一）
const icons = {
  paragraph: '<span class="material-symbols-outlined">format_paragraph</span>',
  h1: '<span class="material-symbols-outlined">looks_one</span>',
  h2: '<span class="material-symbols-outlined">looks_two</span>',
  h3: '<span class="material-symbols-outlined">looks_3</span>',
  bold: '<span class="material-symbols-outlined">format_bold</span>',
  italic: '<span class="material-symbols-outlined">format_italic</span>',
  underline: '<span class="material-symbols-outlined">format_underlined</span>',
  strike: '<span class="material-symbols-outlined">strikethrough_s</span>',
  code: '<span class="material-symbols-outlined">code</span>',
  codeBlock: '<span class="material-symbols-outlined">data_object</span>',
  blockquote: '<span class="material-symbols-outlined">format_quote</span>',
  bulletList: '<span class="material-symbols-outlined">format_list_bulleted</span>',
  orderedList: '<span class="material-symbols-outlined">format_list_numbered</span>',
  taskList: '<span class="material-symbols-outlined">checklist</span>',
  alignLeft: '<span class="material-symbols-outlined">format_align_left</span>',
  alignCenter: '<span class="material-symbols-outlined">format_align_center</span>',
  alignRight: '<span class="material-symbols-outlined">format_align_right</span>',
  link: '<span class="material-symbols-outlined">link</span>',
  image: '<span class="material-symbols-outlined">image</span>',
  table: '<span class="material-symbols-outlined">table</span>',
  hr: '<span class="material-symbols-outlined">horizontal_rule</span>',
  color: '<span class="material-symbols-outlined">format_color_text</span>',
  highlight: '<span class="material-symbols-outlined">format_color_fill</span>',
  fontFamily: '<span class="material-symbols-outlined">font_download</span>',
  fontSize: '<span class="material-symbols-outlined">format_size</span>',
  subscript: '<span class="material-symbols-outlined">subscript</span>',
  superscript: '<span class="material-symbols-outlined">superscript</span>',
  undo: '<span class="material-symbols-outlined">undo</span>',
  redo: '<span class="material-symbols-outlined">redo</span>',
  source: '<span class="material-symbols-outlined">code_blocks</span>',
  // 表格操作专用图标
  insertTable: '<span class="material-symbols-outlined">table</span>',
  insertRowAbove: '<span class="material-symbols-outlined">keyboard_arrow_up</span>',
  insertRowBelow: '<span class="material-symbols-outlined">keyboard_arrow_down</span>',
  insertColumnLeft: '<span class="material-symbols-outlined">keyboard_arrow_left</span>',
  insertColumnRight: '<span class="material-symbols-outlined">keyboard_arrow_right</span>',
  deleteRow: '<span class="material-symbols-outlined">horizontal_rule</span>',
  deleteColumn: '<span class="material-symbols-outlined">more_vert</span>',
  deleteTable: '<span class="material-symbols-outlined">delete_forever</span>'
};

// 2. 分隔符
function createDivider() {
    const div = document.createElement('span');
    div.className = 'tiptap-toolbar-divider';
    return div;
}

// 2. 工具栏分组与下拉菜单实现
function createDropdown(icon, title, options, customRender) {
    const wrapper = document.createElement('div');
    wrapper.className = 'tiptap-toolbar-dropdown';
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.innerHTML = icon + ' <span class="tiptap-toolbar-caret">expand_more</span>';
    btn.title = title;
    btn.className = 'tiptap-toolbar-btn';
    wrapper.appendChild(btn);
    const menu = document.createElement('div');
    menu.className = 'tiptap-toolbar-dropdown-menu';
    options.forEach(opt => {
        if (opt === 'divider') {
            const divider = document.createElement('div');
            divider.style.height = '1px';
            divider.style.background = '#eee';
            divider.style.margin = '4px 0';
            menu.appendChild(divider);
            return;
        }
        const item = document.createElement('div');
        item.className = 'tiptap-toolbar-dropdown-item';
        if (customRender) {
            item.innerHTML = customRender(opt);
        } else {
            item.innerHTML = opt.icon + '<span>' + opt.label + '</span>';
        }
        item.onclick = (e) => {
            e.preventDefault();
            opt.onClick();
            menu.style.display = 'none';
        };
        menu.appendChild(item);
    });
    wrapper.appendChild(menu);
    btn.onclick = (e) => {
        e.preventDefault();
        menu.style.display = menu.style.display === 'block' ? 'none' : 'block';
    };
    document.addEventListener('click', (e) => {
        if (!wrapper.contains(e.target)) menu.style.display = 'none';
    });
    return wrapper;
}

function createButton(icon, title, isActive, onClick) {
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.innerHTML = icon;
    btn.title = title;
    btn.className = 'tiptap-toolbar-btn';
    if (isActive) btn.classList.add('active');
    // 用 mousedown + requestAnimationFrame + return false，彻底阻断 selection 丢失
    btn.addEventListener('mousedown', function(e) {
        e.preventDefault();
        e.stopPropagation();
        requestAnimationFrame(() => onClick(e));
        return false;
    });
    return btn;
}

// 工具函数：关闭所有 Tiptap 弹窗
function closeAllTiptapPanels() {
    document.querySelectorAll('.tiptap-link-panel, .tiptap-image-panel, .tiptap-color-panel, .tiptap-highlight-panel').forEach(el => el.remove());
}

// 全局点击事件监听器，用于关闭弹窗
if (!window._tiptapPanelClickHandler) {
    window._tiptapPanelClickHandler = (e) => {
        // 检查点击的元素是否在弹窗内或工具栏按钮
        const isInPanel = e.target.closest('.tiptap-link-panel, .tiptap-image-panel, .tiptap-color-panel, .tiptap-highlight-panel');
        const isToolbarButton = e.target.closest('.tiptap-toolbar-btn');
        
        // 如果点击的不是弹窗内部且不是工具栏按钮，则关闭所有弹窗
        if (!isInPanel && !isToolbarButton) {
            closeAllTiptapPanels();
        }
    };
    
    // 全局键盘事件监听器，用于 ESC 键关闭弹窗
    window._tiptapPanelKeyHandler = (e) => {
        if (e.key === 'Escape') {
            closeAllTiptapPanels();
        }
    };
    
    // 添加全局事件监听器
    document.addEventListener('click', window._tiptapPanelClickHandler);
    document.addEventListener('keydown', window._tiptapPanelKeyHandler);
}

// CustomDiv 扩展：支持 div 标签，避免被转换为 p 标签
// 关键：content 设置为 'block*' 允许包含其他块级元素（如 heading, paragraph, table 等）
const CustomDiv = Node.create({
    name: 'customDiv',
    group: 'block',
    content: 'block*',
    addAttributes() {
        return {
            class: {
                default: null,
                parseHTML: element => element.getAttribute('class'),
                renderHTML: attributes => attributes.class ? { class: attributes.class } : {},
            },
            style: {
                default: null,
                parseHTML: element => element.getAttribute('style'),
                renderHTML: attributes => attributes.style ? { style: attributes.style } : {},
            },
            id: {
                default: null,
                parseHTML: element => element.getAttribute('id'),
                renderHTML: attributes => attributes.id ? { id: attributes.id } : {},
            },
        };
    },
    parseHTML() {
        return [
            {
                tag: 'div',
            },
        ];
    },
    renderHTML({ HTMLAttributes }) {
        return ['div', HTMLAttributes, 0];
    },
});

jingrow.ui.form.ControlJeditor = class ControlJeditor extends jingrow.ui.form.ControlText {
    make_input() {
        // 检查是否需要重新创建编辑器
        // 只有在编辑器不存在，或者当前值与编辑器内容不匹配时才重新创建
        const needsRecreate = !this.editor || 
                             !this.editor.isEditable || 
                             this._last_record_name !== (this.frm && this.frm.pagename);
        
        if (!needsRecreate) {
            return;
        }
        
        // 记录当前记录名，用于检测记录切换
        this._last_record_name = this.frm && this.frm.pagename;
        
        // 如果编辑器已存在，先销毁它
        if (this.editor) {
            this.editor.destroy();
            this.editor = null;
        }
        
        $(this.input_area).empty();
        this.$input = $('<div class="jeditor"></div>').appendTo(this.input_area);
        this.$toolbar = $('<div class="tiptap-toolbar"></div>').prependTo(this.input_area);

        // 标记是否为外部 set_value 调用，防止死循环
        this._setting_content = false;
        this._showing_source = false;
        this._source_textarea = null;
        // 标记是否正在显示颜色面板，防止工具栏更新时关闭面板
        this._showing_color_panel = false;

        this.editor = new Editor({
            element: this.$input[0],
            extensions: [
                Document.extend({
                    content: '(paragraph | heading | blockquote | codeBlock | horizontalRule | customDiv | table | bulletList | orderedList | taskList)+',
                }),
                CustomDiv,
                Paragraph,
                Text,
                Bold,
                Italic,
                Underline,
                Strike,
                Code,
                CodeBlock,
                Blockquote,
                Heading,
                ListItem,
                BulletList,
                OrderedList,
                TaskList,
                TaskItem,
                Link.configure({ openOnClick: false }),
                ImageResizable,
                Table.configure({ resizable: true }),
                TableRow,
                TableCell.extend({ content: 'paragraph+' }),
                TableHeader,
                HorizontalRule,
                Dropcursor,
                Gapcursor,
                History,
                Highlight.configure({ multicolor: true }),
                Color,
                TextStyle,
                FontFamily,
                FontSize,
                CharacterCount,
                Placeholder.configure({ placeholder: '请输入内容...' }),
                Subscript,
                Superscript,
                TextAlign.configure({ types: ['heading', 'paragraph', 'imageResizable'] }),
                Typography
            ],
            content: this.value || '',
            editable: true,
            onUpdate: ({ editor }) => {
                // 只同步本地 value，不 set_value
                if (!this._setting_content) {
                    this.value = editor.getHTML();
                }
            },
            onSelectionUpdate: ({ editor }) => {
                // 如果正在显示颜色面板，不更新工具栏
                if (!this._showing_color_panel) {
                    this.update_toolbar();
                }
            },
            onFocus: ({ editor }) => {
                // 聚焦时确保编辑器处于可编辑状态
                editor.commands.focus();
            },
            onBlur: ({ editor }) => {
                // 失焦时同步到主表单
                if (this.frm && this.df && this.df.fieldname) {
                    this.frm.set_value(this.df.fieldname, editor.getHTML());
                }
                if (typeof this.df.change === 'function') {
                    this.df.change();
                }
                
                // 失焦时关闭所有弹窗
                closeAllTiptapPanels();
            }
        });
        this.update_toolbar();
        
        // 添加点击事件监听器，确保点击编辑器内容区域时能直接激活编辑
        this.$input.on('click', (e) => {
            // 如果点击的是编辑器内容区域，确保编辑器获得焦点
            if (e.target === this.$input[0] || this.$input[0].contains(e.target)) {
                // 延迟一点确保 DOM 更新完成
                setTimeout(() => {
                    this.editor.commands.focus();
                }, 10);
            }
        });
        
        // 确保编辑器容器可点击
        this.$input.css('cursor', 'text');
        
        // 确保初始值被正确设置
        if (this.value) {
            this.set_value(this.value);
        }
        
        // 确保编辑器在初始化后就能响应点击
        setTimeout(() => {
            if (this.editor && !this.editor.isDestroyed) {
                this.editor.setEditable(true);
            }
        }, 100);
    }

    update_toolbar() {
        const editor = this.editor;
        if (!editor) return;
        
        // 如果正在显示颜色面板，不更新工具栏
        if (this._showing_color_panel) {
            return;
        }
        
        // 清理旧的下拉菜单事件监听器
        this.$toolbar.find('.tiptap-toolbar-dropdown').each(function() {
            if (this._clickHandler) {
                document.removeEventListener('click', this._clickHandler);
            }
        });
        
        this.$toolbar.empty();
        // 标题下拉
        this.$toolbar.append(createDropdown(
            icons.paragraph,
            '段落/标题',
            [
                { icon: icons.h1, label: '标题1', onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), style: 'font-size:2em;font-weight:bold;line-height:1.2;' },
                { icon: icons.h2, label: '标题2', onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), style: 'font-size:1.5em;font-weight:bold;line-height:1.2;' },
                { icon: icons.h3, label: '标题3', onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), style: 'font-size:1.2em;font-weight:bold;line-height:1.2;' },
                { icon: icons.paragraph, label: '正文', onClick: () => editor.chain().focus().setParagraph().run(), style: 'font-size:1em;font-weight:normal;line-height:1.5;' }
            ],
            (opt) => `<span style="${opt.style}">${opt.label}</span>`
        ));
        // 字号下拉
        const fontSizes = [8,9,10,11,12,13,14,16,18,20,24,28,32,36,48,64];
        this.$toolbar.append(createDropdown(
            icons.fontSize,
            '字号',
            fontSizes.map(size => ({
                icon: '',
                label: size + 'px',
                onClick: () => editor.chain().focus().setFontSize(size + 'px').run(),
                style: `font-size:${size}px;line-height:1.2;`
            })),
            (opt) => `<span style="${opt.style}">${opt.label}</span>`
        ));
        
        // 分隔符
        this.$toolbar.append(createDivider());
        
        // 表格下拉
        this.$toolbar.append(createDropdown(
            icons.table,
            '表格',
            [
                { icon: icons.insertTable, label: '插入表格', onClick: () => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run() },
                'divider',
                { icon: icons.insertRowAbove, label: '插入行（上）', onClick: () => editor.chain().focus().addRowBefore().run() },
                { icon: icons.insertRowBelow, label: '插入行（下）', onClick: () => editor.chain().focus().addRowAfter().run() },
                { icon: icons.insertColumnLeft, label: '插入列（左）', onClick: () => editor.chain().focus().addColumnBefore().run() },
                { icon: icons.insertColumnRight, label: '插入列（右）', onClick: () => editor.chain().focus().addColumnAfter().run() },
                'divider',
                { icon: icons.deleteRow, label: '删除行', onClick: () => editor.chain().focus().deleteRow().run() },
                { icon: icons.deleteColumn, label: '删除列', onClick: () => editor.chain().focus().deleteColumn().run() },
                { icon: icons.deleteTable, label: '删除表格', onClick: () => editor.chain().focus().deleteTable().run() }
            ]
        ));
        // 对齐下拉
        this.$toolbar.append(createDropdown(
            icons.alignLeft,
            '对齐方式',
            [
                { icon: icons.alignLeft, label: '左对齐', onClick: () => this.setAlignment(editor, 'left') },
                { icon: icons.alignCenter, label: '居中对齐', onClick: () => this.setAlignment(editor, 'center') },
                { icon: icons.alignRight, label: '右对齐', onClick: () => this.setAlignment(editor, 'right') }
            ]
        ));
        
        // 分隔符
        this.$toolbar.append(createDivider());
        
        // 其它常用按钮
        const buttons = [
            { icon: icons.bold, title: '加粗', isActive: editor.isActive('bold'), onClick: () => editor.chain().focus().toggleBold().run() },
            { icon: icons.italic, title: '斜体', isActive: editor.isActive('italic'), onClick: () => editor.chain().focus().toggleItalic().run() },
            { icon: icons.underline, title: '下划线', isActive: editor.isActive('underline'), onClick: () => editor.chain().focus().toggleUnderline().run() },
            { icon: icons.strike, title: '删除线', isActive: editor.isActive('strike'), onClick: () => editor.chain().focus().toggleStrike().run() },
            { icon: icons.code, title: '行内代码', isActive: editor.isActive('code'), onClick: () => editor.chain().focus().toggleCode().run() }
        ];
        buttons.forEach(btn => {
            this.$toolbar.append(createButton(btn.icon, btn.title, btn.isActive, btn.onClick));
        });
        
        // 分隔符 - 基础格式与高级格式
        this.$toolbar.append(createDivider());
        
        const advancedButtons = [
            { icon: icons.codeBlock, title: '代码块', isActive: editor.isActive('codeBlock'), onClick: () => editor.chain().focus().toggleCodeBlock().run() },
            { icon: icons.blockquote, title: '引用', isActive: editor.isActive('blockquote'), onClick: () => {
                if (editor.isActive('blockquote')) {
                    editor.chain().focus().setParagraph().run();
                } else {
                    editor.chain().focus().setParagraph().toggleBlockquote().run();
                }
            } },
            { icon: icons.subscript, title: '下标', isActive: editor.isActive('subscript'), onClick: () => editor.chain().focus().toggleSubscript().run() },
            { icon: icons.superscript, title: '上标', isActive: editor.isActive('superscript'), onClick: () => editor.chain().focus().toggleSuperscript().run() }
        ];
        advancedButtons.forEach(btn => {
            this.$toolbar.append(createButton(btn.icon, btn.title, btn.isActive, btn.onClick));
        });
        
        // 分隔符 - 高级格式与列表
        this.$toolbar.append(createDivider());
        
        const listButtons = [
            { icon: icons.bulletList, title: '无序列表', isActive: editor.isActive('bulletList'), onClick: () => editor.chain().focus().toggleBulletList().run() },
            { icon: icons.orderedList, title: '有序列表', isActive: editor.isActive('orderedList'), onClick: () => editor.chain().focus().toggleOrderedList().run() },
            { icon: icons.taskList, title: '任务列表', isActive: editor.isActive('taskList'), onClick: () => editor.chain().focus().toggleTaskList().run() }
        ];
        listButtons.forEach(btn => {
            this.$toolbar.append(createButton(btn.icon, btn.title, btn.isActive, btn.onClick));
        });
        
        // 分隔符 - 列表与媒体
        this.$toolbar.append(createDivider());
        
        const mediaButtons = [
            { icon: icons.link, title: '链接', isActive: editor.isActive('link'), onClick: (e) => this.togglePanel(e, editor, 'link') },
            { icon: icons.image, title: '图片', isActive: false, onClick: (e) => this.togglePanel(e, editor, 'image') },
            { icon: icons.hr, title: '分割线', isActive: false, onClick: () => editor.chain().focus().setHorizontalRule().run() }
        ];
        mediaButtons.forEach(btn => {
            this.$toolbar.append(createButton(btn.icon, btn.title, btn.isActive, btn.onClick));
        });
        
        // 分隔符 - 媒体与颜色
        this.$toolbar.append(createDivider());
        
        const colorButtons = [
            { icon: icons.color, title: '文字颜色', isActive: false, onClick: (e) => this.togglePanel(e, editor, 'color') },
            { icon: icons.highlight, title: '背景色', isActive: editor.isActive('highlight'), onClick: (e) => this.togglePanel(e, editor, 'highlight') }
        ];
        colorButtons.forEach(btn => {
            this.$toolbar.append(createButton(btn.icon, btn.title, btn.isActive, btn.onClick));
        });
        
        // 分隔符 - 颜色与历史操作
        this.$toolbar.append(createDivider());
        
        const historyButtons = [
            { icon: icons.undo, title: '撤销', isActive: false, onClick: () => editor.chain().focus().undo().run() },
            { icon: icons.redo, title: '重做', isActive: false, onClick: () => editor.chain().focus().redo().run() }
        ];
        historyButtons.forEach(btn => {
            this.$toolbar.append(createButton(btn.icon, btn.title, btn.isActive, btn.onClick));
        });
        
        // 分隔符 - 历史操作与源码
        this.$toolbar.append(createDivider());
        
        const sourceButton = [
            { icon: icons.source, title: '显示源代码', isActive: this._showing_source, onClick: () => this.toggleSourceMode() }
        ];
        sourceButton.forEach(btn => {
            this.$toolbar.append(createButton(btn.icon, btn.title, btn.isActive, btn.onClick));
        });
    }

    // 统一的弹窗切换方法
    togglePanel(e, editor, panelType) {
        // 检查当前是否已经显示该类型的弹窗
        const existingPanel = document.querySelector(`.tiptap-${panelType}-panel`);
        
        if (existingPanel) {
            // 如果已显示，则关闭
            existingPanel.remove();
        } else {
            // 如果未显示，则打开
            switch (panelType) {
                case 'link':
                    this.showLinkPanel(e, editor);
                    break;
                case 'image':
                    this.showImagePanel(e, editor);
                    break;
                case 'color':
                    this.showColorPanel(e, editor);
                    break;
                case 'highlight':
                    this.showHighlightPanel(e, editor);
                    break;
            }
        }
    }

    // 智能对齐处理方法
    setAlignment(editor, alignment) {
        const { state } = editor;
        const { selection } = state;
        
        // 检查当前选择的节点类型
        const node = state.pg.nodeAt(selection.from);
        
        if (node && node.type.name === 'imageResizable') {
            // 如果是图片节点，更新图片的textAlign属性
            editor.commands.command(({ tr }) => {
                const pos = selection.from;
                tr.setNodeMarkup(pos, undefined, {
                    ...node.attrs,
                    textAlign: alignment,
                });
                return true;
            });
        } else {
            // 如果是文字内容，使用标准的textAlign命令
            editor.chain().focus().setTextAlign(alignment).run();
        }
    }

    // 现代化颜色面板弹窗
    showColorPanel(e, editor) {
        closeAllTiptapPanels();
        this._savedSelection = editor.state.selection;
        
        // 构建面板
        const panel = document.createElement('div');
        panel.className = 'tiptap-color-panel';
        panel.style.position = 'absolute';
        panel.style.zIndex = 9999;
        panel.style.background = '#fff';
        panel.style.border = '1px solid #eee';
        panel.style.borderRadius = '8px';
        panel.style.boxShadow = '0 2px 8px rgba(0,0,0,0.08)';
        panel.style.padding = '10px 12px 8px 12px';
        panel.style.display = 'flex';
        panel.style.flexDirection = 'column';
        panel.style.gap = '8px';
        

        
        // 常用色
        const colors = [
            '#000000', '#262626', '#595959', '#8c8c8c', '#bfbfbf', '#d9d9d9', '#f0f0f0', '#ffffff',
            '#f5222d', '#fa541c', '#fa8c16', '#fadb14', '#52c41a', '#13c2c2', '#1890ff', '#2f54eb', '#722ed1', '#eb2f96'
        ];
        const colorRow = document.createElement('div');
        colorRow.style.display = 'flex';
        colorRow.style.flexWrap = 'wrap';
        colorRow.style.gap = '4px';
        colors.forEach(color => {
            const swatch = document.createElement('div');
            swatch.style.width = '22px';
            swatch.style.height = '22px';
            swatch.style.borderRadius = '4px';
            swatch.style.border = '1px solid #eee';
            swatch.style.background = color;
            swatch.style.cursor = 'pointer';
            swatch.title = color;
            swatch.addEventListener('mousedown', (ev) => {
                ev.preventDefault();
                ev.stopPropagation();
                // 恢复 selection+focus+变色+collapse selection
                if (this._savedSelection) {
                    editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                }
                editor.view.focus();
                editor.commands.setColor(color);
                const { to } = editor.state.selection;
                editor.commands.setTextSelection(to);
                panel.remove();
            });
            colorRow.appendChild(swatch);
        });
        panel.appendChild(colorRow);
        // 自定义色输入
        const inputRow = document.createElement('div');
        inputRow.style.display = 'flex';
        inputRow.style.alignItems = 'center';
        inputRow.style.gap = '6px';
        const input = document.createElement('input');
        input.type = 'text';
        input.placeholder = '自定义颜色（如 #1fc76f）';
        input.style.flex = '1';
        input.style.height = '28px';
        input.style.border = '1px solid #eee';
        input.style.borderRadius = '4px';
        input.style.padding = '0 8px';
        input.style.fontSize = '14px';
        input.onkeydown = (ev) => {
            if (ev.key === 'Enter') {
                const val = input.value.trim();
                if (val) {
                    if (this._savedSelection) {
                        editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                    }
                    editor.view.focus();
                    editor.commands.setColor(val);
                    const { to } = editor.state.selection;
                    editor.commands.setTextSelection(to);
                    panel.remove();
                }
            }
        };
        inputRow.appendChild(input);
        const btn = document.createElement('button');
        btn.innerText = '应用';
        btn.style.height = '28px';
        btn.style.border = 'none';
        btn.style.background = '#222';
        btn.style.color = '#fff';
        btn.style.borderRadius = '4px';
        btn.style.cursor = 'pointer';
        btn.style.fontSize = '14px';
        btn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            const val = input.value.trim();
            if (val) {
                if (this._savedSelection) {
                    editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                }
                editor.view.focus();
                editor.commands.setColor(val);
                const { to } = editor.state.selection;
                editor.commands.setTextSelection(to);
                panel.remove();
            }
        });
        inputRow.appendChild(btn);
        panel.appendChild(inputRow);
        // 增加去除颜色按钮（单独一行）
        const clearRow = document.createElement('div');
        clearRow.style.display = 'flex';
        clearRow.style.justifyContent = 'flex-end';
        clearRow.style.marginTop = '4px';
        const clearBtn = document.createElement('button');
        clearBtn.innerText = '去除颜色';
        clearBtn.style.height = '28px';
        clearBtn.style.border = 'none';
        clearBtn.style.background = '#f0f0f0';
        clearBtn.style.color = '#888';
        clearBtn.style.borderRadius = '4px';
        clearBtn.style.cursor = 'pointer';
        clearBtn.style.fontSize = '14px';
        clearBtn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            if (this._savedSelection) {
                editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
            }
            editor.view.focus();
            editor.commands.unsetColor();
            // 立即 collapse selection 到末尾，确保刷新
            const { to } = editor.state.selection;
            editor.commands.setTextSelection(to);
            panel.remove();
        });
        clearRow.appendChild(clearBtn);
        panel.appendChild(clearRow);
        // 定位到按钮下方（相对 toolbar 内部）
        const btnRect = e.target.getBoundingClientRect();
        const toolbarRect = this.$toolbar[0].getBoundingClientRect();
        panel.style.position = 'absolute';
        panel.style.left = (btnRect.left - toolbarRect.left) + 'px';
        panel.style.top = (btnRect.bottom - toolbarRect.top + 4) + 'px';
        this.$toolbar[0].appendChild(panel);
    }

    // 新增：背景色面板弹窗
    showHighlightPanel(e, editor) {
        closeAllTiptapPanels();
        this._savedSelection = editor.state.selection;
        const panel = document.createElement('div');
        panel.className = 'tiptap-highlight-panel';
        panel.style.position = 'absolute';
        panel.style.zIndex = 9999;
        panel.style.background = '#fff';
        panel.style.border = '1px solid #eee';
        panel.style.borderRadius = '8px';
        panel.style.boxShadow = '0 2px 8px rgba(0,0,0,0.08)';
        panel.style.padding = '10px 12px 8px 12px';
        panel.style.display = 'flex';
        panel.style.flexDirection = 'column';
        panel.style.gap = '8px';
        const colors = [
            '#fffbe6', '#ffe7ba', '#ffd591', '#ffc069', '#ffbb96', '#ff9c6e', '#ff7875', '#ffa39e',
            '#ffd6e7', '#eaff8f', '#b7eb8f', '#87e8de', '#91d5ff', '#adc6ff', '#d3adf7', '#f4bfff', '#f9f0ff'
        ];
        const colorRow = document.createElement('div');
        colorRow.style.display = 'flex';
        colorRow.style.flexWrap = 'wrap';
        colorRow.style.gap = '4px';
        colors.forEach(color => {
            const swatch = document.createElement('div');
            swatch.style.width = '22px';
            swatch.style.height = '22px';
            swatch.style.borderRadius = '4px';
            swatch.style.border = '1px solid #eee';
            swatch.style.background = color;
            swatch.style.cursor = 'pointer';
            swatch.title = color;
            swatch.addEventListener('mousedown', (ev) => {
                ev.preventDefault();
                ev.stopPropagation();
                if (this._savedSelection) {
                    editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                }
                editor.view.focus();
                editor.commands.setHighlight({ color });
                const { to } = editor.state.selection;
                editor.commands.setTextSelection(to);
                panel.remove();
            });
            colorRow.appendChild(swatch);
        });
        panel.appendChild(colorRow);
        const inputRow = document.createElement('div');
        inputRow.style.display = 'flex';
        inputRow.style.alignItems = 'center';
        inputRow.style.gap = '6px';
        const input = document.createElement('input');
        input.type = 'text';
        input.placeholder = '自定义颜色（如 #fffbe6）';
        input.style.flex = '1';
        input.style.height = '28px';
        input.style.border = '1px solid #eee';
        input.style.borderRadius = '4px';
        input.style.padding = '0 8px';
        input.style.fontSize = '14px';
        input.onkeydown = (ev) => {
            if (ev.key === 'Enter') {
                const val = input.value.trim();
                if (val) {
                    if (this._savedSelection) {
                        editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                    }
                    editor.view.focus();
                    editor.commands.setHighlight({ color: val });
                    const { to } = editor.state.selection;
                    editor.commands.setTextSelection(to);
                    panel.remove();
                }
            }
        };
        inputRow.appendChild(input);
        const btn = document.createElement('button');
        btn.innerText = '应用';
        btn.style.height = '28px';
        btn.style.border = 'none';
        btn.style.background = '#222';
        btn.style.color = '#fff';
        btn.style.borderRadius = '4px';
        btn.style.cursor = 'pointer';
        btn.style.fontSize = '14px';
        btn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            const val = input.value.trim();
            if (val) {
                if (this._savedSelection) {
                    editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                }
                editor.view.focus();
                editor.commands.setHighlight({ color: val });
                const { to } = editor.state.selection;
                editor.commands.setTextSelection(to);
                panel.remove();
            }
        });
        inputRow.appendChild(btn);
        panel.appendChild(inputRow);
        // 增加去除背景色按钮（单独一行）
        const clearRow = document.createElement('div');
        clearRow.style.display = 'flex';
        clearRow.style.justifyContent = 'flex-end';
        clearRow.style.marginTop = '4px';
        const clearBtn = document.createElement('button');
        clearBtn.innerText = '去除背景色';
        clearBtn.style.height = '28px';
        clearBtn.style.border = 'none';
        clearBtn.style.background = '#f0f0f0';
        clearBtn.style.color = '#888';
        clearBtn.style.borderRadius = '4px';
        clearBtn.style.cursor = 'pointer';
        clearBtn.style.fontSize = '14px';
        clearBtn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            if (this._savedSelection) {
                editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
            }
            editor.view.focus();
            editor.commands.unsetHighlight();
            // 立即 collapse selection 到末尾，确保刷新
            const { to } = editor.state.selection;
            editor.commands.setTextSelection(to);
            panel.remove();
        });
        clearRow.appendChild(clearBtn);
        panel.appendChild(clearRow);
        // 定位到按钮下方（相对 toolbar 内部）
        const btnRect = e.target.getBoundingClientRect();
        const toolbarRect = this.$toolbar[0].getBoundingClientRect();
        panel.style.position = 'absolute';
        panel.style.left = (btnRect.left - toolbarRect.left) + 'px';
        panel.style.top = (btnRect.bottom - toolbarRect.top + 4) + 'px';
        this.$toolbar[0].appendChild(panel);
    }

    // 新增：自定义链接弹窗
    showLinkPanel(e, editor) {
        closeAllTiptapPanels();
        this._savedSelection = editor.state.selection;
        const panel = document.createElement('div');
        panel.className = 'tiptap-link-panel';
        panel.style.position = 'absolute';
        panel.style.zIndex = 9999;
        panel.style.background = '#fff';
        panel.style.border = '1px solid #eee';
        panel.style.borderRadius = '8px';
        panel.style.boxShadow = '0 2px 8px rgba(0,0,0,0.08)';
        panel.style.padding = '10px 12px 8px 12px';
        panel.style.display = 'flex';
        panel.style.flexDirection = 'column';
        panel.style.gap = '8px';
        // 输入框
        const inputRow = document.createElement('div');
        inputRow.style.display = 'flex';
        inputRow.style.alignItems = 'center';
        inputRow.style.gap = '6px';
        const input = document.createElement('input');
        input.type = 'text';
        input.placeholder = '请输入链接地址（如 https://...）';
        input.style.flex = '1';
        input.style.height = '28px';
        input.style.border = '1px solid #eee';
        input.style.borderRadius = '4px';
        input.style.padding = '0 8px';
        input.style.fontSize = '14px';
        input.onkeydown = (ev) => {
            if (ev.key === 'Enter') {
                const val = input.value.trim();
                if (val) {
                    if (this._savedSelection) {
                        editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                    }
                    editor.view.focus();
                    editor.commands.setLink({ href: val });
                    const { to } = editor.state.selection;
                    editor.commands.setTextSelection(to);
                    panel.remove();
                }
            }
        };
        inputRow.appendChild(input);
        const btn = document.createElement('button');
        btn.innerText = '应用';
        btn.style.height = '28px';
        btn.style.border = 'none';
        btn.style.background = '#222';
        btn.style.color = '#fff';
        btn.style.borderRadius = '4px';
        btn.style.cursor = 'pointer';
        btn.style.fontSize = '14px';
        btn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            const val = input.value.trim();
            if (val) {
                if (this._savedSelection) {
                    editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                }
                editor.view.focus();
                editor.commands.setLink({ href: val });
                const { to } = editor.state.selection;
                editor.commands.setTextSelection(to);
                panel.remove();
            }
        });
        inputRow.appendChild(btn);
        panel.appendChild(inputRow);
        // 去除链接按钮
        const clearRow = document.createElement('div');
        clearRow.style.display = 'flex';
        clearRow.style.justifyContent = 'flex-end';
        clearRow.style.marginTop = '4px';
        const clearBtn = document.createElement('button');
        clearBtn.innerText = '去除链接';
        clearBtn.style.height = '28px';
        clearBtn.style.border = 'none';
        clearBtn.style.background = '#f0f0f0';
        clearBtn.style.color = '#888';
        clearBtn.style.borderRadius = '4px';
        clearBtn.style.cursor = 'pointer';
        clearBtn.style.fontSize = '14px';
        clearBtn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            if (this._savedSelection) {
                editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
            }
            editor.view.focus();
            editor.commands.unsetLink();
            const { to } = editor.state.selection;
            editor.commands.setTextSelection(to);
            panel.remove();
        });
        clearRow.appendChild(clearBtn);
        panel.appendChild(clearRow);
        // 定位到按钮下方
        const btnRect = e.target.getBoundingClientRect();
        const toolbarRect = this.$toolbar[0].getBoundingClientRect();
        panel.style.position = 'absolute';
        panel.style.left = (btnRect.left - toolbarRect.left) + 'px';
        panel.style.top = (btnRect.bottom - toolbarRect.top + 4) + 'px';
        this.$toolbar[0].appendChild(panel);
    }

    // 新增：自定义图片弹窗，支持本地上传和URL
    showImagePanel(e, editor) {
        closeAllTiptapPanels();
        this._savedSelection = editor.state.selection;
        const panel = document.createElement('div');
        panel.className = 'tiptap-image-panel';
        panel.style.position = 'absolute';
        panel.style.zIndex = 9999;
        panel.style.background = '#fff';
        panel.style.border = '1px solid #eee';
        panel.style.borderRadius = '8px';
        panel.style.boxShadow = '0 2px 8px rgba(0,0,0,0.08)';
        panel.style.padding = '10px 12px 8px 12px';
        panel.style.display = 'flex';
        panel.style.flexDirection = 'column';
        panel.style.gap = '8px';
        // URL输入
        const inputRow = document.createElement('div');
        inputRow.style.display = 'flex';
        inputRow.style.alignItems = 'center';
        inputRow.style.gap = '6px';
        const input = document.createElement('input');
        input.type = 'text';
        input.placeholder = '图片地址（如 https://...）';
        input.style.flex = '1';
        input.style.height = '28px';
        input.style.border = '1px solid #eee';
        input.style.borderRadius = '4px';
        input.style.padding = '0 8px';
        input.style.fontSize = '14px';
        input.onkeydown = (ev) => {
            if (ev.key === 'Enter') {
                const val = input.value.trim();
                if (val) {
                    if (this._savedSelection) {
                        editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                    }
                    editor.view.focus();
                    editor.commands.insertContent({ type: 'imageResizable', attrs: { src: val } });
                    const { to } = editor.state.selection;
                    editor.commands.setTextSelection(to);
                    panel.remove();
                }
            }
        };
        inputRow.appendChild(input);
        const btn = document.createElement('button');
        btn.innerText = '应用';
        btn.style.height = '28px';
        btn.style.border = 'none';
        btn.style.background = '#222';
        btn.style.color = '#fff';
        btn.style.borderRadius = '4px';
        btn.style.cursor = 'pointer';
        btn.style.fontSize = '14px';
        btn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            const val = input.value.trim();
            if (val) {
                if (this._savedSelection) {
                    editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                }
                editor.view.focus();
                editor.commands.insertContent({ type: 'imageResizable', attrs: { src: val } });
                const { to } = editor.state.selection;
                editor.commands.setTextSelection(to);
                panel.remove();
            }
        });
        inputRow.appendChild(btn);
        panel.appendChild(inputRow);
        // 本地上传按钮
        const uploadRow = document.createElement('div');
        uploadRow.style.display = 'flex';
        uploadRow.style.justifyContent = 'flex-end';
        uploadRow.style.marginTop = '4px';
        const uploadBtn = document.createElement('button');
        uploadBtn.innerText = '上传本地图片';
        uploadBtn.style.height = '28px';
        uploadBtn.style.border = 'none';
        uploadBtn.style.background = '#1fc76f';
        uploadBtn.style.color = '#fff';
        uploadBtn.style.borderRadius = '4px';
        uploadBtn.style.cursor = 'pointer';
        uploadBtn.style.fontSize = '14px';
        uploadBtn.addEventListener('mousedown', (ev) => {
            ev.preventDefault();
            ev.stopPropagation();
            // 创建文件选择器
            const fileInput = document.createElement('input');
            fileInput.type = 'file';
            fileInput.accept = 'image/*';
            fileInput.style.display = 'none';
            fileInput.addEventListener('change', (event) => {
                const file = event.target.files[0];
                if (!file) return;
                // 使用 jingrow.ui.FileUploader 上传
                new jingrow.ui.FileUploader({
                    dialog_title: '插入图片',
                    files: [file],
                    folder: 'Home/Attachments',
                    allow_multiple: false,
                    restrictions: { allowed_file_types: ['image/*'] },
                    on_success: (file_pg) => {
                        if (this._savedSelection) {
                            editor.view.dispatch(editor.state.tr.setSelection(this._savedSelection));
                        }
                        editor.view.focus();
                        editor.commands.insertContent({ type: 'imageResizable', attrs: { src: file_pg.file_url } });
                        const { to } = editor.state.selection;
                        editor.commands.setTextSelection(to);
                        panel.remove();
                    }
                });
            });
            document.body.appendChild(fileInput);
            fileInput.click();
            setTimeout(() => fileInput.remove(), 1000);
        });
        uploadRow.appendChild(uploadBtn);
        panel.appendChild(uploadRow);
        // 定位到按钮下方
        const btnRect = e.target.getBoundingClientRect();
        const toolbarRect = this.$toolbar[0].getBoundingClientRect();
        panel.style.position = 'absolute';
        panel.style.left = (btnRect.left - toolbarRect.left) + 'px';
        panel.style.top = (btnRect.bottom - toolbarRect.top + 4) + 'px';
        this.$toolbar[0].appendChild(panel);
    }

    // 新增：切换源码模式
    toggleSourceMode() {
        if (this._showing_source) {
            // 从源码模式切回可视化
            if (this._source_textarea) {
                const html = this._source_textarea.value;
                this.editor.commands.setContent(html || '');
                this._source_textarea.remove();
                this._source_textarea = null;
            }
            this.$input.show();
            this._showing_source = false;
            this.update_toolbar();
        } else {
            // 进入源码模式
            const html = this.editor.getHTML();
            
            // 在隐藏之前获取编辑器容器的实际高度
            const editorHeight = this.$input[0].offsetHeight;
            
            // 如果 offsetHeight 为 0，使用 CSS 的 min-height
            const finalHeight = editorHeight > 0 ? editorHeight : 300;
            
            this.$input.hide();
            const textarea = document.createElement('textarea');
            textarea.className = 'jeditor-source-textarea';
            textarea.style.width = '100%';
            textarea.style.height = `${finalHeight}px`;  // 使用编辑器实际高度
            
            textarea.style.fontFamily = 'monospace';
            textarea.style.fontSize = '15px';
            textarea.style.padding = '10px';
            textarea.style.border = '1px solid #eee';
            textarea.style.borderRadius = '6px';
            textarea.style.background = '#f8f8f8';
            textarea.style.boxSizing = 'border-box';  // 确保 padding 包含在高度内
            textarea.style.resize = 'none';  // 禁用拖拽调整大小
            
            // 异步格式化HTML（动态导入 + await）
            this.formatHTML(html).then(formatted => {
                textarea.value = formatted;
            });
            
            this.$input.parent().append(textarea);
            this._source_textarea = textarea;
            this._showing_source = true;
            this.update_toolbar();
        }
    }

    // 使用Prettier格式化HTML，提高可读性（动态导入 + await）
    async formatHTML(html) {
        if (!html) return '';
        
        try {
            // 动态导入Prettier（懒加载，不占主包体积）
            const prettier = await import('prettier/standalone');
            const parserHtml = await import('prettier/parser-html');
            
            const result = await prettier.format(html, {
                parser: 'html',
                plugins: [parserHtml],
                printWidth: 120,
                tabWidth: 2,
                useTabs: false,
                htmlWhitespaceSensitivity: 'ignore',
                bracketSameLine: false,
                singleAttributePerLine: false
            });
            
            return result;
        } catch (error) {
            console.warn('Prettier formatting failed, using simple formatting:', error);
            // 回退到简单格式化
            return this.formatHTMLSimple(html);
        }
    }

    // 简单但有效的HTML格式化函数（回退方案）
    formatHTMLSimple(html) {
        if (!html) return '';
        
        // 在标签之间添加换行
        let formatted = html.replace(/></g, '>\n<');
        
        // 分割成行并处理缩进
        const lines = formatted.split('\n');
        let indentLevel = 0;
        const indentSize = 2;
        
        const result = lines.map(line => {
            const trimmed = line.trim();
            if (!trimmed) return '';
            
            // 闭合标签减少缩进
            if (trimmed.match(/^<\/[^>]+>$/)) {
                indentLevel = Math.max(0, indentLevel - 1);
            }
            
            // 添加缩进
            const indented = ' '.repeat(indentLevel * indentSize) + trimmed;
            
            // 开放标签增加缩进（排除自闭合标签）
            if (trimmed.match(/^<[^/][^>]*[^/]>$/) && !trimmed.match(/^<[^>]*\/>$/)) {
                indentLevel++;
            }
            
            return indented;
        });
        
        return result.join('\n');
    }

    get_value() {
        if (this.editor && this.editor.getHTML) {
            return this.editor.getHTML();
        }
        return '';
    }

    set_value(value) {
        // 强制更新编辑器内容，即使编辑器内容相同
        if (this.editor) {
            this._setting_content = true;
            this.editor.commands.setContent(value || '');
            this._setting_content = false;
        }
        // 同时更新本地 value
        this.value = value || '';
        
        // 检查是否需要重新创建编辑器（处理记录切换的情况）
        const currentRecordName = this.frm && this.frm.pagename;
        if (currentRecordName !== this._last_record_name) {
            // 记录已切换，需要重新创建编辑器
            this._last_record_name = currentRecordName;
            // 延迟重新创建，避免在设置值的过程中重新创建
            setTimeout(() => {
                if (this.editor) {
                    this.editor.destroy();
                    this.editor = null;
                }
                this.make_input();
            }, 0);
        }
    }

    get_input_value() {
        if (this.editor && this.editor.getHTML) {
            return this.editor.getHTML();
        }
        return '';
    }

    parse_validate_and_set_in_model(value) {
        this.value = value;
    }

    // 添加清理方法
    remove() {
        // 清理编辑器实例
        if (this.editor) {
            this.editor.destroy();
            this.editor = null;
        }
        
        // 清理颜色面板标记
        this._showing_color_panel = false;
        
        // 清理源码模式
        if (this._source_textarea) {
            this._source_textarea.remove();
            this._source_textarea = null;
        }
        this._showing_source = false;
        
        // 关闭所有弹窗
        closeAllTiptapPanels();
        
        // 调用父类清理方法
        if (super.remove) {
            super.remove();
        }
    }
};

// 样式建议放到全局样式文件，临时内联如下：
const style = document.createElement('style');
style.innerHTML = `
.tiptap-toolbar {
  display: flex;
  gap: 4px;
  padding: 6px 0 4px 0;
  border-bottom: 1px solid #eee;
  background: #fafbfc;
  position: sticky;
  top: 0;
  z-index: 3;
}
.tiptap-toolbar-btn {
  background: none;
  border: none;
  padding: 4px;
  border-radius: 4px;
  cursor: pointer;
  color: #222;
  transition: background 0.2s;
  display: flex;
  align-items: center;
}
.tiptap-toolbar-btn.active {
  background: #e6f0ff;
  color: #1fc76f;
}
.tiptap-toolbar-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.jeditor {
  min-height: 300px;
  background: #fff;
  border: 1px solid #d9d9d9;
  border-radius: 6px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
  padding: 8px;
  font-size: 1.1em;
  transition: border 0.2s, box-shadow 0.2s;
  outline: none;
}
.jeditor:focus,
.jeditor:focus-within,
.jeditor[contenteditable="true"]:focus {
  border: 1.5px solid #1fc76f;
  box-shadow: 0 0 0 2px #1fc76f22;
  outline: none;
}
.jeditor[contenteditable="true"],
.jeditor *:focus,
.jeditor *:focus-visible,
.jeditor *:active {
  outline: none;
  border: none;
  box-shadow: none;
}
`;
document.head.appendChild(style);

// 3. 样式优化，极简、线性、紧凑，分组/下拉菜单风格
if (!document.getElementById('tiptap-toolbar-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-toolbar-style';
    style.innerHTML = `
    .tiptap-toolbar { 
        display: flex; 
        flex-wrap: wrap; 
        background: #fff; 
        border-bottom: 1px solid #eee; 
        padding: 6px 8px; 
        margin-bottom: 4px; 
        border-radius: 4px 4px 0 0; 
        box-shadow: 0 1px 2px rgba(0,0,0,0.03); 
        align-items: center; 
        gap: 2px; 
    }
    .tiptap-toolbar-btn { 
        background: none; 
        border: none; 
        outline: none; 
        padding: 0 6px; 
        margin: 0; 
        border-radius: 6px; 
        cursor: pointer; 
        display: inline-flex; 
        align-items: center; 
        justify-content: center; 
        transition: all 0.15s cubic-bezier(0.2, 0, 0.2, 1); 
        color: #444; 
        font-size: 20px; 
        height: 32px; 
        min-width: 32px; 
        position: relative;
    }
    .tiptap-toolbar-btn:hover { 
        background: #f0f2f5; 
        color: #1fc76f; 
        transform: translateY(-1px);
        box-shadow: 0 2px 4px rgba(0,0,0,0.08);
    }
    .tiptap-toolbar-btn.active { 
        background: rgba(31, 199, 111, 0.1); 
        color: #1fc76f; 
        box-shadow: none; 
    }
    .tiptap-toolbar-btn .material-symbols-outlined { 
        font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 24; 
        font-size: 18px; 
        line-height: 1; 
    }
    .tiptap-toolbar-divider { 
        display: inline-block; 
        width: 1px; 
        height: 20px; 
        background: linear-gradient(to bottom, transparent, #e5e6eb, transparent); 
        margin: 0 6px; 
        vertical-align: middle; 
    }
    .tiptap-toolbar-dropdown { 
        position: relative; 
        display: inline-block; 
    }
    .tiptap-toolbar-caret { 
        font-family: 'Material Symbols Outlined';
        font-size: 14px; 
        margin-left: 2px; 
        opacity: 0.7;
        transition: all 0.2s ease;
        font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 20;
    }
    .tiptap-toolbar-dropdown:hover .tiptap-toolbar-caret {
        opacity: 1;
        color: #1fc76f;
    }
    .tiptap-toolbar-dropdown-menu { 
        display: none; 
        position: absolute; 
        top: 100%; 
        left: 0; 
        min-width: 180px; 
        background: #fff; 
        border: 1px solid #eee; 
        border-radius: 8px; 
        box-shadow: 0 4px 16px rgba(0,0,0,0.12); 
        z-index: 999; 
        padding: 6px 0; 
        backdrop-filter: blur(8px);
    }
    .tiptap-toolbar-dropdown-item { 
        display: flex; 
        align-items: center; 
        gap: 12px; 
        padding: 8px 16px; 
        cursor: pointer; 
        color: #333; 
        font-size: 14px; 
        border-radius: 4px; 
        margin: 0 4px;
        transition: all 0.15s cubic-bezier(0.2, 0, 0.2, 1); 
    }
    .tiptap-toolbar-dropdown-item:hover { 
        background: linear-gradient(135deg, #f0f2f5, #e8f5e8); 
        color: #1fc76f; 
        transform: translateX(2px);
    }
    `;
    document.head.appendChild(style);
}

// 表格样式补充
if (!document.getElementById('tiptap-table-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-table-style';
    style.innerHTML = `
    .jeditor table { border-collapse: collapse; width: 100%; background: #fff; }
    .jeditor th, .jeditor td { border: 1px solid #e0e0e0; padding: 6px 8px; min-width: 40px; }
    .jeditor th { background: #f7f7f7; font-weight: bold; }
    .jeditor tr.selected > td, .jeditor tr.selected > th { background: #e6f0ff; }
    .jeditor td:focus, .jeditor th:focus { outline: 2px solid #1fc76f; }
    `;
    document.head.appendChild(style);
}

// 代码块样式补充（主流审美）
if (!document.getElementById('tiptap-codeblock-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-codeblock-style';
    style.innerHTML = `
    .jeditor pre {
      background: #f6f8fa;
      border-radius: 8px;
      padding: 14px 16px;
      font-family: 'JetBrains Mono', 'Fira Mono', 'Menlo', 'Consolas', 'Liberation Mono', monospace;
      font-size: 15px;
      line-height: 1.7;
      color: #222;
      overflow-x: auto;
      margin: 8px 0;
      box-shadow: 0 1px 4px rgba(0,0,0,0.04);
      border: 1px solid #e5e6eb;
      position: relative;
    }
    .jeditor pre code {
      background: none;
      padding: 0;
      border: none;
      font-family: inherit;
      font-size: inherit;
      color: inherit;
    }
    .jeditor pre::-webkit-scrollbar {
      height: 8px;
      background: #f0f0f0;
      border-radius: 4px;
    }
    .jeditor pre::-webkit-scrollbar-thumb {
      background: #e0e0e0;
      border-radius: 4px;
    }
    `;
    document.head.appendChild(style);
}

// 样式补充
if (!document.getElementById('tiptap-color-panel-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-color-panel-style';
    style.innerHTML = `
    .tiptap-color-panel { min-width: 220px; }
    .tiptap-color-panel input[type=text] { outline: none; }
    .tiptap-color-panel input[type=text]:focus { border-color: #1fc76f; }
    .tiptap-color-panel button:hover { background: #1fc76f; }
    `;
    document.head.appendChild(style);
}

// 样式补充
if (!document.getElementById('tiptap-highlight-panel-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-highlight-panel-style';
    style.innerHTML = `
    .tiptap-highlight-panel { min-width: 220px; }
    .tiptap-highlight-panel input[type=text] { outline: none; }
    .tiptap-highlight-panel input[type=text]:focus { border-color: #1fc76f; }
    .tiptap-highlight-panel button:hover { background: #1fc76f; }
    `;
    document.head.appendChild(style);
}

// 图片缩放拖动样式补充
if (!document.getElementById('tiptap-image-resize-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-image-resize-style';
    style.innerHTML = `
    [data-type="imageResizable"] { 
        box-shadow: 0 0 0 1px #1fc76f33; 
        transition: box-shadow 0.2s; 
        position: relative;
    }
    [data-type="imageResizable"]:hover,
    [data-type="imageResizable"].ProseMirror-selectednode { 
        box-shadow: 0 0 0 2px #1fc76f; 
    }
    [data-type="imageResizable"]:hover .image-drag-handle,
    [data-type="imageResizable"].ProseMirror-selectednode .image-drag-handle {
        background: rgba(31, 199, 111, 0.1);
        border: 1px dashed #1fc76f;
    }
    [data-type="imageResizable"]:hover .image-resize-handle,
    [data-type="imageResizable"].ProseMirror-selectednode .image-resize-handle {
        transform: scale(1.1);
        box-shadow: 0 0 4px #1fc76f;
    }
    /* 缩放手柄默认隐藏，只在悬浮时显示 */
    .image-resize-handle {
        opacity: 0;
        transition: opacity 0.2s ease, transform 0.2s ease;
    }
    [data-type="imageResizable"]:hover .image-resize-handle,
    [data-type="imageResizable"].ProseMirror-selectednode .image-resize-handle {
        opacity: 1;
    }
    .image-drag-handle {
        transition: all 0.2s ease;
        background: transparent;
        border: 1px dashed transparent;
    }
    .image-drag-handle:hover {
        background: rgba(31, 199, 111, 0.15) !important;
        border: 1px dashed #1fc76f !important;
    }
    .image-resize-handle {
        transition: all 0.2s ease;
    }
    .image-resize-handle:hover {
        transform: scale(1.2) !important;
        box-shadow: 0 0 6px #1fc76f !important;
    }
    `;
    document.head.appendChild(style);
}

// blockquote 样式增强
if (!document.getElementById('tiptap-blockquote-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-blockquote-style';
    style.innerHTML = `
    .jeditor blockquote {
      border-left: 4px solid #1fc76f;
      background: #f8fefb;
      margin: 8px 0;
      padding: 10px 18px;
      color: #444;
      font-size: 1.05em;
      border-radius: 4px;
      position: relative;
    }
    .jeditor blockquote:before {
      content: "\\201C";
      color: #1fc76f;
      font-size: 2em;
      position: absolute;
      left: 8px;
      top: 2px;
      opacity: 0.18;
      pointer-events: none;
    }
    `;
    document.head.appendChild(style);
}

// 行内代码样式美化
if (!document.getElementById('tiptap-inline-code-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-inline-code-style';
    style.innerHTML = `
    .jeditor code {
      background: #f6f8fa;
      color: #d6336c;
      font-family: 'JetBrains Mono', 'Fira Mono', 'Menlo', 'Consolas', 'Liberation Mono', monospace;
      font-size: 0.97em;
      border-radius: 4px;
      padding: 2px 6px;
      margin: 0 2px;
      border: none;
      word-break: break-all;
    }
    `;
    document.head.appendChild(style);
}

// 图片对齐样式补充
if (!document.getElementById('tiptap-image-align-style')) {
    const style = document.createElement('style');
    style.id = 'tiptap-image-align-style';
    style.innerHTML = `
    [data-type="imageResizable"] { 
        max-width: 100%;
        margin: 8px 0;
    }
    [data-type="imageResizable"][data-text-align="left"] {
        margin-left: 0;
        margin-right: auto;
    }
    [data-type="imageResizable"][data-text-align="center"] {
        margin-left: auto;
        margin-right: auto;
    }
    [data-type="imageResizable"][data-text-align="right"] {
        margin-left: auto;
        margin-right: 0;
    }
    `;
    document.head.appendChild(style);
}