feat: improve ocd conflict merge ids
This commit is contained in:
parent
a946dc7ae8
commit
d34d1709ef
|
|
@ -72,6 +72,7 @@
|
|||
"vue": "^3.2.45"
|
||||
},
|
||||
"dependencies": {
|
||||
"nanoid": "3.3.11",
|
||||
"prismjs": "^1.27.0"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ importers:
|
|||
|
||||
.:
|
||||
dependencies:
|
||||
nanoid:
|
||||
specifier: 3.3.11
|
||||
version: 3.3.11
|
||||
prismjs:
|
||||
specifier: ^1.27.0
|
||||
version: 1.30.0
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
} from '../../interface/Element'
|
||||
import { IRow, IRowElement } from '../../interface/Row'
|
||||
import { deepClone, getUUID, nextTick } from '../../utils'
|
||||
import { prepareOcdDocumentForSave } from '../../../utils/ocd'
|
||||
import { Cursor } from '../cursor/Cursor'
|
||||
import { CanvasEvent } from '../event/CanvasEvent'
|
||||
import { GlobalEvent } from '../event/GlobalEvent'
|
||||
|
|
@ -1196,7 +1197,7 @@ export class Draw {
|
|||
}
|
||||
return {
|
||||
version,
|
||||
data,
|
||||
data: prepareOcdDocumentForSave(data),
|
||||
options: deepClone(this.options)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { ICatalog } from '../../interface/Catalog'
|
|||
import { IEditorResult } from '../../interface/Editor'
|
||||
import { IGetValueOption } from '../../interface/Draw'
|
||||
import { deepClone } from '../../utils'
|
||||
import { prepareOcdDocumentForSave } from '../../../utils/ocd'
|
||||
|
||||
export class WorkerManager {
|
||||
private draw: Draw
|
||||
|
|
@ -78,7 +79,7 @@ export class WorkerManager {
|
|||
this.valueWorker.onmessage = evt => {
|
||||
resolve({
|
||||
version,
|
||||
data: evt.data,
|
||||
data: prepareOcdDocumentForSave(evt.data),
|
||||
options: deepClone(this.draw.getOptions())
|
||||
})
|
||||
}
|
||||
|
|
|
|||
22
src/main.ts
22
src/main.ts
|
|
@ -26,6 +26,10 @@ import { Dialog } from './components/dialog/Dialog'
|
|||
import { formatPrismToken } from './utils/prism'
|
||||
import { Signature } from './components/signature/Signature'
|
||||
import { debounce, nextTick, scrollIntoView } from './utils'
|
||||
import {
|
||||
prepareOcdDocumentForOpen,
|
||||
prepareOcdDocumentForSave
|
||||
} from './utils/ocd'
|
||||
|
||||
/**
|
||||
* 从本地文件URL中提取文件路径
|
||||
|
|
@ -249,7 +253,7 @@ window.onload = function () {
|
|||
} catch {
|
||||
editorData = { main: [{ value: text }] }
|
||||
}
|
||||
instance.command.executeSetValue(editorData)
|
||||
instance.command.executeSetValue(prepareOcdDocumentForOpen(editorData))
|
||||
console.log('[iframe] 通过 Electron 加载本地文件完成:', localFilePath)
|
||||
} catch (err) {
|
||||
console.error('[iframe] 本地文件解析失败:', err)
|
||||
|
|
@ -273,7 +277,7 @@ window.onload = function () {
|
|||
} catch {
|
||||
editorData = { main: [{ value: text }] }
|
||||
}
|
||||
instance.command.executeSetValue(editorData)
|
||||
instance.command.executeSetValue(prepareOcdDocumentForOpen(editorData))
|
||||
console.log('[iframe] 根据 filePath 加载完成:', url)
|
||||
} catch (err) {
|
||||
console.error('[iframe] 加载失败:', err)
|
||||
|
|
@ -334,7 +338,7 @@ window.onload = function () {
|
|||
}
|
||||
|
||||
// 设置编辑器内容
|
||||
instance.command.executeSetValue(editorData)
|
||||
instance.command.executeSetValue(prepareOcdDocumentForOpen(editorData))
|
||||
console.log('文档已打开')
|
||||
} catch (error) {
|
||||
console.error('打开文档失败:', error)
|
||||
|
|
@ -358,7 +362,11 @@ window.onload = function () {
|
|||
try {
|
||||
// 获取编辑器内容
|
||||
const editorValue = instance.command.getValue()
|
||||
const content = JSON.stringify(editorValue.data, null, 2)
|
||||
const content = JSON.stringify(
|
||||
prepareOcdDocumentForSave(editorValue.data),
|
||||
null,
|
||||
2
|
||||
)
|
||||
|
||||
// 创建下载链接
|
||||
const blob = new Blob([content], { type: 'application/json' })
|
||||
|
|
@ -391,7 +399,11 @@ window.onload = function () {
|
|||
saveCallbackDom.onclick = function () {
|
||||
try {
|
||||
const editorValue = instance.command.getValue()
|
||||
const content = JSON.stringify(editorValue.data, null, 2)
|
||||
const content = JSON.stringify(
|
||||
prepareOcdDocumentForSave(editorValue.data),
|
||||
null,
|
||||
2
|
||||
)
|
||||
|
||||
const parentWin: any = window.parent || window
|
||||
const viewer =
|
||||
|
|
|
|||
97
src/utils/ocd.ts
Normal file
97
src/utils/ocd.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { nanoid } from 'nanoid'
|
||||
import { IEditorData } from '../editor'
|
||||
|
||||
const CONFLICT_MARKER_HIGHLIGHT = '#fff3cd'
|
||||
const CONFLICT_MARKER_COLOR = '#b42318'
|
||||
const CONFLICT_MARKER_REG = /^(<<<<<<<|=======|>>>>>>>)\b/
|
||||
|
||||
type UnknownRecord = Record<string, unknown>
|
||||
|
||||
function isRecord(value: unknown): value is UnknownRecord {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||
}
|
||||
|
||||
function isElementList(value: unknown): value is UnknownRecord[] {
|
||||
return Array.isArray(value) && value.every(isRecord)
|
||||
}
|
||||
|
||||
function isConflictMarkerText(value: unknown) {
|
||||
return typeof value === 'string' && CONFLICT_MARKER_REG.test(value.trim())
|
||||
}
|
||||
|
||||
function normalizeConflictElement(element: UnknownRecord, isMarker: boolean) {
|
||||
if (isMarker) {
|
||||
return
|
||||
}
|
||||
if (element.highlight === CONFLICT_MARKER_HIGHLIGHT) {
|
||||
delete element.highlight
|
||||
}
|
||||
if (element.color === CONFLICT_MARKER_COLOR) {
|
||||
delete element.color
|
||||
}
|
||||
}
|
||||
|
||||
function prepareElementList(elementList: UnknownRecord[]) {
|
||||
for (const element of elementList) {
|
||||
if (isElementList(element.valueList)) {
|
||||
const isMarker =
|
||||
element._ocdConflictMarker === true ||
|
||||
element.valueList.some(item => isConflictMarkerText(item.value))
|
||||
for (const item of element.valueList) {
|
||||
if (typeof item.id !== 'string' || !item.id) {
|
||||
item.id = nanoid()
|
||||
}
|
||||
normalizeConflictElement(item, isMarker || isConflictMarkerText(item.value))
|
||||
prepareNestedElement(item)
|
||||
}
|
||||
}
|
||||
prepareNestedElement(element)
|
||||
}
|
||||
}
|
||||
|
||||
function prepareNestedElement(element: UnknownRecord) {
|
||||
const trList = element.trList
|
||||
if (Array.isArray(trList)) {
|
||||
for (const tr of trList) {
|
||||
if (!isRecord(tr) || !Array.isArray(tr.tdList)) continue
|
||||
for (const td of tr.tdList) {
|
||||
if (!isRecord(td) || !isElementList(td.value)) continue
|
||||
prepareElementList(td.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const control = element.control
|
||||
if (isRecord(control) && isElementList(control.value)) {
|
||||
prepareElementList(control.value)
|
||||
}
|
||||
}
|
||||
|
||||
function cloneEditorData(data: IEditorData): IEditorData {
|
||||
if (typeof structuredClone === 'function') {
|
||||
return structuredClone(data) as IEditorData
|
||||
}
|
||||
return JSON.parse(JSON.stringify(data)) as IEditorData
|
||||
}
|
||||
|
||||
export function prepareOcdDocumentForSave(data: IEditorData): IEditorData {
|
||||
const prepared = cloneEditorData(data)
|
||||
;(['header', 'main', 'footer'] as const).forEach(key => {
|
||||
const elementList = prepared[key]
|
||||
if (isElementList(elementList)) {
|
||||
prepareElementList(elementList)
|
||||
}
|
||||
})
|
||||
return prepared
|
||||
}
|
||||
|
||||
export function prepareOcdDocumentForOpen(data: IEditorData): IEditorData {
|
||||
if (!isRecord(data)) return data
|
||||
;(['header', 'main', 'footer'] as const).forEach(key => {
|
||||
const elementList = data[key]
|
||||
if (isElementList(elementList)) {
|
||||
prepareElementList(elementList)
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user