Summernote (Super simple WYSIWYG editor) adaptation for react http://summernote.org
npm install @iqs/react-summernoteReact SummerNote 是一個 React 版本的 WYSIWYG 的 rich text editor,基於 SummerNote 建構
* Stable Version: v2.3.19
* 版本修改紀錄:Changelog
上面連結是一個 React SummerNote 的基本展示
!Demo
React SummerNote 依賴以下套件
#### 必要套件
* react: ^16.8.6
* react-dom: ^16.8.6
* prop-types: ^15.7.2
#### 第三方套件
* bootstrap: ^4.6.2
* popper.js: ^1.16.1
* summernote: ^0.8.18
* jquery: ^3.6.1
* store: ^2.0.12
#### 必要依賴安裝
```
npm i bootstrap popper.js summernote jquery store --save
#### 安裝 React SummerNote
``
npm i @iqs/react-summernote --save
#### 設定 Webpack
使 jQuery, store 可以在 Component 中被存取,而不需額外 import
`js`
{
...,
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
store: "store",
})
]
}
`jsx
import React from 'react'
import { render } from 'react-dom'
import SummerNote from 'react-summernote'
import 'react-summernote/dist/main.css'
// 自動載入必要套件
SummerNote.ImportCode()
render(
lang: 'en',
height: 350,
dialogsInBody: true,
toolbar: [
['style', ['style']],
['font', ['bold', 'underline', 'clear']],
['fontname', ['fontname']],
['para', ['ul', 'ol', 'paragraph']],
// plugin
["table", ["jTable", "jMerge", "jBackcolor", "jBorderColor", "jAlign", "jTableInfo", "jWidthHeightReset"]],
['insert', ['link', 'picture', 'video']],
['view', ['fullscreen', 'codeview']],
//["anchor",["anchor", "toc", "markAnchor", "editAnchor"]]
]
}}
onChange={e => console.log(e)}
/>
, document.getElementById('root')
)
`
* Insert
* picture: open image dialoglink
* : open link dialogvideo
* : open video dialogtable
* : insert a tablehr
* : insert a horizontal rulefontname
* Font Style
* : set font familyfontsize
* : set font sizecolor
* : set foreground and background colorforecolor
* : set foreground colorbackcolor
* : set background colorbold
* : toggle font weightitalic
* : toggle italicunderline
* : toggle underlinestrikethrough
* : toggle strikethroughsuperscript
* : toggle superscriptsubscript
* : toggle subscriptclear
* : clear font stylestyle
* Paragraph style
* : format selected blockol
* : toggle ordered listul
* : toggle unordered listparagraph
* : dropdown for paragraph alignheight
* : set line heightfullscreen
* Misc
* : toggle fullscreen editing modecodeview
* : toggle wysiwyg and html editing modeundo
* : undoredo
* : redohelp
* : open help dialogjTable
* Table (Plugin)
* : 表格欄位長寬縮放jMerge
* : 框選後合併 celljBackcolor
* : cell 的背景色jBorderColor
* : 整個表格 border 顏色jAlign
* : cell 的對齊方式jTableInfo
* : 調整整個 table 的 marginjWidthHeightReset
* : 重設 cell 寬高
設置 options props,即可設置客製化功能與 UI 顯示
更詳細的設定方式,可以參閱上面的官方說明
下面簡單示範如何使用新版 API 控制編輯器 (version > v2.0.0)
`jsx
import React, { Component } from 'react'
import SummerNote from './SummerNote'
class App extends Component {
constructor(props) {
super(props)
this.editor = React.createRef()
}
componentDidMount(){
const editor = this.editor.current
editor.focus() // 焦點設置在 editor 上
editor.isEmpty() // 編輯器內容是否為空
editor.reset() // 清除編輯器所有內容
editor.disable() // 使編輯器禁止輸入
editor.enable() // 使編輯器可以輸入
editor.insertImage() // 插入圖片 (詳情可參考下一個段落)
editor.insertNode(/ html node /) // 插入 HTML 節點
editor.insertText('') // 插入純文字
}
render() {
return (
}
}
`
自訂上傳圖片的方法,複製圖片(剪貼簿中)貼上編輯器時,就會觸發該方法
`jsx
import React, { Component } from 'react'
import SummerNote from './SummerNote'
class App extends Component {
constructor(props) {
super(props)
this.editor = React.createRef();
}
onImageUpload = file => {
let image = file[0]
this.editor.current.insertImage('https://i.imgur.com/JOOEENx.png', ($image) => {
$image.css("width", Math.floor($image.width() / 2));
$image.attr("title", image.name);
})
}
render() {
return (
}
}
`
!1
貼上 Word 內容時,SummerNote 會解析剪貼簿中的 rtf 內容,解析後會自動將 部分轉換成 base64 格式的圖片資源,這些 都會被加上 class .zap-img-uploading,可以在使用 jQuery 進行後續處理
`jsx
import React, { Component } from 'react'
import SummerNote from './SummerNote'
function onImagePasteFromWord($imgs) {
// $imgs collect imgs from this pasting action
$imgs.removeClass('zap-img-uploading')
}
class App extends Component {
render() {
return (
}
}
`
貼上 Excel 內容時,SummerNote 會解析剪貼簿中的 HTML 內容,解析後會自動將樣式附加進去,但目前不支援包含 Excel 中的圖片,需額外逐一手動複製貼上
如果專案也有使用 Bootstrap 等套件,不希望重複引用,可以自行引入必要依賴
`js
// 自動載入必要套件
//SummerNote.ImportCode()
// 以下為必要依賴,可以自行在您的專案中引入 (須注意順序)
require('bootstrap/dist/css/bootstrap.min.css')
require('bootstrap/js/dist/modal')
require('bootstrap/js/dist/dropdown')
require('bootstrap/js/dist/tooltip')
require('bootstrap/js/dist/tab')
require('summernote/dist/summernote-bs4.css')
require('summernote/dist/summernote-bs4.min.js')
require('react-summernote/plugin/custom/summernote-patch-dom')
require('react-summernote/plugin/custom/summernote-patch-handle')
`
> summernote-patch-dom: 用於修復字體、字型等樣式無法正常套用到框選範圍內的所有節點。因官方尚未發布涵蓋 Summernote PR#4472 的版本,故在此使用 plugin 覆寫 dom.walkPoint, dom.nextPointWithEmptyNode0.8.18
>
> 目前 Summernote 版本 ,待官方發佈新版本後可移除此 plugin
>
> 參考:Summernote issue#4471
> summernote-patch-handle: 用於修復圖片顯示框位置偏移。因官方尚未發布涵蓋 Summernote PR#4283 的版本,故在此使用 plugin 覆寫 modules.handle.update0.8.18
>
> 目前 Summernote 版本 ,待官方發佈新版本後可移除此 plugin
從 2.0.4 的版本開始,引入了 table plugin,可針對 table 元素進行更多操作
`js`
require('react-summernote/plugin/summernote-ext-table')
require('react-summernote/plugin/summernote-ext-table.css')
若要自行引入 plugin 可參考 Plugin 介紹
請嘗試引用 src/plugin 裡面的 plugin
以 table plugin 為例
`js`
require('@iqs/react-summernote/src/plugin/misc/summernote-ext-table')
require('@iqs/react-summernote/src/plugin/misc/summernote-ext-table.css')
summernote 包含一個原始碼的 xss 過濾機制,規則如下:
`js`
/<\/(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|ilayer|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|t(?:itle|extarea)|xml)[^>]?>/gi
在 options 中修改內建白名單,即可客製化保留部分 tag 不被過濾
`jsx`
height: 350,
toolbar: [
['view', ['fullscreen', 'codeview']],
],
// 白名單
codeviewFilterRegex: /<\/(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|ilayer|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|t(?:itle|extarea)|xml)[^>]?>/gi,
// 白名單
codeviewFilter: true, // 是否開啟白名單過濾
codeviewIframeFilter: false // 是否開啟 iframe src 網址過濾
}}
/>
, document.getElementById('root')
更多詳細設定可以參閱官方文件
- YouTube 網域 + 路徑 + id
- https://youtube.com/embed/Dm_BrGu1sHMhttps://www.youtube.com/watch?v=Dm_BrGu1sHM&t=300
- YouTube 網域 + 路徑 + id + 時戳
- https://m.youtube.com/v/Dm_BrGu1sHM?t=300
- https://m.youtube.com/v/Dm_BrGu1sHM?t=300&si=YsiSA_iLcKJMtDVq
- 網址附帶的其他參數需放在時戳之後
-
| 網域 | 路徑 | id | 時戳 |
| ---------------------------------------------------------- | ------------------------------------------------------------ | ---------- | ------------------------------------------------------ |
| youtube.com/www.youtube.com/
m.youtube.com/
| embed/v/
watch?v=
watch?
(任意字元)&v= | (11個字元) | ?t=(任意字元)&t=
(任意字元)t=
(任意字元) |
- Instagram 網域 + 路徑 + id
- https://www.instagram.com/p/Cy8sEXrv9xuhttps://www.instagram.com/p/Cy8sEXrv9xu?igshid=MzRlODBiNWFlZA==
- 網址附帶的其他參數需放在 id 之後
-
| 網域 | 路徑 | id |
| ---------------------------------------- | ---- | ---------- |
| www.instagram.com/instagram.com/ | p/ | (任意字元) |
- 優酷網域 + 路徑 + id_ + id + .htmlhttps://v.youku.com/v_show/id_XNTA3MzUyMTUyMA==.html
- .html
- 網址附帶的其他參數需放在 之後https://v.youku.com/v_show/id_XNTA3MzUyMTUyMA==.html?spm=a2hja.14919748_WEBHOME_NEW.drawer15.d_zj1_4&s=efbfbd4a46efbfbd5975&scm=20140719.manual.19594.show_efbfbd4a46efbfbd5975
-
| 網域 | 路徑 | 前綴 | id | 後綴 |
| -------------- | --------- | ----- | ------------------------------- | ------- |
| v.youku.com/ | v_show/ | id_ | (至少一個任意字元)(零或數個=) | .html |
- DailyMotion網域 + 路徑 + id
- https://www.dailymotion.com/video/x8pi9hp
| 網域 | 路徑 | id | 參數 |
| ---------------------- | -------------------- | -------------------------------------- | ------------------------------------------------------ |
| www.dailymotion.com/ | video/ hub/
| (至少一個非_的字元)(多個非#的字元) | (零組或一組 (#video=)(至少一個非 _ 或 & 的字元)) |
: v16.20.2
- npm: v8.19.4以 nvm 安裝
`bash
nvm install v16.20.2
nvm use v16.20.2
`$3
安裝依賴套件
- npm ci 依據 package-lock.json 安裝套件`bash
npm ci
`
$3
npm 有準備以下指令,分別說明如下,如果您也想貢獻程式碼,可以參考使用:
*
npm run build:用於打包整個套件,輸出到 dist 目錄下的一個 main.js 檔案,用於發布新的套件版本
* npm run web:以 src/start.js 為起始,打包出一個 demo 網站,輸出到 docs,並且使用 production 產品模式執行,用於發布成 Repo 的 Page 網站
* npm run dev:以 src/start.js 為起始,打包出一個 demo 網站,輸出到 docs,並且使用 dev 開發模式執行,用於發布成 Repo 的 Page 網站
* npm run test:啟動一個 webpack-dev-server,以 src/test.js 為起始,用於測試直接引用打包 (build) 後的 summernote ,觀察引用打包後的程式執行起來是否有問題
* npm start:開發人員主要模式,啟動一個 webpack-dev-server,以 src/start.js 為起始,用於測試原始程式執行起來是否有問題,並開發新功能
$3
可使用 vscode extension Commit Message Editor 編輯 Commit Message- 依據 Conventional Commits (中文版)
- Type 必填,選對修改事項類型,不清楚選哪種可依據 Angular CONTRIBUTING - Commit Message Format
- Title 必填,概述修改事項 (Short description)
- Scope 可選,目前未定義
- Body 可選,可描寫變更的內容
- Footer 可選,可寫 commit 簽署者資訊
$3
#### Summernote.jsxSummernote 連結器,與原生 Summernote 對接
#### App.jsx
引入使用 Summernote Component,DEMO 呈現依賴此檔案設定
#### ImportCode.js
ImportCode 會引入所有 Plugin,若有新增 Plugin 需要在此引入
`javascript=
module.exports = function () {
// ...
require('../plugin/custom/summernote-custom-style')
}
`
#### SummernotePlugin
@iqs/react-summernote:
v2.2.20 開始- src/components/SummernotePlugin.jsx: 可在使用 React-Summernote 時匯入自定義的 Button 或 Plugin
- src/components/SummernotePlugin.d.ts: 設定 Summernote Types
`jsx
import SummerNote, { SummernotePlugin } from '@iqs/react-summernote'
`Methods
-
SummernotePlugin.createSummernoteButton
- SummernotePlugin.createSummernotePluginTypes
- global
$.summernote
- SummernotePlugin.createSummernotePlugin
- SummernotePlugin.SummernotePluginClass
- SummernotePlugin.SummernotePluginFunction
- SummernotePlugin.createSummernoteButton
- SummernotePlugin.SummernoteContext
- ...#### Plugin
src/plugin/
Plugin 目錄架構由 Awesome Summernote 訂定,IQS 自己寫的都放在 src/plugin/custom/
檔案名稱以
summernote- 開頭,Plugin 名稱、按鈕名稱以 小駝峰 命名
有新增 Plugin 記得更新文件 src/plugin/README.md
For maintainer
$3
iq-service-inc.github.io/react-summernote1. push 到 master 分支
2. 觸發 Github Workflow Deploy Master Branch to Github Pages
3. 待 Workflow 完成即上版完成
$3
NPM - @iqs/react-summernote1. 修改 README.md 版本號
2. 修改 package.json 版本號
3. 更新 CHANGELOG.md
4. push 到 master 分支
5. 發布 Github Release
- 選擇新 Tag
- 標題為 Tag
- 內容貼 CHANGELOG
- 內容最後附上差異比對連結
- e.g.
`markdown
Full Changelog: https://github.com/iq-service-inc/react-summernote/compare/v2.2.19...v2.2.20
`6. 觸發 Github Workflow Publish Package to npmjs
7. 待 Workflow 完成即發佈完成
For repo admins
.github/workflows/ 存放所有 Github Workflows
1. Deploy Master Branch to Github Pages: 自動部署 Pages
2. Publish Package to npmjs: 發佈 npm 套件
> 若發布流程失敗,出現
404 Not Found - PUT https://registry.npmjs.org/@iqs%2freact-summernote - Not found` 等訊息,可能是 Token 無效或過期The MIT License (MIT)
Copyright (c) 2025 Zap