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