2.3.9 • Published 2 days ago

@iqs/react-summernote v2.3.9

Weekly downloads
-
License
MIT
Repository
github
Last release
2 days ago

React SummerNote

React SummerNote 是一個 React 版本的 WYSIWYG 的 rich text editor,基於 SummerNote 建構

  • Stable Version: v2.3.9

  • 版本修改紀錄:Changelog

Online Demo

上面連結是一個 React SummerNote 的基本展示

Demo

Package Dependencies

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

Install

必要依賴安裝

npm i bootstrap popper.js summernote jquery store --save

安裝 React SummerNote

npm i @iqs/react-summernote --save 

設定 Webpack

使 jQuery, store 可以在 Component 中被存取,而不需額外 import

{
    ...,
    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery",
            store: "store",
        })
    ] 
}

Super simple to use

import React from 'react'
import { render } from 'react-dom'
import SummerNote from 'react-summernote'

// 自動載入必要套件
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')
)

options.toolbar

  • 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

設置 options props,即可設置客製化功能與 UI 顯示

summernote deep-dive

更詳細的設定方式,可以參閱上面的官方說明

Control Editor

下面簡單示範如何使用新版 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}/>)
    }
}

Upload Image

自訂上傳圖片的方法,複製圖片(剪貼簿中)貼上編輯器時,就會觸發該方法

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}/>)
    }
}

1

Paste from Office Word

貼上 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} />)
    }
}

Wordpaste

Paste from Office Excel

貼上 Excel 內容時,SummerNote 會解析剪貼簿中的 HTML 內容,解析後會自動將樣式附加進去,但目前不支援包含 Excel 中的圖片,需額外逐一手動複製貼上

Excel

自行 import 必要依賴

如果專案也有使用 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 issue#4471

summernote-patch-handle: 用於修復圖片顯示框位置偏移。因官方尚未發布涵蓋 Summernote PR#4283 的版本,故在此使用 plugin 覆寫 modules.handle.update

目前 Summernote 版本 0.8.18,待官方發佈新版本後可移除此 plugin

Plugin

2.0.4 的版本開始,引入了 table plugin,可針對 table 元素進行更多操作

require('react-summernote/plugin/summernote-ext-table')
require('react-summernote/plugin/summernote-ext-table.css')

其他 Plugin

若要自行引入 plugin 可參考 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')

XSS 白名單

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

  • 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

  • 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

  • DailyMotion網域 + 路徑 + id
    • https://www.dailymotion.com/video/x8pi9hp
網域路徑id參數
www.dailymotion.com/video/ hub/(至少一個非_的字元)(多個非#的字元)(零組或一組 (#video=)(至少一個非 _& 的字元))

For contributor

Setup Node

  • node: v16.20.2
  • npm: v8.19.4

以 nvm 安裝

nvm install v16.20.2
nvm use v16.20.2

Install Dependencies

安裝依賴套件

  • npm ci 依據 package-lock.json 安裝套件
npm ci

NPM Scripts

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 為起始,用於測試原始程式執行起來是否有問題,並開發新功能

Commit Message

可使用 vscode extension Commit Message Editor 編輯 Commit Message

Code Structure

Summernote.jsx

src/components/SummerNote.jsx

Summernote 連結器,與原生 Summernote 對接

App.jsx

src/components/App.jsx

引入使用 Summernote Component,DEMO 呈現依賴此檔案設定

ImportCode.js

src/components/ImportCode.js

ImportCode 會引入所有 Plugin,若有新增 Plugin 需要在此引入

module.exports = function () {
    // ...
    require('../plugin/custom/summernote-custom-style')
}

SummernotePlugin

@iqs/react-summernote: v2.2.20 開始

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

src/plugin/

Plugin 目錄架構由 Awesome Summernote 訂定,IQS 自己寫的都放在 src/plugin/custom/

檔案名稱以 summernote- 開頭,Plugin 名稱、按鈕名稱以 小駝峰 命名

有新增 Plugin 記得更新文件 src/plugin/README.md

For maintainer

上版 DEMO 網站流程

iq-service-inc.github.io/react-summernote

  1. pushmaster 分支

  2. 觸發 Github Workflow Deploy Master Branch to Github Pages

  3. 待 Workflow 完成即上版完成

發佈 npm 套件流程

NPM - @iqs/react-summernote

  1. 修改 README.md 版本號

  2. 修改 package.json 版本號

  3. 更新 CHANGELOG.md

  4. pushmaster 分支

  5. 發布 Github Release

    • 選擇新 Tag
    • 標題為 Tag
    • 內容貼 CHANGELOG
    • 內容最後附上差異比對連結
      • e.g.
        **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 無效或過期

License

The MIT License (MIT)
Copyright (c) 2023 Zap

2.3.9

2 days ago

2.3.8

12 days ago

2.3.7

1 month ago

2.3.6

1 month ago

2.3.5

3 months ago

2.3.4

3 months ago

2.3.2

4 months ago

2.3.3

4 months ago

2.3.1

4 months ago

2.3.0

4 months ago

2.2.20

4 months ago

2.2.17

9 months ago

2.2.18

7 months ago

2.2.15

11 months ago

2.2.16

10 months ago

2.2.14

11 months ago

2.2.19

6 months ago

2.2.13

11 months ago

2.2.11

11 months ago

2.2.12

11 months ago

2.2.10

1 year ago

2.2.10-beta.0

1 year ago

2.2.10-beta.3

1 year ago

2.2.10-beta.2

1 year ago

2.2.8-beta1

2 years ago

2.2.9

2 years ago

2.2.8

2 years ago

2.2.7

2 years ago

2.2.6

2 years ago

2.2.3

2 years ago

2.2.2

2 years ago

2.2.5

2 years ago

2.2.4

2 years ago

2.2.1

2 years ago

2.2.0

2 years ago

2.1.2

2 years ago

2.1.1

2 years ago

2.0.10

3 years ago