Hi WebODFler, currently the spec of OpSetParagraphStyle has a parameter "position" which identifies the paragraph to set the style for by being somewhere inside that paragraph. Worked fine so far, but poses a big problem on doing OT versus all kind of other operations. (There is also anothe issue, in that there are the parameters "styleNameBefore" and "styleNameAfter", of which only "styleNameAfter" is used, and for the other so far no use is seen. So ideally "styleNameBefore" is removed and "styleNameAfter" is renamed to just "styleName") To refresh your memories, this is the background: Two clients A and B create operations based on the same state of the document, which they first apply locally and only then exchange with the other clients. The goal is to have the documents at all clients to converge against each other in the end, ideally being identical, after all operations have been applied at all clients. So A now gets the operations from B and needs to have them transformed against its own locally applied operations, while B gets the ones from A and needs the reverse, A's operations being transformed against its own locally applied operations. There are cases where tie-breaking is needed, usually when the same object gets modified by the two ops which have to be transformed each other, think of two OpUpdateParagraphStyle modifying the same style or two OpInsertText targetting at the same position. Here some arbitrary priority is needed, which needs to be based on a property which is the same everywhere (e.g. order of memberIds or which op is first on the server). Sometimes longer sequences of ops are transformed against each other. Which means that when dealing with the non-first ops these are based on virtual states of the documents and thus querying additional properties from the document is not possible. Applying the ops to some temp document for that is possibly way too expensive (unless we could do some light-weight shadow document, but the remove/inserttext ops need the full DOM), especially on multi-op transformation lots of documents would need to be created. (place of the cross-transformation of the ops does not matter for this) Now here are the samples where things fail ATM (always assuming A's ops have priority): Doc: text:pText A: [<setParagraphStyle pos="0" styleNameAfter="S1" memberId="A"/>] B: [<setParagraphStyle pos="3" styleNameAfter="S2" memberId="B"/>] Obviously hard to know if both target the same paragraph. Proposal: fix by identifying the paragraph with by its first position Using this proposal, there is another issue: Doc: text:pABtext:pCtext:p/ A: [<setParagraphStyle pos="3" styleNameAfter="S1" memberId="A"/>] B: [<removeText pos="0" length="1" memberId="B"/>] How can the setParagraphStyle op be transformed against the removeText op, in such a way that the pos attribute again points to the begin of the paragraph? There is no information in the removeText op which paragraphs are affected and how. So while OT between two OpSetParagraphStyle might be fixable by just using the first position in the paragraph as id, this will fail with transformation versus OpRemoveText, because its spec addresses the touched objects only indirectly and thus cannot provide the needed information to transform OpSetParagraphStyle against it. How to solve that? Naively I would now propose to change the spec of OpRemoveText, which has anyway evolved to something that no longer matches its name. It would need to change to an op which is as specific as needed in its spec so that other ops can transform against it. Which surely is a general rule, as I find out by that :) How a new spec might look like? No real idea yet, but it needs to tell which paragraphs and which parts in it are removed. So OpSetParagraphStyle can be properly transformed against it. So no real question here, just loud thinking. Comments welcome. Cheers Friedrich -- Friedrich W. H. Kossebau // KO GmbH http://kogmbh.com/legal/
On 26 June 2013 03:26, Friedrich W. H. Kossebau
(There is also anothe issue, in that there are the parameters "styleNameBefore" and "styleNameAfter", of which only "styleNameAfter" is used, and for the other so far no use is seen. So ideally "styleNameBefore" is removed and "styleNameAfter" is renamed to just "styleName")
+1 for this.
Now here are the samples where things fail ATM (always assuming A's ops have priority): Doc: text:pText A: [<setParagraphStyle pos="0" styleNameAfter="S1" memberId="A"/>] B: [<setParagraphStyle pos="3" styleNameAfter="S2" memberId="B"/>] Obviously hard to know if both target the same paragraph. Proposal: fix by identifying the paragraph with by its first position
...
text:p>text:p/ A: [<setParagraphStyle pos="3" styleNameAfter="S1" memberId="A"/>] B: [<removeText pos="0" length="1" memberId="B"/>] How can the setParagraphStyle op be transformed against the removeText op, in such a way that the pos attribute again points to the begin of the paragraph? There is no information in the removeText op which paragraphs are affected and how.
The desired intent is that each client end up with the same document,
Using this proposal, there is another issue:
though the ops
are processed in a different order right.
Consider the following scenario:
text:pP1
A: [
On 26 June 2013 19:58, Philip Peitsch
On 26 June 2013 03:26, Friedrich W. H. Kossebau
wrote: (There is also anothe issue, in that there are the parameters "styleNameBefore" and "styleNameAfter", of which only "styleNameAfter" is used, and for the other so far no use is seen. So ideally "styleNameBefore" is removed and "styleNameAfter" is renamed to just "styleName")
+1 for this.
Now here are the samples where things fail ATM (always assuming A's ops have priority): Doc: text:pText A: [<setParagraphStyle pos="0" styleNameAfter="S1" memberId="A"/>] B: [<setParagraphStyle pos="3" styleNameAfter="S2" memberId="B"/>] Obviously hard to know if both target the same paragraph. Proposal: fix by identifying the paragraph with by its first position
...
text:p>text:p/ A: [<setParagraphStyle pos="3" styleNameAfter="S1" memberId="A"/>] B: [<removeText pos="0" length="1" memberId="B"/>] How can the setParagraphStyle op be transformed against the removeText op, in such a way that the pos attribute again points to the begin of the paragraph? There is no information in the removeText op which paragraphs are affected and how.
The desired intent is that each client end up with the same document,
Using this proposal, there is another issue: though the ops are processed in a different order right.
Consider the following scenario: text:pP1
A: [
] B: [ ] Client A processes A then B, and ends up with the style applied to both paragraphs (this is the intended result). Client B splits first, then needs to realise that the style should be applied to the new paragraph as well.
If setParagraphStyle carries both the start and end of the paragraph positions, it would be trivial to tell where the old styled paragraph ended. Every paragraph up to this point is expected to carry the new style. For the above example, client B would perform the following
1. Apply splitParagraph at position 1 (just after the 'P'). This inserts a new cursor position. 2. Transform setParagraphStyle end pos (or length) by +1 3. setParagraphStyle fetches all paragraphs in the specified range and applies the style to these
Is there a glaring hole in that approach?
A further thought on this.
The key problem with the removeText is that it can change the paragraph
boundaries. Potentially to cope with this, the setParagraphStyle can assert
that it's start position *is* a
paragraph boundary, and if this isn't the case, skip to the next following
paragraph
(as long as the following paragraph start is before the setParagraphStyle
end).
This would handle the the following case:
text:pP1text:pP2
A: [
Am Mittwoch, 26. Juni 2013, 19:58:27 schrieben Sie:
On 26 June 2013 03:26, Friedrich W. H. Kossebau
wrote: Now here are the samples where things fail ATM (always assuming A's ops have priority): Doc: text:pText A: [<setParagraphStyle pos="0" styleNameAfter="S1" memberId="A"/>] B: [<setParagraphStyle pos="3" styleNameAfter="S2" memberId="B"/>] Obviously hard to know if both target the same paragraph. Proposal: fix by identifying the paragraph with by its first position
...
Using this proposal, there is another issue:
text:p>text:p/ A: [<setParagraphStyle pos="3" styleNameAfter="S1" memberId="A"/>] B: [<removeText pos="0" length="1" memberId="B"/>] How can the setParagraphStyle op be transformed against the removeText op, in such a way that the pos attribute again points to the begin of the paragraph? There is no information in the removeText op which paragraphs are affected and how.
The desired intent is that each client end up with the same document, though the ops are processed in a different order right.
Right.
Consider the following scenario: text:pP1
A: [
] B: [ ] Client A processes A then B, and ends up with the style applied to both paragraphs (this is the intended result). Client B splits first, then needs to realise that the style should be applied to the new paragraph as well.
Yes, another nice example where just the (starting) position of the paragraph with setParagraphStyle op would not work in OT.
If setParagraphStyle carries both the start and end of the paragraph positions, it would be trivial to tell where the old styled paragraph ended. Every paragraph up to this point is expected to carry the new style. For the above example, client B would perform the following
1. Apply splitParagraph at position 1 (just after the 'P'). This inserts a new cursor position. 2. Transform setParagraphStyle end pos (or length) by +1 3. setParagraphStyle fetches all paragraphs in the specified range and applies the style to these
Is there a glaring hole in that approach?
That basic approach should be fine, yes.
Just that instead of 3) there would be instead another setParagraphStyle op
created, which sets the given style for the second of the split paragraphs.
This would then result in no further troubles if e.g. B not only has
participants (2)
-
Friedrich W. H. Kossebau
-
Philip Peitsch