From 4032edcf7d9ee959ce64f0e5090a39a05054a36a Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Wed, 14 Jun 2017 02:35:21 -0400 Subject: [PATCH] Ignore note markup conflicts without cache when text content matches --- chrome/content/zotero/xpcom/sync/syncLocal.js | 30 ++++++++++ test/tests/syncLocalTest.js | 58 +++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/chrome/content/zotero/xpcom/sync/syncLocal.js b/chrome/content/zotero/xpcom/sync/syncLocal.js index a8bbd905e..036c9c6d8 100644 --- a/chrome/content/zotero/xpcom/sync/syncLocal.js +++ b/chrome/content/zotero/xpcom/sync/syncLocal.js @@ -1547,6 +1547,15 @@ Zotero.Sync.Data.Local = { } var localChanged = false; + var normalizeHTML = (str) => { + let parser = Components.classes["@mozilla.org/xmlextras/domparser;1"] + .createInstance(Components.interfaces.nsIDOMParser); + str = parser.parseFromString(str, 'text/html'); + str = str.body.textContent; + // Normalize internal spaces + str = str.replace(/\s+/g, ' '); + return str; + }; // Massage some old data conflicts = conflicts.filter((x) => { @@ -1567,6 +1576,27 @@ Zotero.Sync.Data.Local = { } } } + // Ignore notes with the same text content + // + // These can happen to people upgrading to 5.0 with notes that were added without going + // through TinyMCE (e.g., from translators) + else if (x[0].field == 'note' && x[0].op == 'add' && x[1].op == 'add') { + let a = x[0].value; + let b = x[1].value; + try { + a = normalizeHTML(a); + b = normalizeHTML(b); + if (a == b) { + Zotero.debug("Notes differ only by markup -- using remote version"); + changes.push(x[1]); + return false; + } + } + catch (e) { + Zotero.logError(e); + return true + } + } return true; }); diff --git a/test/tests/syncLocalTest.js b/test/tests/syncLocalTest.js index cfade8e6d..dbc0e4d40 100644 --- a/test/tests/syncLocalTest.js +++ b/test/tests/syncLocalTest.js @@ -1965,6 +1965,64 @@ describe("Zotero.Sync.Data.Local", function() { ); }) + it("should automatically use remote version for note markup differences when text content matches", function () { + var val2 = "

Foo bar
bar foo

"; + + var json1 = { + key: "AAAAAAAA", + version: 0, + itemType: "note", + note: "Foo bar
bar foo", + dateModified: "2017-06-13 13:45:12" + }; + var json2 = { + key: "AAAAAAAA", + version: 5, + itemType: "note", + note: val2, + dateModified: "2017-06-13 13:45:12" + }; + var ignoreFields = ['dateAdded', 'dateModified']; + var result = Zotero.Sync.Data.Local._reconcileChangesWithoutCache( + 'item', json1, json2, ignoreFields + ); + assert.lengthOf(result.changes, 1); + assert.sameDeepMembers( + result.changes, + [ + { + field: "note", + op: "add", + value: val2 + } + ] + ); + assert.lengthOf(result.conflicts, 0); + }); + + it("should show conflict for note markup differences when text content doesn't match", function () { + var json1 = { + key: "AAAAAAAA", + version: 0, + itemType: "note", + note: "Foo bar?", + dateModified: "2017-06-13 13:45:12" + }; + var json2 = { + key: "AAAAAAAA", + version: 5, + itemType: "note", + note: "

Foo bar!

", + dateModified: "2017-06-13 13:45:12" + }; + var ignoreFields = ['dateAdded', 'dateModified']; + var result = Zotero.Sync.Data.Local._reconcileChangesWithoutCache( + 'item', json1, json2, ignoreFields + ); + assert.lengthOf(result.changes, 0); + assert.lengthOf(result.conflicts, 1); + }); + it("should automatically use remote version for conflicting fields when both sides are in trash", function () { var json1 = { key: "AAAAAAAA",