diff --git a/services/track-changes/app/coffee/DiffGenerator.coffee b/services/track-changes/app/coffee/DiffGenerator.coffee index b8028d9f99..996c936612 100644 --- a/services/track-changes/app/coffee/DiffGenerator.coffee +++ b/services/track-changes/app/coffee/DiffGenerator.coffee @@ -35,8 +35,25 @@ module.exports = DiffGenerator = diff = [ u: initialContent ] for update in updates diff = DiffGenerator.applyUpdateToDiff diff, update + diff = DiffGenerator.compressDiff diff return diff + compressDiff: (diff) -> + newDiff = [] + for part in diff + lastPart = newDiff[newDiff.length - 1] + if lastPart? and lastPart.i? and part.i? and lastPart.meta.user_id == part.meta.user_id + lastPart.i += part.i + lastPart.meta.start_ts = Math.min(lastPart.meta.start_ts, part.meta.start_ts) + lastPart.meta.end_ts = Math.max(lastPart.meta.end_ts, part.meta.end_ts) + else if lastPart? and lastPart.d? and part.d? and lastPart.meta.user_id == part.meta.user_id + lastPart.d += part.d + lastPart.meta.start_ts = Math.min(lastPart.meta.start_ts, part.meta.start_ts) + lastPart.meta.end_ts = Math.max(lastPart.meta.end_ts, part.meta.end_ts) + else + newDiff.push part + return newDiff + applyOpToDiff: (diff, op, meta) -> position = 0 diff --git a/services/track-changes/test/acceptance/coffee/GettingADiffTests.coffee b/services/track-changes/test/acceptance/coffee/GettingADiffTests.coffee index ed0e0e42d6..6fe573c19e 100644 --- a/services/track-changes/test/acceptance/coffee/GettingADiffTests.coffee +++ b/services/track-changes/test/acceptance/coffee/GettingADiffTests.coffee @@ -51,8 +51,7 @@ describe "Getting a diff", -> @lines = ["one two three four"] @expected_diff = [ { u: "one " } - { i: "two ", meta: { start_ts: @from + twoMinutes, end_ts: @from + twoMinutes, user: @user } } - { i: "three ", meta: { start_ts: @to - twoMinutes, end_ts: @to - twoMinutes, user: @user } } + { i: "two three ", meta: { start_ts: @from + twoMinutes, end_ts: @to - twoMinutes, user: @user } } ] MockDocUpdaterApi.docs[@doc_id] = diff --git a/services/track-changes/test/unit/coffee/DiffGenerator/DiffGeneratorTests.coffee b/services/track-changes/test/unit/coffee/DiffGenerator/DiffGeneratorTests.coffee index 9fd59d69f5..43c86cfb5d 100644 --- a/services/track-changes/test/unit/coffee/DiffGenerator/DiffGeneratorTests.coffee +++ b/services/track-changes/test/unit/coffee/DiffGenerator/DiffGeneratorTests.coffee @@ -10,6 +10,7 @@ describe "DiffGenerator", -> @DiffGenerator = SandboxedModule.require modulePath @ts = Date.now() @user_id = "mock-user-id" + @user_id_2 = "mock-user-id-2" @meta = { start_ts: @ts, end_ts: @ts, user_id: @user_id } @@ -62,6 +63,7 @@ describe "DiffGenerator", -> { i: "mock-update-3" } ] @DiffGenerator.applyUpdateToDiff = sinon.stub().returns(@diff) + @DiffGenerator.compressDiff = sinon.stub().returns(@diff) @result = @DiffGenerator.buildDiff(@content, @updates) it "should return the diff", -> @@ -80,6 +82,50 @@ describe "DiffGenerator", -> .calledWith(sinon.match.any, update) .should.equal true + it "should compress the diff", -> + @DiffGenerator.compressDiff + .calledWith(@diff) + .should.equal true + + describe "compressDiff", -> + describe "with adjacent inserts with the same user_id", -> + it "should create one update with combined meta data and min/max timestamps", -> + diff = @DiffGenerator.compressDiff([ + { i: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }} + { i: "bar", meta: { start_ts: 5, end_ts: 15, user_id: @user_id }} + ]) + expect(diff).to.deep.equal([ + { i: "foobar", meta: { start_ts: 5, end_ts: 20, user_id: @user_id }} + ]) + + describe "with adjacent inserts with different user_ids", -> + it "should leave the inserts unchanged", -> + input = [ + { i: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }} + { i: "bar", meta: { start_ts: 5, end_ts: 15, user_id: @user_id_2 }} + ] + output = @DiffGenerator.compressDiff(input) + expect(output).to.deep.equal(input) + + describe "with adjacent deletes with the same user_id", -> + it "should create one update with combined meta data and min/max timestamps", -> + diff = @DiffGenerator.compressDiff([ + { d: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }} + { d: "bar", meta: { start_ts: 5, end_ts: 15, user_id: @user_id }} + ]) + expect(diff).to.deep.equal([ + { d: "foobar", meta: { start_ts: 5, end_ts: 20, user_id: @user_id }} + ]) + + describe "with adjacent deletes with different user_ids", -> + it "should leave the deletes unchanged", -> + input = [ + { d: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }} + { d: "bar", meta: { start_ts: 5, end_ts: 15, user_id: @user_id_2 }} + ] + output = @DiffGenerator.compressDiff(input) + expect(output).to.deep.equal(input) + describe "applyUpdateToDiff", -> describe "an insert", -> it "should insert into the middle of (u)nchanged text", ->