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'); } } })();