Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

530 请问 mention 提及插件没有做集成吗 #533

Merged
merged 3 commits into from
Feb 7, 2025

Conversation

cycleccc
Copy link
Collaborator

@cycleccc cycleccc commented Feb 6, 2025

Changes Overview

Implementation Approach

Testing Done

Verification Steps

Additional Notes

Checklist

  • I have created a changeset for this PR if necessary.
  • My changes do not break the library.
  • I have added tests where applicable.
  • I have followed the project guidelines.
  • I have fixed any lint issues.

Related Issues

Summary by CodeRabbit

  • New Features

    • Introduced a mention plugin that lets users tag individuals or entities in the editor using the "@" symbol. The enhancement offers a smooth experience by displaying a modal for easy selection and proper insertion of mentions.
  • Documentation

    • Added comprehensive guides detailing installation, configuration, and usage instructions to help users quickly adopt and benefit from the new mention functionality.

@cycleccc cycleccc linked an issue Feb 6, 2025 that may be closed by this pull request
Copy link
Contributor

coderabbitai bot commented Feb 6, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This pull request introduces a new mention plugin for the wangEditor editor. The changes include new documentation, package configuration, build setup, and module implementations covering type definitions, HTML conversion, and editor integration for mention functionality. The plugin intercepts the "@" input to trigger a mention selector modal and renders mention elements appropriately in the editor.

Changes

File(s) Change Summary
.changeset/wise-ducks-grin.md, packages/plugin-mention/README-en.md, packages/plugin-mention/README.md Added new documentation outlining installation, usage, config, and HTML rendering details for the mention plugin.
packages/plugin-mention/package.json, packages/plugin-mention/rollup.config.js, packages/plugin-mention/src/index.ts Introduced new package metadata, build configuration, and module entry point for @wangeditor-next/plugin-mention.
packages/plugin-mention/src/module/{custom-types.ts,elem-to-html.ts,index.ts,interface.ts,parse-elem-html.ts,plugin.ts,render-elem.ts} Implemented the core mention module functionality including type definitions, HTML conversion, plugin extension (modal trigger and node insertion), and rendering logic.
packages/plugin-mention/src/utils/dom.ts Added utility exports with documentation to support DOM operations and compatibility.
packages/plugin-mention/tsconfig.json Added a new TypeScript configuration file extending the base config for the plugin package.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant E as Editor
    participant M as Mention Plugin
    U->>E: Types "@"
    E->>M: withMention intercepts input
    M->>E: Calls showModal() to display mention selector
    U->>M: Selects a mention option
    M->>E: Inserts mention node into content
    E->>M: Renders mention via renderMention
Loading

Possibly related issues

Poem

I’m a rabbit, coding with delight,
Hopping through lines in the digital light.
With a tap of "@", friends appear on screen,
A mention magic—swift and keen.
Happy hops in code, our plugin shines bright!
🐰✨


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (11)
packages/plugin-mention/src/module/index.ts (1)

1-4: Enhance module documentation.

Consider adding more detailed JSDoc documentation including:

  • Purpose and functionality of the mention plugin
  • Usage examples
  • Configuration options
  • Dependencies and requirements
 /**
  * @description mention module entry
+ * @description Implements mention functionality for the editor, allowing users to tag/mention others
+ * @example
+ * ```ts
+ * import mentionModule from '@wangeditor-next/plugin-mention'
+ * // Add usage example
+ * ```
+ * @requires @wangeditor-next/editor
  * @author wangfupeng
  */
packages/plugin-mention/src/module/custom-types.ts (2)

12-12: Consider using a more specific type for info.

Using any type reduces type safety. Consider defining a specific interface for the info property to better document the expected structure and improve type checking.

-  info: any
+  info: {
+    id?: string | number
+    name?: string
+    [key: string]: unknown
+  }

13-13: Translate Chinese comment to English for consistency.

Consider translating the Chinese comment "void 元素必须有一个空 text" to English.

-  children: EmptyText[] // void 元素必须有一个空 text
+  children: EmptyText[] // void elements must have an empty text
packages/plugin-mention/src/module/interface.ts (1)

8-13: Add JSDoc documentation and explicit return types.

Consider adding documentation for the methods and making return types explicit for better maintainability.

 export interface IExtendConfig {
   mentionConfig: {
+    /**
+     * Called when the mention modal needs to be displayed
+     * @param editor The editor instance
+     */
-    showModal: (editor: IDomEditor) => void
+    showModal: (editor: IDomEditor) => void
+    /**
+     * Called when the mention modal needs to be hidden
+     * @param editor The editor instance
+     */
-    hideModal: (editor: IDomEditor) => void
+    hideModal: (editor: IDomEditor) => void
   }
 }
packages/plugin-mention/rollup.config.js (1)

10-16: Consider adding source maps for development builds.

Source maps are helpful for debugging. Consider enabling them in development builds.

 const esmConf = createRollupConfig({
   output: {
     file: pkg.module,
     format: 'esm',
     name,
+    sourcemap: process.env.NODE_ENV === 'development'
   },
 })

 // ... similar change for umdConf

Also applies to: 21-27

packages/plugin-mention/src/module/parse-elem-html.ts (1)

28-34: Consider using type guard instead of type assertion.

Using type assertion with as MentionElement might hide type mismatches. Consider using a type guard to ensure type safety.

-  return {
+  const mentionElement = {
     type: 'mention',
     value,
     info,
     children: [{ text: '' }], // void node 必须有一个空白 text
-  } as MentionElement
+  }
+  
+  function isMentionElement(elem: any): elem is MentionElement {
+    return (
+      elem.type === 'mention' &&
+      typeof elem.value === 'string' &&
+      Array.isArray(elem.children) &&
+      elem.children.length === 1 &&
+      'text' in elem.children[0]
+    )
+  }
+  
+  if (!isMentionElement(mentionElement)) {
+    throw new Error('Invalid mention element structure')
+  }
+  
+  return mentionElement
packages/plugin-mention/src/module/render-elem.ts (1)

14-14: Add type validation for mention element.

The type casting as MentionElement might hide type mismatches. Consider adding runtime type validation.

-  const { value = '' } = elem as MentionElement
+  if (elem.type !== 'mention') {
+    throw new Error('Invalid element type')
+  }
+  const mentionElem = elem as MentionElement
+  const { value = '' } = mentionElem
packages/plugin-mention/README.md (2)

9-9: Provide Alternate Text for the Demo Image

The demo image at line 9 does not include any alt text. For better accessibility and to satisfy markdown lint rules (MD045), please add descriptive alt text.

-![](./_img/demo.png)
+![Demo image showing mention plugin usage](./_img/demo.png)

61-79: Editor Configuration and Typographical Correction

The configuration snippet (lines 66-76) clearly demonstrates how to integrate the mention configuration into the editor setup.

Typographical Issue:
Line 78 contains a duplicated phrase ("创建创建和工具栏"). A simple correction would improve clarity.

-// 创建创建和工具栏,会用到 editorConfig 。具体查看 wangEditor 文档
+// 创建编辑器和工具栏,会用到 editorConfig 。具体查看 wangEditor 文档
packages/plugin-mention/README-en.md (2)

9-9: Add Alt Text to Demo Image for Accessibility

Similar to the Chinese documentation, the demo image here lacks alt text. Please include descriptive alt text to ensure accessibility and compliance with markdown best practices.

-![](./_img/demo.png)
+![Demo image demonstrating the mention plugin](./_img/demo.png)
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

9-9: Images should have alternate text (alt text)
null

(MD045, no-alt-text)


31-60: Modal Display and Mention Insertion Example – Minor Typo

The showModal function, including its inner insertMention implementation, is well-documented and clear. However, note a minor typo in the inline comment: “move curser” should be “move cursor.”

-    editor.move(1) // move curser
+    editor.move(1) // move cursor
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a82fa34 and 1ea130c.

⛔ Files ignored due to path filters (1)
  • packages/plugin-mention/_img/demo.png is excluded by !**/*.png
📒 Files selected for processing (15)
  • .changeset/wise-ducks-grin.md (1 hunks)
  • packages/plugin-mention/README-en.md (1 hunks)
  • packages/plugin-mention/README.md (1 hunks)
  • packages/plugin-mention/package.json (1 hunks)
  • packages/plugin-mention/rollup.config.js (1 hunks)
  • packages/plugin-mention/src/index.ts (1 hunks)
  • packages/plugin-mention/src/module/custom-types.ts (1 hunks)
  • packages/plugin-mention/src/module/elem-to-html.ts (1 hunks)
  • packages/plugin-mention/src/module/index.ts (1 hunks)
  • packages/plugin-mention/src/module/interface.ts (1 hunks)
  • packages/plugin-mention/src/module/parse-elem-html.ts (1 hunks)
  • packages/plugin-mention/src/module/plugin.ts (1 hunks)
  • packages/plugin-mention/src/module/render-elem.ts (1 hunks)
  • packages/plugin-mention/src/utils/dom.ts (1 hunks)
  • packages/plugin-mention/tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/plugin-mention/src/utils/dom.ts
  • packages/plugin-mention/src/index.ts
  • packages/plugin-mention/tsconfig.json
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
packages/plugin-mention/README-en.md

9-9: Images should have alternate text (alt text)
null

(MD045, no-alt-text)

🔇 Additional comments (15)
packages/plugin-mention/src/module/index.ts (2)

6-11: LGTM!

The imports are well-organized, following a logical pattern with external dependencies first followed by internal modules.


20-20: LGTM!

The default export is appropriate for this module entry point.

packages/plugin-mention/rollup.config.js (1)

3-3: Consider compatibility with older Node.js versions.

The JSON import assertion syntax is relatively new and may not be supported in all environments. Consider using require() or dynamic import for better compatibility.

✅ Verification successful

🌐 Web query:

Which Node.js versions support JSON import assertions?

💡 Result:

JSON import assertions in Node.js have evolved through different versions with changing syntax and experimental flags:

## Support Timeline
**Experimental phase with `assert { type: 'json' }`:**
- **Node.js ≥17.1**: Initial experimental support via flag [`--experimental-json-modules`][3][6].
- **Node.js ≥18.x**: Available experimentally but required manual flag activation[2][6].

**Syntax change to `with { type: 'json' }`:**
- **Node.js ≥18.19 & ≥20.10**: Introduced new syntax (`with`) for import attributes[7][8].
- **Node.js ≥22**: Dropped support for legacy `assert` syntax; only supports new [`with` keyword][8].

## Current Status (2025)
- **Legacy behavior**: Use **`import data from './file.json' assert { type: 'json' }`** in:
    - **Node.js <18.19** or **<20.x** (experimental).
    - Requires flag [`--experimental-json-modules`][6].
  
- **Modern behavior**: Use **`import data from './file.json' with { type: 'json' }`** in:
    - **Node.js ≥18.19**, **≥20.x**, and later LTS/stable releases[7][8].

---

For example:
```javascript
// Pre-v18/v20:
import jsonData from './data.json' assert { type: 'json' };

// Post-v18/v20:
import jsonData from './data.json' with { type: 'json' };
```

Citations:

- 1: https://v8.dev/features/import-assertions
- 2: https://www.stefanjudis.com/snippets/how-to-import-json-files-in-es-modules-node-js/
- 3: https://miyauchi.dev/posts/import-assertions-json-modules/
- 4: https://www.emmanuelgautier.com/blog/node-module-import-assert-json
- 5: https://www.proposals.es/proposals/Import%20Assertions
- 6: https://nodejs.org/download/release/v18.11.0/docs/api/esm.html
- 7: https://nodejs.org/api/esm.html
- 8: https://github.com/nodejs/node/issues/51622
- 9: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

JSON Import Assertions May Hinder Compatibility on Older Node Versions

  • The syntax import pkg from './package.json' assert { type: 'json' } is fully supported only in Node.js v17.1+ (albeit experimentally) and in later versions with appropriate flags.
  • For projects that need to run on Node versions earlier than v17.1 or without experimental flag usage, using require() or dynamic imports would provide broader compatibility.
.changeset/wise-ducks-grin.md (1)

1-6: LGTM!

The changeset correctly describes the feature addition and uses the appropriate version increment.

packages/plugin-mention/package.json (1)

1-48: Package Metadata and Configuration Validation

The package metadata for the new @wangeditor-next/plugin-mention is well-defined. The file correctly declares the name, version, description, module type, export fields (supporting both ESM and CommonJS), and peer dependencies. Please ensure that the path specified in the "types" field (i.e. "dist/plugin-mention/src/index.d.ts") matches the actual build output and that the scripts for development and build are functioning as expected.

packages/plugin-mention/README.md (5)

1-4: Clear Title and Language Navigation

The title ("# wangEditor mention 插件") and the link to the English documentation are clearly provided at the top. This is helpful for users looking for guidance in both Chinese and English.


11-16: Installation Instructions are Clear

The installation section correctly shows the command to add the plugin using Yarn. This straightforward instruction is clear for users.


17-20: Usage Link for Vue Example

The provided link to the Vue 示例源码 is useful for developers looking for a practical example of how to integrate the plugin.


21-29: Accurate Plugin Registration Example

The code snippet showing how to register the mention module (lines 23-29) is accurate and clearly instructs that the registration must occur before creating the editor. This is crucial for proper integration.


30-59: Modal Setup and Mention Insertion Example

The detailed example demonstrating the showModal function, which positions the modal based on the cursor and container positions, is well illustrated. The nested insertMention function clearly shows how to construct and insert a mention node.

One minor note: consider verifying that the null check on domRange is sufficient for all edge cases where document.getSelection() might return null.

packages/plugin-mention/README-en.md (5)

1-4: Concise English Title and Language Switch

The English documentation starts with a clear title and provides a link to the Chinese version for users who need it. This is a solid approach to support a bilingual audience.


11-16: Clear Installation Instructions

The installation instructions using Yarn are straightforward and correct.


21-30: Plugin Registration Code is Clear

The code snippet (lines 23-30) demonstrates how to import and register the module before editor creation, which is clearly stated as a requirement.


67-77: Editor Configuration is Well-Outlined

The configuration snippet provided (lines 67-77) is straightforward and correctly shows how to integrate the mention configuration into the editor's extended configuration. This clarity will help users apply custom settings.


82-90: HTML Rendering Example is Informative

The HTML snippet example (lines 86-88) elegantly shows how a mention node will be rendered, including the emphasis on decoding the data-info attribute. This helps clarify the expected output.

Comment on lines +13 to +18
const module: Partial<IModuleConf> = {
editorPlugin: withMention,
renderElems: [renderElemConf],
elemsToHtml: [elemToHtmlConf],
parseElemsHtml: [parseHtmlConf],
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify the implementation of imported configurations.

The module configuration looks well-structured. However, we should verify that all imported configurations (elemToHtmlConf, parseHtmlConf, renderElemConf) are properly implemented and tested.


🏁 Script executed:

#!/bin/bash
# Check implementation of imported configurations
echo "Checking elem-to-html implementation..."
ast-grep --pattern 'const elemToHtmlConf = {
  type: $_,
  $$$
}'

echo "Checking parse-elem-html implementation..."
ast-grep --pattern 'const parseHtmlConf = {
  selector: $_,
  $$$
}'

echo "Checking render-elem implementation..."
ast-grep --pattern 'const renderElemConf = {
  type: $_,
  $$$
}'

Length of output: 4095


I ran a second check using a plain text search to locate the definitions of both elemToHtmlConf and renderElemConf. The search confirmed that while parseHtmlConf is defined (and our previous output shows multiple definitions), neither elemToHtmlConf nor renderElemConf appear to be defined anywhere in the repository.

It appears that in the module configuration for the mention plugin the imported configurations for converting elements to HTML and for rendering elements are missing their implementations. You might need to confirm whether these configurations are defined elsewhere or if they should be added.

  • elemToHtmlConf is not defined.
  • renderElemConf is not defined.

Please verify if these are intentionally omitted (for example, if the mention plugin doesn’t support these features) or if they need to be implemented.

Comment on lines +11 to +16
function mentionToHtml(elem: SlateElement, _childrenHtml: string): string {
const { value = '', info = {} } = elem as MentionElement
const infoStr = encodeURIComponent(JSON.stringify(info))

return `<span data-w-e-type="mention" data-w-e-is-void data-w-e-is-inline data-value="${value}" data-info="${infoStr}">@${value}</span>`
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add input validation and HTML escaping to prevent XSS.

The current implementation could be vulnerable to XSS attacks. Consider:

  1. Validating the value and info properties
  2. Escaping HTML special characters in value
  3. Adding error handling for JSON.stringify
+import { escapeHtml } from '@wangeditor-next/core-utils'
+
 function mentionToHtml(elem: SlateElement, _childrenHtml: string): string {
   const { value = '', info = {} } = elem as MentionElement
-  const infoStr = encodeURIComponent(JSON.stringify(info))
+  if (typeof value !== 'string') {
+    console.warn('Invalid mention value:', value)
+    return ''
+  }
+  
+  let infoStr = ''
+  try {
+    infoStr = encodeURIComponent(JSON.stringify(info))
+  } catch (err) {
+    console.error('Failed to stringify mention info:', err)
+    return ''
+  }
+  
+  const escapedValue = escapeHtml(value)
-  return `<span data-w-e-type="mention" data-w-e-is-void data-w-e-is-inline data-value="${value}" data-info="${infoStr}">@${value}</span>`
+  return `<span data-w-e-type="mention" data-w-e-is-void data-w-e-is-inline data-value="${escapedValue}" data-info="${infoStr}">@${escapedValue}</span>`
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function mentionToHtml(elem: SlateElement, _childrenHtml: string): string {
const { value = '', info = {} } = elem as MentionElement
const infoStr = encodeURIComponent(JSON.stringify(info))
return `<span data-w-e-type="mention" data-w-e-is-void data-w-e-is-inline data-value="${value}" data-info="${infoStr}">@${value}</span>`
}
import { escapeHtml } from '@wangeditor-next/core-utils'
function mentionToHtml(elem: SlateElement, _childrenHtml: string): string {
const { value = '', info = {} } = elem as MentionElement
if (typeof value !== 'string') {
console.warn('Invalid mention value:', value)
return ''
}
let infoStr = ''
try {
infoStr = encodeURIComponent(JSON.stringify(info))
} catch (err) {
console.error('Failed to stringify mention info:', err)
return ''
}
const escapedValue = escapeHtml(value)
return `<span data-w-e-type="mention" data-w-e-is-void data-w-e-is-inline data-value="${escapedValue}" data-info="${infoStr}">@${escapedValue}</span>`
}

Comment on lines +18 to +19
const value = elem.getAttribute('data-value') || ''
const rawInfo = decodeURIComponent(elem.getAttribute('data-info') || '')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for required attributes.

The function should validate that required attributes are present and handle missing attributes gracefully.

-  const value = elem.getAttribute('data-value') || ''
-  const rawInfo = decodeURIComponent(elem.getAttribute('data-info') || '')
+  const value = elem.getAttribute('data-value')
+  if (!value) {
+    throw new Error('Missing required attribute: data-value')
+  }
+  const rawInfoAttr = elem.getAttribute('data-info')
+  const rawInfo = rawInfoAttr ? decodeURIComponent(rawInfoAttr) : ''
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const value = elem.getAttribute('data-value') || ''
const rawInfo = decodeURIComponent(elem.getAttribute('data-info') || '')
const value = elem.getAttribute('data-value')
if (!value) {
throw new Error('Missing required attribute: data-value')
}
const rawInfoAttr = elem.getAttribute('data-info')
const rawInfo = rawInfoAttr ? decodeURIComponent(rawInfoAttr) : ''

Comment on lines +17 to +35
const vnode = h(
'span',
{
props: {
contentEditable: false, // 不可编辑
},
style: {
marginLeft: '3px',
marginRight: '3px',
backgroundColor: 'var(--w-e-textarea-slight-bg-color)',
border: selected // 选中/不选中,样式不一样
? '2px solid var(--w-e-textarea-selected-border-color)' // wangEditor 提供了 css var https://www.wangeditor.com/v5/theme.html
: '2px solid transparent',
borderRadius: '3px',
padding: '0 3px',
},
},
`@${value}`, // 如 `@张三`
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance accessibility with ARIA attributes.

Add ARIA attributes to improve accessibility for screen readers.

   const vnode = h(
     'span',
     {
       props: {
         contentEditable: false, // 不可编辑
+        role: 'button',
+        'aria-label': `Mention ${value}`,
       },
       style: {
         marginLeft: '3px',
         marginRight: '3px',
         backgroundColor: 'var(--w-e-textarea-slight-bg-color)',
         border: selected
           ? '2px solid var(--w-e-textarea-selected-border-color)'
           : '2px solid transparent',
         borderRadius: '3px',
         padding: '0 3px',
       },
     },
     `@${value}`,
   )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const vnode = h(
'span',
{
props: {
contentEditable: false, // 不可编辑
},
style: {
marginLeft: '3px',
marginRight: '3px',
backgroundColor: 'var(--w-e-textarea-slight-bg-color)',
border: selected // 选中/不选中,样式不一样
? '2px solid var(--w-e-textarea-selected-border-color)' // wangEditor 提供了 css var https://www.wangeditor.com/v5/theme.html
: '2px solid transparent',
borderRadius: '3px',
padding: '0 3px',
},
},
`@${value}`, // 如 `@张三`
)
const vnode = h(
'span',
{
props: {
contentEditable: false, // 不可编辑
role: 'button',
'aria-label': `Mention ${value}`,
},
style: {
marginLeft: '3px',
marginRight: '3px',
backgroundColor: 'var(--w-e-textarea-slight-bg-color)',
border: selected
? '2px solid var(--w-e-textarea-selected-border-color)'
: '2px solid transparent',
borderRadius: '3px',
padding: '0 3px',
},
},
`@${value}`,
)

Comment on lines +10 to +15
function getMentionConfig(editor: IDomEditor) {
const { EXTEND_CONF } = editor.getConfig()
const { mentionConfig } = EXTEND_CONF as IExtendConfig

return mentionConfig
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for config retrieval.

The getMentionConfig function should handle cases where the config is missing or invalid.

 function getMentionConfig(editor: IDomEditor) {
   const { EXTEND_CONF } = editor.getConfig()
+  if (!EXTEND_CONF) {
+    throw new Error('Editor config is missing EXTEND_CONF')
+  }
   const { mentionConfig } = EXTEND_CONF as IExtendConfig
+  if (!mentionConfig) {
+    throw new Error('Mention config is missing in EXTEND_CONF')
+  }
   return mentionConfig
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function getMentionConfig(editor: IDomEditor) {
const { EXTEND_CONF } = editor.getConfig()
const { mentionConfig } = EXTEND_CONF as IExtendConfig
return mentionConfig
}
function getMentionConfig(editor: IDomEditor) {
const { EXTEND_CONF } = editor.getConfig()
if (!EXTEND_CONF) {
throw new Error('Editor config is missing EXTEND_CONF')
}
const { mentionConfig } = EXTEND_CONF as IExtendConfig
if (!mentionConfig) {
throw new Error('Mention config is missing in EXTEND_CONF')
}
return mentionConfig
}

Comment on lines +36 to +59
setTimeout(() => {
// 展示 modal (异步,以便准确获取光标位置)
if (showModal) { showModal(newEditor) }

// 监听,隐藏 modal(异步,等待 modal 渲染后再监听)
setTimeout(() => {
function hide() {
if (hideModal) { hideModal(newEditor) }
}
newEditor.once('fullScreen', hide)
newEditor.once('unFullScreen', hide)
newEditor.once('scroll', hide)
newEditor.once('modalOrPanelShow', hide)
newEditor.once('modalOrPanelHide', hide)

function hideOnChange() {
if (newEditor.selection != null) {
hide()
newEditor.off('change', hideOnChange) // 及时解绑
}
}
newEditor.on('change', hideOnChange)
})
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Clean up timeouts and event listeners.

The nested timeouts and event listeners should be properly cleaned up to prevent memory leaks.

+  let showModalTimeout: NodeJS.Timeout
+  let listenerTimeout: NodeJS.Timeout
+
   if (t === '@') {
-    setTimeout(() => {
+    showModalTimeout = setTimeout(() => {
       // 展示 modal (异步,以便准确获取光标位置)
       if (showModal) { showModal(newEditor) }
 
       // 监听,隐藏 modal(异步,等待 modal 渲染后再监听)
-      setTimeout(() => {
+      listenerTimeout = setTimeout(() => {
         function hide() {
           if (hideModal) { hideModal(newEditor) }
+          // Clean up all event listeners
+          newEditor.off('fullScreen', hide)
+          newEditor.off('unFullScreen', hide)
+          newEditor.off('scroll', hide)
+          newEditor.off('modalOrPanelShow', hide)
+          newEditor.off('modalOrPanelHide', hide)
         }
         newEditor.once('fullScreen', hide)
         newEditor.once('unFullScreen', hide)
         newEditor.once('scroll', hide)
         newEditor.once('modalOrPanelShow', hide)
         newEditor.once('modalOrPanelHide', hide)
 
         function hideOnChange() {
           if (newEditor.selection != null) {
             hide()
             newEditor.off('change', hideOnChange)
           }
         }
         newEditor.on('change', hideOnChange)
       })
     })
+
+    // Clean up timeouts when editor is destroyed
+    newEditor.once('destroy', () => {
+      clearTimeout(showModalTimeout)
+      clearTimeout(listenerTimeout)
+    })
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setTimeout(() => {
// 展示 modal (异步,以便准确获取光标位置)
if (showModal) { showModal(newEditor) }
// 监听,隐藏 modal(异步,等待 modal 渲染后再监听)
setTimeout(() => {
function hide() {
if (hideModal) { hideModal(newEditor) }
}
newEditor.once('fullScreen', hide)
newEditor.once('unFullScreen', hide)
newEditor.once('scroll', hide)
newEditor.once('modalOrPanelShow', hide)
newEditor.once('modalOrPanelHide', hide)
function hideOnChange() {
if (newEditor.selection != null) {
hide()
newEditor.off('change', hideOnChange) // 及时解绑
}
}
newEditor.on('change', hideOnChange)
})
})
let showModalTimeout: NodeJS.Timeout
let listenerTimeout: NodeJS.Timeout
if (t === '@') {
showModalTimeout = setTimeout(() => {
// 展示 modal (异步,以便准确获取光标位置)
if (showModal) { showModal(newEditor) }
// 监听,隐藏 modal(异步,等待 modal 渲染后再监听)
listenerTimeout = setTimeout(() => {
function hide() {
if (hideModal) { hideModal(newEditor) }
// Clean up all event listeners
newEditor.off('fullScreen', hide)
newEditor.off('unFullScreen', hide)
newEditor.off('scroll', hide)
newEditor.off('modalOrPanelShow', hide)
newEditor.off('modalOrPanelHide', hide)
}
newEditor.once('fullScreen', hide)
newEditor.once('unFullScreen', hide)
newEditor.once('scroll', hide)
newEditor.once('modalOrPanelShow', hide)
newEditor.once('modalOrPanelHide', hide)
function hideOnChange() {
if (newEditor.selection != null) {
hide()
newEditor.off('change', hideOnChange) // 及时解绑
}
}
newEditor.on('change', hideOnChange)
})
})
// Clean up timeouts when editor is destroyed
newEditor.once('destroy', () => {
clearTimeout(showModalTimeout)
clearTimeout(listenerTimeout)
})
}

@cycleccc cycleccc merged commit 140d22c into master Feb 7, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

请问@ mention 提及插件没有做集成吗?
1 participant