From 00567278747cd2d2cdb410f31381bf4166139d58 Mon Sep 17 00:00:00 2001 From: tongxiaodong Date: Mon, 24 Apr 2023 16:30:52 +0800 Subject: [PATCH 1/5] fix: unsupported node mark --- src/plugins/sync-plugin.js | 42 ++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/plugins/sync-plugin.js b/src/plugins/sync-plugin.js index e4d5163..3a6af6d 100644 --- a/src/plugins/sync-plugin.js +++ b/src/plugins/sync-plugin.js @@ -671,7 +671,19 @@ const createNodeFromYElement = ( : { type: 'added' } } } - const node = schema.node(el.nodeName, attrs, children) + const nodeAttrs = {}; + const nodeMarks = []; + + for (const key in attrs) { + if (key.includes('yelement_mark_')) { + const markName = key.replace('yelement_mark_',''); + let markValue = JSON.parse(attrs[key]); + nodeMarks.push(schema.mark(markName, markValue)) + } else { + nodeAttrs[key] = attrs[key] + } + } + const node = schema.node(el.nodeName, nodeAttrs, children, nodeMarks); mapping.set(el, node) return node } catch (e) { @@ -750,12 +762,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) => @@ -965,6 +981,17 @@ const marksToAttributes = (marks) => { return pattrs } +const nodeMarksToAttributes = (marks) => { + const pattrs = {} + const prefix = 'yelement_mark_' + marks.forEach((mark) => { + if (mark.type.name !== 'ychange') { + pattrs[`${prefix}${mark.type.name}`] = JSON.stringify(mark.attrs || {}) + } + }) + return pattrs +} + /** * @private * @param {{transact: Function}} y @@ -984,10 +1011,13 @@ 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) @@ -995,7 +1025,7 @@ export const updateYFragment = (y, yDomFragment, pNode, mapping) => { } // 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) } } From 41df6c2af2b8a1eedfff8df78b6e83da2a51bdf8 Mon Sep 17 00:00:00 2001 From: tongxiaodong Date: Wed, 26 Apr 2023 15:42:38 +0800 Subject: [PATCH 2/5] fix: equalYTypePNode add equalMarks --- src/plugins/sync-plugin.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/plugins/sync-plugin.js b/src/plugins/sync-plugin.js index 3a6af6d..33bead0 100644 --- a/src/plugins/sync-plugin.js +++ b/src/plugins/sync-plugin.js @@ -796,7 +796,7 @@ const createTypeFromTextOrElementNode = (node, mapping) => const isObject = (val) => typeof val === 'object' && val !== null const equalAttrs = (pattrs, yattrs) => { - const keys = Object.keys(pattrs).filter((key) => pattrs[key] !== null) + const keys = Object.keys(pattrs).filter((key) => pattrs[key] !== null && !key.includes('yelement_mark_')) let eq = keys.length === Object.keys(yattrs).filter((key) => yattrs[key] !== null).length @@ -810,6 +810,25 @@ const equalAttrs = (pattrs, yattrs) => { return eq } +const equalMarks = (yattrs, pmarks) => { + const keys = Object.keys(yattrs).filter((key) => key.includes('yelement_mark_')); + + let eq = + keys.length === pmarks.length; + + let pMarkAttr = nodeMarksToAttributes(pmarks); + + console.log('yattrs:',yattrs , 'pMarkAttr',pMarkAttr); + + for (let i = 0; i < keys.length && eq; i++) { + const key = keys[i]; + const l = JSON.stringify(pMarkAttr[key]) + const r = yattrs[key] + eq = key === 'ychange' || l === r ; + } + return eq +} + /** * @typedef {Array|PModel.Node>} NormalizedPNodeContent */ @@ -865,6 +884,7 @@ const equalYTypePNode = (ytype, pnode) => { const normalizedContent = normalizePNodeContent(pnode) return ytype._length === normalizedContent.length && equalAttrs(ytype.getAttributes(), pnode.attrs) && + equalMarks(ytype.getAttributes(), pnode.marks) && ytype.toArray().every((ychild, i) => equalYTypePNode(ychild, normalizedContent[i]) ) From 4d28275351a34560e6ee0cd6138b72c70b464866 Mon Sep 17 00:00:00 2001 From: tongxiaodong Date: Thu, 4 May 2023 18:27:44 +0800 Subject: [PATCH 3/5] fix: mark use toJSON --- src/plugins/sync-plugin.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/plugins/sync-plugin.js b/src/plugins/sync-plugin.js index 33bead0..abe3afa 100644 --- a/src/plugins/sync-plugin.js +++ b/src/plugins/sync-plugin.js @@ -20,6 +20,7 @@ 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' /** * @param {Y.Item} item @@ -675,10 +676,10 @@ const createNodeFromYElement = ( const nodeMarks = []; for (const key in attrs) { - if (key.includes('yelement_mark_')) { + if (key.startsWith('yelement_mark_')) { const markName = key.replace('yelement_mark_',''); - let markValue = JSON.parse(attrs[key]); - nodeMarks.push(schema.mark(markName, markValue)) + let markValue = attrs[key]; + nodeMarks.push(schema.mark(markName, markValue.attrs)) } else { nodeAttrs[key] = attrs[key] } @@ -796,7 +797,7 @@ const createTypeFromTextOrElementNode = (node, mapping) => const isObject = (val) => typeof val === 'object' && val !== null const equalAttrs = (pattrs, yattrs) => { - const keys = Object.keys(pattrs).filter((key) => pattrs[key] !== null && !key.includes('yelement_mark_')) + const keys = Object.keys(pattrs).filter((key) => pattrs[key] !== null && !key.startsWith('yelement_mark_')) let eq = keys.length === Object.keys(yattrs).filter((key) => yattrs[key] !== null).length @@ -811,20 +812,18 @@ const equalAttrs = (pattrs, yattrs) => { } const equalMarks = (yattrs, pmarks) => { - const keys = Object.keys(yattrs).filter((key) => key.includes('yelement_mark_')); + const keys = Object.keys(yattrs).filter((key) => key.startsWith('yelement_mark_')); let eq = keys.length === pmarks.length; let pMarkAttr = nodeMarksToAttributes(pmarks); - console.log('yattrs:',yattrs , 'pMarkAttr',pMarkAttr); - for (let i = 0; i < keys.length && eq; i++) { const key = keys[i]; - const l = JSON.stringify(pMarkAttr[key]) + const l = pMarkAttr[key] const r = yattrs[key] - eq = key === 'ychange' || l === r ; + eq = key === 'ychange' || f.equalityDeep(l,r); } return eq } @@ -1006,7 +1005,7 @@ const nodeMarksToAttributes = (marks) => { const prefix = 'yelement_mark_' marks.forEach((mark) => { if (mark.type.name !== 'ychange') { - pattrs[`${prefix}${mark.type.name}`] = JSON.stringify(mark.attrs || {}) + pattrs[`${prefix}${mark.type.name}`] = mark.toJSON() } }) return pattrs From 25a749c81104d86b52ea12816584c2de73ae483c Mon Sep 17 00:00:00 2001 From: tongxiaodong Date: Wed, 10 May 2023 20:47:43 +0800 Subject: [PATCH 4/5] fix: "use const " and "adjust parameter order" --- src/plugins/sync-plugin.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/plugins/sync-plugin.js b/src/plugins/sync-plugin.js index abe3afa..7b3ac76 100644 --- a/src/plugins/sync-plugin.js +++ b/src/plugins/sync-plugin.js @@ -22,6 +22,8 @@ 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 * @param {Y.Snapshot} [snapshot] @@ -676,9 +678,9 @@ const createNodeFromYElement = ( const nodeMarks = []; for (const key in attrs) { - if (key.startsWith('yelement_mark_')) { - const markName = key.replace('yelement_mark_',''); - let markValue = attrs[key]; + 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] @@ -797,10 +799,10 @@ const createTypeFromTextOrElementNode = (node, mapping) => const isObject = (val) => typeof val === 'object' && val !== null const equalAttrs = (pattrs, yattrs) => { - const keys = Object.keys(pattrs).filter((key) => pattrs[key] !== null && !key.startsWith('yelement_mark_')) + 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] @@ -812,13 +814,10 @@ const equalAttrs = (pattrs, yattrs) => { } const equalMarks = (yattrs, pmarks) => { - const keys = Object.keys(yattrs).filter((key) => key.startsWith('yelement_mark_')); - + const keys = Object.keys(yattrs).filter((key) => key.startsWith(MarkPrefix)); let eq = keys.length === pmarks.length; - let pMarkAttr = nodeMarksToAttributes(pmarks); - for (let i = 0; i < keys.length && eq; i++) { const key = keys[i]; const l = pMarkAttr[key] @@ -882,8 +881,8 @@ const equalYTypePNode = (ytype, pnode) => { ) { const normalizedContent = normalizePNodeContent(pnode) return ytype._length === normalizedContent.length && - equalAttrs(ytype.getAttributes(), pnode.attrs) && - equalMarks(ytype.getAttributes(), pnode.marks) && + equalAttrs(pnode.attrs, ytype.getAttributes()) && + equalMarks(pnode.marks, ytype.getAttributes()) && ytype.toArray().every((ychild, i) => equalYTypePNode(ychild, normalizedContent[i]) ) @@ -1002,10 +1001,9 @@ const marksToAttributes = (marks) => { const nodeMarksToAttributes = (marks) => { const pattrs = {} - const prefix = 'yelement_mark_' marks.forEach((mark) => { if (mark.type.name !== 'ychange') { - pattrs[`${prefix}${mark.type.name}`] = mark.toJSON() + pattrs[`${MarkPrefix}${mark.type.name}`] = mark.toJSON() } }) return pattrs From 2d7813a51acabc30015fac10c32a44dc351fc970 Mon Sep 17 00:00:00 2001 From: tongxiaodong Date: Fri, 12 May 2023 18:44:44 +0800 Subject: [PATCH 5/5] fix: parameter order is reversed --- src/plugins/sync-plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/sync-plugin.js b/src/plugins/sync-plugin.js index 7b3ac76..ca5e998 100644 --- a/src/plugins/sync-plugin.js +++ b/src/plugins/sync-plugin.js @@ -813,7 +813,7 @@ const equalAttrs = (pattrs, yattrs) => { return eq } -const equalMarks = (yattrs, pmarks) => { +const equalMarks = (pmarks, yattrs) => { const keys = Object.keys(yattrs).filter((key) => key.startsWith(MarkPrefix)); let eq = keys.length === pmarks.length;