diff --git a/index.html b/index.html
index 30b2f62..38a7e7d 100644
--- a/index.html
+++ b/index.html
@@ -208,6 +208,7 @@
可见页码:1
页面:1/1
+ 字数:0
编辑模式
diff --git a/src/editor/core/command/Command.ts b/src/editor/core/command/Command.ts
index f5894b9..84df0fc 100644
--- a/src/editor/core/command/Command.ts
+++ b/src/editor/core/command/Command.ts
@@ -57,6 +57,7 @@ export class Command {
private static print: Function
private static getImage: Function
private static getValue: Function
+ private static getWordCount: Function
private static pageMode: Function
private static pageScaleRecovery: Function
private static pageScaleMinus: Function
@@ -112,6 +113,7 @@ export class Command {
Command.print = adapt.print.bind(adapt)
Command.getImage = adapt.getImage.bind(adapt)
Command.getValue = adapt.getValue.bind(adapt)
+ Command.getWordCount = adapt.getWordCount.bind(adapt)
Command.pageMode = adapt.pageMode.bind(adapt)
Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt)
Command.pageScaleMinus = adapt.pageScaleMinus.bind(adapt)
@@ -315,6 +317,10 @@ export class Command {
return Command.getValue()
}
+ public getWordCount(): Promise {
+ return Command.getWordCount()
+ }
+
// 页面模式、页面缩放
public executePageMode(payload: PageMode) {
return Command.pageMode(payload)
diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts
index bdf320f..2ed2279 100644
--- a/src/editor/core/command/CommandAdapt.ts
+++ b/src/editor/core/command/CommandAdapt.ts
@@ -23,6 +23,7 @@ import { CanvasEvent } from '../event/CanvasEvent'
import { HistoryManager } from '../history/HistoryManager'
import { Position } from '../position/Position'
import { RangeManager } from '../range/RangeManager'
+import { WorkerManager } from '../worker/WorkerManager'
export class CommandAdapt {
@@ -37,6 +38,7 @@ export class CommandAdapt {
private tableTool: TableTool
private options: Required
private control: Control
+ private workerManager: WorkerManager
constructor(draw: Draw) {
this.draw = draw
@@ -47,6 +49,7 @@ export class CommandAdapt {
this.tableTool = draw.getTableTool()
this.options = draw.getOptions()
this.control = draw.getControl()
+ this.workerManager = draw.getWorkerManager()
}
public mode(payload: EditorMode) {
@@ -1243,6 +1246,10 @@ export class CommandAdapt {
return this.draw.getValue()
}
+ public getWordCount(): Promise {
+ return this.workerManager.getWordCount()
+ }
+
public pageMode(payload: PageMode) {
this.draw.setPageMode(payload)
}
diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts
index fc03a8f..1b63299 100644
--- a/src/editor/core/draw/Draw.ts
+++ b/src/editor/core/draw/Draw.ts
@@ -41,6 +41,7 @@ import { CheckboxParticle } from './particle/CheckboxParticle'
import { DeepRequired } from '../../interface/Common'
import { ControlComponent } from '../../dataset/enum/Control'
import { formatElementList } from '../../utils/element'
+import { WorkerManager } from '../worker/WorkerManager'
export class Draw {
@@ -79,6 +80,7 @@ export class Draw {
private subscriptParticle: SubscriptParticle
private checkboxParticle: CheckboxParticle
private control: Control
+ private workerManager: WorkerManager
private rowList: IRow[]
private painterStyle: IElementStyle | null
@@ -138,6 +140,8 @@ export class Draw {
const globalEvent = new GlobalEvent(this, this.canvasEvent)
globalEvent.register()
+ this.workerManager = new WorkerManager(this)
+
this.rowList = []
this.painterStyle = null
this.painterOptions = null
@@ -363,6 +367,10 @@ export class Draw {
return this.control
}
+ public getWorkerManager(): WorkerManager {
+ return this.workerManager
+ }
+
public getRowCount(): number {
return this.rowList.length
}
diff --git a/src/editor/core/worker/WorkerManager.ts b/src/editor/core/worker/WorkerManager.ts
new file mode 100644
index 0000000..efd2ede
--- /dev/null
+++ b/src/editor/core/worker/WorkerManager.ts
@@ -0,0 +1,29 @@
+import { Draw } from '../draw/Draw'
+import WordCountWorker from './works/wordCount?worker'
+
+export class WorkerManager {
+
+ private draw: Draw
+ private wordCountWorker: Worker
+
+ constructor(draw: Draw) {
+ this.draw = draw
+ this.wordCountWorker = new WordCountWorker()
+ }
+
+ public getWordCount(): Promise {
+ return new Promise((resolve, reject) => {
+ this.wordCountWorker.onmessage = (evt) => {
+ resolve(evt.data)
+ }
+
+ this.wordCountWorker.onerror = (evt) => {
+ reject(evt)
+ }
+
+ const elementList = this.draw.getOriginalElementList()
+ this.wordCountWorker.postMessage(elementList)
+ })
+ }
+
+}
\ No newline at end of file
diff --git a/src/editor/core/worker/works/wordCount.ts b/src/editor/core/worker/works/wordCount.ts
new file mode 100644
index 0000000..2a98eae
--- /dev/null
+++ b/src/editor/core/worker/works/wordCount.ts
@@ -0,0 +1,129 @@
+import { IElement } from '../../../interface/Element'
+
+enum ElementType {
+ TEXT = 'text',
+ TABLE = 'table',
+ HYPERLINK = 'hyperlink',
+ CONTROL = 'control'
+}
+
+enum ControlComponent {
+ VALUE = 'value'
+}
+
+const ZERO = '\u200B'
+const WRAP = '\n'
+
+function pickText(elementList: IElement[]): string {
+ let text = ''
+ let e = 0
+ while (e < elementList.length) {
+ const element = elementList[e]
+ // 表格、超链接递归处理
+ if (element.type === ElementType.TABLE) {
+ if (element.trList) {
+ for (let t = 0; t < element.trList.length; t++) {
+ const tr = element.trList[t]
+ for (let d = 0; d < tr.tdList.length; d++) {
+ const td = tr.tdList[d]
+ text += pickText(td.value)
+ }
+ }
+ }
+ } else if (element.type === ElementType.HYPERLINK) {
+ const hyperlinkId = element.hyperlinkId
+ const valueList: IElement[] = []
+ while (e < elementList.length) {
+ const hyperlinkE = elementList[e]
+ if (hyperlinkId !== hyperlinkE.hyperlinkId) {
+ e--
+ break
+ }
+ delete hyperlinkE.type
+ valueList.push(hyperlinkE)
+ e++
+ }
+ text += pickText(valueList)
+ } else if (element.type === ElementType.CONTROL) {
+ const controlId = element.controlId
+ const valueList: IElement[] = []
+ while (e < elementList.length) {
+ const controlE = elementList[e]
+ if (controlId !== controlE.controlId) {
+ e--
+ break
+ }
+ if (controlE.controlComponent === ControlComponent.VALUE) {
+ delete controlE.type
+ valueList.push(controlE)
+ }
+ e++
+ }
+ text += pickText(valueList)
+ }
+ // 文本追加
+ if (!element.type || element.type === ElementType.TEXT) {
+ text += element.value
+ }
+ e++
+ }
+ return text
+}
+
+function groupText(text: string): string[] {
+ const characterList: string[] = []
+ // 英文或数字整体分隔为一个字数
+ const numberReg = /[0-9]/
+ const letterReg = /[A-Za-z]/
+ const blankReg = /\s/
+ // for of 循环字符
+ let isPreLetter = false
+ let isPreNumber = false
+ let compositionText = ''
+ // 处理组合文本
+ function pushCompositionText() {
+ if (compositionText) {
+ characterList.push(compositionText)
+ compositionText = ''
+ }
+ }
+ for (const t of text) {
+ if (letterReg.test(t)) {
+ if (!isPreLetter) {
+ pushCompositionText()
+ }
+ compositionText += t
+ isPreLetter = true
+ isPreNumber = false
+ } else if (numberReg.test(t)) {
+ if (!isPreNumber) {
+ pushCompositionText()
+ }
+ compositionText += t
+ isPreLetter = false
+ isPreNumber = true
+ } else {
+ pushCompositionText()
+ isPreLetter = false
+ isPreNumber = false
+ if (!blankReg.test(t)) {
+ characterList.push(t)
+ }
+ }
+ }
+ pushCompositionText()
+ return characterList
+}
+
+onmessage = (evt) => {
+ const elementList = evt.data
+ // 提取文本
+ const originText = pickText(elementList)
+ // 过滤文本
+ const filterText = originText
+ .replace(new RegExp(`^${ZERO}`), '')
+ .replace(new RegExp(ZERO, 'g'), WRAP)
+ // 文本分组
+ const textGroup = groupText(filterText)
+ postMessage(textGroup.length)
+}
diff --git a/src/main.ts b/src/main.ts
index 6b298aa..64818c6 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -754,6 +754,11 @@ window.onload = function () {
activeMode.classList.add('active')
}
+ instance.listener.contentChange = async function () {
+ const wordCount = await instance.command.getWordCount()
+ document.querySelector('.word-count')!.innerText = `${wordCount || 0}`
+ }
+
instance.listener.saved = function (payload) {
console.log('elementList: ', payload)
}