www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 79748b91320eea7cfd755b47078387519ab018fa
parent d78089d4b9cb70dcec61581154c1396730132cc7
Author: Dan Stillman <dstillman@zotero.org>
Date:   Thu,  7 Apr 2016 21:06:49 -0400

Fix #940, UI not updating when dragging child item between parents

Diffstat:
Mchrome/content/zotero/xpcom/data/items.js | 11+++++++++++
Mchrome/content/zotero/xpcom/itemTreeView.js | 7++++++-
Mtest/tests/itemTest.js | 56+++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtest/tests/itemTreeViewTest.js | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 152 insertions(+), 2 deletions(-)

diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js @@ -491,6 +491,7 @@ Zotero.Items = function() { var onRow = function (row, setFunc) { var itemID = row.getResultByIndex(0); + // If we've finished a set of rows for an item, process them if (lastItemID && itemID !== lastItemID) { setFunc(lastItemID, rows); rows = []; @@ -543,9 +544,14 @@ Zotero.Items = function() { } } ); + // Process unprocessed rows if (lastItemID) { setAttachmentItem(lastItemID, rows); } + // Otherwise clear existing entries for passed items + else if (ids.length) { + ids.forEach(id => setAttachmentItem(id, [])); + } // // Notes @@ -591,9 +597,14 @@ Zotero.Items = function() { } } ); + // Process unprocessed rows if (lastItemID) { setNoteItem(lastItemID, rows); } + // Otherwise clear existing entries for passed items + else if (ids.length) { + ids.forEach(id => setNoteItem(id, [])); + } // Mark all top-level items as having child items loaded sql = "SELECT itemID FROM items I WHERE libraryID=?" + idSQL + " AND itemID NOT IN " diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js @@ -712,9 +712,13 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio sort = id; } + // If item was moved from one parent to another, remove from old parent + else if (parentItemID && parentIndex != -1 && this._rowMap[parentItemID] != parentIndex) { + this._removeRow(row); + } // If not moved from under one item to another, just resort the row, // which also invalidates it and refreshes it - else if (!(parentItemID && parentIndex != -1 && this._rowMap[parentItemID] != parentIndex)) { + else { sort = id; } @@ -870,6 +874,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio else { this._refreshItemRowMap(); } + this._refreshItemRowMap(); if (singleSelect) { if (!extraData[singleSelect] || !extraData[singleSelect].skipSelect) { diff --git a/test/tests/itemTest.js b/test/tests/itemTest.js @@ -372,6 +372,26 @@ describe("Zotero.Item", function () { }) }); + describe("#getCreators()", function () { + it("should update after creators are removed", function* () { + var item = createUnsavedDataObject('item'); + item.setCreators([ + { + creatorType: "author", + name: "A" + } + ]); + yield item.saveTx(); + + assert.lengthOf(item.getCreators(), 1); + + item.setCreators([]); + yield item.saveTx(); + + assert.lengthOf(item.getCreators(), 0); + }); + }); + describe("#setCreators", function () { it("should accept an array of creators in API JSON format", function* () { var creators = [ @@ -459,6 +479,25 @@ describe("Zotero.Item", function () { var item = yield createDataObject('item'); assert.lengthOf(item.getAttachments(), 0); }) + + it("should update after an attachment is moved to another item", function* () { + var item1 = yield createDataObject('item'); + var item2 = yield createDataObject('item'); + var item3 = new Zotero.Item('attachment'); + item3.parentID = item1.id; + item3.attachmentLinkMode = 'linked_url'; + item3.setField('url', 'http://example.com'); + yield item3.saveTx(); + + assert.lengthOf(item1.getAttachments(), 1); + assert.lengthOf(item2.getAttachments(), 0); + + item3.parentID = item2.id; + yield item3.saveTx(); + + assert.lengthOf(item1.getAttachments(), 0); + assert.lengthOf(item2.getAttachments(), 1); + }); }) describe("#getNotes()", function () { @@ -499,7 +538,22 @@ describe("Zotero.Item", function () { it("#should return an empty array for an item with no notes", function* () { var item = yield createDataObject('item'); assert.lengthOf(item.getNotes(), 0); - }) + }); + + it("should update after a note is moved to another item", function* () { + var item1 = yield createDataObject('item'); + var item2 = yield createDataObject('item'); + var item3 = yield createDataObject('item', { itemType: 'note', parentID: item1.id }); + + assert.lengthOf(item1.getNotes(), 1); + assert.lengthOf(item2.getNotes(), 0); + + item3.parentID = item2.id; + yield item3.saveTx(); + + assert.lengthOf(item1.getNotes(), 0); + assert.lengthOf(item2.getNotes(), 1); + }); }) describe("#attachmentCharset", function () { diff --git a/test/tests/itemTreeViewTest.js b/test/tests/itemTreeViewTest.js @@ -308,6 +308,86 @@ describe("Zotero.ItemTreeView", function() { }) describe("#drop()", function () { + it("should move a child item from one item to another", function* () { + var collection = yield createDataObject('collection'); + yield waitForItemsLoad(win); + var item1 = yield createDataObject('item', { title: "A", collections: [collection.id] }); + var item2 = yield createDataObject('item', { title: "B", collections: [collection.id] }); + var item3 = yield createDataObject('item', { itemType: 'note', parentID: item1.id }); + + let view = zp.itemsView; + yield view.selectItem(item3.id, true); + + var deferred = Zotero.Promise.defer(); + view.addEventListener('select', () => deferred.resolve()); + + view.drop(view.getRowIndexByID(item2.id), 0, { + dropEffect: 'copy', + effectAllowed: 'copy', + types: { + contains: function (type) { + return type == 'zotero/item'; + } + }, + getData: function (type) { + if (type == 'zotero/item') { + return item3.id + ""; + } + }, + mozItemCount: 1 + }) + + yield deferred.promise; + + // Old parent should be empty + assert.isFalse(view.isContainerOpen(view.getRowIndexByID(item1.id))); + assert.isTrue(view.isContainerEmpty(view.getRowIndexByID(item1.id))); + + // New parent should be open + assert.isTrue(view.isContainerOpen(view.getRowIndexByID(item2.id))); + assert.isFalse(view.isContainerEmpty(view.getRowIndexByID(item2.id))); + }); + + it("should move a child item from last item in list to another", function* () { + var collection = yield createDataObject('collection'); + yield waitForItemsLoad(win); + var item1 = yield createDataObject('item', { title: "A", collections: [collection.id] }); + var item2 = yield createDataObject('item', { title: "B", collections: [collection.id] }); + var item3 = yield createDataObject('item', { itemType: 'note', parentID: item2.id }); + + let view = zp.itemsView; + yield view.selectItem(item3.id, true); + + var deferred = Zotero.Promise.defer(); + view.addEventListener('select', () => deferred.resolve()); + + view.drop(view.getRowIndexByID(item1.id), 0, { + dropEffect: 'copy', + effectAllowed: 'copy', + types: { + contains: function (type) { + return type == 'zotero/item'; + } + }, + getData: function (type) { + if (type == 'zotero/item') { + return item3.id + ""; + } + }, + mozItemCount: 1 + }) + + yield deferred.promise; + + // Old parent should be empty + assert.isFalse(view.isContainerOpen(view.getRowIndexByID(item2.id))); + assert.isTrue(view.isContainerEmpty(view.getRowIndexByID(item2.id))); + + // New parent should be open + assert.isTrue(view.isContainerOpen(view.getRowIndexByID(item1.id))); + assert.isFalse(view.isContainerEmpty(view.getRowIndexByID(item1.id))); + }); + it("should create a top-level attachment when a file is dragged", function* () { var file = getTestDataDirectory(); file.append('test.png');