www

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

commit 9259bfd49af1c1d776f68a0401884fb7b35903dd
parent 395d596105a55823bf584c08839833f100d5507e
Author: Dan Stillman <dstillman@zotero.org>
Date:   Tue, 24 Feb 2015 23:45:42 -0500

Merge pull request #626 from aurimasv/isbn-import

Tweaks to ISBN handling
Diffstat:
Mchrome/content/zotero/xpcom/cite.js | 100++++++++-----------------------------------------------------------------------
Mchrome/content/zotero/xpcom/data/item.js | 18++++++++++++++++++
Achrome/content/zotero/xpcom/isbn.js | 11+++++++++++
Mchrome/content/zotero/xpcom/translation/translate.js | 26++++++++++++++++++++++++++
Mchrome/content/zotero/xpcom/utilities.js | 147++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mchrome/content/zotero/xpcom/utilities_internal.js | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcomponents/zotero-service.js | 1+
7 files changed, 233 insertions(+), 144 deletions(-)

diff --git a/chrome/content/zotero/xpcom/cite.js b/chrome/content/zotero/xpcom/cite.js @@ -522,100 +522,20 @@ Zotero.Cite.System.prototype = { throw "Zotero.Cite.System.retrieveItem called on non-item "+item; } - // don't return URL or accessed information for journal articles if a - // pages field exists - var itemType = Zotero.ItemTypes.getName(zoteroItem.itemTypeID); - var cslType = CSL_TYPE_MAPPINGS[itemType]; - if(!cslType) cslType = "article"; - var ignoreURL = ((zoteroItem.getField("accessDate", true, true) || zoteroItem.getField("url", true, true)) && - ["journalArticle", "newspaperArticle", "magazineArticle"].indexOf(itemType) !== -1 - && zoteroItem.getField("pages") - && !Zotero.Prefs.get("export.citePaperJournalArticleURL")); - - var cslItem = { - 'id':zoteroItem.id, - 'type':cslType - }; + var cslItem = Zotero.Utilities.itemToCSLJSON(zoteroItem); - // get all text variables (there must be a better way) - // TODO: does citeproc-js permit short forms? - for(var variable in CSL_TEXT_MAPPINGS) { - var fields = CSL_TEXT_MAPPINGS[variable]; - if(variable == "URL" && ignoreURL) continue; - for each(var field in fields) { - var value = zoteroItem.getField(field, false, true).toString(); - if(value != "") { - // Strip enclosing quotes - if(value.match(/^".+"$/)) { - value = value.substr(1, value.length-2); - } - cslItem[variable] = value; - break; - } - } - } - - // separate name variables - var authorID = Zotero.CreatorTypes.getPrimaryIDForType(zoteroItem.itemTypeID); - var creators = zoteroItem.getCreators(); - for each(var creator in creators) { - if(creator.creatorTypeID == authorID) { - var creatorType = "author"; - } else { - var creatorType = Zotero.CreatorTypes.getName(creator.creatorTypeID); - } - - var creatorType = CSL_NAMES_MAPPINGS[creatorType]; - if(!creatorType) continue; - - var nameObj = {'family':creator.ref.lastName, 'given':creator.ref.firstName}; - - if(cslItem[creatorType]) { - cslItem[creatorType].push(nameObj); - } else { - cslItem[creatorType] = [nameObj]; - } - } - - // get date variables - for(var variable in CSL_DATE_MAPPINGS) { - var date = zoteroItem.getField(CSL_DATE_MAPPINGS[variable], false, true); - if(date) { - var dateObj = Zotero.Date.strToDate(date); - // otherwise, use date-parts - var dateParts = []; - if(dateObj.year) { - // add year, month, and day, if they exist - dateParts.push(dateObj.year); - if(dateObj.month !== undefined) { - dateParts.push(dateObj.month+1); - if(dateObj.day) { - dateParts.push(dateObj.day); - } - } - cslItem[variable] = {"date-parts":[dateParts]}; - - // if no month, use season as month - if(dateObj.part && !dateObj.month) { - cslItem[variable].season = dateObj.part; - } - } else { - // if no year, pass date literally - cslItem[variable] = {"literal":date}; - } + if (!Zotero.Prefs.get("export.citePaperJournalArticleURL")) { + var itemType = Zotero.ItemTypes.getName(zoteroItem.itemTypeID); + // don't return URL or accessed information for journal articles if a + // pages field exists + if (["journalArticle", "newspaperArticle", "magazineArticle"].indexOf(itemType) !== -1 + && zoteroItem.getField("pages") + ) { + delete cslItem.URL; + delete cslItem.accessed; } } - - // extract PMID - var extra = zoteroItem.getField("extra", false, true); - if(typeof extra === "string") { - var m = /(?:^|\n)PMID:\s*([0-9]+)/.exec(extra); - if(m) cslItem.PMID = m[1]; - m = /(?:^|\n)PMCID:\s*((?:PMC)?[0-9]+)/.exec(extra); - if(m) cslItem.PMCID = m[1]; - } - //this._cache[zoteroItem.id] = cslItem; return cslItem; }, diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js @@ -821,6 +821,24 @@ Zotero.Item.prototype.setField = function(field, value, loadIn) { value = value.replace(/[\r\n]+/g, " ");; } + if (fieldID == Zotero.ItemFields.getID('ISBN')) { + // Hyphenate ISBNs, but only if everything is in expected format and valid + let isbns = ('' + value).trim().split(/\s*[,;]\s*|\s+/), + newISBNs = '', + failed = false; + for (let i=0; i<isbns.length; i++) { + let isbn = Zotero.Utilities.Internal.hyphenateISBN(isbns[i]); + if (!isbn) { + failed = true; + break; + } + + newISBNs += ' ' + isbn; + } + + if (!failed) value = newISBNs.substr(1); + } + if (!loadIn) { // Save date field as multipart date // TEMP - filingDate diff --git a/chrome/content/zotero/xpcom/isbn.js b/chrome/content/zotero/xpcom/isbn.js @@ -0,0 +1,11 @@ +/** THIS FILE WAS GENERATED AUTOMATICALLY **/ + +/** + * ISBN Registrant ranges from https://www.isbn-international.org/range_file_generation +**/ +Zotero.ISBN = {}; +Zotero.ISBN.ranges = (function() { + var ranges = {"978":{"0":["00","19","200","699","7000","8499","85000","89999","900000","949999","9500000","9999999"],"1":["00","09","100","329","330","399","4000","5499","55000","86979","869800","998999","9990000","9999999"],"2":["00","19","200","349","400","699","7000","8399","35000","39999","84000","89999","900000","949999","9500000","9999999"],"3":["00","02","04","19","030","033","200","699","0340","0369","7000","8499","03700","03999","85000","89999","95400","96999","99000","99499","99500","99999","900000","949999","9500000","9539999","9700000","9899999"],"5":["01","19","200","420","430","430","440","440","450","699","0050","0099","4210","4299","4310","4399","4410","4499","7000","8499","9200","9299","9501","9799","9910","9999","00000","00499","85000","89999","91000","91999","93000","94999","98000","98999","900000","909999","9500000","9500999","9900000","9909999"],"600":["00","09","100","499","5000","8999","90000","99999"],"601":["00","19","85","99","200","699","7000","7999","80000","84999"],"602":["00","07","200","699","0800","0899","0900","1099","1100","1199","1200","1399","1500","1699","7500","7999","8000","9499","14000","14999","17000","17999","18000","18999","19000","19999","70000","74999","95000","99999"],"603":["00","04","05","49","500","799","8000","8999","90000","99999"],"604":["0","4","50","89","900","979","9800","9999"],"605":["01","02","04","09","030","039","100","399","4000","5999","9000","9999","60000","89999"],"606":["0","0","10","49","500","799","8000","9199","92000","99999"],"607":["00","39","400","749","7500","9499","95000","99999"],"608":["0","0","7","9","10","19","200","449","4500","6499","65000","69999"],"609":["00","39","400","799","8000","9499","95000","99999"],"612":["00","29","50","99","300","399","4000","4499","45000","49999"],"613":["0","9"],"615":["00","09","100","499","5000","7999","80000","89999"],"616":["00","19","200","699","7000","8999","90000","99999"],"617":["00","49","500","699","7000","8999","90000","99999"],"618":["00","19","200","499","5000","7999","80000","99999"],"619":["00","14","150","699","7000","8999","90000","99999"],"621":["00","29","400","599","8000","8999","95000","99999"],"7":["00","09","100","499","5000","7999","80000","89999","900000","999999"],"80":["00","19","200","699","7000","8499","85000","89999","900000","999999"],"82":["00","19","200","689","7000","8999","90000","98999","690000","699999","990000","999999"],"83":["00","19","200","599","7000","8499","60000","69999","85000","89999","900000","999999"],"84":["00","13","140","149","200","699","7000","8499","9000","9199","9700","9999","15000","19999","85000","89999","92400","92999","95000","96999","920000","923999","930000","949999"],"85":["00","19","200","549","5500","5999","7000","8499","60000","69999","85000","89999","98000","99999","900000","979999"],"86":["00","29","300","599","6000","7999","80000","89999","900000","999999"],"87":["00","29","400","649","7000","7999","85000","94999","970000","999999"],"88":["00","19","200","599","910","929","6000","8499","9300","9399","85000","89999","95000","99999","900000","909999","940000","949999"],"89":["00","24","250","549","990","999","5500","8499","85000","94999","97000","98999","950000","969999"],"90":["00","19","90","90","94","94","200","499","5000","6999","8500","8999","70000","79999","800000","849999"],"91":["0","1","20","49","500","649","7000","7999","85000","94999","970000","999999"],"92":["0","5","60","79","800","899","9000","9499","95000","98999","990000","999999"],"93":["00","09","100","499","5000","7999","80000","94999","950000","999999"],"94":["000","599","6000","8999","90000","99999"],"950":["00","49","500","899","9000","9899","99000","99999"],"951":["0","1","20","54","550","889","8900","9499","95000","99999"],"952":["00","19","60","65","80","94","200","499","5000","5999","6600","6699","7000","7999","9500","9899","67000","69999","99000","99999"],"953":["0","0","10","14","51","54","150","509","6000","9499","55000","59999","95000","99999"],"954":["00","28","300","799","2900","2999","8000","8999","9300","9999","90000","92999"],"955":["20","40","550","749","0000","1999","4500","4999","7500","7999","8000","9499","41000","43999","44000","44999","50000","54999","95000","99999"],"956":["00","19","200","699","7000","9999"],"957":["00","02","05","19","21","27","31","43","440","819","0300","0499","2000","2099","8200","9699","28000","30999","97000","99999"],"958":["00","56","600","799","8000","9499","57000","59999","95000","99999"],"959":["00","19","200","699","7000","8499","85000","99999"],"960":["00","19","93","93","200","659","690","699","6600","6899","7000","8499","9400","9799","85000","92999","98000","99999"],"961":["00","19","200","599","6000","8999","90000","94999"],"962":["00","19","200","699","900","999","7000","8499","8700","8999","85000","86999"],"963":["00","19","200","699","7000","8499","9000","9999","85000","89999"],"964":["00","14","150","249","300","549","970","989","2500","2999","5500","8999","9900","9999","90000","96999"],"965":["00","19","200","599","7000","7999","90000","99999"],"966":["00","12","14","14","130","139","170","199","279","289","300","699","910","949","980","999","1500","1699","2000","2789","2900","2999","7000","8999","90000","90999","95000","97999"],"967":["00","00","60","89","300","499","900","989","0100","0999","5000","5999","9900","9989","10000","19999","99900","99999"],"968":["01","39","400","499","800","899","5000","7999","9000","9999"],"969":["0","1","20","22","24","39","400","749","7500","9999","23000","23999"],"970":["01","59","600","899","9000","9099","9700","9999","91000","96999"],"971":["02","02","06","49","97","98","000","015","500","849","0160","0199","0300","0599","8500","9099","9600","9699","9900","9999","91000","95999"],"972":["0","1","20","54","550","799","8000","9499","95000","99999"],"973":["0","0","20","54","100","169","550","759","1700","1999","7600","8499","8900","9499","85000","88999","95000","99999"],"974":["00","19","200","699","7000","8499","9500","9999","85000","89999","90000","94999"],"975":["02","24","250","599","990","999","6000","9199","00000","01999","92000","98999"],"976":["0","3","40","59","600","799","8000","9499","95000","99999"],"977":["00","19","90","99","200","499","700","849","5000","6999","85000","89999"],"978":["000","199","900","999","2000","2999","8000","8999","30000","79999"],"979":["20","29","000","099","400","799","1000","1499","3000","3999","8000","9499","15000","19999","95000","99999"],"980":["00","19","200","599","6000","9999"],"981":["00","11","200","289","290","299","310","399","3000","3099","4000","9999","17000","19999"],"982":["00","09","70","89","100","699","9000","9799","98000","99999"],"983":["00","01","45","49","50","79","020","199","800","899","2000","3999","9000","9899","40000","44999","99000","99999"],"984":["00","39","400","799","8000","8999","90000","99999"],"985":["00","39","400","599","6000","8999","90000","99999"],"986":["00","11","120","559","5600","7999","80000","99999"],"987":["00","09","30","35","40","44","500","899","1000","1999","3600","3999","9000","9499","20000","29999","45000","49999","95000","99999"],"988":["00","11","200","799","8000","9699","12000","14999","15000","16999","17000","19999","97000","99999"],"9925":["0","2","30","54","550","734","7350","9999"],"9926":["0","1","20","39","400","799","8000","9999"],"9927":["00","09","100","399","4000","4999"],"9929":["0","3","40","54","550","799","8000","9999"],"9930":["00","49","500","939","9400","9999"],"9931":["00","29","300","899","9000","9999"],"9932":["00","39","400","849","8500","9999"],"9933":["0","0","10","39","400","899","9000","9999"],"9934":["0","0","10","49","500","799","8000","9999"],"9937":["0","2","30","49","500","799","8000","9999"],"9938":["00","79","800","949","9500","9999"],"9939":["0","4","50","79","800","899","9000","9999"],"9940":["0","1","20","49","500","899","9000","9999"],"9942":["00","84","900","984","8500","8999","9850","9999"],"9943":["00","29","300","399","975","999","4000","9749"],"9944":["60","69","80","89","100","499","700","799","900","999","0000","0999","5000","5999"],"9945":["00","00","08","39","57","57","010","079","400","569","580","849","8500","9999"],"9946":["0","1","20","39","400","899","9000","9999"],"9947":["0","1","20","79","800","999"],"9949":["0","0","10","39","75","89","400","749","9000","9999"],"9950":["00","29","300","849","8500","9999"],"9953":["0","0","10","39","60","89","400","599","9000","9999"],"9955":["00","39","400","929","9300","9999"],"9957":["00","39","70","84","88","99","400","699","8500","8799"],"9958":["00","01","10","18","20","49","020","029","040","089","500","899","0300","0399","0900","0999","1900","1999","9000","9999"],"9959":["0","1","20","79","98","99","800","949","970","979","9500","9699"],"9960":["00","59","600","899","9000","9999"],"9961":["0","2","30","69","700","949","9500","9999"],"9962":["00","54","56","59","600","849","5500","5599","8500","9999"],"9963":["0","1","30","54","250","279","550","734","2000","2499","2800","2999","7350","7499","7500","9999"],"9964":["0","6","70","94","950","999"],"9965":["00","39","400","899","9000","9999"],"9966":["20","69","000","149","750","959","1500","1999","7000","7499","9600","9999"],"9971":["0","5","60","89","900","989","9900","9999"],"9972":["1","1","00","09","30","59","200","249","600","899","2500","2999","9000","9999"],"9973":["00","05","10","69","060","089","700","969","0900","0999","9700","9999"],"9974":["0","2","30","54","95","99","550","749","7500","9499"],"9975":["0","0","45","89","100","299","900","949","3000","3999","4000","4499","9500","9999"],"9977":["00","89","900","989","9900","9999"],"9978":["00","29","40","94","300","399","950","989","9900","9999"],"9979":["0","4","50","64","66","75","650","659","760","899","9000","9999"],"9980":["0","3","40","89","900","989","9900","9999"],"9981":["00","09","20","79","100","159","800","949","1600","1999","9500","9999"],"9982":["00","79","800","989","9900","9999"],"9983":["80","94","950","989","9900","9999"],"9984":["00","49","500","899","9000","9999"],"9986":["00","39","97","99","400","899","940","969","9000","9399"],"9987":["00","39","400","879","8800","9999"],"9988":["0","2","30","54","550","749","7500","9999"],"9989":["0","0","30","59","100","199","600","949","2000","2999","9500","9999"],"99901":["00","49","80","99","500","799"],"99903":["0","1","20","89","900","999"],"99904":["0","5","60","89","900","999"],"99905":["0","3","40","79","800","999"],"99906":["0","2","30","59","70","89","90","94","600","699","950","999"],"99908":["0","0","10","89","900","999"],"99909":["0","3","40","94","950","999"],"99910":["0","2","30","89","900","999"],"99911":["00","59","600","999"],"99912":["0","3","60","89","400","599","900","999"],"99913":["0","2","30","35","600","604"],"99914":["0","4","50","89","900","999"],"99915":["0","4","50","79","800","999"],"99916":["0","2","30","69","700","999"],"99919":["0","2","40","69","70","79","300","399","800","849","850","899","900","999"],"99921":["0","1","8","8","20","69","90","99","700","799"],"99922":["0","3","40","69","700","999"],"99926":["0","0","10","59","87","89","90","99","600","869"],"99927":["0","2","30","59","600","999"],"99928":["0","0","10","79","800","999"],"99932":["0","0","7","7","10","59","80","99","600","699"],"99935":["0","2","7","8","30","59","90","99","600","699"],"99936":["0","0","10","59","600","999"],"99937":["0","1","20","59","600","999"],"99938":["0","1","20","59","90","99","600","899"],"99940":["0","0","10","69","700","999"],"99941":["0","2","30","79","800","999"],"99953":["0","2","30","79","94","99","800","939"],"99954":["0","2","30","69","88","99","700","879"],"99955":["0","1","20","59","80","99","600","799"],"99956":["00","59","86","99","600","859"],"99958":["0","4","50","93","940","949","950","999"],"99960":["0","0","10","94","950","999"],"99961":["0","3","40","89","900","999"],"99963":["00","49","92","99","500","919"],"99966":["0","2","30","69","80","94","700","799"],"99967":["0","1","20","59","600","899"],"99971":["0","5","60","84","850","999"],"99974":["40","79","800","999"],"99976":["0","1","20","59","600","799"]},"979":{"10":["00","19","200","699","7000","8999","90000","97599","976000","999999"],"11":["00","24","250","549","5500","8499","85000","94999","950000","999999"],"12":["200","200"]}}; + ranges['978']['99968']=ranges['978']['99912'];ranges['978']['9935']=ranges['978']['9941']=ranges['978']['9956']=ranges['978']['9933'];ranges['978']['9976']=ranges['978']['9971'];ranges['978']['99949']=ranges['978']['99903'];ranges['978']['9968']=ranges['978']['9930'];ranges['978']['99929']=ranges['978']['99930']=ranges['978']['99931']=ranges['978']['99942']=ranges['978']['99944']=ranges['978']['99948']=ranges['978']['99950']=ranges['978']['99952']=ranges['978']['99962']=ranges['978']['99969']=ranges['978']['99915'];ranges['978']['99917']=ranges['978']['99910'];ranges['978']['99920']=ranges['978']['99970']=ranges['978']['99972']=ranges['978']['99914'];ranges['978']['99933']=ranges['978']['99943']=ranges['978']['99946']=ranges['978']['99959']=ranges['978']['99927'];ranges['978']['81']=ranges['978']['80'];ranges['978']['9967']=ranges['978']['9970']=ranges['978']['9965'];ranges['978']['9936']=ranges['978']['9952']=ranges['978']['9954']=ranges['978']['9926'];ranges['978']['99965']=ranges['978']['99922'];ranges['978']['9928']=ranges['978']['9927'];ranges['978']['99947']=ranges['978']['99916'];ranges['978']['9985']=ranges['978']['9939'];ranges['978']['99918']=ranges['978']['99925']=ranges['978']['99973']=ranges['978']['99975']=ranges['978']['99905'];ranges['978']['99939']=ranges['978']['99945']=ranges['978']['99904'];ranges['978']['989']=ranges['978']['972'];ranges['978']['620']=ranges['978']['613'];ranges['978']['4']=ranges['978']['0'];ranges['978']['99923']=ranges['978']['99924']=ranges['978']['99934']=ranges['978']['99957']=ranges['978']['99964']=ranges['978']['9947'];ranges['978']['614']=ranges['978']['609'];ranges['978']['9948']=ranges['978']['9951']=ranges['978']['9932']; + return ranges; +})(); diff --git a/chrome/content/zotero/xpcom/translation/translate.js b/chrome/content/zotero/xpcom/translation/translate.js @@ -616,6 +616,32 @@ Zotero.Translate.Sandbox = { if(setShortTitle) item.shortTitle = title; } + /* Clean up ISBNs + * Allow multiple ISBNs, but... + * (1) validate all ISBNs + * (2) convert all ISBNs to ISBN-13 + * (3) remove any duplicates + * (4) separate them with space + */ + if (item.ISBN) { + // Match ISBNs with groups separated by various dashes or even spaces + var isbnRe = /\b(?:97[89][\s\x2D\xAD\u2010-\u2015\u2043\u2212]*)?(?:\d[\s\x2D\xAD\u2010-\u2015\u2043\u2212]*){9}[\dx](?![\x2D\xAD\u2010-\u2015\u2043\u2212])\b/gi, + validISBNs = [], + isbn; + while (isbn = isbnRe.exec(item.ISBN)) { + var validISBN = Zotero.Utilities.cleanISBN(isbn[0]); + if (!validISBN) { + // Back up and move up one character + isbnRe.lastIndex = isbn.index + 1; + continue; + } + + var isbn13 = Zotero.Utilities.toISBN13(validISBN); + if (validISBNs.indexOf(isbn13) == -1) validISBNs.push(isbn13); + } + item.ISBN = validISBNs.join(' '); + } + // refuse to save very long tags if(item.tags) { for(var i=0; i<item.tags.length; i++) { diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js @@ -278,13 +278,20 @@ Zotero.Utilities = { /** * Clean and validate ISBN. * Return isbn if valid, otherwise return false + * @param {String} isbn + * @param {Boolean} [dontValidate=false] Do not validate check digit + * @return {String|Boolean} Valid ISBN or false */ - "cleanISBN":function(/**String*/ isbn) { + "cleanISBN":function(isbn, dontValidate) { isbn = isbn.replace(/[^0-9a-z]+/ig, '').toUpperCase() //we only want to ignore punctuation, spaces - .match(/(?:97[89][0-9]{10}|[0-9]{9}[0-9X])/); //13 digit or 10 digit + .match(/\b(?:97[89][0-9]{10}|[0-9]{9}[0-9X])\b/); //13 digit or 10 digit if(!isbn) return false; isbn = isbn[0]; - + + if (dontValidate && (isbn.length == 10 || isbn.length == 13)) { + return isbn; + } + if(isbn.length == 10) { // Verify ISBN-10 checksum var sum = 0; @@ -310,6 +317,34 @@ Zotero.Utilities = { return false; }, + + /* + * Convert ISBN 10 to ISBN 13 + * @param {String} isbn ISBN 10 or ISBN 13 + * cleanISBN + * @return {String} ISBN-13 + */ + "toISBN13": function(isbn) { + if (!/^(?:97[89])?\d{9}[\dxX]$/.test(isbn) + && !(isbn = Zotero.Utilities.cleanISBN(isbn)) + ) { + throw new Error('Invalid ISBN: ' + isbn); + } + + if (isbn.length == 13) return isbn; // Recalculate check digit? + + isbn = '978' + isbn.substr(0,9); + + var sum = 0; + for (var i = 0; i < 12; i++) { + sum += isbn[i] * (i%2 ? 3 : 1); + } + + var checkDigit = 10 - (sum % 10); + if (checkDigit == 10) checkDigit = 0; + + return isbn + checkDigit; + }, /** * Clean and validate ISSN. @@ -1476,89 +1511,84 @@ Zotero.Utilities = { /** * Converts an item from toArray() format to citeproc-js JSON - * @param {Zotero.Item} item + * @param {Zotero.Item} zoteroItem * @return {Object} The CSL item */ - "itemToCSLJSON":function(item) { - if(item instanceof Zotero.Item) { - item = item.toArray(); + "itemToCSLJSON":function(zoteroItem) { + if (zoteroItem instanceof Zotero.Item) { + zoteroItem = zoteroItem.toArray(); } - var itemType = item.itemType; - var cslType = CSL_TYPE_MAPPINGS[itemType]; - if(!cslType) cslType = "article"; + var cslType = CSL_TYPE_MAPPINGS[zoteroItem.itemType] || "article"; + var itemTypeID = Zotero.ItemTypes.getID(zoteroItem.itemType); var cslItem = { - 'id':item.itemID, + 'id':zoteroItem.itemID, 'type':cslType }; - // Map text fields - var itemTypeID = Zotero.ItemTypes.getID(itemType); + // get all text variables (there must be a better way) for(var variable in CSL_TEXT_MAPPINGS) { var fields = CSL_TEXT_MAPPINGS[variable]; for(var i=0, n=fields.length; i<n; i++) { - var field = fields[i], value = undefined; + var field = fields[i], + value; - if(field in item) { - value = item[field]; + if(field in zoteroItem) { + value = zoteroItem[field]; } else { var fieldID = Zotero.ItemFields.getID(field), - baseMapping + baseMapping; if(Zotero.ItemFields.isValidForType(fieldID, itemTypeID) && (baseMapping = Zotero.ItemFields.getBaseIDFromTypeAndField(itemTypeID, fieldID))) { - value = item[Zotero.ItemTypes.getName(baseMapping)]; + value = zoteroItem[Zotero.ItemTypes.getName(baseMapping)]; } } - if(!value) continue; + if (!value) continue; - var valueLength = value.length; - if(valueLength) { + if (typeof value == 'string') { + if (field == 'ISBN') { + // Only use the first ISBN in CSL JSON + var isbn = value.match(/^(?:97[89]-?)?(?:\d-?){9}[\dx](?!-)\b/i); + if (isbn) value = isbn[0]; + } + // Strip enclosing quotes - if(value[0] === '"' && value[valueLength-1] === '"') { - value = value.substr(1, valueLength-2); + if(value.charAt(0) == '"' && value.indexOf('"', 1) == value.length - 1) { + value = value.substring(1, value.length-1); } + cslItem[variable] = value; + break; } - - cslItem[variable] = value; - break; } } // separate name variables - var authorID = Zotero.CreatorTypes.getPrimaryIDForType(itemTypeID); - var authorFieldName = Zotero.CreatorTypes.getName(authorID); - var creators = item.creators; - if(creators) { - for(var i=0, n=creators.length; i<n; i++) { - var creator = creators[i]; - - if(creator.creatorType == authorFieldName) { - var creatorType = "author"; - } else { - var creatorType = CSL_NAMES_MAPPINGS[creator.creatorType] - } - - if(!creatorType) continue; - - if(creator.fieldMode == 1) { - var nameObj = {'literal':creator.lastName}; - } else { - var nameObj = {'family':creator.lastName, 'given':creator.firstName}; - } - - if(cslItem[creatorType]) { - cslItem[creatorType].push(nameObj); - } else { - cslItem[creatorType] = [nameObj]; - } + var author = Zotero.CreatorTypes.getName(Zotero.CreatorTypes.getPrimaryIDForType(itemTypeID)); + var creators = zoteroItem.creators; + for(var i=0; i<creators.length; i++) { + var creator = creators[i]; + var creatorType = creator.creatorType; + if(creatorType == author) { + creatorType = "author"; + } + + creatorType = CSL_NAMES_MAPPINGS[creatorType]; + if(!creatorType) continue; + + var nameObj = {'family':creator.lastName, 'given':creator.firstName}; + + if(cslItem[creatorType]) { + cslItem[creatorType].push(nameObj); + } else { + cslItem[creatorType] = [nameObj]; } } // get date variables for(var variable in CSL_DATE_MAPPINGS) { - var date = item[CSL_DATE_MAPPINGS[variable]]; + var date = zoteroItem[CSL_DATE_MAPPINGS[variable]]; if(date) { var dateObj = Zotero.Date.strToDate(date); // otherwise, use date-parts @@ -1584,8 +1614,17 @@ Zotero.Utilities = { } } } + + // extract PMID + var extra = zoteroItem.extra; + if(typeof extra === "string") { + var m = /(?:^|\n)PMID:\s*([0-9]+)/.exec(extra); + if(m) cslItem.PMID = m[1]; + m = /(?:^|\n)PMCID:\s*((?:PMC)?[0-9]+)/.exec(extra); + if(m) cslItem.PMCID = m[1]; + } - //this._cache[item.id] = cslItem; + //this._cache[zoteroItem.id] = cslItem; return cslItem; }, diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js @@ -350,6 +350,80 @@ Zotero.Utilities.Internal = { childWindow = childWindow.parent; if(childWindow === parentWindow) return true; } + }, + + /** + * Hyphenate an ISBN based on the registrant table available from + * https://www.isbn-international.org/range_file_generation + * See isbn.js + * + * @param {String} isbn ISBN-10 or ISBN-13 + * @param {Boolean} dontValidate Do not attempt to validate check digit + * @return {String} Hyphenated ISBN or empty string if invalid ISBN is supplied + */ + "hyphenateISBN": function(isbn, dontValidate) { + isbn = Zotero.Utilities.cleanISBN(isbn, dontValidate); + if (!isbn) return ''; + + var ranges = Zotero.ISBN.ranges, + parts = [], + uccPref, + i = 0; + if (isbn.length == 10) { + uccPref = '978'; + } else { + uccPref = isbn.substr(0,3); + if (!ranges[uccPref]) return ''; // Probably invalid ISBN, but the checksum is OK + parts.push(uccPref); + i = 3; // Skip ahead + } + + var group = '', + found = false; + while (i < isbn.length-3 /* check digit, publication, registrant */) { + group += isbn.charAt(i); + if (ranges[uccPref][group]) { + parts.push(group); + found = true; + break; + } + i++; + } + + if (!found) return ''; // Did not find a valid group + + // Array of registrant ranges that are valid for a group + // Array always contains an even number of values (as string) + // From left to right, the values are paired so that the first indicates a + // lower bound of the range and the right indicates an upper bound + // The ranges are sorted by increasing number of characters + var regRanges = ranges[uccPref][group]; + + var registrant = ''; + found = false; + i++; // Previous loop 'break'ed early + while (!found && i < isbn.length-2 /* check digit, publication */) { + registrant += isbn.charAt(i); + + for(let j=0; j < regRanges.length && registrant.length >= regRanges[j].length; j+=2) { + if(registrant.length == regRanges[j].length + && registrant >= regRanges[j] && registrant <= regRanges[j+1] // Falls within the range + ) { + parts.push(registrant); + found = true; + break; + } + } + + i++; + } + + if (!found) return ''; // Outside of valid range, but maybe we need to update our data + + parts.push(isbn.substring(i,isbn.length-1)); // Publication is the remainder up to last digit + parts.push(isbn.charAt(isbn.length-1)); // Check digit + + return parts.join('-'); } } diff --git a/components/zotero-service.js b/components/zotero-service.js @@ -46,6 +46,7 @@ const xpcomFilesAll = [ 'translation/translate_firefox', 'translation/tlds', 'utilities', + 'isbn', 'utilities_internal', 'utilities_translate' ];