feat:data persistence
This commit is contained in:
@@ -7,12 +7,14 @@ import { KeyMap } from "../../dataset/enum/Keymap"
|
||||
import { IElement } from "../../interface/Element"
|
||||
import { ICurrentPosition } from "../../interface/Position"
|
||||
import { writeTextByElementList } from "../../utils/clipboard"
|
||||
import { zipElementList } from "../../utils/element"
|
||||
import { Cursor } from "../cursor/Cursor"
|
||||
import { Draw } from "../draw/Draw"
|
||||
import { HyperlinkParticle } from "../draw/particle/HyperlinkParticle"
|
||||
import { ImageParticle } from "../draw/particle/ImageParticle"
|
||||
import { TableTool } from "../draw/particle/table/TableTool"
|
||||
import { HistoryManager } from "../history/HistoryManager"
|
||||
import { Listener } from "../listener/Listener"
|
||||
import { Position } from "../position/Position"
|
||||
import { RangeManager } from "../range/RangeManager"
|
||||
|
||||
@@ -32,6 +34,7 @@ export class CanvasEvent {
|
||||
private imageParticle: ImageParticle
|
||||
private tableTool: TableTool
|
||||
private hyperlinkParticle: HyperlinkParticle
|
||||
private listener: Listener
|
||||
|
||||
constructor(draw: Draw) {
|
||||
this.isAllowDrag = false
|
||||
@@ -48,6 +51,7 @@ export class CanvasEvent {
|
||||
this.imageParticle = this.draw.getImageParticle()
|
||||
this.tableTool = this.draw.getTableTool()
|
||||
this.hyperlinkParticle = this.draw.getHyperlinkParticle()
|
||||
this.listener = this.draw.getListener()
|
||||
}
|
||||
|
||||
public register() {
|
||||
@@ -349,6 +353,12 @@ export class CanvasEvent {
|
||||
this.cut()
|
||||
} else if (evt.ctrlKey && evt.key === KeyMap.A) {
|
||||
this.selectAll()
|
||||
} else if (evt.ctrlKey && evt.key === KeyMap.S) {
|
||||
const saved = this.listener.saved
|
||||
if (saved) {
|
||||
saved(this.save())
|
||||
}
|
||||
evt.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,4 +455,10 @@ export class CanvasEvent {
|
||||
this.isCompositing = false
|
||||
}
|
||||
|
||||
public save(): IElement[] {
|
||||
const elementList = this.draw.getOriginalElementList()
|
||||
const data = zipElementList(elementList)
|
||||
return data
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
IPageScaleChange,
|
||||
IPageSizeChange,
|
||||
IRangeStyleChange,
|
||||
ISaved,
|
||||
IVisiblePageNoListChange
|
||||
} from "../../interface/Listener"
|
||||
|
||||
@@ -13,6 +14,7 @@ export class Listener {
|
||||
public intersectionPageNoChange: IIntersectionPageNoChange | null
|
||||
public pageSizeChange: IPageSizeChange | null
|
||||
public pageScaleChange: IPageScaleChange | null
|
||||
public saved: ISaved | null
|
||||
|
||||
constructor() {
|
||||
this.rangeStyleChange = null
|
||||
@@ -20,6 +22,7 @@ export class Listener {
|
||||
this.intersectionPageNoChange = null
|
||||
this.pageSizeChange = null
|
||||
this.pageScaleChange = null
|
||||
this.saved = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IElement } from "../../interface/Element"
|
||||
|
||||
export const EDITOR_ELEMENT_STYLE = [
|
||||
export const EDITOR_ELEMENT_STYLE_ATTR = [
|
||||
'bold',
|
||||
'color',
|
||||
'highlight',
|
||||
@@ -24,4 +24,23 @@ export const EDITOR_ELEMENT_COPY_ATTR: Array<keyof IElement> = [
|
||||
'rowFlex',
|
||||
'url',
|
||||
'hyperlinkId'
|
||||
]
|
||||
|
||||
export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
|
||||
'type',
|
||||
'font',
|
||||
'size',
|
||||
'bold',
|
||||
'color',
|
||||
'italic',
|
||||
'highlight',
|
||||
'underline',
|
||||
'strikeout',
|
||||
'rowFlex',
|
||||
'trList',
|
||||
'width',
|
||||
'height',
|
||||
'url',
|
||||
'colgroup',
|
||||
'valueList'
|
||||
]
|
||||
@@ -8,6 +8,7 @@ export enum KeyMap {
|
||||
Down = "ArrowDown",
|
||||
A = "a",
|
||||
C = "c",
|
||||
S = "s",
|
||||
X = "x",
|
||||
Y = "y",
|
||||
Z = "z"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { IElement } from ".."
|
||||
import { RowFlex } from "../dataset/enum/Row"
|
||||
|
||||
export interface IRangeStype {
|
||||
@@ -24,3 +25,5 @@ export type IIntersectionPageNoChange = (payload: number) => void
|
||||
export type IPageSizeChange = (payload: number) => void
|
||||
|
||||
export type IPageScaleChange = (payload: number) => void
|
||||
|
||||
export type ISaved = (payload: IElement[]) => void
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { getUUID } from "."
|
||||
import { deepClone, getUUID } from "."
|
||||
import { ElementType, IElement } from ".."
|
||||
import { ZERO } from "../dataset/constant/Common"
|
||||
import { EDITOR_ELEMENT_ZIP_ATTR } from "../dataset/constant/Element"
|
||||
|
||||
export function formatElementList(elementList: IElement[]) {
|
||||
if (elementList[0]?.value !== ZERO) {
|
||||
@@ -59,4 +60,70 @@ export function formatElementList(elementList: IElement[]) {
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function zipElementList(payload: IElement[]): IElement[] {
|
||||
const elementList = deepClone(payload)
|
||||
const zipElementListData: IElement[] = []
|
||||
let e = 0
|
||||
while (e < elementList.length) {
|
||||
let element = elementList[e]
|
||||
// 筛选所需项
|
||||
if (e === 0 && element.value === ZERO) {
|
||||
e++
|
||||
continue
|
||||
}
|
||||
// 表格处理
|
||||
if (element.type === ElementType.TABLE) {
|
||||
if (element.trList) {
|
||||
for (let t = 0; t < element.trList.length; t++) {
|
||||
const tr = element.trList[t]
|
||||
delete tr.id
|
||||
for (let d = 0; d < tr.tdList.length; d++) {
|
||||
const td = tr.tdList[d]
|
||||
tr.tdList[d] = {
|
||||
colspan: td.colspan,
|
||||
rowspan: td.rowspan,
|
||||
value: zipElementList(td.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (element.type === ElementType.HYPERLINK) {
|
||||
// 超链接处理
|
||||
const hyperlinkId = element.hyperlinkId
|
||||
const hyperlinkElement: IElement = {
|
||||
type: ElementType.HYPERLINK,
|
||||
value: '',
|
||||
url: element.url
|
||||
}
|
||||
const valueList: IElement[] = []
|
||||
while (e < elementList.length) {
|
||||
const hyperlinkE = elementList[e]
|
||||
if (hyperlinkId !== hyperlinkE.hyperlinkId) {
|
||||
e--
|
||||
break
|
||||
}
|
||||
delete hyperlinkE.type
|
||||
delete hyperlinkE.url
|
||||
valueList.push(hyperlinkE)
|
||||
e++
|
||||
}
|
||||
hyperlinkElement.valueList = zipElementList(valueList)
|
||||
element = hyperlinkElement
|
||||
}
|
||||
// 压缩保留字段
|
||||
const newElement: IElement = {
|
||||
value: element.value === ZERO ? `\n` : element.value,
|
||||
}
|
||||
EDITOR_ELEMENT_ZIP_ATTR.forEach(attr => {
|
||||
const value = element[attr] as never
|
||||
if (value !== undefined) {
|
||||
newElement[attr] = value
|
||||
}
|
||||
})
|
||||
zipElementListData.push(newElement)
|
||||
e++
|
||||
}
|
||||
return zipElementListData
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export function debounce(func: Function, delay: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export function deepClone(obj: any) {
|
||||
export function deepClone<T>(obj: T): T {
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
return obj
|
||||
}
|
||||
@@ -20,6 +20,7 @@ export function deepClone(obj: any) {
|
||||
newObj = obj.map(item => deepClone(item))
|
||||
} else {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
// @ts-ignore
|
||||
return newObj[key] = deepClone(obj[key])
|
||||
})
|
||||
}
|
||||
|
||||
+5
-1
@@ -194,7 +194,7 @@ window.onload = function () {
|
||||
}])
|
||||
// 初始化编辑器
|
||||
const container = document.querySelector<HTMLDivElement>('.editor')!
|
||||
const instance = new Editor(container, data, {
|
||||
const instance = new Editor(container, <IElement[]>data, {
|
||||
margins: [100, 120, 100, 120]
|
||||
})
|
||||
console.log('实例: ', instance)
|
||||
@@ -541,4 +541,8 @@ window.onload = function () {
|
||||
document.querySelector<HTMLSpanElement>('.page-scale-percentage')!.innerText = `${Math.floor(payload * 10 * 10)}%`
|
||||
}
|
||||
|
||||
instance.listener.saved = function (payload) {
|
||||
console.log('elementList: ', payload)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user