Skip to content

Commit

Permalink
Add support for overlapping marks
Browse files Browse the repository at this point in the history
This is inspired from this PL: yjs#52
  • Loading branch information
Idriss mahjoubi committed Jun 16, 2022
1 parent 8817b52 commit b6a191c
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 14 deletions.
35 changes: 26 additions & 9 deletions src/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,18 +269,35 @@ export function yDocToProsemirrorJSON (
}

if (d.attributes) {
text.marks = Object.keys(d.attributes).map((type) => {
const attrs = d.attributes[type]
const mark = {
type
}
let marks = []
text.marks = Object.keys(d.attributes).forEach((type) => {
let attrs = d.attributes[type]
if (Array.isArray(attrs)) {
// multiple marks of same type
attrs.forEach(singleAttrs => {
const mark = {
type
}

if (Object.keys(attrs)) {
mark.attrs = attrs
}
if (Object.keys(singleAttrs)) {
mark.attrs = singleAttrs
}

marks.push(mark)
})
} else {
const mark = {
type
}

return mark
if (Object.keys(attrs)) {
mark.attrs = attrs
}

marks.push(mark)
}
})
text.marks = marks
}
return text
})
Expand Down
44 changes: 39 additions & 5 deletions src/plugins/sync-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,15 @@ const createTextNodesFromYText = (text, schema, mapping, snapshot, prevSnapshot,
const delta = deltas[i]
const marks = []
for (const markName in delta.attributes) {
marks.push(schema.mark(markName, delta.attributes[markName]))
if (Array.isArray(delta.attributes[markName])) {
// multiple marks of same type
delta.attributes[markName].forEach(attrs => {
marks.push(schema.mark(markName, attrs))
})
} else {
// single mark
marks.push(schema.mark(markName, delta.attributes[markName]))
}
}
nodes.push(schema.text(delta.insert, marks))
}
Expand Down Expand Up @@ -569,6 +577,14 @@ const equalAttrs = (pattrs, yattrs) => {
return eq
}

const containsEqualMark = (pattrs, yattrs) => {
if (Array.isArray(yattrs)) {
return !!yattrs.find(el => equalAttrs(pattrs, el))
} else {
return equalAttrs(pattrs, yattrs)
}
}

/**
* @typedef {Array<Array<PModel.Node>|PModel.Node>} NormalizedPNodeContent
*/
Expand All @@ -595,15 +611,24 @@ const normalizePNodeContent = pnode => {
}
return res
}

const countYTextMarks = (yattrs) => {
let count = 0
object.forEach(yattrs, (val) => {
if (Array.isArray(val)) {
count += val.length
} else {
count++
}
})
return count
}
/**
* @param {Y.XmlText} ytext
* @param {Array<any>} ptexts
*/
const equalYTextPText = (ytext, ptexts) => {
const delta = ytext.toDelta()
return delta.length === ptexts.length && delta.every((d, i) => d.insert === /** @type {any} */ (ptexts[i]).text && object.keys(d.attributes || {}).length === ptexts[i].marks.length && ptexts[i].marks.every(mark => equalAttrs(d.attributes[mark.type.name] || {}, mark.attrs)))
}
return delta.length === ptexts.length && delta.every((d, i) => d.insert === /** @type {any} */ (ptexts[i]).text && countYTextMarks(d.attributes || {}) === ptexts[i].marks.length && ptexts[i].marks.every(mark => containsEqualMark(d.attributes[mark.type.name] || {}, mark.attrs)))}

/**
* @param {Y.XmlElement|Y.XmlText|Y.XmlHook} ytype
Expand Down Expand Up @@ -706,7 +731,16 @@ const marksToAttributes = marks => {
const pattrs = {}
marks.forEach(mark => {
if (mark.type.name !== 'ychange') {
pattrs[mark.type.name] = mark.attrs
if (pattrs[mark.type.name] && Array.isArray(pattrs[mark.type.name])) {
// already has multiple marks of same type
pattrs[mark.type.name].push(mark.attrs)
} else if (pattrs[mark.type.name]) {
// already has mark of same type, change to array
pattrs[mark.type.name] = [pattrs[mark.type.name], mark.attrs]
} else {
// first mark of this type
pattrs[mark.type.name] = mark.attrs
}
}
})
return pattrs
Expand Down

0 comments on commit b6a191c

Please sign in to comment.