Adds sync support for related items
Might fix (or break) other stuff, but who remembers?
This commit is contained in:
parent
19b08a604a
commit
33de40ad95
7 changed files with 630 additions and 296 deletions
|
@ -407,11 +407,13 @@
|
|||
<method name="seeAlsoClick">
|
||||
<body>
|
||||
<![CDATA[
|
||||
var seealsoList = this.item.getSeeAlso();
|
||||
if(seealsoList && seealsoList.length > 0)
|
||||
var relatedList = this.item.relatedItemsBidirectional;
|
||||
if (relatedList.length > 0) {
|
||||
this.id('seeAlsoPopup').showPopup(this.id('seeAlsoLabel'),-1,-1,'popup',0,0);
|
||||
else
|
||||
}
|
||||
else {
|
||||
this.id('seeAlso').add();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
|
|
@ -42,15 +42,12 @@
|
|||
<![CDATA[
|
||||
var r = "";
|
||||
|
||||
if(this.item)
|
||||
{
|
||||
var seealso = this.item.getSeeAlso();
|
||||
if(seealso)
|
||||
{
|
||||
seealso = Zotero.Items.get(seealso);
|
||||
for(var i = 0; i < seealso.length; i++)
|
||||
{
|
||||
r = r + seealso[i].getField('title') + ", ";
|
||||
if (this.item) {
|
||||
var related = this.item.relatedItemsBidirectional;
|
||||
if (related) {
|
||||
related = Zotero.Items.get(related);
|
||||
for(var i = 0; i < related.length; i++) {
|
||||
r = r + related[i].getField('title') + ", ";
|
||||
}
|
||||
r = r.substr(0,r.length-2);
|
||||
}
|
||||
|
@ -67,20 +64,16 @@
|
|||
while(rows.hasChildNodes())
|
||||
rows.removeChild(rows.firstChild);
|
||||
|
||||
if(this.item)
|
||||
{
|
||||
var seealso = this.item.getSeeAlso();
|
||||
|
||||
if(seealso)
|
||||
{
|
||||
seealso = Zotero.Items.get(seealso);
|
||||
for(var i = 0; i < seealso.length; i++)
|
||||
{
|
||||
if (this.item) {
|
||||
var related = this.item.relatedItemsBidirectional;
|
||||
if (related) {
|
||||
related = Zotero.Items.get(related);
|
||||
for (var i = 0; i < related.length; i++) {
|
||||
var icon= document.createElement("image");
|
||||
var type = Zotero.ItemTypes.getName(seealso[i].getType());
|
||||
var type = Zotero.ItemTypes.getName(related[i].itemTypeID);
|
||||
if (type=='attachment')
|
||||
{
|
||||
switch (seealso[i].getAttachmentLinkMode())
|
||||
switch (related[i].getAttachmentLinkMode())
|
||||
{
|
||||
case Zotero.Attachments.LINK_MODE_LINKED_URL:
|
||||
type += '-web-link';
|
||||
|
@ -102,12 +95,13 @@
|
|||
icon.setAttribute('src','chrome://zotero/skin/treeitem-' + type + '.png');
|
||||
|
||||
var label = document.createElement("label");
|
||||
label.setAttribute('value', seealso[i].getField('title'));
|
||||
label.setAttribute('value', related[i].getField('title'));
|
||||
label.setAttribute('crop','end');
|
||||
label.setAttribute('flex','1');
|
||||
|
||||
var box = document.createElement('box');
|
||||
box.setAttribute('onclick',"this.parentNode.parentNode.parentNode.parentNode.parentNode.showItem('"+seealso[i].getID()+"')");
|
||||
box.setAttribute('onclick',
|
||||
"document.getBindingParent(this).showItem('" + related[i].id + "')");
|
||||
box.setAttribute('class','zotero-clicky');
|
||||
box.setAttribute('flex','1');
|
||||
box.appendChild(icon);
|
||||
|
@ -115,16 +109,17 @@
|
|||
|
||||
var remove = document.createElement("label");
|
||||
remove.setAttribute('value','-');
|
||||
remove.setAttribute('onclick',"this.parentNode.parentNode.parentNode.parentNode.parentNode.remove('"+seealso[i].getID()+"');");
|
||||
remove.setAttribute('onclick',
|
||||
"document.getBindingParent(this).remove('" + related[i].id + "');");
|
||||
remove.setAttribute('class','zotero-clicky');
|
||||
|
||||
var row = document.createElement("row");
|
||||
row.appendChild(box);
|
||||
row.appendChild(remove);
|
||||
row.setAttribute('id','seealso-'+seealso[i].getID());
|
||||
row.setAttribute('id', 'seealso-' + related[i].id);
|
||||
rows.appendChild(row);
|
||||
}
|
||||
this.updateCount(seealso.length);
|
||||
this.updateCount(related.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -146,8 +141,9 @@
|
|||
{
|
||||
for(var i = 0; i < io.dataOut.length; i++)
|
||||
{
|
||||
this.item.addSeeAlso(io.dataOut[i]);
|
||||
this.item.addRelatedItem(io.dataOut[i]);
|
||||
}
|
||||
this.item.save();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
|
@ -156,12 +152,15 @@
|
|||
<parameter name="id"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if(id)
|
||||
{
|
||||
this.item.removeSeeAlso(id);
|
||||
var rows = this.id('seeAlsoRows');
|
||||
rows.removeChild(this.id('seealso-'+id));
|
||||
this.updateCount();
|
||||
if(id) {
|
||||
// TODO: set attribute on reload to determine
|
||||
// which of these is necessary
|
||||
this.item.removeRelatedItem(id);
|
||||
this.item.save();
|
||||
|
||||
var item = Zotero.Items.get(id);
|
||||
item.removeRelatedItem(this.item.id);
|
||||
item.save();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
|
@ -206,13 +205,8 @@
|
|||
<parameter name="count"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if(count == null)
|
||||
{
|
||||
var seealso = this.item.getSeeAlso();
|
||||
if(seealso)
|
||||
count = seealso.length;
|
||||
else
|
||||
count = 0;
|
||||
if (count == null) {
|
||||
var count = this.item.relatedItemsBidirectional.length;
|
||||
}
|
||||
|
||||
var str = 'pane.item.related.count.';
|
||||
|
|
|
@ -69,7 +69,9 @@ Zotero.Item.prototype._init = function () {
|
|||
this._primaryDataLoaded = false;
|
||||
this._creatorsLoaded = false;
|
||||
this._itemDataLoaded = false;
|
||||
this._relatedItemsLoaded = false;
|
||||
|
||||
this._changed = false;
|
||||
this._changedPrimaryData = false;
|
||||
this._changedItemData = false;
|
||||
this._changedCreators = false;
|
||||
|
@ -87,6 +89,8 @@ Zotero.Item.prototype._init = function () {
|
|||
this._attachmentMIMEType = null;
|
||||
this._attachmentCharset = null;
|
||||
this._attachmentPath = null;
|
||||
|
||||
this._relatedItems = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,6 +104,10 @@ Zotero.Item.prototype.__defineGetter__('firstCreator', function () { return this
|
|||
//Zotero.Item.prototype.__defineGetter__('numNotes', function () { return this._itemID; });
|
||||
//Zotero.Item.prototype.__defineGetter__('numAttachments', function () { return this._itemID; });
|
||||
|
||||
Zotero.Item.prototype.__defineGetter__('relatedItems', function () { var ids = this._getRelatedItems(true); return ids ? ids : []; });
|
||||
Zotero.Item.prototype.__defineSetter__('relatedItems', function (arr) { this._setRelatedItems(arr); });
|
||||
Zotero.Item.prototype.__defineGetter__('relatedItemsReverse', function () { var ids = this._getRelatedItemsReverse(); return ids ? ids : []; });
|
||||
Zotero.Item.prototype.__defineGetter__('relatedItemsBidirectional', function () { var ids = this._getRelatedItemsBidirectional(); return ids ? ids : []; });
|
||||
|
||||
/*
|
||||
* Deprecated -- use id property
|
||||
|
@ -329,7 +337,8 @@ Zotero.Item.prototype.loadFromRow = function(row, reload) {
|
|||
* Check if any data fields have changed since last save
|
||||
*/
|
||||
Zotero.Item.prototype.hasChanged = function() {
|
||||
return !!(this._changedPrimaryData
|
||||
return !!(this._changed
|
||||
|| this._changedPrimaryData
|
||||
|| this._changedCreators
|
||||
|| this._changedItemData
|
||||
|| this._changedNote
|
||||
|
@ -906,6 +915,69 @@ Zotero.Item.prototype.removeCreator = function(orderIndex) {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype.addRelatedItem = function (itemID) {
|
||||
var parsedInt = parseInt(itemID);
|
||||
if (parsedInt != itemID) {
|
||||
throw ("itemID '" + itemID + "' not an integer in Zotero.Item.addRelatedItem()");
|
||||
}
|
||||
itemID = parsedInt;
|
||||
|
||||
if (itemID == this.id) {
|
||||
Zotero.debug("Can't relate item to itself in Zotero.Item.addRelatedItem()", 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
var current = this._getRelatedItems(true);
|
||||
if (current && current.indexOf(itemID) != -1) {
|
||||
Zotero.debug("Item " + this.id + " already related to item "
|
||||
+ itemID + " in Zotero.Item.addItem()");
|
||||
return false;
|
||||
}
|
||||
|
||||
var item = Zotero.Items.get(itemID);
|
||||
if (!item) {
|
||||
throw ("Can't relate item to invalid item " + itemID
|
||||
+ " in Zotero.Item.addRelatedItem()");
|
||||
}
|
||||
/*
|
||||
var otherCurrent = item.relatedItems;
|
||||
if (otherCurrent.length && otherCurrent.indexOf(this.id) != -1) {
|
||||
Zotero.debug("Other item " + itemID + " already related to item "
|
||||
+ this.id + " in Zotero.Item.addItem()");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
this._prepFieldChange('relatedItems');
|
||||
this._relatedItems.push(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype.removeRelatedItem = function (itemID) {
|
||||
var parsedInt = parseInt(itemID);
|
||||
if (parsedInt != itemID) {
|
||||
throw ("itemID '" + itemID + "' not an integer in Zotero.Item.removeRelatedItem()");
|
||||
}
|
||||
itemID = parsedInt;
|
||||
|
||||
var current = this._getRelatedItems(true);
|
||||
if (current) {
|
||||
var index = current.indexOf(itemID);
|
||||
}
|
||||
|
||||
if (!current || index == -1) {
|
||||
Zotero.debug("Item " + this.id + " isn't related to item "
|
||||
+ itemID + " in Zotero.Item.removeRelatedItem()");
|
||||
return false;
|
||||
}
|
||||
|
||||
this._prepFieldChange('relatedItems');
|
||||
this._relatedItems.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save changes back to database
|
||||
*
|
||||
|
@ -1232,6 +1304,59 @@ Zotero.Item.prototype.save = function() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Related items
|
||||
if (this._changed.relatedItems) {
|
||||
var removed = [];
|
||||
var newids = [];
|
||||
var currentIDs = this._getRelatedItems(true);
|
||||
if (!currentIDs) {
|
||||
currentIDs = [];
|
||||
}
|
||||
|
||||
if (this._previousData && this._previousData.related) {
|
||||
for each(var id in this._previousData.related) {
|
||||
if (currentIDs.indexOf(id) == -1) {
|
||||
removed.push(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for each(var id in currentIDs) {
|
||||
if (this._previousData && this._previousData.related &&
|
||||
this._previousData.related.indexOf(id) != -1) {
|
||||
continue;
|
||||
}
|
||||
newids.push(id);
|
||||
}
|
||||
|
||||
if (removed.length) {
|
||||
var sql = "DELETE FROM itemSeeAlso WHERE itemID=? "
|
||||
+ "AND linkedItemID IN ("
|
||||
+ removed.map(function () '?').join()
|
||||
+ ")";
|
||||
Zotero.DB.query(sql, [itemID].concat(removed));
|
||||
}
|
||||
|
||||
if (newids.length) {
|
||||
var sql = "INSERT INTO itemSeeAlso (itemID, linkedItemID) VALUES (?,?)";
|
||||
var insertStatement = Zotero.DB.getStatement(sql);
|
||||
|
||||
for each(var linkedItemID in newids) {
|
||||
insertStatement.bindInt32Parameter(0, itemID);
|
||||
insertStatement.bindInt32Parameter(1, linkedItemID);
|
||||
|
||||
try {
|
||||
insertStatement.execute();
|
||||
}
|
||||
catch (e) {
|
||||
throw (e + ' [ERROR: ' + Zotero.DB.getLastErrorString() + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Notifier.trigger('modify', 'item', removed.concat(newids));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1585,6 +1710,59 @@ Zotero.Item.prototype.save = function() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Related items
|
||||
if (this._changed.relatedItems) {
|
||||
var removed = [];
|
||||
var newids = [];
|
||||
var currentIDs = this._getRelatedItems(true);
|
||||
if (!currentIDs) {
|
||||
currentIDs = [];
|
||||
}
|
||||
|
||||
if (this._previousData && this._previousData.related) {
|
||||
for each(var id in this._previousData.related) {
|
||||
if (currentIDs.indexOf(id) == -1) {
|
||||
removed.push(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for each(var id in currentIDs) {
|
||||
if (this._previousData && this._previousData.related &&
|
||||
this._previousData.related.indexOf(id) != -1) {
|
||||
continue;
|
||||
}
|
||||
newids.push(id);
|
||||
}
|
||||
|
||||
if (removed.length) {
|
||||
var sql = "DELETE FROM itemSeeAlso WHERE itemID=? "
|
||||
+ "AND linkedItemID IN ("
|
||||
+ removed.map(function () '?').join()
|
||||
+ ")";
|
||||
Zotero.DB.query(sql, [this.id].concat(removed));
|
||||
}
|
||||
|
||||
if (newids.length) {
|
||||
var sql = "INSERT INTO itemSeeAlso (itemID, linkedItemID) VALUES (?,?)";
|
||||
var insertStatement = Zotero.DB.getStatement(sql);
|
||||
|
||||
for each(var linkedItemID in newids) {
|
||||
insertStatement.bindInt32Parameter(0, this.id);
|
||||
insertStatement.bindInt32Parameter(1, linkedItemID);
|
||||
|
||||
try {
|
||||
insertStatement.execute();
|
||||
}
|
||||
catch (e) {
|
||||
throw (e + ' [ERROR: ' + Zotero.DB.getLastErrorString() + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Notifier.trigger('modify', 'item', removed.concat(newids));
|
||||
}
|
||||
}
|
||||
|
||||
//Zotero.History.commit();
|
||||
|
@ -1625,7 +1803,6 @@ Zotero.Item.prototype.save = function() {
|
|||
|
||||
if (isNew) {
|
||||
var id = this.id;
|
||||
Zotero.debug('DISABLING ITEM');
|
||||
this._disabled = true;
|
||||
return id;
|
||||
}
|
||||
|
@ -2568,116 +2745,6 @@ Zotero.Item.prototype.removeAllTags = function() {
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods dealing with See Also links
|
||||
//
|
||||
// save() is not required for See Also functions
|
||||
//
|
||||
Zotero.Item.prototype.addSeeAlso = function(itemID) {
|
||||
if (itemID==this.id) {
|
||||
Zotero.debug('Cannot add item as See Also of itself', 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
var relatedItem = Zotero.Items.get(itemID);
|
||||
|
||||
if (!relatedItem) {
|
||||
Zotero.DB.commitTransaction();
|
||||
throw ("Cannot add invalid item " + itemID + " as See Also");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check both ways, using a UNION to take advantage of indexes
|
||||
var sql = "SELECT (SELECT COUNT(*) FROM itemSeeAlso WHERE itemID=?1 AND "
|
||||
+ "linkedItemID=?2) + (SELECT COUNT(*) FROM itemSeeAlso WHERE "
|
||||
+ "linkedItemID=?1 AND itemID=?2)";
|
||||
if (Zotero.DB.valueQuery(sql, [this.id, itemID])) {
|
||||
Zotero.DB.commitTransaction();
|
||||
Zotero.debug("Item " + itemID + " already linked", 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
var notifierData = {};
|
||||
notifierData[this.id] = { old: this.serialize() };
|
||||
notifierData[relatedItem.id] = { old: relatedItem.serialize() };
|
||||
|
||||
var sql = "INSERT INTO itemSeeAlso VALUES (?,?)";
|
||||
Zotero.DB.query(sql, [this.id, {int:itemID}]);
|
||||
Zotero.DB.commitTransaction();
|
||||
Zotero.Notifier.trigger('modify', 'item', [this.id, itemID], notifierData);
|
||||
return true;
|
||||
}
|
||||
|
||||
Zotero.Item.prototype.removeSeeAlso = function(itemID) {
|
||||
if (!this.id) {
|
||||
throw ('Cannot remove related item of unsaved item');
|
||||
}
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
var relatedItem = Zotero.Items.get(itemID);
|
||||
if (!relatedItem) {
|
||||
Zotero.DB.commitTransaction();
|
||||
throw ("Cannot remove invalid item " + itemID + " as See Also");
|
||||
return false;
|
||||
}
|
||||
|
||||
var notifierData = {};
|
||||
notifierData[this.id] = { old: this.serialize() };
|
||||
notifierData[relatedItem.id] = { old: relatedItem.serialize() };
|
||||
|
||||
var sql = "DELETE FROM itemSeeAlso WHERE itemID=? AND linkedItemID=?";
|
||||
Zotero.DB.query(sql, [this.id, itemID]);
|
||||
var sql = "DELETE FROM itemSeeAlso WHERE itemID=? AND linkedItemID=?";
|
||||
Zotero.DB.query(sql, [itemID, this.id]);
|
||||
Zotero.DB.commitTransaction();
|
||||
Zotero.Notifier.trigger('modify', 'item', [this.id, itemID], notifierData);
|
||||
}
|
||||
|
||||
Zotero.Item.prototype.removeAllRelated = function() {
|
||||
if (!this.id) {
|
||||
throw ('Cannot remove related items of unsaved item');
|
||||
}
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
var relateds = this.getSeeAlso();
|
||||
if (!relateds) {
|
||||
Zotero.DB.commitTransaction();
|
||||
return;
|
||||
}
|
||||
|
||||
var notifierData = {};
|
||||
notifierData[this.id] = { old: this.serialize() };
|
||||
|
||||
for each(var id in relateds) {
|
||||
var item = Zotero.Items.get(id);
|
||||
if (item) {
|
||||
notifierData[item.id] = { old: item.serialize() };
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.DB.query("DELETE FROM itemSeeAlso WHERE itemID=?", this.id);
|
||||
Zotero.DB.query("DELETE FROM itemSeeAlso WHERE linkedItemID=?", this.id);
|
||||
Zotero.DB.commitTransaction();
|
||||
|
||||
var ids = [this.id].concat(relateds);
|
||||
|
||||
Zotero.Notifier.trigger('modify', 'item', ids, notifierData);
|
||||
}
|
||||
|
||||
Zotero.Item.prototype.getSeeAlso = function() {
|
||||
if (!this.id) {
|
||||
return false;
|
||||
}
|
||||
// Check both ways, using a UNION to take advantage of indexes
|
||||
var sql ="SELECT linkedItemID FROM itemSeeAlso WHERE itemID=?1 UNION "
|
||||
+ "SELECT itemID FROM itemSeeAlso WHERE linkedItemID=?1";
|
||||
return Zotero.DB.columnQuery(sql, this.id);
|
||||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype.getImageSrc = function() {
|
||||
var itemType = Zotero.ItemTypes.getName(this.itemTypeID);
|
||||
if (itemType == 'attachment') {
|
||||
|
@ -2886,10 +2953,9 @@ Zotero.Item.prototype.clone = function(includePrimary) {
|
|||
}
|
||||
}
|
||||
|
||||
if (obj.seeAlso) {
|
||||
for each(var id in obj.seeAlso) {
|
||||
newItem.addSeeAlso(id)
|
||||
}
|
||||
if (obj.related) {
|
||||
// DEBUG: this will add reverse-only relateds too
|
||||
newItem.relatedItems = obj.related;
|
||||
}
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
|
@ -3017,16 +3083,16 @@ Zotero.Item.prototype.erase = function(deleteChildren) {
|
|||
Zotero.DB.query(sql);
|
||||
}
|
||||
|
||||
// Flag See Also links for notification
|
||||
var relateds = this.getSeeAlso();
|
||||
// Flag related items for notification
|
||||
var relateds = this._getRelatedItemsBidirectional();
|
||||
if (relateds) {
|
||||
for each(var id in relateds) {
|
||||
var i = Zotero.Items.get(id);
|
||||
if (!changedItemsNotifierData[i.id]) {
|
||||
changedItemsNotifierData[i.id] = { old: i.serialize() };
|
||||
var relatedItem = Zotero.Items.get(id);
|
||||
if (changedItems.indexOf(id) != -1) {
|
||||
changedItemsNotifierData[id] = { old: relatedItem.serialize() };
|
||||
changedItems.push(id);
|
||||
}
|
||||
}
|
||||
changedItems = changedItems.concat(relateds);
|
||||
}
|
||||
|
||||
// Clear fulltext cache
|
||||
|
@ -3191,7 +3257,7 @@ Zotero.Item.prototype.toArray = function (mode) {
|
|||
}
|
||||
}
|
||||
|
||||
arr.related = this.getSeeAlso();
|
||||
arr.related = this._getRelatedItemsBidirectional();
|
||||
if (!arr.related) {
|
||||
arr.related = [];
|
||||
}
|
||||
|
@ -3319,10 +3385,10 @@ Zotero.Item.prototype.serialize = function(mode) {
|
|||
}
|
||||
}
|
||||
|
||||
arr.related = this.getSeeAlso();
|
||||
if (!arr.related) {
|
||||
arr.related = [];
|
||||
}
|
||||
var related = this._getRelatedItems(true);
|
||||
var reverse = this._getRelatedItemsReverse();
|
||||
arr.related = related ? related : [];
|
||||
arr.relatedReverse = reverse ? reverse : [];
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
@ -3394,6 +3460,196 @@ Zotero.Item.prototype._loadItemData = function() {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype._loadRelatedItems = function() {
|
||||
if (!this.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._primaryDataLoaded) {
|
||||
this.loadPrimaryData(true);
|
||||
}
|
||||
|
||||
var sql = "SELECT linkedItemID FROM itemSeeAlso WHERE itemID=?";
|
||||
var ids = Zotero.DB.columnQuery(sql, this.id);
|
||||
|
||||
this._relatedItems = [];
|
||||
|
||||
if (ids) {
|
||||
for each(var id in ids) {
|
||||
this._relatedItems.push(Zotero.Items.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
this._relatedItemsLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns related items this item point to
|
||||
*
|
||||
* @param bool asIDs Return as itemIDs
|
||||
* @return array Array of itemIDs, or FALSE if none
|
||||
*/
|
||||
Zotero.Item.prototype._getRelatedItems = function (asIDs) {
|
||||
if (!this._relatedItemsLoaded) {
|
||||
this._loadRelatedItems();
|
||||
}
|
||||
|
||||
if (this._relatedItems.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return itemIDs
|
||||
if (asIDs) {
|
||||
var ids = [];
|
||||
for each(var item in this._relatedItems) {
|
||||
ids.push(item.id);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Return Zotero.Item objects
|
||||
var objs = [];
|
||||
for each(var item in this._relatedItems) {
|
||||
objs.push(item);
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns related items that point to this item
|
||||
*
|
||||
* @return array Array of itemIDs, or FALSE if none
|
||||
*/
|
||||
Zotero.Item.prototype._getRelatedItemsReverse = function () {
|
||||
if (!this.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var sql = "SELECT itemID FROM itemSeeAlso WHERE linkedItemID=?";
|
||||
return Zotero.DB.columnQuery(sql, this.id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns related items this item points to and that point to this item
|
||||
*
|
||||
* @return array|bool Array of itemIDs, or false if none
|
||||
*/
|
||||
Zotero.Item.prototype._getRelatedItemsBidirectional = function () {
|
||||
var related = this._getRelatedItems(true);
|
||||
var reverse = this._getRelatedItemsReverse();
|
||||
if (reverse) {
|
||||
if (!related) {
|
||||
return reverse;
|
||||
}
|
||||
|
||||
for each(var id in reverse) {
|
||||
if (related.indexOf(id) == -1) {
|
||||
related.push(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!related) {
|
||||
return false;
|
||||
}
|
||||
return related;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype._setRelatedItems = function (itemIDs) {
|
||||
if (!this._relatedItemsLoaded) {
|
||||
this._loadRelatedItems();
|
||||
}
|
||||
|
||||
if (itemIDs.constructor.name != 'Array') {
|
||||
throw ('ids must be an array in Zotero.Items._setRelatedItems()');
|
||||
}
|
||||
|
||||
var currentIDs = this._getRelatedItems(true);
|
||||
if (!currentIDs) {
|
||||
currentIDs = [];
|
||||
}
|
||||
var oldIDs = []; // children being kept
|
||||
var newIDs = []; // new children
|
||||
|
||||
if (itemIDs.length == 0) {
|
||||
if (currentIDs.length == 0) {
|
||||
Zotero.debug('No related items added', 4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i in itemIDs) {
|
||||
var id = itemIDs[i];
|
||||
var parsedInt = parseInt(id);
|
||||
if (parsedInt != id) {
|
||||
throw ("itemID '" + id + "' not an integer in Zotero.Item.addRelatedItem()");
|
||||
}
|
||||
id = parsedInt;
|
||||
|
||||
if (id == this.id) {
|
||||
Zotero.debug("Can't relate item to itself in Zotero.Item._setRelatedItems()", 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentIDs.indexOf(id) != -1) {
|
||||
Zotero.debug("Item " + this.id + " is already related to item " + id);
|
||||
oldIDs.push(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
var item = Zotero.Items.get(id);
|
||||
if (!item) {
|
||||
throw ("Can't relate item to invalid item " + id
|
||||
+ " in Zotero.Item._setRelatedItems()");
|
||||
}
|
||||
/*
|
||||
var otherCurrent = item.relatedItems;
|
||||
if (otherCurrent.length && otherCurrent.indexOf(this.id) != -1) {
|
||||
Zotero.debug("Other item " + id + " already related to item "
|
||||
+ this.id + " in Zotero.Item._setRelatedItems()");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
newIDs.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as changed if new or removed ids
|
||||
if (newIDs.length > 0 || oldIDs.length != currentIDs.length) {
|
||||
this._prepFieldChange('relatedItems');
|
||||
}
|
||||
else {
|
||||
Zotero.debug('Related items not changed in Zotero.Item._setRelatedItems()', 4);
|
||||
return false;
|
||||
}
|
||||
|
||||
newIDs = oldIDs.concat(newIDs);
|
||||
this._relatedItems = [];
|
||||
for each(var itemID in newIDs) {
|
||||
this._relatedItems.push(Zotero.Items.get(itemID));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// TODO: use for stuff other than related items
|
||||
Zotero.Item.prototype._prepFieldChange = function (field) {
|
||||
if (!this._changed) {
|
||||
this._changed = {};
|
||||
}
|
||||
this._changed[field] = true;
|
||||
|
||||
// Save a copy of the data before changing
|
||||
if (this.id && this.exists() && !this._previousData) {
|
||||
this._previousData = this.serialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype._generateKey = function () {
|
||||
return Zotero.ID.getKey();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
Zotero.Items = new function() {
|
||||
// Privileged methods
|
||||
this.get = get;
|
||||
this.exist = exist;
|
||||
this.getAll = getAll;
|
||||
this.getUpdated = getUpdated;
|
||||
this.add = add;
|
||||
|
@ -100,6 +101,14 @@ Zotero.Items = new function() {
|
|||
}
|
||||
|
||||
|
||||
function exist(itemIDs) {
|
||||
var sql = "SELECT itemID FROM items WHERE itemID IN ("
|
||||
+ itemIDs.map(function () '?').join() + ")";
|
||||
var exist = Zotero.DB.columnQuery(sql, itemIDs);
|
||||
return exist ? exist : [];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns all items in the database
|
||||
*
|
||||
|
|
|
@ -167,64 +167,6 @@ Zotero.Tag.prototype.getLinkedItems = function (asIDs) {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Tag.prototype._setLinkedItems = function (itemIDs) {
|
||||
if (!this._linkedItemsLoaded) {
|
||||
this._loadLinkedItems();
|
||||
}
|
||||
|
||||
if (itemIDs.constructor.name != 'Array') {
|
||||
throw ('ids must be an array in Zotero.Tag._setLinkedItems()');
|
||||
}
|
||||
|
||||
var currentIDs = this.getLinkedItems(true);
|
||||
if (!currentIDs) {
|
||||
currentIDs = [];
|
||||
}
|
||||
var oldIDs = []; // children being kept
|
||||
var newIDs = []; // new children
|
||||
|
||||
if (itemIDs.length == 0) {
|
||||
if (currentIDs.length == 0) {
|
||||
Zotero.debug('No linked items added', 4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i in itemIDs) {
|
||||
var id = parseInt(itemIDs[i]);
|
||||
if (isNaN(id)) {
|
||||
throw ("Invalid itemID '" + itemIDs[i]
|
||||
+ "' in Zotero.Tag._setLinkedItems()");
|
||||
}
|
||||
|
||||
if (currentIDs.indexOf(id) != -1) {
|
||||
Zotero.debug("Item " + itemIDs[i]
|
||||
+ " is already linked to tag " + this.id);
|
||||
oldIDs.push(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
newIDs.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as changed if new or removed ids
|
||||
if (newIDs.length > 0 || oldIDs.length != currentIDs.length) {
|
||||
this._prepFieldChange('linkedItems');
|
||||
}
|
||||
else {
|
||||
Zotero.debug('Linked items not changed in Zotero.Tag._setLinkedItems()', 4);
|
||||
return false;
|
||||
}
|
||||
|
||||
newIDs = oldIDs.concat(newIDs);
|
||||
|
||||
var items = Zotero.Items.get(itemIDs);
|
||||
this._linkedItems = items ? items : [];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Tag.prototype.addItem = function (itemID) {
|
||||
var current = this.getLinkedItems(true);
|
||||
if (current && current.indexOf(itemID) != -1) {
|
||||
|
@ -524,6 +466,64 @@ Zotero.Tag.prototype._loadLinkedItems = function() {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Tag.prototype._setLinkedItems = function (itemIDs) {
|
||||
if (!this._linkedItemsLoaded) {
|
||||
this._loadLinkedItems();
|
||||
}
|
||||
|
||||
if (itemIDs.constructor.name != 'Array') {
|
||||
throw ('ids must be an array in Zotero.Tag._setLinkedItems()');
|
||||
}
|
||||
|
||||
var currentIDs = this.getLinkedItems(true);
|
||||
if (!currentIDs) {
|
||||
currentIDs = [];
|
||||
}
|
||||
var oldIDs = []; // children being kept
|
||||
var newIDs = []; // new children
|
||||
|
||||
if (itemIDs.length == 0) {
|
||||
if (currentIDs.length == 0) {
|
||||
Zotero.debug('No linked items added', 4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i in itemIDs) {
|
||||
var id = parseInt(itemIDs[i]);
|
||||
if (isNaN(id)) {
|
||||
throw ("Invalid itemID '" + itemIDs[i]
|
||||
+ "' in Zotero.Tag._setLinkedItems()");
|
||||
}
|
||||
|
||||
if (currentIDs.indexOf(id) != -1) {
|
||||
Zotero.debug("Item " + itemIDs[i]
|
||||
+ " is already linked to tag " + this.id);
|
||||
oldIDs.push(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
newIDs.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as changed if new or removed ids
|
||||
if (newIDs.length > 0 || oldIDs.length != currentIDs.length) {
|
||||
this._prepFieldChange('linkedItems');
|
||||
}
|
||||
else {
|
||||
Zotero.debug('Linked items not changed in Zotero.Tag._setLinkedItems()', 4);
|
||||
return false;
|
||||
}
|
||||
|
||||
newIDs = oldIDs.concat(newIDs);
|
||||
|
||||
var items = Zotero.Items.get(itemIDs);
|
||||
this._linkedItems = items ? items : [];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Zotero.Tag.prototype._prepFieldChange = function (field) {
|
||||
if (!this._changed) {
|
||||
this._changed = {};
|
||||
|
|
|
@ -1067,6 +1067,7 @@ Zotero.Sync.Server.Data = new function() {
|
|||
this.buildUploadXML = buildUploadXML;
|
||||
this.itemToXML = itemToXML;
|
||||
this.xmlToItem = xmlToItem;
|
||||
this.removeMissingRelatedItems = removeMissingRelatedItems;
|
||||
this.collectionToXML = collectionToXML;
|
||||
this.xmlToCollection = xmlToCollection;
|
||||
this.creatorToXML = creatorToXML;
|
||||
|
@ -1087,6 +1088,7 @@ Zotero.Sync.Server.Data = new function() {
|
|||
}
|
||||
|
||||
var remoteCreatorStore = {};
|
||||
var relatedItemsStore = {};
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
|
@ -1100,21 +1102,23 @@ Zotero.Sync.Server.Data = new function() {
|
|||
continue;
|
||||
}
|
||||
|
||||
Zotero.debug("Processing remotely changed " + types);
|
||||
|
||||
var toSaveParents = [];
|
||||
var toSaveChildren = [];
|
||||
var toDeleteParents = [];
|
||||
var toDeleteChildren = [];
|
||||
var toReconcile = [];
|
||||
|
||||
//
|
||||
// Handle modified objects
|
||||
//
|
||||
Zotero.debug("Processing remotely changed " + types);
|
||||
|
||||
typeloop:
|
||||
for each(var xmlNode in xml[types][type]) {
|
||||
var localDelete = false;
|
||||
|
||||
// Get local object with same id
|
||||
var obj = Zotero[Types].get(parseInt(xmlNode.@id));
|
||||
|
||||
// TODO: check local deleted items for possible conflict
|
||||
|
||||
if (obj) {
|
||||
// Key match -- same item
|
||||
if (obj.key == xmlNode.@key.toString()) {
|
||||
|
@ -1130,6 +1134,24 @@ Zotero.Sync.Server.Data = new function() {
|
|||
// linked to a creator whose id changed)
|
||||
|| uploadIDs.updated[types].indexOf(obj.id) != -1) {
|
||||
|
||||
// Merge and store related items, since CR doesn't
|
||||
// affect related items
|
||||
if (type == 'item') {
|
||||
// TODO: skip conflict if only related items changed
|
||||
|
||||
var related = xmlNode.related.toString();
|
||||
related = related ? related.split(' ') : [];
|
||||
for each(var relID in obj.relatedItems) {
|
||||
if (related.indexOf(relID) == -1) {
|
||||
related.push(relID);
|
||||
}
|
||||
}
|
||||
if (related.length) {
|
||||
relatedItemsStore[obj.id] = related;
|
||||
}
|
||||
Zotero.Sync.Server.Data.removeMissingRelatedItems(xmlNode);
|
||||
}
|
||||
|
||||
var remoteObj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode);
|
||||
|
||||
// Some types we don't bother to reconcile
|
||||
|
@ -1138,24 +1160,31 @@ Zotero.Sync.Server.Data = new function() {
|
|||
Zotero.Sync.addToUpdated(uploadIDs.updated.items, obj.id);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
obj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode, obj);
|
||||
}
|
||||
|
||||
// Overwrite local below
|
||||
}
|
||||
// Mark other types for conflict resolution
|
||||
else {
|
||||
/*
|
||||
// For now, show item conflicts even if only
|
||||
// dateModified changed, since we need to handle
|
||||
// creator conflicts there
|
||||
if (type != 'item') {
|
||||
// Skip if only dateModified changed
|
||||
// Skip item if dateModified is the only modified
|
||||
// field (and no linked creators changed)
|
||||
if (type == 'item') {
|
||||
var diff = obj.diff(remoteObj, false, true);
|
||||
if (!diff) {
|
||||
continue;
|
||||
// Check if creators changed
|
||||
var creatorsChanged = false;
|
||||
var creators = obj.getCreators();
|
||||
creators = creators.concat(remoteObj.getCreators());
|
||||
for each(var creator in creators) {
|
||||
if (remoteCreatorStore[obj.id]) {
|
||||
creatorsChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!creatorsChanged) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Will be handled by item CR for now
|
||||
if (type == 'creator') {
|
||||
|
@ -1178,17 +1207,14 @@ Zotero.Sync.Server.Data = new function() {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
// Local object hasn't been modified -- overwrite
|
||||
else {
|
||||
obj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode, obj);
|
||||
}
|
||||
|
||||
// Overwrite local below
|
||||
}
|
||||
|
||||
// Key mismatch -- different objects with same id,
|
||||
// so change id of local object
|
||||
else {
|
||||
var oldID = parseInt(xmlNode.@id);
|
||||
|
||||
var newID = Zotero.ID.get(types, true);
|
||||
|
||||
Zotero.debug("Changing " + type + " " + oldID + " id to " + newID);
|
||||
|
@ -1222,6 +1248,9 @@ Zotero.Sync.Server.Data = new function() {
|
|||
// Add items linked to creators to updated array,
|
||||
// since their timestamps will be set to the
|
||||
// transaction timestamp
|
||||
//
|
||||
// Note: Don't need to change collection children or
|
||||
// related items, since they're stored as objects
|
||||
if (type == 'creator') {
|
||||
var linkedItems = obj.getLinkedItems();
|
||||
if (linkedItems) {
|
||||
|
@ -1229,22 +1258,18 @@ Zotero.Sync.Server.Data = new function() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Note: Don't need to change collection children
|
||||
// since they're stored as objects
|
||||
|
||||
uploadIDs.changed[types][oldID] = {
|
||||
oldID: oldID,
|
||||
newID: newID
|
||||
};
|
||||
|
||||
// Process new item
|
||||
obj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode);
|
||||
obj = null;
|
||||
}
|
||||
}
|
||||
// Object doesn't exist
|
||||
|
||||
// Object doesn't exist locally
|
||||
else {
|
||||
// Reconcile locally deleted objects
|
||||
// Check if object has been deleted locally
|
||||
for each(var pair in uploadIDs.deleted[types]) {
|
||||
if (pair.id != parseInt(xmlNode.@id) ||
|
||||
pair.key != xmlNode.@key.toString()) {
|
||||
|
@ -1258,24 +1283,31 @@ Zotero.Sync.Server.Data = new function() {
|
|||
throw ('Delete reconciliation unimplemented for ' + types);
|
||||
}
|
||||
|
||||
var remoteObj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode);
|
||||
|
||||
// TODO: order reconcile by parent/child?
|
||||
|
||||
toReconcile.push([
|
||||
'deleted',
|
||||
remoteObj
|
||||
]);
|
||||
|
||||
continue typeloop;
|
||||
localDelete = true;
|
||||
}
|
||||
|
||||
// Create locally
|
||||
obj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode);
|
||||
}
|
||||
|
||||
// Temporarily remove and store related items that don't yet exist
|
||||
if (type == 'item') {
|
||||
var missing = Zotero.Sync.Server.Data.removeMissingRelatedItems(xmlNode);
|
||||
if (missing.length) {
|
||||
relatedItemsStore[xmlNode.@id] = missing;
|
||||
}
|
||||
}
|
||||
|
||||
// Create or overwrite locally
|
||||
obj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode, obj);
|
||||
|
||||
if (localDelete) {
|
||||
// TODO: order reconcile by parent/child?
|
||||
|
||||
toReconcile.push([
|
||||
'deleted',
|
||||
obj
|
||||
]);
|
||||
}
|
||||
// Child items have to be saved after parent items
|
||||
if (type == 'item' && obj.getSource()) {
|
||||
else if (type == 'item' && obj.getSource()) {
|
||||
toSaveChildren.push(obj);
|
||||
}
|
||||
else {
|
||||
|
@ -1348,6 +1380,7 @@ Zotero.Sync.Server.Data = new function() {
|
|||
for each(var obj in io.dataOut) {
|
||||
// TODO: do we need to make sure item isn't already being saved?
|
||||
|
||||
// Handle items deleted during merge
|
||||
if (obj.ref == 'deleted') {
|
||||
// Deleted item was remote
|
||||
if (obj.left != 'deleted') {
|
||||
|
@ -1358,6 +1391,10 @@ Zotero.Sync.Server.Data = new function() {
|
|||
toDeleteChildren.push(obj.id);
|
||||
}
|
||||
|
||||
if (relatedItemsStore[obj.id]) {
|
||||
delete relatedItemsStore[obj.id];
|
||||
}
|
||||
|
||||
uploadIDs.deleted[types].push({
|
||||
id: obj.id,
|
||||
key: obj.left.key
|
||||
|
@ -1394,11 +1431,9 @@ Zotero.Sync.Server.Data = new function() {
|
|||
}
|
||||
}
|
||||
|
||||
// Sort collections in order of parent collections,
|
||||
// so referenced parent collections always exist when saving
|
||||
if (type == 'collection') {
|
||||
var collections = [];
|
||||
|
||||
// Sort collections in order of parent collections,
|
||||
// so referenced parent collections always exist when saving
|
||||
var cmp = function (a, b) {
|
||||
var pA = a.parent;
|
||||
var pB = b.parent;
|
||||
|
@ -1408,35 +1443,45 @@ Zotero.Sync.Server.Data = new function() {
|
|||
return (pA < pB) ? -1 : 1;
|
||||
};
|
||||
toSaveParents.sort(cmp);
|
||||
}
|
||||
|
||||
Zotero.debug('Saving merged ' + types);
|
||||
for each(var obj in toSaveParents) {
|
||||
// If collection, temporarily clear subcollections before
|
||||
// saving since referenced collections may not exist yet
|
||||
if (type == 'collection') {
|
||||
var childCollections = obj.getChildCollections(true);
|
||||
if (childCollections) {
|
||||
obj.childCollections = [];
|
||||
|
||||
// Temporarily remove and store subcollections before saving
|
||||
// since referenced collections may not exist yet
|
||||
var collections = [];
|
||||
for each(var obj in toSaveParents) {
|
||||
var colIDs = obj.getChildCollections(true);
|
||||
if (!colIDs.length) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var id = obj.save();
|
||||
|
||||
// Store subcollections
|
||||
if (type == 'collection') {
|
||||
// TODO: use exist(), like related items above
|
||||
obj.childCollections = [];
|
||||
collections.push({
|
||||
obj: obj,
|
||||
childCollections: childCollections
|
||||
childCollections: colIDs
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Save objects
|
||||
Zotero.debug('Saving merged ' + types);
|
||||
for each(var obj in toSaveParents) {
|
||||
obj.save();
|
||||
}
|
||||
for each(var obj in toSaveChildren) {
|
||||
obj.save();
|
||||
}
|
||||
|
||||
// Set subcollections
|
||||
if (type == 'collection') {
|
||||
// Add back related items (which now exist)
|
||||
if (type == 'item') {
|
||||
for (var itemID in relatedItemsStore) {
|
||||
item = Zotero.Items.get(itemID);
|
||||
for each(var id in relatedItemsStore[itemID]) {
|
||||
item.addRelatedItem(id);
|
||||
}
|
||||
item.save();
|
||||
}
|
||||
}
|
||||
// Add back subcollections
|
||||
else if (type == 'collection') {
|
||||
for each(var collection in collections) {
|
||||
if (collection.collections) {
|
||||
collection.obj.childCollections = collection.collections;
|
||||
|
@ -1631,6 +1676,11 @@ Zotero.Sync.Server.Data = new function() {
|
|||
xml.creator += newCreator;
|
||||
}
|
||||
|
||||
// Related items
|
||||
if (item.related.length) {
|
||||
xml.related = item.related.join(' ');
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
|
@ -1645,7 +1695,7 @@ Zotero.Sync.Server.Data = new function() {
|
|||
function xmlToItem(xmlItem, item, skipPrimary) {
|
||||
if (!item) {
|
||||
if (skipPrimary) {
|
||||
item = new Zotero.Item(null);
|
||||
item = new Zotero.Item;
|
||||
}
|
||||
else {
|
||||
item = new Zotero.Item(parseInt(xmlItem.@id));
|
||||
|
@ -1740,10 +1790,31 @@ Zotero.Sync.Server.Data = new function() {
|
|||
}
|
||||
}
|
||||
|
||||
// Related items
|
||||
var related = xmlItem.related.toString();
|
||||
item.relatedItems = related ? related.split(' ') : [];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
function removeMissingRelatedItems(xmlNode) {
|
||||
var missing = [];
|
||||
var related = xmlNode.related.toString();
|
||||
var relIDs = related ? related.split(' ') : [];
|
||||
if (relIDs.length) {
|
||||
var exist = Zotero.Items.exist(relIDs);
|
||||
for each(var id in relIDs) {
|
||||
if (exist.indexOf(id) == -1) {
|
||||
missing.push(id);
|
||||
}
|
||||
}
|
||||
xmlNode.related = exist.join(' ');
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
|
||||
function collectionToXML(collection) {
|
||||
var xml = <collection/>;
|
||||
|
||||
|
|
|
@ -1017,9 +1017,10 @@ Zotero.Translate.prototype._itemTagsAndSeeAlso = function(item, newItem) {
|
|||
if(item.seeAlso) {
|
||||
for each(var seeAlso in item.seeAlso) {
|
||||
if(this._IDMap[seeAlso]) {
|
||||
newItem.addSeeAlso(this._IDMap[seeAlso]);
|
||||
newItem.addRelatedItem(this._IDMap[seeAlso]);
|
||||
}
|
||||
}
|
||||
newItem.save();
|
||||
}
|
||||
if(item.tags) {
|
||||
var tagsToAdd = {};
|
||||
|
@ -1407,9 +1408,10 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
|||
if(item.seeAlso) {
|
||||
for each(var seeAlso in item.seeAlso) {
|
||||
if(this._IDMap[seeAlso]) {
|
||||
newItem.addSeeAlso(this._IDMap[seeAlso]);
|
||||
newItem.addRelatedItem(this._IDMap[seeAlso]);
|
||||
}
|
||||
}
|
||||
newItem.save();
|
||||
}
|
||||
|
||||
// handle tags, if this is an import translation or automatic tagging is
|
||||
|
|
Loading…
Add table
Reference in a new issue