- Use jsdom in node.js for unescaping HTML

- Add itemToExportFormat and itemToServerJSON utility functions
- Support asynchronous translator loading (this will only be used in node.js)
- Fix cases where Safari/Chrome code was incorrectly applied in node.js
- Add Zotero.ItemFields.getItemTypeFields() to connector cachedTypes.js
This commit is contained in:
Simon Kornblith 2011-07-08 03:42:26 +00:00
parent 167806a5bd
commit e2993b94a4
7 changed files with 303 additions and 260 deletions

View file

@ -48,7 +48,7 @@ Zotero.Connector_Types = new function() {
this[schemaType][entry.name] = entry;
}
}
}
};
/**
* Passes schema to a callback
@ -56,24 +56,24 @@ Zotero.Connector_Types = new function() {
*/
this.getSchema = function(callback) {
callback(Zotero.Connector_Types.schema);
}
};
}
Zotero.CachedTypes = function() {
this.getID = function(idOrName) {
if(!Zotero.Connector_Types[this.schemaType][idOrName]) return false;
return Zotero.Connector_Types[this.schemaType][idOrName].id;
}
};
this.getName = function(idOrName) {
if(!Zotero.Connector_Types[this.schemaType][idOrName]) return false;
return Zotero.Connector_Types[this.schemaType][idOrName].name;
}
};
this.getLocalizedString = function(idOrName) {
if(!Zotero.Connector_Types[this.schemaType][idOrName]) return false;
return Zotero.Connector_Types[this.schemaType][idOrName].localizedString;
}
};
}
Zotero.ItemTypes = new function() {
@ -90,7 +90,7 @@ Zotero.ItemTypes = new function() {
} else if(Zotero.isSafari) {
return safari.extension.baseURI+"images/itemTypes/"+Zotero.Connector_Types["itemTypes"][idOrName].icon;
}
}
};
}
Zotero.CreatorTypes = new function() {
@ -105,7 +105,7 @@ Zotero.CreatorTypes = new function() {
creatorTypes.push(Zotero.Connector_Types["creatorTypes"][itemType.creatorTypes[i]]);
}
return creatorTypes;
}
};
}
Zotero.ItemFields = new function() {
@ -119,7 +119,7 @@ Zotero.ItemFields = new function() {
return Zotero.Connector_Types["itemTypes"][typeIdOrName].fields.indexOf(
Zotero.Connector_Types["fields"][fieldIdOrName].id) !== -1;
}
};
this.getFieldIDFromTypeAndBase = function(itemType, baseField) {
if(!Zotero.Connector_Types["fields"][baseField]
@ -138,5 +138,9 @@ Zotero.ItemFields = new function() {
}
return false;
}
};
this.getItemTypeFields = function(idOrName) {
return Zotero.Connector_Types["itemTypes"][typeIdOrName].fields.slice();
};
}

View file

@ -56,120 +56,9 @@ Zotero.Translate.ItemSaver.prototype = {
* Saves items to server
*/
"_saveToServer":function(items, callback) {
const IGNORE_FIELDS = ["seeAlso", "attachments", "complete"];
var newItems = [];
for(var i in items) {
var item = items[i];
var newItem = {};
newItems.push(newItem);
var typeID = Zotero.ItemTypes.getID(item.itemType);
if(!typeID) {
Zotero.debug("Translate: Invalid itemType "+item.itemType+"; saving as webpage");
item.itemType = "webpage";
typeID = Zotero.ItemTypes.getID(item.itemType);
}
var fieldID;
for(var field in item) {
if(IGNORE_FIELDS.indexOf(field) !== -1) continue;
var val = item[field];
if(field === "itemType") {
newItem[field] = val;
} else if(field === "creators") {
// normalize creators
var newCreators = newItem.creators = [];
for(var j in val) {
var creator = val[j];
// Single-field mode
if (!creator.firstName || (creator.fieldMode && creator.fieldMode == 1)) {
var newCreator = {
name: creator.lastName
};
}
// Two-field mode
else {
var newCreator = {
firstName: creator.firstName,
lastName: creator.lastName
};
}
// ensure creatorType is present and valid
newCreator.creatorType = "author";
if(creator.creatorType) {
if(Zotero.CreatorTypes.getID(creator.creatorType)) {
newCreator.creatorType = creator.creatorType;
} else {
Zotero.debug("Translate: Invalid creator type "+creator.creatorType+"; falling back to author");
}
}
newCreators.push(newCreator);
}
} else if(field === "tags") {
// normalize tags
var newTags = newItem.tags = [];
for(var j in val) {
var tag = val[j];
if(typeof tag === "object") {
if(tag.tag) {
tag = tag.tag;
} else if(tag.name) {
tag = tag.name;
} else {
Zotero.debug("Translate: Discarded invalid tag");
continue;
}
}
newTags.push({"tag":tag.toString(), "type":1})
}
} else if(field === "notes") {
// normalize notes
var newNotes = newItem.notes = [];
for(var j in val) {
var note = val[j];
if(typeof note === "object") {
if(!note.note) {
Zotero.debug("Translate: Discarded invalid note");
continue;
}
note = note.note;
}
newNotes.push({"itemType":"note", "note":note.toString()});
}
} else if(fieldID = Zotero.ItemFields.getID(field)) {
// if content is not a string, either stringify it or delete it
if(typeof val !== "string") {
if(val || val === 0) {
val = val.toString();
} else {
continue;
}
}
// map from base field if possible
var itemFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(typeID, fieldID);
if(itemFieldID) {
newItem[Zotero.ItemFields.getName(itemFieldID)] = val;
continue; // already know this is valid
}
// if field is valid for this type, set field
if(Zotero.ItemFields.isValidForType(fieldID, typeID)) {
newItem[field] = val;
} else {
Zotero.debug("Translate: Discarded field "+field+": field not valid for type "+item.itemType, 3);
}
} else if(field !== "complete") {
Zotero.debug("Translate: Discarded unknown field "+field, 3);
}
}
newItems.push(Zotero.Utilities.itemToServerJSON(items[i]));
}
var url = 'users/%%USERID%%/items?key=%%APIKEY%%';

View file

@ -42,7 +42,7 @@ Zotero.Translators = new function() {
this.init = function(translators) {
if(!translators) {
translators = [];
if(!Zotero.isFx && localStorage["translatorMetadata"]) {
if((Zotero.isChrome || Zotero.isSafari) && localStorage["translatorMetadata"]) {
try {
translators = JSON.parse(localStorage["translatorMetadata"]);
if(typeof translators !== "object") {
@ -186,17 +186,17 @@ Zotero.Translators = new function() {
if(j === 0) {
converterFunctions.push(null);
} else if(Zotero.isFx) {
} else if(Zotero.isChrome || Zotero.isSafari) {
// in Chrome/Safari, the converterFunction needs to be passed as JSON, so
// just push an array with the proper and proxyHosts
converterFunctions.push([properHosts[j-1], proxyHosts[j-1]]);
} else {
// in Firefox, push the converterFunction
converterFunctions.push(new function() {
var re = new RegExp('^https?://(?:[^/]\\.)?'+Zotero.Utilities.quotemeta(properHosts[j-1]), "gi");
var proxyHost = proxyHosts[j-1].replace(/\$/g, "$$$$");
return function(uri) { return uri.replace(re, "$&."+proxyHost) };
});
} else {
// in Chrome/Safari, the converterFunction needs to be passed as JSON, so
// just push an array with the proper and proxyHosts
converterFunctions.push([properHosts[j-1], proxyHosts[j-1]]);
}
// don't add translator more than once
@ -244,17 +244,6 @@ Zotero.Translators = new function() {
if(reset) {
var serializedTranslators = newMetadata;
if(!Zotero.isFx) {
// clear cached translatorCode
Zotero.debug("Translators: Resetting translators");
// XXX this is only to clear localStorage for people who installed yesterday and
// should disappear soon
for(var i in localStorage) {
if(i.substr(0, TRANSLATOR_CODE_PREFIX.length) === TRANSLATOR_CODE_PREFIX) {
delete localStorage[i];
}
}
}
} else {
var serializedTranslators = [];
var hasChanged = false;
@ -300,7 +289,7 @@ Zotero.Translators = new function() {
}
// Store
if(!Zotero.isFx) {
if(Zotero.isChrome || Zotero.isSafari) {
localStorage["translatorMetadata"] = JSON.stringify(serializedTranslators);
}
@ -440,7 +429,7 @@ Zotero.Translator.prototype.init = function(info) {
}
if(info.code) {
this.code = preprocessCode(info.code);
this.code = Zotero.Translators.preprocessCode(info.code);
} else if(this.hasOwnProperty("code")) {
delete this.code;
}

View file

@ -283,48 +283,48 @@ Zotero.Translate.Sandbox = {
var sandbox;
var haveTranslatorFunction = function(translator) {
translation.translator[0] = translator;
if(!translation._loadTranslator(translator)) throw new Error("Translator could not be loaded");
if(Zotero.isFx) {
// do same origin check
var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager);
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var outerSandboxURI = ioService.newURI(typeof translate._sandboxLocation === "object" ?
translate._sandboxLocation.location : translate._sandboxLocation, null, null);
var innerSandboxURI = ioService.newURI(typeof translation._sandboxLocation === "object" ?
translation._sandboxLocation.location : translation._sandboxLocation, null, null);
Zotero.debug(outerSandboxURI.spec);
Zotero.debug(innerSandboxURI.spec);
try {
secMan.checkSameOriginURI(outerSandboxURI, innerSandboxURI, false);
} catch(e) {
throw new Error("getTranslatorObject() may not be called from web or search "+
"translators to web or search translators from different origins.");
translation._loadTranslator(translator, function() {
if(Zotero.isFx) {
// do same origin check
var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager);
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var outerSandboxURI = ioService.newURI(typeof translate._sandboxLocation === "object" ?
translate._sandboxLocation.location : translate._sandboxLocation, null, null);
var innerSandboxURI = ioService.newURI(typeof translation._sandboxLocation === "object" ?
translation._sandboxLocation.location : translation._sandboxLocation, null, null);
Zotero.debug(outerSandboxURI.spec);
Zotero.debug(innerSandboxURI.spec);
try {
secMan.checkSameOriginURI(outerSandboxURI, innerSandboxURI, false);
} catch(e) {
throw new Error("getTranslatorObject() may not be called from web or search "+
"translators to web or search translators from different origins.");
}
}
}
translation._prepareTranslation();
setDefaultHandlers(translate, translation);
sandbox = translation._sandboxManager.sandbox;
if(sandbox.Export) {
sandbox.Export.Zotero = sandbox.Zotero;
sandbox = sandbox.Export;
} else {
translate._debug("COMPAT WARNING: "+translate.translator[0].label+" does "+
"not export any properties. Only detect"+translate._entryFunctionSuffix+
" and do"+translate._entryFunctionSuffix+" will be available in "+
"connectors.");
}
if(callback) {
callback(sandbox);
translate.decrementAsyncProcesses();
}
translation._prepareTranslation();
setDefaultHandlers(translate, translation);
sandbox = translation._sandboxManager.sandbox;
if(sandbox.Export) {
sandbox.Export.Zotero = sandbox.Zotero;
sandbox = sandbox.Export;
} else {
translate._debug("COMPAT WARNING: "+translate.translator[0].label+" does "+
"not export any properties. Only detect"+translate._entryFunctionSuffix+
" and do"+translate._entryFunctionSuffix+" will be available in "+
"connectors.");
}
if(callback) {
callback(sandbox);
translate.decrementAsyncProcesses();
}
});
};
if(typeof translation.translator[0] === "object") {
@ -929,27 +929,24 @@ Zotero.Translate.Base.prototype = {
this._libraryID = libraryID;
this._saveAttachments = saveAttachments === undefined || saveAttachments;
var me = this;
if(typeof this.translator[0] === "object") {
// already have a translator object, so use it
this._translateHaveTranslator();
this._loadTranslator(this.translator[0], function() { me._translateTranslatorLoaded() });
} else {
// need to get translator first
var me = this;
Zotero.Translators.get(this.translator[0],
function(translator) {
me.translator[0] = translator;
me._translateHaveTranslator();
me._loadTranslator(translator, function() { me._translateTranslatorLoaded() });
});
}
},
/**
* Called when translator has been retrieved
* Called when translator has been retrieved and loaded
*/
"_translateHaveTranslator":function() {
// load translators
if(!this._loadTranslator(this.translator[0])) return;
"_translateTranslatorLoaded":function() {
// set display options to default if they don't exist
if(!this._displayOptions) this._displayOptions = this.translator[0].displayOptions;
@ -1091,7 +1088,7 @@ Zotero.Translate.Base.prototype = {
},
/**
* Runs detect code for a translator
* Begins running detect code for a translator, first loading it
*/
"_detect":function() {
// there won't be any translators if we need an RPC call
@ -1100,7 +1097,15 @@ Zotero.Translate.Base.prototype = {
return;
}
if(!this._loadTranslator(this._potentialTranslators[0])) return
var me = this;
this._loadTranslator(this._potentialTranslators[0],
function() { me._detectTranslatorLoaded() });
},
/**
* Runs detect code for a translator
*/
"_detectTranslatorLoaded":function() {
this._prepareDetection();
this.incrementAsyncProcesses();
@ -1130,7 +1135,7 @@ Zotero.Translate.Base.prototype = {
* @param {Zotero.Translator} translator
* @return {Boolean} Whether the translator could be successfully loaded
*/
"_loadTranslator":function(translator) {
"_loadTranslator":function(translator, callback) {
var sandboxLocation = this._getSandboxLocation();
if(!this._sandboxLocation || sandboxLocation != this._sandboxLocation) {
this._sandboxLocation = sandboxLocation;
@ -1155,10 +1160,9 @@ Zotero.Translate.Base.prototype = {
}
this.complete(false, "parse error");
return false;
}
return true;
if(callback) callback();
},
/**
@ -1494,9 +1498,13 @@ Zotero.Translate.Import.prototype.complete = function(returnValue, error) {
* Get all potential import translators, ordering translators with the right file extension first
*/
Zotero.Translate.Import.prototype._getTranslatorsGetPotentialTranslators = function() {
var me = this;
Zotero.Translators.getImportTranslatorsForLocation(this.location,
function(translators) { me._getTranslatorsTranslatorsReceived(translators) });
if(this.location) {
var me = this;
Zotero.Translators.getImportTranslatorsForLocation(this.location,
function(translators) { me._getTranslatorsTranslatorsReceived(translators) });
} else {
Zotero.Translate.Base.prototype._getTranslatorsGetPotentialTranslators.call(this);
}
}
/**
@ -1507,10 +1515,13 @@ Zotero.Translate.Import.prototype.getTranslators = function() {
if(!this._string && !this.location) {
if(this._currentState === "detect") throw new Error("getTranslators: detection is already running");
this._currentState = "detect";
this._foundTranslators = Zotero.Translators.getAllForType(this.type);
this._potentialTranslators = [];
this.complete(true);
return this._foundTranslators;
var me = this;
Zotero.Translators.getAllForType(this.type, function(translators) {
me._potentialTranslators = [];
me._foundTranslators = translators;
me.complete(true);
});
if(this._currentState === null) return this._foundTranslators;
} else {
Zotero.Translate.Base.prototype.getTranslators.call(this);
}
@ -1519,46 +1530,61 @@ Zotero.Translate.Import.prototype.getTranslators = function() {
/**
* Overload {@link Zotero.Translate.Base#_loadTranslator} to prepare translator IO
*/
Zotero.Translate.Import.prototype._loadTranslator = function(translator) {
Zotero.Translate.Import.prototype._loadTranslator = function(translator, callback) {
// call super
var returnVal = Zotero.Translate.Base.prototype._loadTranslator.call(this, translator);
if(!returnVal) return returnVal;
var me = this;
Zotero.Translate.Base.prototype._loadTranslator.call(this, translator, function() {
me._loadTranslatorPrepareIO(translator, callback);
});
}
/**
* Prepare translator IO
*/
Zotero.Translate.Import.prototype._loadTranslatorPrepareIO = function(translator, callback) {
var dataMode = (translator ? translator : this._potentialTranslators[0]).configOptions["dataMode"];
var err = false;
if(this._io) {
try {
this._io.reset(dataMode);
} catch(e) {
err = e;
var me = this;
var initCallback = function(status, err) {
if(!status) {
me.complete(false, err);
} else {
me._sandboxManager.importObject(me._io);
if(callback) callback();
}
} else {
};
var err = false;
if(!this._io) {
if(Zotero.Translate.IO.Read && this.location && this.location instanceof Components.interfaces.nsIFile) {
try {
this._io = new Zotero.Translate.IO.Read(this.location, dataMode);
this._io = new Zotero.Translate.IO.Read(this.location);
} catch(e) {
err = e;
}
} else {
try {
this._io = new Zotero.Translate.IO.String(this._string, this.path ? this.path : "", dataMode);
this._io = new Zotero.Translate.IO.String(this._string, this.path ? this.path : "");
} catch(e) {
err = e;
}
}
if(err) {
this.complete(false, err);
return;
}
}
try {
this._io.init(dataMode, initCallback);
} catch(e) {
err = e;
}
if(err) {
Zotero.debug("Translate: Preparing IO for "+translator.label+" failed: ");
Zotero.debug(err);
this.complete(false, err);
return false;
return;
}
this._sandboxManager.importObject(this._io);
return true;
}
/**
@ -1853,10 +1879,6 @@ Zotero.Translate.IO.String = function(string, uri, mode) {
}
this._stringPointer = 0;
this._uri = uri;
if(mode) {
this.reset(mode);
}
}
Zotero.Translate.IO.String.prototype = {
@ -1868,16 +1890,16 @@ Zotero.Translate.IO.String.prototype = {
"_getXML":"r"
},
"_initRDF":function() {
"_initRDF":function(callback) {
Zotero.debug("Translate: Initializing RDF data store");
this._dataStore = new Zotero.RDF.AJAW.RDFIndexedFormula();
this.RDF = new Zotero.Translate.IO._RDFSandbox(this._dataStore);
if(this._string.length) {
var parser = new Zotero.RDF.AJAW.RDFParser(this._dataStore);
parser.parse(Zotero.Translate.IO.parseDOMXML(this._string), this._uri);
callback(true);
}
this.RDF = new Zotero.Translate.IO._RDFSandbox(this._dataStore);
},
"setCharacterSet":function(charset) {},
@ -1936,12 +1958,14 @@ Zotero.Translate.IO.String.prototype = {
}
},
"reset":function(newMode) {
"init":function(newMode, callback) {
this._stringPointer = 0;
this._mode = newMode;
if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1) {
this._initRDF();
this._initRDF(callback);
} else {
callback(true);
}
},

View file

@ -325,9 +325,6 @@ Zotero.Translate.IO.Read = function(file, mode) {
}
Zotero.debug("Translate: Detected file charset as "+this._charset);
// We know the charset now. Open a converter stream.
if(mode) this.reset(mode);
}
Zotero.Translate.IO.Read.prototype = {
@ -437,7 +434,7 @@ Zotero.Translate.IO.Read.prototype = {
}
},
"reset":function(newMode) {
"init":function(newMode, callback) {
if(Zotero.Translate.IO.maintainedInstances.indexOf(this) === -1) {
Zotero.Translate.IO.maintainedInstances.push(this);
}
@ -447,6 +444,8 @@ Zotero.Translate.IO.Read.prototype = {
if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1 && !this.RDF) {
this._initRDF();
}
callback(true);
},
"close":function() {

View file

@ -664,33 +664,7 @@ Zotero.Translate.ItemGetter.prototype = {
returnItemArray.date = Zotero.Date.multipartToStr(returnItemArray.date);
}
returnItemArray.uniqueFields = {};
// get base fields, not just the type-specific ones
var itemTypeID = returnItem.itemTypeID;
var allFields = Zotero.ItemFields.getItemTypeFields(itemTypeID);
for each(var field in allFields) {
var fieldName = Zotero.ItemFields.getName(field);
if(returnItemArray[fieldName] !== undefined) {
var baseField = Zotero.ItemFields.getBaseIDFromTypeAndField(itemTypeID, field);
var baseName = null;
if(baseField && baseField != field) {
baseName = Zotero.ItemFields.getName(baseField);
}
if(baseName) {
returnItemArray[baseName] = returnItemArray[fieldName];
returnItemArray.uniqueFields[baseName] = returnItemArray[fieldName];
} else {
returnItemArray.uniqueFields[fieldName] = returnItemArray[fieldName];
}
}
}
// preserve notes
if(returnItemArray.note) returnItemArray.uniqueFields.note = returnItemArray.note;
var returnItemArray = Zotero.Utilities.itemToExportFormat(returnItemArray);
// TODO: Change tag.tag references in translators to tag.name
// once translators are 1.5-only

View file

@ -222,6 +222,17 @@ Zotero.Utilities = {
var nsISUHTML = Components.classes["@mozilla.org/feed-unescapehtml;1"]
.getService(Components.interfaces.nsIScriptableUnescapeHTML);
return nsISUHTML.unescape(str);
} else if(Zotero.isNode) {
var doc = require('jsdom').jsdom(str, null, {
"features":{
"FetchExternalResources":false,
"ProcessExternalResources":false,
"MutationEvents":false,
"QuerySelector":false
}
});
if(!doc.documentElement) return str;
return doc.documentElement.textContent;
} else {
var node = document.createElement("div");
node.innerHTML = str;
@ -796,6 +807,159 @@ Zotero.Utilities = {
dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
},
/**
* Adds all fields to an item in toArray() format and adds a unique (base) fields to
* uniqueFields array
*/
"itemToExportFormat":function(item) {
item.uniqueFields = {};
// get base fields, not just the type-specific ones
var itemTypeID = (item.itemTypeID ? item.itemTypeID : Zotero.ItemTypes.getID(item.itemType));
var allFields = Zotero.ItemFields.getItemTypeFields(itemTypeID);
for(var i in allFields) {
var field = allFields[i];
var fieldName = Zotero.ItemFields.getName(field);
if(item[fieldName] !== undefined) {
var baseField = Zotero.ItemFields.getBaseIDFromTypeAndField(itemTypeID, field);
var baseName = null;
if(baseField && baseField != field) {
baseName = Zotero.ItemFields.getName(baseField);
}
if(baseName) {
item[baseName] = item[fieldName];
item.uniqueFields[baseName] = item[fieldName];
} else {
item.uniqueFields[fieldName] = item[fieldName];
}
}
}
// preserve notes
if(item.note) item.uniqueFields.note = item.note;
return item;
},
/**
* Converts an item from toArray() format to content=json format used by the server
*/
"itemToServerJSON":function(item) {
const IGNORE_FIELDS = ["seeAlso", "attachments", "complete"];
var newItem = {};
var typeID = Zotero.ItemTypes.getID(item.itemType);
if(!typeID) {
Zotero.debug("Translate: Invalid itemType "+item.itemType+"; saving as webpage");
item.itemType = "webpage";
typeID = Zotero.ItemTypes.getID(item.itemType);
}
var fieldID;
for(var field in item) {
if(IGNORE_FIELDS.indexOf(field) !== -1) continue;
var val = item[field];
if(field === "itemType") {
newItem[field] = val;
} else if(field === "creators") {
// normalize creators
var newCreators = newItem.creators = [];
for(var j in val) {
var creator = val[j];
// Single-field mode
if (!creator.firstName || (creator.fieldMode && creator.fieldMode == 1)) {
var newCreator = {
name: creator.lastName
};
}
// Two-field mode
else {
var newCreator = {
firstName: creator.firstName,
lastName: creator.lastName
};
}
// ensure creatorType is present and valid
newCreator.creatorType = "author";
if(creator.creatorType) {
if(Zotero.CreatorTypes.getID(creator.creatorType)) {
newCreator.creatorType = creator.creatorType;
} else {
Zotero.debug("Translate: Invalid creator type "+creator.creatorType+"; falling back to author");
}
}
newCreators.push(newCreator);
}
} else if(field === "tags") {
// normalize tags
var newTags = newItem.tags = [];
for(var j in val) {
var tag = val[j];
if(typeof tag === "object") {
if(tag.tag) {
tag = tag.tag;
} else if(tag.name) {
tag = tag.name;
} else {
Zotero.debug("Translate: Discarded invalid tag");
continue;
}
}
newTags.push({"tag":tag.toString(), "type":1})
}
} else if(field === "notes") {
// normalize notes
var newNotes = newItem.notes = [];
for(var j in val) {
var note = val[j];
if(typeof note === "object") {
if(!note.note) {
Zotero.debug("Translate: Discarded invalid note");
continue;
}
note = note.note;
}
newNotes.push({"itemType":"note", "note":note.toString()});
}
} else if(fieldID = Zotero.ItemFields.getID(field)) {
// if content is not a string, either stringify it or delete it
if(typeof val !== "string") {
if(val || val === 0) {
val = val.toString();
} else {
continue;
}
}
// map from base field if possible
var itemFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(typeID, fieldID);
if(itemFieldID) {
newItem[Zotero.ItemFields.getName(itemFieldID)] = val;
continue; // already know this is valid
}
// if field is valid for this type, set field
if(Zotero.ItemFields.isValidForType(fieldID, typeID)) {
newItem[field] = val;
} else {
Zotero.debug("Translate: Discarded field "+field+": field not valid for type "+item.itemType, 3);
}
} else if(field !== "complete") {
Zotero.debug("Translate: Discarded unknown field "+field, 3);
}
}
return newItem;
}
}