www

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

commit 41db61ecb9f17b92511806f223aee5d0e5c52ec5
parent 52fd0d992dee8e4a4f3b8e786abbbf708987897c
Author: Adomas VenĨkauskas <adomas.ven@gmail.com>
Date:   Wed, 17 May 2017 17:12:05 +0300

Move citation unserialization

Using new es6 class syntax because getters/setters don't
retain `this` context with Zotero.extendClass and we're building
with at least FX45 on every platform now where the syntax is supported

Diffstat:
Mchrome/content/zotero/xpcom/integration.js | 383+++++++++++++++++++++++++++++++++++++++----------------------------------------
1 file changed, 188 insertions(+), 195 deletions(-)

diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js @@ -878,7 +878,7 @@ Zotero.Integration.Interface.prototype.setDocPrefs = Zotero.Promise.coroutine(fu let field = Zotero.Integration.Field.loadExisting(fields[i]); if (convertItems && field.type === INTEGRATION_TYPE_ITEM) { - var citation = this._session.unserializeCitation(field.code); + var citation = field.unserialize(); if (!citation.properties.dontUpdate) { fieldsToConvert.push(field); fieldNoteTypes.push(this._session.data.prefs.noteType); @@ -1121,7 +1121,7 @@ Zotero.Integration.Fields.prototype._processFields = Zotero.Promise.coroutine(fu if (field.type === INTEGRATION_TYPE_ITEM) { var noteIndex = field.getNoteIndex(); try { - yield this._session.addCitation(i, noteIndex, field.code); + yield this._session.addCitation(i, noteIndex, field.unserialize()); } catch(e) { var removeCode = false; @@ -1347,7 +1347,7 @@ Zotero.Integration.Fields.prototype.addEditCitation = Zotero.Promise.coroutine(f } try { - citation = session.unserializeCitation(field.code); + citation = field.unserialize(); } catch(e) {} if (citation) { @@ -1869,17 +1869,9 @@ Zotero.Integration._oldCitationLocatorMap = { /** * Adds a citation to the arrays representing the document */ -Zotero.Integration.Session.prototype.addCitation = Zotero.Promise.coroutine(function* (index, noteIndex, arg) { +Zotero.Integration.Session.prototype.addCitation = Zotero.Promise.coroutine(function* (index, noteIndex, citation) { var index = parseInt(index, 10); - if(typeof(arg) == "string") { // text field - if(arg == "!" || arg == "X") return; - - var citation = this.unserializeCitation(arg, index); - } else { // a citation already - var citation = arg; - } - // get items yield this.lookupItems(citation, index); @@ -2038,127 +2030,6 @@ Zotero.Integration.Session.prototype.lookupItems = Zotero.Promise.coroutine(func }); /** - * Unserializes a JSON citation into a citation object (sans items) - */ -Zotero.Integration.Session.prototype.unserializeCitation = function(code, index) { - var firstBracket = code.indexOf("{"); - if (firstBracket !== -1) { // JSON field - code = code.substr(firstBracket); - - // fix for corrupted fields - var lastBracket = code.lastIndexOf("}"); - if(lastBracket+1 != code.length) { - if(index) this.updateIndices[index] = true; - code = code.substr(0, lastBracket+1); - } - - // get JSON - try { - var citation = JSON.parse(code); - } catch(e) { - // fix for corrupted fields (corrupted by Word, somehow) - try { - var citation = JSON.parse(code.substr(0, code.length-1)); - } catch(e) { - // another fix for corrupted fields (corrupted by 2.1b1) - try { - var citation = JSON.parse(code.replace(/{{((?:\s*,?"unsorted":(?:true|false)|\s*,?"custom":"(?:(?:\\")?[^"]*\s*)*")*)}}/, "{$1}")); - } catch(e) { - throw new Zotero.Integration.CorruptFieldException(code, e); - } - } - } - - // fix for uppercase citation codes - if(citation.CITATIONITEMS) { - if(index) this.updateIndices[index] = true; - citation.citationItems = []; - for (var i=0; i<citation.CITATIONITEMS.length; i++) { - for (var j in citation.CITATIONITEMS[i]) { - switch (j) { - case 'ITEMID': - var field = 'itemID'; - break; - - // 'position', 'custom' - default: - var field = j.toLowerCase(); - } - if (!citation.citationItems[i]) { - citation.citationItems[i] = {}; - } - citation.citationItems[i][field] = citation.CITATIONITEMS[i][j]; - } - } - } - - if(!citation.properties) citation.properties = {}; - - for (let citationItem of citation.citationItems) { - // for upgrade from Zotero 2.0 or earlier - if(citationItem.locatorType) { - citationItem.label = citationItem.locatorType; - delete citationItem.locatorType; - } else if(citationItem.suppressAuthor) { - citationItem["suppress-author"] = citationItem["suppressAuthor"]; - delete citationItem.suppressAuthor; - } - - // fix for improper upgrade from Zotero 2.1 in <2.1.5 - if(parseInt(citationItem.label) == citationItem.label) { - const locatorTypeTerms = ["page", "book", "chapter", "column", "figure", "folio", - "issue", "line", "note", "opus", "paragraph", "part", "section", "sub verbo", - "volume", "verse"]; - citationItem.label = locatorTypeTerms[parseInt(citationItem.label)]; - } - - // for update from Zotero 2.1 or earlier - if(citationItem.uri) { - citationItem.uris = citationItem.uri; - delete citationItem.uri; - } - } - - // for upgrade from Zotero 2.0 or earlier - if(citation.sort) { - citation.properties.unsorted = !citation.sort; - delete citation.sort; - } - if(citation.custom) { - citation.properties.custom = citation.custom; - delete citation.custom; - } - if(!citation.citationID) citation.citationID = Zotero.randomString(); - - citation.properties.field = code; - } else { // ye olde style field - var underscoreIndex = code.indexOf("_"); - var itemIDs = code.substr(0, underscoreIndex).split("|"); - - var lastIndex = code.lastIndexOf("_"); - if(lastIndex != underscoreIndex+1) { - var locatorString = code.substr(underscoreIndex+1, lastIndex-underscoreIndex-1); - var locators = locatorString.split("|"); - } - - var citationItems = new Array(); - for(var i=0; i<itemIDs.length; i++) { - var citationItem = {id:itemIDs[i]}; - if(locators) { - citationItem.locator = locators[i].substr(1); - citationItem.label = Zotero.Integration._oldCitationLocatorMap[locators[i][0]]; - } - citationItems.push(citationItem); - } - - var citation = {"citationItems":citationItems, properties:{}}; - if(index) this.updateIndices[index] = true; - } - - return citation; -} - -/** * Gets integration bibliography */ Zotero.Integration.Session.prototype.getBibliography = function() { @@ -2821,24 +2692,60 @@ Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = Zotero.Promise.corout return [zoteroItem, needUpdate]; }); -Zotero.Integration.Field = function(field) { - this.dirty = false; - this._field = field; - this.type = INTEGRATION_TYPE_TEMP; - - return new Proxy(this, Zotero.Integration.Field.proxyHandler); -}; -// Proxy properties through to the integration field -Zotero.Integration.Field.proxyHandler = { - get: function(target, name) { - if (name in target) { - return target[name]; +Zotero.Integration.Field = class { + constructor(field) { + // This is not the best solution in terms of performance + for (let prop in field) { + if (!(prop in this)) this[prop] = field[prop]; } - return target._field[name]; + this.dirty = false; + this._field = field; + this.type = INTEGRATION_TYPE_TEMP; } -}; + + get text() {return this._text = this._text ? this._text : this.getText()} + set text(v) {return this._text = v; this.dirty = true} + get code() {return this._code = this._code ? this._code : this.getCode()} + set code(v) {return this._code = v; this.dirty = true} + + clearCode() { + this.code = '{}'; + }; + + writeToDoc(doc) { + let text = this._text; + let isRich = false; + // If RTF wrap with RTF tags + if (text.indexOf("\\") !== -1) { + text = "{\\rtf "+text+"}"; + isRich = true; + } + this._field.setText(text, isRich); + + // Boo. Inconsistent. + if (this.type == INTEGRATION_TYPE_ITEM) { + this._field.setCode(`ITEM CSL_CITATION ${JSON.stringify(this.code)}`); + } else if (this.type == INTEGRATION_TYPE_BIBLIOGRAPHY) { + this._field.setCode(`BIBL ${this.code} CSL_BIBLIOGRAPHY`); + } + this.dirty = false; + + // Retrigger retrieval from doc. + this._text = null; + this._code = null; + }; + + getCode() { + let code = this._field.getCode(); + let start = code.indexOf('{'); + if (start == -1) { + return '{}'; + } + return code.substr(start, start + code.indexOf('}')); + }; +}; /** * Load existing field in document and return correct instance of field type @@ -2878,64 +2785,150 @@ Zotero.Integration.Field.loadExisting = function(docField) { return field; }; -Zotero.defineProperty(Zotero.Integration.Field.prototype, 'text', { - get: () => this._text = this._text ? this._text : this.getText(), - set: (v) => {this._text = v; this.dirty = true} -}); +Zotero.Integration.CitationField = class extends Zotero.Integration.Field { + constructor(field) { + super(field); + this.type = INTEGRATION_TYPE_ITEM; + } + + /** + * Don't be fooled, this should be as simple as JSON.parse(). + * The schema for the code is defined @ https://raw.githubusercontent.com/citation-style-language/schema/master/csl-citation.json + * + * However, over the years and different versions of Zotero there's been changes to the schema, + * incorrect serialization, etc. Therefore this function is cruft-full and we can't get rid of it. + * + * @returns {{citationItems: Object[], properties: Object}} + */ + unserialize() { + function unserialize(code) { + try { + return JSON.parse(code); + } catch(e) { + // fix for corrupted fields (corrupted by 2.1b1) + try { + return JSON.parse(code.replace(/{{((?:\s*,?"unsorted":(?:true|false)|\s*,?"custom":"(?:(?:\\")?[^"]*\s*)*")*)}}/, "{$1}")); + } catch(e) { + throw new Zotero.Integration.CorruptFieldException(code, e); + } + } + } + + function upgradeCruft(citation, code) { + // fix for uppercase citation codes + if(citation.CITATIONITEMS) { + citation.citationItems = []; + for (var i=0; i<citation.CITATIONITEMS.length; i++) { + for (var j in citation.CITATIONITEMS[i]) { + switch (j) { + case 'ITEMID': + var field = 'itemID'; + break; -Zotero.defineProperty(Zotero.Integration.Field.prototype, 'code', { - get: () => this._code = this._code ? this._code : this.getCode(), - set: (v) => {this._code = v; this.dirty = true;} -}); + // 'position', 'custom' + default: + var field = j.toLowerCase(); + } + if (!citation.citationItems[i]) { + citation.citationItems[i] = {}; + } + citation.citationItems[i][field] = citation.CITATIONITEMS[i][j]; + } + } + } -Zotero.Integration.Field.prototype = { - writeToDoc: function(doc) { - this.dirty = false; + if(!citation.properties) citation.properties = {}; - let text = this._text; - let isRich = false; - // If RTF wrap with RTF tags - if (text.indexOf("\\") !== -1) { - text = "{\\rtf "+text+"}"; - isRich = true; - } - this._field.setText(text, isRich); + for (let citationItem of citation.citationItems) { + // for upgrade from Zotero 2.0 or earlier + if(citationItem.locatorType) { + citationItem.label = citationItem.locatorType; + delete citationItem.locatorType; + } else if(citationItem.suppressAuthor) { + citationItem["suppress-author"] = citationItem["suppressAuthor"]; + delete citationItem.suppressAuthor; + } - // Boo. Inconsistent. - if (this.type == INTEGRATION_TYPE_ITEM) { - this._field.setCode(`ITEM CSL_CITATION ${JSON.stringify(this._data)}`); - } else if (this.type == INTEGRATION_TYPE_BIBLIOGRAPHY) { - this._field.setCode(`BIBL ${JSON.stringify(this._data)} CSL_BIBLIOGRAPHY`); - } + // fix for improper upgrade from Zotero 2.1 in <2.1.5 + if(parseInt(citationItem.label) == citationItem.label) { + const locatorTypeTerms = ["page", "book", "chapter", "column", "figure", "folio", + "issue", "line", "note", "opus", "paragraph", "part", "section", "sub verbo", + "volume", "verse"]; + citationItem.label = locatorTypeTerms[parseInt(citationItem.label)]; + } - // Retrigger retrieval from doc. - this._text = null; - this._code = null; - }, - - getCode: function() { - let code = this._field.getCode(); - let start = code.indexOf('{'); - if (start == -1) { - return '{}'; + // for update from Zotero 2.1 or earlier + if(citationItem.uri) { + citationItem.uris = citationItem.uri; + delete citationItem.uri; + } + } + + // for upgrade from Zotero 2.0 or earlier + if(citation.sort) { + citation.properties.unsorted = !citation.sort; + delete citation.sort; + } + if(citation.custom) { + citation.properties.custom = citation.custom; + delete citation.custom; + } + if(!citation.citationID) citation.citationID = Zotero.randomString(); + + citation.properties.field = code; + return citation; } - return code.substr(start, start + code.indexOf('}')); - } -}; + + function unserializePreZotero1_0(code) { + var underscoreIndex = code.indexOf("_"); + var itemIDs = code.substr(0, underscoreIndex).split("|"); + + var lastIndex = code.lastIndexOf("_"); + if(lastIndex != underscoreIndex+1) { + var locatorString = code.substr(underscoreIndex+1, lastIndex-underscoreIndex-1); + var locators = locatorString.split("|"); + } + var citationItems = new Array(); + for(var i=0; i<itemIDs.length; i++) { + var citationItem = {id:itemIDs[i]}; + if(locators) { + citationItem.locator = locators[i].substr(1); + citationItem.label = Zotero.Integration._oldCitationLocatorMap[locators[i][0]]; + } + citationItems.push(citationItem); + } -Zotero.Integration.CitationField = function(field) { - Zotero.Integration.Field.call(this, field); - this.type = INTEGRATION_TYPE_ITEM; + return {"citationItems":citationItems, properties:{}}; + } + - return new Proxy(this, Zotero.Integration.Field.proxyHandler); + if (this.code[0] == '{') { // JSON field + return upgradeCruft(unserialize(this.code), this.code); + } else { // ye olde style field + return unserializePreZotero1_0(this.code); + } + }; + + clearCode() { + this.code = JSON.stringify({citationItems: [], properties: {}}); + this.writeToDoc(); + } }; -Zotero.extendClass(Zotero.Integration.Field, Zotero.Integration.CitationField); -Zotero.Integration.BibliographyField = function(field) { - Zotero.Integration.Field.call(this, field); - this.type = INTEGRATION_TYPE_BIBLIOGRAPHY; - return new Proxy(this, Zotero.Integration.Field.proxyHandler); +Zotero.Integration.BibliographyField = class extends Zotero.Integration.Field { + constructor(field) { + super(field); + this.type = INTEGRATION_TYPE_BIBLIOGRAPHY; + this.type = INTEGRATION_TYPE_ITEM; + }; + + unserialize() { + try { + return JSON.parse(this.code); + } catch(e) { + throw new Zotero.Integration.CorruptFieldException(this.code, e); + } + } }; -Zotero.extendClass(Zotero.Integration.Field, Zotero.Integration.BibliographyField);