| const warnings = (function () { | |
| const fieldCrossRefMap = { | |
| doi: function (result) { return result.DOI }, | |
| journal: function (result) { return result['container-title'][0] }, | |
| pages: function (result) { return result.page }, | |
| title: function (result) { return result.title[0] } | |
| } | |
| return { | |
| expectedFields: { | |
| inproceedings: ['author', 'booktitle', 'pages', 'publisher', 'title', 'year', 'doi'], | |
| article: ['author', 'journal', 'number', 'pages', 'title', 'volume', 'year', 'doi'], | |
| techreport: ['author', 'institution', 'title', 'year'], | |
| incollection: ['author', 'booktitle', 'pages', 'publisher', 'title', 'year'], | |
| book: ['author', 'publisher', 'title', 'year'], | |
| inbook: ['author', 'booktitle', 'pages', 'publisher', 'title', 'year'], | |
| proceedings: ['editor', 'publisher', 'title', 'year'], | |
| phdthesis: ['author', 'school', 'title', 'year'], | |
| mastersthesis: ['author', 'school', 'title', 'year'], | |
| bachelorsthesis: ['author', 'school', 'title', 'year'], | |
| electronic: ['author', 'title', 'url', 'year'], | |
| misc: ['author', 'howpublished', 'title', 'year'] | |
| }, | |
| computeAllWarnings: function (entries) { | |
| var that = this; | |
| var warnings = {}; | |
| $.each(entries, function (id, entry) { | |
| warnings[id] = that.computeWarnings(entry); | |
| }); | |
| return warnings; | |
| }, | |
| computeWarnings: function (entry) { | |
| var warningsList = []; | |
| if (editable) { | |
| warningsList = warningsList.concat(warnings.computeMissingFieldWarning(entry)); | |
| warningsList = warningsList.concat(warnings.computeTitleCapitalizationWarning(entry)); | |
| warningsList = warningsList.concat(warnings.computeProtectedIdentifierCapitalizationWarning(entry)); | |
| $.each(entry, function (field, value) { | |
| computeFirstNameUnknown(warningsList, field, value); | |
| computeWholeFieldCapitalizationProtected(warningsList, field, value); | |
| }); | |
| } | |
| return warningsList; | |
| }, | |
| computeMissingFieldWarning: function (entry) { | |
| function condenseTitle(title) { | |
| return title.toLowerCase().replace(/\W+/g, ''); | |
| } | |
| var warningsList = []; | |
| if (entry) { | |
| var expected = warnings.expectedFields[entry['type']]; | |
| if (expected) { | |
| $.each(expected, function (i, field) { | |
| if (!entry[field] || entry[field].trim() === '') { | |
| warningsList.push({ | |
| type: `missing or empty field '${field}'`, | |
| fix: { | |
| description: 'try to load from CrossRef', 'function': function (onFix) { | |
| page.notify('Loading data from CrossRef...'); | |
| const searchString = (entry.doi ? `/${entry.doi}` : `?query=${entry.title.replace(/\W+/g, '+')}`); | |
| fetch(`https://api.crossref.org/works${searchString}`).then(response => { | |
| return response.json() | |
| }).then(data => { | |
| if (!data.message) { | |
| throw 'No return message'; | |
| } | |
| const result = (entry.doi ? data.message : data.message.items[0]); | |
| if (!entry.doi && condenseTitle(entry.title) != condenseTitle(result.title[0])) { | |
| throw `Titles do not match: "${entry.title}" and "${result.title[0]}"`; | |
| } | |
| page.notify(`Paper found on CrossRef titled '${result.title}'`); | |
| let value = (fieldCrossRefMap[field] ? fieldCrossRefMap[field](result) : result[field]); | |
| if (!value) { | |
| page.notify(`However, field '${field}' not available in the CrossRef record.`, 'error') | |
| } else { | |
| if (field === 'pages') { | |
| value = value.replace('-', '--'); | |
| } | |
| entry[field] = value; | |
| page.notify(`Updated field '${field}' with value '${value}'.`) | |
| onFix(entry); | |
| } | |
| }).catch(error => { | |
| console.error(error); | |
| page.notify(`Could not find a publication with this ${(entry.doi ? 'DOI' : 'title')} on CrossRef.`, 'error'); | |
| }); | |
| } | |
| } | |
| }); | |
| } | |
| }); | |
| } | |
| } | |
| return warningsList; | |
| }, | |
| computeTitleCapitalizationWarning: function (entry) { | |
| if (!entry) { | |
| return []; | |
| } | |
| var warningsList = []; | |
| $.each(['booktitle', 'journal'], function (i, field) { | |
| if (entry[field]) { | |
| var value = entry[field]; | |
| var capitalizationCorrect = true; | |
| var correctedValue = ''; | |
| $.each(value.split(' '), function (i, word) { | |
| var capitalizedWord = word; | |
| if (!word.match(/\d.*/)) { | |
| if ((word.length >= 5 || i == 0) && word.toLowerCase() == word) { | |
| capitalizationCorrect = false; | |
| capitalizedWord = word.charAt(0).toUpperCase() + word.substring(1); | |
| } | |
| } | |
| correctedValue += (correctedValue ? ' ' : '') + capitalizedWord; | |
| }); | |
| if (!capitalizationCorrect) { | |
| warningsList.push({ | |
| type: 'capitalization in field "' + field + '"', | |
| fix: { | |
| description: 'capitalize longer words', 'function': function (onFix) { | |
| entry[field] = correctedValue; | |
| onFix(entry); | |
| } | |
| } | |
| }); | |
| } | |
| } | |
| }); | |
| return warningsList; | |
| }, | |
| computeProtectedIdentifierCapitalizationWarning: function (entry) { | |
| if (!entry) { | |
| return []; | |
| } | |
| var warningsList = []; | |
| $.each(['title'], function (i, field) { | |
| if (entry[field]) { | |
| var value = entry[field]; | |
| var capitalizationCorrect = true; | |
| var correctedValue = value; | |
| if (value.indexOf('{') < 0) { | |
| $.each(value.split(/[\s,:\-()\/]+/), function (i, word) { | |
| if (!word.startsWith('{')) { | |
| var subword = word.substring(1); | |
| if (subword.length > 0 && subword.toLowerCase() != subword) { | |
| capitalizationCorrect = false; | |
| var re = new RegExp('\{?' + word + '\}?', 'g'); | |
| correctedValue = correctedValue.replace(re, '{' + word + '}'); | |
| } | |
| } | |
| }); | |
| if (!capitalizationCorrect) { | |
| warningsList.push({ | |
| type: 'non-protected capitalization of identifier in field "' + field + '"', | |
| fix: { | |
| description: 'protect identifiers', 'function': function (onFix) { | |
| entry[field] = correctedValue; | |
| onFix(entry); | |
| } | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| }); | |
| return warningsList; | |
| } | |
| }; | |
| function computeFirstNameUnknown(warningsList, field, value) { | |
| if (field === 'author' || field === 'editor') { | |
| var firstNameKnown = true; | |
| $.each(value.split(' and '), function (i, name) { | |
| var parsedName = name.trim().split(','); | |
| if (parsedName.length > 1) { | |
| var firstName = parsedName[1].trim().split(' ')[0].trim(); | |
| if (firstName.indexOf('.') > 0 || firstName.length < 2) { | |
| firstNameKnown = false; | |
| } | |
| } else { | |
| firstNameKnown = false; | |
| } | |
| }); | |
| if (!firstNameKnown) { | |
| warningsList.push('unknown or abbreviated first name in field "' + field + '"'); | |
| } | |
| } | |
| } | |
| function computeWholeFieldCapitalizationProtected(warningsList, field, value) { | |
| if (value.indexOf('{') === 0 && value.lastIndexOf('}') === value.length - 1 && value.length > 10 && (value.split("{").length - 1 === 1)) { | |
| warningsList.push('whole field "' + field + '" with protected capitalization'); | |
| } | |
| } | |
| })(); |