React SummerNote 是一個 React 版本的 WYSIWYG 的 rich text editor,基於 SummerNote 建構
-
Stable Version:
v2.3.17
-
版本修改紀錄:Changelog
上面連結是一個 React SummerNote 的基本展示
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
npm i @iqs/react-summernote --save
使 jQuery, store 可以在 Component 中被存取,而不需額外 import
{
...,
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
store: "store",
})
]
}
import React from 'react'
import { render } from 'react-dom'
import SummerNote from 'react-summernote'
import 'react-summernote/dist/main.css'
// 自動載入必要套件
SummerNote.ImportCode()
render(
<SummerNote value="Default value"
options={{
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 dialog -
link
: open link dialog -
video
: open video dialog -
table
: insert a table -
hr
: insert a horizontal rule
-
- Font Style
-
fontname
: set font family -
fontsize
: set font size -
color
: set foreground and background color -
forecolor
: set foreground color -
backcolor
: set background color -
bold
: toggle font weight -
italic
: toggle italic -
underline
: toggle underline -
strikethrough
: toggle strikethrough -
superscript
: toggle superscript -
subscript
: toggle subscript -
clear
: clear font style
-
- Paragraph style
-
style
: format selected block -
ol
: toggle ordered list -
ul
: toggle unordered list -
paragraph
: dropdown for paragraph align -
height
: set line height
-
- Misc
-
fullscreen
: toggle fullscreen editing mode -
codeview
: toggle wysiwyg and html editing mode -
undo
: undo -
redo
: redo -
help
: open help dialog
-
- Table (Plugin)
-
jTable
: 表格欄位長寬縮放 -
jMerge
: 框選後合併 cell -
jBackcolor
: cell 的背景色 -
jBorderColor
: 整個表格 border 顏色 -
jAlign
: cell 的對齊方式 -
jTableInfo
: 調整整個 table 的 margin -
jWidthHeightReset
: 重設 cell 寬高
-
設置 options
props,即可設置客製化功能與 UI 顯示
更詳細的設定方式,可以參閱上面的官方說明
下面簡單示範如何使用新版 API 控制編輯器 (version > v2.0.0
)
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 (<SummerNote ref={this.editor}/>)
}
}
自訂上傳圖片的方法,複製圖片(剪貼簿中)貼上編輯器時,就會觸發該方法
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 (<SummerNote onImageUpload={this.onImageUpload} ref={this.editor}/>)
}
}
貼上 Word 內容時,SummerNote 會解析剪貼簿中的 rtf 內容,解析後會自動將 <img>
部分轉換成 base64 格式的圖片資源,這些 <img>
都會被加上 class .zap-img-uploading
,可以在使用 jQuery 進行後續處理
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 (<SummerNote onImagePasteFromWord={onChange} />)
}
}
貼上 Excel 內容時,SummerNote 會解析剪貼簿中的 HTML 內容,解析後會自動將樣式附加進去,但目前不支援包含 Excel 中的圖片,需額外逐一手動複製貼上
如果專案也有使用 Bootstrap 等套件,不希望重複引用,可以自行引入必要依賴
// 自動載入必要套件
//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.nextPointWithEmptyNode
目前 Summernote 版本
0.8.18
,待官方發佈新版本後可移除此 plugin
summernote-patch-handle
: 用於修復圖片顯示框位置偏移。因官方尚未發布涵蓋 Summernote PR#4283 的版本,故在此使用 plugin 覆寫modules.handle.update
目前 Summernote 版本
0.8.18
,待官方發佈新版本後可移除此 plugin
從 2.0.4
的版本開始,引入了 table plugin,可針對 table 元素進行更多操作
require('react-summernote/plugin/summernote-ext-table')
require('react-summernote/plugin/summernote-ext-table.css')
若要自行引入 plugin 可參考 Plugin 介紹
請嘗試引用 src/plugin
裡面的 plugin
以 table plugin 為例
require('@iqs/react-summernote/src/plugin/misc/summernote-ext-table')
require('@iqs/react-summernote/src/plugin/misc/summernote-ext-table.css')
summernote 包含一個原始碼的 xss 過濾機制,規則如下:
/<\/*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|ilayer|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|t(?:itle|extarea)|xml)[^>]*?>/gi
在 options
中修改內建白名單,即可客製化保留部分 tag 不被過濾
<SummerNote value="Default value"
options={{
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')
更多詳細設定可以參閱官方文件
以下是依據 Summernote 0.8.18 videoDialog 整理出已知的有效網址
- YouTube 網域 + 路徑 + id
https://youtube.com/embed/Dm_BrGu1sHM
- YouTube 網域 + 路徑 + id + 時戳
https://www.youtube.com/watch?v=Dm_BrGu1sHM&t=300
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/Cy8sEXrv9xu
-
網址附帶的其他參數需放在 id 之後
https://www.instagram.com/p/Cy8sEXrv9xu?igshid=MzRlODBiNWFlZA==
網域 | 路徑 | id |
---|---|---|
www.instagram.com/ instagram.com/
|
p/ |
(任意字元) |
- 優酷網域 + 路徑 +
id_
+ id +.html
https://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= )(至少一個非 _ 或 & 的字元)) |
-
node
: v16.20.2 -
npm
: v8.19.4
以 nvm 安裝
nvm install v16.20.2
nvm use v16.20.2
安裝依賴套件
-
npm ci
依據package-lock.json
安裝套件
npm ci
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
為起始,用於測試原始程式執行起來是否有問題,並開發新功能
可使用 vscode extension Commit Message Editor 編輯 Commit Message
- 依據 Conventional Commits (中文版)
- Type 必填,選對修改事項類型,不清楚選哪種可依據 Angular CONTRIBUTING - Commit Message Format
- Title 必填,概述修改事項 (Short description)
- Scope 可選,目前未定義
- Body 可選,可描寫變更的內容
- Footer 可選,可寫 commit 簽署者資訊
Summernote 連結器,與原生 Summernote 對接
引入使用 Summernote Component,DEMO 呈現依賴此檔案設定
ImportCode 會引入所有 Plugin,若有新增 Plugin 需要在此引入
module.exports = function () {
// ...
require('../plugin/custom/summernote-custom-style')
}
@iqs/react-summernote: v2.2.20
開始
-
src/components/SummernotePlugin.jsx: 可在使用 React-Summernote 時匯入自定義的 Button 或 Plugin
-
src/components/SummernotePlugin.d.ts: 設定 Summernote Types
import SummerNote, { SummernotePlugin } from '@iqs/react-summernote'
Methods
SummernotePlugin.createSummernoteButton
SummernotePlugin.createSummernotePlugin
Types
- global
$.summernote
SummernotePlugin.createSummernotePlugin
SummernotePlugin.SummernotePluginClass
SummernotePlugin.SummernotePluginFunction
SummernotePlugin.createSummernoteButton
SummernotePlugin.SummernoteContext
- ...
Plugin 目錄架構由 Awesome Summernote 訂定,IQS 自己寫的都放在 src/plugin/custom/
檔案名稱以 summernote-
開頭,Plugin 名稱、按鈕名稱以 小駝峰 命名
有新增 Plugin 記得更新文件 src/plugin/README.md
iq-service-inc.github.io/react-summernote
-
push 到 master 分支
-
觸發 Github Workflow Deploy Master Branch to Github Pages
-
待 Workflow 完成即上版完成
-
修改 README.md 版本號
-
修改 package.json 版本號
-
更新 CHANGELOG.md
-
push 到 master 分支
-
- 選擇新 Tag
- 標題為 Tag
- 內容貼 CHANGELOG
- 內容最後附上差異比對連結
- e.g.
**Full Changelog**: https://github.com/iq-service-inc/react-summernote/compare/v2.2.19...v2.2.20
-
觸發 Github Workflow Publish Package to npmjs
-
待 Workflow 完成即發佈完成
.github/workflows/ 存放所有 Github Workflows
-
Deploy Master Branch to Github Pages: 自動部署 Pages
-
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) 2023 Zap