Skip to content

Commit

Permalink
fix: mark on element
Browse files Browse the repository at this point in the history
  • Loading branch information
jibin2706 committed Aug 4, 2023
1 parent 6349748 commit f9cf33f
Showing 1 changed file with 55 additions and 8 deletions.
63 changes: 55 additions & 8 deletions src/plugins/sync-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import * as random from 'lib0/random'
import * as environment from 'lib0/environment'
import * as dom from 'lib0/dom'
import * as eventloop from 'lib0/eventloop'
import * as f from 'lib0/function'

const MarkPrefix = '_mark_'

/**
* @param {Y.Item} item
Expand Down Expand Up @@ -671,7 +674,19 @@ const createNodeFromYElement = (
: { type: 'added' }
}
}
const node = schema.node(el.nodeName, attrs, children)
const nodeAttrs = {}
const nodeMarks = []

for (const key in attrs) {
if (key.startsWith(MarkPrefix)) {
const markName = key.replace(MarkPrefix, '')
const markValue = attrs[key]
nodeMarks.push(schema.mark(markName, markValue.attrs))
} else {
nodeAttrs[key] = attrs[key]
}
}
const node = schema.node(el.nodeName, nodeAttrs, children, nodeMarks)
mapping.set(el, node)
return node
} catch (e) {
Expand Down Expand Up @@ -750,12 +765,16 @@ const createTypeFromTextNodes = (nodes, mapping) => {
*/
const createTypeFromElementNode = (node, mapping) => {
const type = new Y.XmlElement(node.type.name)
const nodeMarksAttr = nodeMarksToAttributes(node.marks)
for (const key in node.attrs) {
const val = node.attrs[key]
if (val !== null && key !== 'ychange') {
type.setAttribute(key, val)
}
}
for (const key in nodeMarksAttr) {
type.setAttribute(key, nodeMarksAttr[key])
}
type.insert(
0,
normalizePNodeContent(node).map((n) =>
Expand Down Expand Up @@ -783,7 +802,7 @@ const equalAttrs = (pattrs, yattrs) => {
const keys = Object.keys(pattrs).filter((key) => pattrs[key] !== null)
let eq =
keys.length ===
Object.keys(yattrs).filter((key) => yattrs[key] !== null).length
Object.keys(yattrs).filter((key) => yattrs[key] !== null && !key.startsWith(MarkPrefix)).length
for (let i = 0; i < keys.length && eq; i++) {
const key = keys[i]
const l = pattrs[key]
Expand All @@ -794,6 +813,20 @@ const equalAttrs = (pattrs, yattrs) => {
return eq
}

const equalMarks = (pmarks, yattrs) => {
const keys = Object.keys(yattrs).filter((key) => key.startsWith(MarkPrefix))
let eq =
keys.length === pmarks.length
const pMarkAttr = nodeMarksToAttributes(pmarks)
for (let i = 0; i < keys.length && eq; i++) {
const key = keys[i]
const l = pMarkAttr[key]
const r = yattrs[key]
eq = key === 'ychange' || f.equalityDeep(l, r)
}
return eq
}

/**
* @typedef {Array<Array<PModel.Node>|PModel.Node>} NormalizedPNodeContent
*/
Expand Down Expand Up @@ -848,7 +881,8 @@ const equalYTypePNode = (ytype, pnode) => {
) {
const normalizedContent = normalizePNodeContent(pnode)
return ytype._length === normalizedContent.length &&
equalAttrs(ytype.getAttributes(), pnode.attrs) &&
equalAttrs(pnode.attrs, ytype.getAttributes()) &&
equalMarks(pnode.marks, ytype.getAttributes()) &&
ytype.toArray().every((ychild, i) =>
equalYTypePNode(ychild, normalizedContent[i])
)
Expand Down Expand Up @@ -965,6 +999,16 @@ const marksToAttributes = (marks) => {
return pattrs
}

const nodeMarksToAttributes = (marks) => {
const pattrs = {}
marks.forEach((mark) => {
if (mark.type.name !== 'ychange') {
pattrs[`${MarkPrefix}${mark.type.name}`] = mark.toJSON()
}
})
return pattrs
}

/**
* @private
* @param {{transact: Function}} y
Expand All @@ -984,18 +1028,21 @@ export const updateYFragment = (y, yDomFragment, pNode, mapping) => {
if (yDomFragment instanceof Y.XmlElement) {
const yDomAttrs = yDomFragment.getAttributes()
const pAttrs = pNode.attrs
for (const key in pAttrs) {
if (pAttrs[key] !== null) {
if (yDomAttrs[key] !== pAttrs[key] && key !== 'ychange') {
yDomFragment.setAttribute(key, pAttrs[key])
const pNodeMarksAttr = nodeMarksToAttributes(pNode.marks)
const attrs = { ...pAttrs, ...pNodeMarksAttr }

for (const key in attrs) {
if (attrs[key] !== null) {
if (yDomAttrs[key] !== attrs[key] && key !== 'ychange') {
yDomFragment.setAttribute(key, attrs[key])
}
} else {
yDomFragment.removeAttribute(key)
}
}
// remove all keys that are no longer in pAttrs
for (const key in yDomAttrs) {
if (pAttrs[key] === undefined) {
if (attrs[key] === undefined) {
yDomFragment.removeAttribute(key)
}
}
Expand Down

0 comments on commit f9cf33f

Please sign in to comment.