From 020e061c611f983c50da0a859def1913958e15f6 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Fri, 25 Mar 2016 12:37:24 -0400 Subject: [PATCH 01/18] Begin work on 2.4.0 --- inc/js/tinymce-buttons-bak.js | 464 ++++++++++++++ inc/js/tinymce-buttons.js | 682 ++++++++------------- inc/js/tinymce-buttons.ts | 486 +++++++++++++++ inc/options-page-wrapper.php | 6 +- inc/peer-review.php | 4 + inc/tinymce-init.php | 4 +- inc/tinymce-views/formatted-reference.html | 159 +++++ inc/tinymce-views/formatted-reference.js | 21 + inc/tinymce-views/formatted-reference.ts | 33 + inc/tinymce-views/inline-citation.html | 27 + inc/tinymce-views/tinymce-views.css | 103 ++++ 11 files changed, 1568 insertions(+), 421 deletions(-) create mode 100644 inc/js/tinymce-buttons-bak.js create mode 100644 inc/js/tinymce-buttons.ts create mode 100644 inc/tinymce-views/formatted-reference.html create mode 100644 inc/tinymce-views/formatted-reference.js create mode 100644 inc/tinymce-views/formatted-reference.ts create mode 100644 inc/tinymce-views/inline-citation.html create mode 100644 inc/tinymce-views/tinymce-views.css diff --git a/inc/js/tinymce-buttons-bak.js b/inc/js/tinymce-buttons-bak.js new file mode 100644 index 00000000..976edd06 --- /dev/null +++ b/inc/js/tinymce-buttons-bak.js @@ -0,0 +1,464 @@ +(function() { + + tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function(editor, url) { + editor.addButton('abt_ref_id_parser_mce_button', { + type: 'menubutton', + image: url + '/../images/book.png', + title: "Academic Blogger's Toolkit", + icon: true, + menu: [{ + text: 'Bibliography Tools', + menu: [ + // Inline Citation Menu Item + { + text: 'Inline Citation', + onclick: function() { + editor.windowManager.open({ + title: 'Insert Citation', + width: 600, + height: 58, + body: [{ + type: 'textbox', + name: 'citation_number', + label: 'Citation Number', + value: '' + }, { + type: 'container', + html: 'Protip: Use the keyboard shortcut to access this menu
PC/Linux: (Ctrl+Alt+C) | Mac: (Cmd+Alt+C)' + }], + + onsubmit: function(e) { + editor.insertContent( + '[cite num="' + e.data.citation_number + '"]' + ); + } + }); + } + }, + // Separator + { + text: '-' + }, + // Single Reference Menu Item + { + text: 'Formatted Reference', + onclick: function() { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + width: 600, + height: 125, + body: [{ + type: 'textbox', + name: 'ref_id_number', + label: 'PMID or URL (Beta)', + value: '' + }, { + type: 'listbox', + label: 'Citation Format', + name: 'ref_id_citation_type', + 'values': [{ + text: 'American Medical Association (AMA)', + value: 'AMA' + }, { + text: 'American Psychological Association (APA)', + value: 'APA' + }] + + }, { + type: 'checkbox', + name: 'ref_id_include_link', + label: 'Include link to PubMed?' + }, { + type: 'container', + html: 'Protip: Use the keyboard shortcut to access this menu
PC/Linux: (Ctrl+Alt+R) | Mac: (Cmd+Alt+R)' + }], + onsubmit: function(e) { + + editor.setProgressState(1); + var inputText = e.data.ref_id_number; + var citationFormat = e.data.ref_id_citation_type; + var includePubmedLink = e.data.ref_id_include_link; + var requestURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + inputText + '&version=2.0&retmode=json'; + var isPubmedCitation = true; + + var PMIDtest = new RegExp(/^[0-9]+$/); + if (!PMIDtest.test(inputText)) { + requestURL = inputText; + isPubmedCitation = false; + } + + var request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.onload = function() { + if (request.readyState === 4) { + if (request.status === 200) { + output = parseRequestData(JSON.parse(request.responseText), inputText, citationFormat, includePubmedLink, isPubmedCitation); + editor.insertContent(output); + editor.setProgressState(0); + } else { + alert('ERROR: PMID not recognized.'); + editor.setProgressState(0); + return; + } + } + }; + request.send(null); + + } + }); + } + } + ] + }, { + text: 'Tracked Link', + onclick: function() { + var user_selection = tinyMCE.activeEditor.selection.getContent({ + format: 'text' + }); + editor.windowManager.open({ + title: 'Insert Tracked Link', + width: 600, + height: 160, + buttons: [{ + text: 'Insert', + onclick: 'submit' + }], + body: [{ + type: 'textbox', + name: 'tracked_url', + label: 'URL', + value: '' + }, { + type: 'textbox', + name: 'tracked_title', + label: 'Link Text', + value: user_selection + }, { + type: 'textbox', + name: 'tracked_tag', + label: 'Custom Tag ID', + tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', + value: '' + }, { + type: 'checkbox', + name: 'tracked_new_window', + label: 'Open link in a new window/tab' + }, ], + onsubmit: function(e) { + var trackedUrl = e.data.tracked_url; + var trackedTitle = e.data.tracked_title; + var trackedTag = e.data.tracked_tag; + var trackedLink; + + + if (e.data.tracked_new_window) { + trackedLink = '' + trackedTitle + ''; + } else { + trackedLink = '' + trackedTitle + ''; + } + + editor.execCommand('mceInsertContent', false, trackedLink); + } + }); + } + }, { + text: '-' + }, { + text: 'Request More Tools', + onclick: function() { + editor.windowManager.open({ + title: 'Request More Tools', + body: [ + + { + type: 'label', + text: "Have a feature or tool in mind that isn't available? Visit the link below to send a feature request. We'll do our best to make it happen." + }, { + type: 'button', + text: 'Send us your thoughts!', + onclick: function() { + window.open('https://github.com/dsifford/academic-bloggers-toolkit/issues', '_blank'); + }, + } + + ], + onsubit: function() { + return; + } + }); + } + } + + ] + }); + editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + width: 600, + height: 125, + body: [{ + type: 'textbox', + name: 'ref_id_number', + label: 'PMID or URL (Beta)', + value: '' + }, { + type: 'listbox', + label: 'Citation Format', + name: 'ref_id_citation_type', + 'values': [{ + text: 'American Medical Association (AMA)', + value: 'AMA' + }, { + text: 'American Psychological Association (APA)', + value: 'APA' + }] + + }, { + type: 'checkbox', + name: 'ref_id_include_link', + label: 'Include link to PubMed?' + }], + onsubmit: function(e) { + + editor.setProgressState(1); + var PMID = e.data.ref_id_number; + var citationFormat = e.data.ref_id_citation_type; + var includePubmedLink = e.data.ref_id_include_link; + + var request = new XMLHttpRequest(); + request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); + request.onload = function() { + if (request.readyState === 4) { + if (request.status === 200) { + output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); + editor.insertContent(output); + editor.setProgressState(0); + } else { + alert('ERROR: PMID not recognized.'); + editor.setProgressState(0); + return; + } + } + }; + request.send(null); + + } + }); + }); + + editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { + editor.windowManager.open({ + title: 'Insert Citation', + width: 600, + height: 58, + body: [{ + type: 'textbox', + name: 'citation_number', + label: 'Citation Number', + value: '' + }], + onsubmit: function(e) { + editor.insertContent( + '[cite num="' + e.data.citation_number + '"]' + ); + } + }); + }); + + }); + + function parseRequestData(data, PMID, citationFormat, includePubmedLink, isPubmedCitation) { + + var authorsRaw = data.result[PMID].authors; + var title = data.result[PMID].title; + var journalName = data.result[PMID].source; + var pubYear = data.result[PMID].pubdate.substr(0, 4); + var volume = data.result[PMID].volume; + var issue = data.result[PMID].issue; + var pages = data.result[PMID].pages; + + var authors = ''; + var output, i; + + if (citationFormat === 'AMA') { + + /** + * AUTHOR PARSING + */ + + // 0 AUTHORS + if (authorsRaw.length === 0) { + alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); + } + // 1 AUTHOR + else if (authorsRaw.length === 1) { + authors = data.result[PMID].authors[0].name; + } + // 2 - 6 AUTHORS + else if (authorsRaw.length > 1 && authorsRaw.length < 7) { + + for (i = 0; i < authorsRaw.length - 1; i++) { + authors += authorsRaw[i].name + ', '; + } + authors += authorsRaw[authorsRaw.length - 1].name + '. '; + } + // >7 AUTHORS + else { + for (i = 0; i < 3; i++) { + authors += authorsRaw[i].name + ', '; + } + authors += 'et al. '; + } + + // NO VOLUME NUMBER + if (volume === '') { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; + } + // NO ISSUE NUMBER + else if (issue === '' || issue === undefined) { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; + } else { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + '(' + issue + '): ' + pages + '.'; + } + + + } else if (citationFormat === 'APA') { + + /** + * AUTHOR PARSING + */ + + // 0 AUTHORS + if (authorsRaw.length === 0) { + alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); + } + // 1 AUTHOR + else if (authorsRaw.length === 1) { + + // Check to see if both initials are listed + if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; + } else { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; + } + + } + // 2 Authors + else if (authorsRaw.length === 2) { + + if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { + + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; + + } else { + + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; + + } + + if ((/( \w\w)/g).test(data.result[PMID].authors[1].name)) { + + authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 3) + ', ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 2, data.result[PMID].authors[1].name.length - 1) + '. ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; + + } else { + + authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 2) + ', ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; + + } + + } + // 3-7 AUTHORS + else if (authorsRaw.length > 2 && authorsRaw.length < 8) { + + for (i = 0; i < authorsRaw.length - 1; i++) { + + if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } else { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } + + } + + if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { + + authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } else { + + authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } + + } + // >7 AUTHORS + else { + + for (i = 0; i < 6; i++) { + + if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } else { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } + + } + + if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { + + authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } else { + + authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } + + + } + + output = authors + '(' + pubYear + '). ' + title + ' ' + journalName + ', ' + (volume !== '' ? volume : '') + (issue !== '' ? '(' + issue + '), ' : '') + pages + '.'; + + } + + // INCLUDE LINK TO PUBMED IF CHECKBOX IS CHECKED + if (includePubmedLink) { + output += ' PMID: ' + PMID + ''; + } + + return output; + + + } + +}) +(); diff --git a/inc/js/tinymce-buttons.js b/inc/js/tinymce-buttons.js index 331b85c8..de2b6c9f 100644 --- a/inc/js/tinymce-buttons.js +++ b/inc/js/tinymce-buttons.js @@ -1,266 +1,185 @@ -(function() { - - tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function(editor, url) { - editor.addButton('abt_ref_id_parser_mce_button', { - type: 'menubutton', - image: url + '/../images/book.png', - title: "Academic Blogger's Toolkit", - icon: true, - menu: [{ - text: 'Bibliography Tools', - menu: [ - // Inline Citation Menu Item - { - text: 'Inline Citation', - onclick: function() { - editor.windowManager.open({ - title: 'Insert Citation', - width: 600, - height: 58, - body: [{ - type: 'textbox', - name: 'citation_number', - label: 'Citation Number', - value: '' - }, { - type: 'container', - html: 'Protip: Use the keyboard shortcut to access this menu
PC/Linux: (Ctrl+Alt+C) | Mac: (Cmd+Alt+C)' - }], - - onsubmit: function(e) { - editor.insertContent( - '[cite num="' + e.data.citation_number + '"]' - ); - } - }); - } - }, - // Separator - { - text: '-' - }, - // Single Reference Menu Item - { - text: 'Formatted Reference', - onclick: function() { - editor.windowManager.open({ - title: 'Insert Formatted Reference', - width: 600, - height: 125, - body: [{ +tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) { + var ABT_Button = { + type: 'menubutton', + image: url + '/../images/book.png', + title: 'Academic Blogger\'s Toolkit', + icon: true, + menu: [], + }; + var separator = { text: '-' }; + var bibToolsMenu = { + text: 'Bibliography Tools', + menu: [], + }; + var trackedLink = { + text: 'Tracked Link', + onclick: function () { + var user_selection = tinyMCE.activeEditor.selection.getContent({ format: 'text' }); + editor.windowManager.open({ + title: 'Insert Tracked Link', + width: 600, + height: 160, + buttons: [{ + text: 'Insert', + onclick: 'submit' + }], + body: [ + { + type: 'textbox', + name: 'tracked_url', + label: 'URL', + value: '' + }, + { + type: 'textbox', + name: 'tracked_title', + label: 'Link Text', + value: user_selection + }, + { + type: 'textbox', + name: 'tracked_tag', + label: 'Custom Tag ID', + tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', + value: '' + }, + { + type: 'checkbox', + name: 'tracked_new_window', + label: 'Open link in a new window/tab' + }, + ], + onsubmit: function (e) { + var trackedUrl = e.data.tracked_url; + var trackedTitle = e.data.tracked_title; + var trackedTag = e.data.tracked_tag; + var trackedLink = ("" + trackedTitle + ""); + editor.execCommand('mceInsertContent', false, trackedLink); + } + }); + } + }; + var requestTools = { + text: 'Request More Tools', + onclick: function () { + editor.windowManager.open({ + title: 'Request More Tools', + body: [{ + type: 'container', + html: "
" + + "Have a feature or tool in mind that isn't available?
" + + "Open an issue on the GitHub repository and let me know!" + + "
", + }], + buttons: [], + }); + } + }; + var inlineCitation = { + text: 'Inline Citation', + onclick: function () { + editor.windowManager.open({ + title: 'Inline Citation', + url: AU_locationInfo.tinymceViewsURL + 'inline-citation.html', + width: 400, + height: 85, + onClose: function (e) { + editor.insertContent('[cite num="' + e.target.params.data + '"]'); + } + }); + } + }; + var formattedReference = { + text: 'Formatted Reference', + onclick: function () { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', + width: 600, + height: 'auto', + onclose: function (e) { + console.log(e); + }, + }); + } + }; + bibToolsMenu.menu.push(inlineCitation, separator, formattedReference); + ABT_Button.menu.push(bibToolsMenu, trackedLink, separator, requestTools); + editor.addButton('abt_ref_id_parser_mce_button', ABT_Button); + editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function () { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + width: 600, + height: 125, + body: [{ type: 'textbox', name: 'ref_id_number', label: 'PMID', value: '' - }, { + }, { type: 'listbox', label: 'Citation Format', name: 'ref_id_citation_type', 'values': [{ - text: 'American Medical Association (AMA)', - value: 'AMA' - }, { - text: 'American Psychological Association (APA)', - value: 'APA' - }] - - }, { + text: 'American Medical Association (AMA)', + value: 'AMA' + }, { + text: 'American Psychological Association (APA)', + value: 'APA' + }] + }, { type: 'checkbox', name: 'ref_id_include_link', label: 'Include link to PubMed?' - }, { - type: 'container', - html: 'Protip: Use the keyboard shortcut to access this menu
PC/Linux: (Ctrl+Alt+R) | Mac: (Cmd+Alt+R)' - }], - onsubmit: function(e) { - - editor.setProgressState(1); - var PMID = e.data.ref_id_number; - var citationFormat = e.data.ref_id_citation_type; - var includePubmedLink = e.data.ref_id_include_link; - - var request = new XMLHttpRequest(); - request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); - request.onload = function() { - if (request.readyState === 4) { + } + ], + onsubmit: function (e) { + editor.setProgressState(1); + var PMID = e.data.ref_id_number; + var citationFormat = e.data.ref_id_citation_type; + var includePubmedLink = e.data.ref_id_include_link; + var request = new XMLHttpRequest(); + request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); + request.onload = function () { + if (request.readyState === 4) { if (request.status === 200) { - output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); - editor.insertContent(output); - editor.setProgressState(0); - } else { - alert('ERROR: PMID not recognized.'); - editor.setProgressState(0); - return; + var output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); + editor.insertContent(output); + editor.setProgressState(0); } - } - }; - request.send(null); - - } - }); - } + else { + alert('ERROR: PMID not recognized.'); + editor.setProgressState(0); + return; + } + } + }; + request.send(null); } - ] - }, { - text: 'Tracked Link', - onclick: function() { - var user_selection = tinyMCE.activeEditor.selection.getContent({ - format: 'text' - }); - editor.windowManager.open({ - title: 'Insert Tracked Link', - width: 600, - height: 160, - buttons: [{ - text: 'Insert', - onclick: 'submit' - }], - body: [{ - type: 'textbox', - name: 'tracked_url', - label: 'URL', - value: '' - }, { - type: 'textbox', - name: 'tracked_title', - label: 'Link Text', - value: user_selection - }, { - type: 'textbox', - name: 'tracked_tag', - label: 'Custom Tag ID', - tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', - value: '' - }, { - type: 'checkbox', - name: 'tracked_new_window', - label: 'Open link in a new window/tab' - }, ], - onsubmit: function(e) { - var trackedUrl = e.data.tracked_url; - var trackedTitle = e.data.tracked_title; - var trackedTag = e.data.tracked_tag; - var trackedLink; - - - if (e.data.tracked_new_window) { - trackedLink = '' + trackedTitle + ''; - } else { - trackedLink = '' + trackedTitle + ''; - } - - editor.execCommand('mceInsertContent', false, trackedLink); - } - }); - } - }, { - text: '-' - }, { - text: 'Request More Tools', - onclick: function() { - editor.windowManager.open({ - title: 'Request More Tools', - body: [ - - { - type: 'label', - text: "Have a feature or tool in mind that isn't available? Visit the link below to send a feature request. We'll do our best to make it happen." - }, { - type: 'button', - text: 'Send us your thoughts!', - onclick: function() { - window.open('https://github.com/dsifford/academic-bloggers-toolkit/issues', '_blank'); - }, - } - - ], - onsubit: function() { - return; - } - }); - } - } - - ] + }); }); - editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { - editor.windowManager.open({ - title: 'Insert Formatted Reference', - width: 600, - height: 125, - body: [{ - type: 'textbox', - name: 'ref_id_number', - label: 'PMID', - value: '' - }, { - type: 'listbox', - label: 'Citation Format', - name: 'ref_id_citation_type', - 'values': [{ - text: 'American Medical Association (AMA)', - value: 'AMA' - }, { - text: 'American Psychological Association (APA)', - value: 'APA' - }] - - }, { - type: 'checkbox', - name: 'ref_id_include_link', - label: 'Include link to PubMed?' - }], - onsubmit: function(e) { - - editor.setProgressState(1); - var PMID = e.data.ref_id_number; - var citationFormat = e.data.ref_id_citation_type; - var includePubmedLink = e.data.ref_id_include_link; - - var request = new XMLHttpRequest(); - request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); - request.onload = function() { - if (request.readyState === 4) { - if (request.status === 200) { - output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); - editor.insertContent(output); - editor.setProgressState(0); - } else { - alert('ERROR: PMID not recognized.'); - editor.setProgressState(0); - return; - } + editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function () { + editor.windowManager.open({ + title: 'Insert Citation', + width: 600, + height: 58, + body: [{ + type: 'textbox', + name: 'citation_number', + label: 'Citation Number', + value: '' + }], + onsubmit: function (e) { + editor.insertContent('[cite num="' + e.data.citation_number + '"]'); } - }; - request.send(null); - - } - }); - }); - - editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { - editor.windowManager.open({ - title: 'Insert Citation', - width: 600, - height: 58, - body: [{ - type: 'textbox', - name: 'citation_number', - label: 'Citation Number', - value: '' - }], - onsubmit: function(e) { - editor.insertContent( - '[cite num="' + e.data.citation_number + '"]' - ); - } - }); + }); }); - - }); - - function parseRequestData(data, PMID, citationFormat, includePubmedLink) { - +}); +function parseRequestData(data, PMID, citationFormat, includePubmedLink) { var authorsRaw = data.result[PMID].authors; var title = data.result[PMID].title; var journalName = data.result[PMID].source; @@ -268,189 +187,120 @@ var volume = data.result[PMID].volume; var issue = data.result[PMID].issue; var pages = data.result[PMID].pages; - var authors = ''; var output, i; - if (citationFormat === 'AMA') { - - /** - * AUTHOR PARSING - */ - - // 0 AUTHORS - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - // 1 AUTHOR - else if (authorsRaw.length === 1) { - authors = data.result[PMID].authors[0].name; - } - // 2 - 6 AUTHORS - else if (authorsRaw.length > 1 && authorsRaw.length < 7) { - - for (i = 0; i < authorsRaw.length - 1; i++) { - authors += authorsRaw[i].name + ', '; + if (authorsRaw.length === 0) { + alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); } - authors += authorsRaw[authorsRaw.length - 1].name + '. '; - } - // >7 AUTHORS - else { - for (i = 0; i < 3; i++) { - authors += authorsRaw[i].name + ', '; + else if (authorsRaw.length === 1) { + authors = data.result[PMID].authors[0].name; } - authors += 'et al. '; - } - - // NO VOLUME NUMBER - if (volume === '') { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } - // NO ISSUE NUMBER - else if (issue === '' || issue === undefined) { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } else { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + '(' + issue + '): ' + pages + '.'; - } - - - } else if (citationFormat === 'APA') { - - /** - * AUTHOR PARSING - */ - - // 0 AUTHORS - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - // 1 AUTHOR - else if (authorsRaw.length === 1) { - - // Check to see if both initials are listed - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; - } else { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; + else if (authorsRaw.length > 1 && authorsRaw.length < 7) { + for (i = 0; i < authorsRaw.length - 1; i++) { + authors += authorsRaw[i].name + ', '; + } + authors += authorsRaw[authorsRaw.length - 1].name + '. '; + } + else { + for (i = 0; i < 3; i++) { + authors += authorsRaw[i].name + ', '; + } + authors += 'et al. '; + } + if (volume === '') { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; } - - } - // 2 Authors - else if (authorsRaw.length === 2) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - - } else { - - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - + else if (issue === '' || issue === undefined) { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; } - - if ((/( \w\w)/g).test(data.result[PMID].authors[1].name)) { - - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 3) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 2, data.result[PMID].authors[1].name.length - 1) + '. ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - - } else { - - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 2) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - + else { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + '(' + issue + '): ' + pages + '.'; } - - } - // 3-7 AUTHORS - else if (authorsRaw.length > 2 && authorsRaw.length < 8) { - - for (i = 0; i < authorsRaw.length - 1; i++) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } else { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } - + } + else if (citationFormat === 'APA') { + if (authorsRaw.length === 0) { + alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); + } + else if (authorsRaw.length === 1) { + if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; + } + else { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; + } } - - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } else { - - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - + else if (authorsRaw.length === 2) { + if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; + } + else { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; + } + if ((/( \w\w)/g).test(data.result[PMID].authors[1].name)) { + authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 3) + ', ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 2, data.result[PMID].authors[1].name.length - 1) + '. ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; + } + else { + authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 2) + ', ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; + } } - - } - // >7 AUTHORS - else { - - for (i = 0; i < 6; i++) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } else { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } - + else if (authorsRaw.length > 2 && authorsRaw.length < 8) { + for (i = 0; i < authorsRaw.length - 1; i++) { + if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + } + else { + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + } + } + if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { + authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + } + else { + authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + } } - - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } else { - - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - + else { + for (i = 0; i < 6; i++) { + if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + } + else { + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + } + } + if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { + authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + } + else { + authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + } } - - - } - - output = authors + '(' + pubYear + '). ' + title + ' ' + journalName + ', ' + (volume !== '' ? volume : '') + (issue !== '' ? '(' + issue + '), ' : '') + pages + '.'; - + output = authors + '(' + pubYear + '). ' + title + ' ' + journalName + ', ' + (volume !== '' ? volume : '') + (issue !== '' ? '(' + issue + '), ' : '') + pages + '.'; } - - // INCLUDE LINK TO PUBMED IF CHECKBOX IS CHECKED if (includePubmedLink) { - output += ' PMID: ' + PMID + ''; + output += ' PMID: ' + PMID + ''; } - return output; - - - } - -}) -(); +} diff --git a/inc/js/tinymce-buttons.ts b/inc/js/tinymce-buttons.ts new file mode 100644 index 00000000..92628d77 --- /dev/null +++ b/inc/js/tinymce-buttons.ts @@ -0,0 +1,486 @@ +declare var tinymce, tinyMCE, AU_locationInfo + +interface Author { + authtype: string + clusterid: string + name: string +} + +interface AuthorObj { + [i: number]: Author + length: number +} + +interface TinyMCEMenuItem { + text: string + menu?: TinyMCEMenuItem[] + onclick?: (e?: Event) => void +} + +interface TinyMCEWindowElement { + type: string + name: string + label: string + value: string + tooltip?: string +} + +interface TinyMCEWindowMangerObject { + title: string + width: number + height: any + body?: TinyMCEWindowElement[] + url?: string + onclose?: (e?: Event) => void +} + +interface TinyMCEPluginButton { + type: string + image: string + title: string + icon: boolean + menu: TinyMCEMenuItem[] +} + +tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) => { + + let ABT_Button: TinyMCEPluginButton = { + type: 'menubutton', + image: url + '/../images/book.png', + title: 'Academic Blogger\'s Toolkit', + icon: true, + menu: [], + }; + + //================================================== + // MENU ITEMS + //================================================== + + let separator: TinyMCEMenuItem = { text: '-' }; + + + let bibToolsMenu: TinyMCEMenuItem = { + text: 'Bibliography Tools', + menu: [], + }; + + + let trackedLink: TinyMCEMenuItem = { + text: 'Tracked Link', + onclick: () => { + + let user_selection = tinyMCE.activeEditor.selection.getContent({format: 'text'}); + + /** TODO: Fix this so it doesn't suck */ + editor.windowManager.open({ + title: 'Insert Tracked Link', + width: 600, + height: 160, + buttons: [{ + text: 'Insert', + onclick: 'submit' + }], + body: [ + { + type: 'textbox', + name: 'tracked_url', + label: 'URL', + value: '' + }, + { + type: 'textbox', + name: 'tracked_title', + label: 'Link Text', + value: user_selection + }, + { + type: 'textbox', + name: 'tracked_tag', + label: 'Custom Tag ID', + tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', + value: '' + }, + { + type: 'checkbox', + name: 'tracked_new_window', + label: 'Open link in a new window/tab' + }, + ], + onsubmit: (e) => { + let trackedUrl = e.data.tracked_url; + let trackedTitle = e.data.tracked_title; + let trackedTag = e.data.tracked_tag; + let trackedLink = `${trackedTitle}`; + + editor.execCommand('mceInsertContent', false, trackedLink); + + } + }); + } + } + // End Tracked Link Menu Item + + let requestTools: TinyMCEMenuItem = { + text: 'Request More Tools', + onclick: () => { + editor.windowManager.open({ + title: 'Request More Tools', + body: [{ + type: 'container', + html: + `
` + + `Have a feature or tool in mind that isn't available?
` + + `Open an issue on the GitHub repository and let me know!` + + `
`, + }], + buttons: [], + }); + } + } + + + let inlineCitation: TinyMCEMenuItem = { + text: 'Inline Citation', + onclick: () => { + editor.windowManager.open({ + title: 'Inline Citation', + url: AU_locationInfo.tinymceViewsURL + 'inline-citation.html', + width: 400, + height: 85, + onClose: (e) => { + editor.insertContent( + '[cite num="' + e.target.params.data + '"]' + ); + } + }); + } + } + + let formattedReference: TinyMCEMenuItem = { + text: 'Formatted Reference', + onclick: () => { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', + width: 600, + height: 'auto', + onclose: (e) => { + console.log(e); + }, + }); + } + + // onsubmit: function(e) { + // + // editor.setProgressState(1); + // var inputText = e.data.ref_id_number; + // var citationFormat = e.data.ref_id_citation_type; + // var includePubmedLink = e.data.ref_id_include_link; + // var requestURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + inputText + '&version=2.0&retmode=json'; + // + // var request = new XMLHttpRequest(); + // request.open('GET', requestURL, true); + // request.onload = function() { + // if (request.readyState === 4) { + // if (request.status === 200) { + // console.log(request.responseText) + // let output = parseRequestData(JSON.parse(request.responseText), inputText, citationFormat, includePubmedLink); + // editor.insertContent(output); + // editor.setProgressState(0); + // } else { + // alert('ERROR: PMID not recognized.'); + // editor.setProgressState(0); + // return; + // } + // } + // }; + // request.send(null); + // + // } + // }); + + } + + bibToolsMenu.menu.push(inlineCitation, separator, formattedReference); + ABT_Button.menu.push(bibToolsMenu, trackedLink, separator, requestTools); + + + editor.addButton('abt_ref_id_parser_mce_button', ABT_Button); + + + + + + editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + width: 600, + height: 125, + body: [{ + type: 'textbox', + name: 'ref_id_number', + label: 'PMID', + value: '' + }, { + type: 'listbox', + label: 'Citation Format', + name: 'ref_id_citation_type', + 'values': [{ + text: 'American Medical Association (AMA)', + value: 'AMA' + }, { + text: 'American Psychological Association (APA)', + value: 'APA' + }] + + }, { + type: 'checkbox', + name: 'ref_id_include_link', + label: 'Include link to PubMed?' + } + ], + onsubmit: function(e) { + + editor.setProgressState(1); + var PMID = e.data.ref_id_number; + var citationFormat = e.data.ref_id_citation_type; + var includePubmedLink = e.data.ref_id_include_link; + + var request = new XMLHttpRequest(); + request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); + request.onload = function() { + if (request.readyState === 4) { + if (request.status === 200) { + let output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); + editor.insertContent(output); + editor.setProgressState(0); + } else { + alert('ERROR: PMID not recognized.'); + editor.setProgressState(0); + return; + } + } + }; + request.send(null); + + } + }); + }); + + editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { + editor.windowManager.open({ + title: 'Insert Citation', + width: 600, + height: 58, + body: [{ + type: 'textbox', + name: 'citation_number', + label: 'Citation Number', + value: '' + }], + onsubmit: function(e) { + editor.insertContent( + '[cite num="' + e.data.citation_number + '"]' + ); + } + }); + }); + +}); + +function parseRequestData(data, PMID, citationFormat, includePubmedLink): string { + + var authorsRaw: AuthorObj = data.result[PMID].authors; + var title: string = data.result[PMID].title; + var journalName: string = data.result[PMID].source; + var pubYear: string = data.result[PMID].pubdate.substr(0, 4); + var volume: string = data.result[PMID].volume; + var issue: string = data.result[PMID].issue; + var pages: string = data.result[PMID].pages; + + var authors = ''; + var output, i; + + if (citationFormat === 'AMA') { + + /** + * AUTHOR PARSING + */ + + // 0 AUTHORS + if (authorsRaw.length === 0) { + alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); + } + // 1 AUTHOR + else if (authorsRaw.length === 1) { + authors = data.result[PMID].authors[0].name; + } + // 2 - 6 AUTHORS + else if (authorsRaw.length > 1 && authorsRaw.length < 7) { + + for (i = 0; i < authorsRaw.length - 1; i++) { + authors += authorsRaw[i].name + ', '; + } + authors += authorsRaw[authorsRaw.length - 1].name + '. '; + } + // >7 AUTHORS + else { + for (i = 0; i < 3; i++) { + authors += authorsRaw[i].name + ', '; + } + authors += 'et al. '; + } + + // NO VOLUME NUMBER + if (volume === '') { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; + } + // NO ISSUE NUMBER + else if (issue === '' || issue === undefined) { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; + } else { + output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + '(' + issue + '): ' + pages + '.'; + } + + + } else if (citationFormat === 'APA') { + + /** + * AUTHOR PARSING + */ + + // 0 AUTHORS + if (authorsRaw.length === 0) { + alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); + } + // 1 AUTHOR + else if (authorsRaw.length === 1) { + + // Check to see if both initials are listed + if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; + } else { + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; + } + + } + // 2 Authors + else if (authorsRaw.length === 2) { + + if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { + + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; + + } else { + + authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + + data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; + + } + + if ((/( \w\w)/g).test(data.result[PMID].authors[1].name)) { + + authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 3) + ', ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 2, data.result[PMID].authors[1].name.length - 1) + '. ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; + + } else { + + authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 2) + ', ' + + data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; + + } + + } + // 3-7 AUTHORS + else if (authorsRaw.length > 2 && authorsRaw.length < 8) { + + for (i = 0; i < authorsRaw.length - 1; i++) { + + if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } else { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } + + } + + if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { + + authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } else { + + authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } + + } + // >7 AUTHORS + else { + + for (i = 0; i < 6; i++) { + + if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } else { + + authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + + data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; + + } + + } + + if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { + + authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } else { + + authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + + data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; + + } + + + } + + output = authors + '(' + pubYear + '). ' + title + ' ' + journalName + ', ' + (volume !== '' ? volume : '') + (issue !== '' ? '(' + issue + '), ' : '') + pages + '.'; + + } + + // INCLUDE LINK TO PUBMED IF CHECKBOX IS CHECKED + if (includePubmedLink) { + output += ' PMID: ' + PMID + ''; + } + + return output; + + +} diff --git a/inc/options-page-wrapper.php b/inc/options-page-wrapper.php index f4110d5e..65211426 100644 --- a/inc/options-page-wrapper.php +++ b/inc/options-page-wrapper.php @@ -32,8 +32,8 @@ Classes / IDs used in this plugin: - Anchor Links: - .cite, .cite-return + Inline Citations: + .cite Peer Review Boxes: @@ -41,7 +41,7 @@ Citation Tooltips: - .abt_tooltip + .abt_tooltip, .abt_tooltip_arrow diff --git a/inc/peer-review.php b/inc/peer-review.php index 2127bbe4..51df472d 100644 --- a/inc/peer-review.php +++ b/inc/peer-review.php @@ -365,6 +365,10 @@ function abt_image_enqueue() { 'button' => __( 'Use this image', 'abt-textdomain' ), ) ); + wp_localize_script( 'meta-box-image', 'AU_locationInfo', array( + 'jsURL' => plugins_url('academic-bloggers-toolkit/inc/js/'), + 'tinymceViewsURL' => plugins_url('academic-bloggers-toolkit/inc/tinymce-views/') + )); wp_enqueue_script( 'meta-box-image' ); } } diff --git a/inc/tinymce-init.php b/inc/tinymce-init.php index 99c24124..3ac970aa 100644 --- a/inc/tinymce-init.php +++ b/inc/tinymce-init.php @@ -1,4 +1,4 @@ - \ No newline at end of file + ?> diff --git a/inc/tinymce-views/formatted-reference.html b/inc/tinymce-views/formatted-reference.html new file mode 100644 index 00000000..0a7092f0 --- /dev/null +++ b/inc/tinymce-views/formatted-reference.html @@ -0,0 +1,159 @@ + + + + + +
+ + +
+
+ +
+ + diff --git a/inc/tinymce-views/formatted-reference.js b/inc/tinymce-views/formatted-reference.js new file mode 100644 index 00000000..a699f99b --- /dev/null +++ b/inc/tinymce-views/formatted-reference.js @@ -0,0 +1,21 @@ +var addManuallyButton = document.getElementById('add-manually'); +addManuallyButton.addEventListener('click', function (e) { + var manualCitation = document.getElementById('manual-citation'); + var pubmedRelated = document.getElementById('pubmed-related'); + pubmedRelated.style.display = 'none'; + manualCitation.style.display = ''; +}); +var manualCitationSelection = document.getElementById('manual-type-selection'); +manualCitationSelection.addEventListener('change', function (e) { + var modalContainer = top.document.querySelector('div.mce-floatpanel[aria-label="Insert Formatted Reference"]'); + modalContainer.style.height = '536px'; + modalContainer.children[0].children[1].style.height = '500px'; + for (var i = 0; i < e.srcElement.childElementCount; i++) { + console.log(manualCitationSelection.children[i]); + if (manualCitationSelection.children[i].attributes[0].value === e.target.value) { + document.getElementById("manual-" + manualCitationSelection.children[i].attributes[0].value).style.display = ''; + continue; + } + document.getElementById("manual-" + manualCitationSelection.children[i].attributes[0].value).style.display = 'none'; + } +}); diff --git a/inc/tinymce-views/formatted-reference.ts b/inc/tinymce-views/formatted-reference.ts new file mode 100644 index 00000000..2ab95297 --- /dev/null +++ b/inc/tinymce-views/formatted-reference.ts @@ -0,0 +1,33 @@ +interface Window { + tinymce: any; +} + +let addManuallyButton = document.getElementById('add-manually'); +addManuallyButton.addEventListener('click', (e: Event) => { + + let manualCitation = document.getElementById('manual-citation'); + let pubmedRelated = document.getElementById('pubmed-related'); + + pubmedRelated.style.display = 'none'; + manualCitation.style.display = ''; + +}) + + +let manualCitationSelection = document.getElementById('manual-type-selection'); +manualCitationSelection.addEventListener('change', (e: Event) => { + + let modalContainer = top.document.querySelector('div.mce-floatpanel[aria-label="Insert Formatted Reference"]'); + (modalContainer).style.height = '536px'; + (modalContainer).children[0].children[1].style.height = '500px'; + + for (let i = 0; i < e.srcElement.childElementCount; i++) { + console.log(manualCitationSelection.children[i]) + if (manualCitationSelection.children[i].attributes[0].value === (e.target).value) { + document.getElementById(`manual-${manualCitationSelection.children[i].attributes[0].value}`).style.display = ''; + continue; + } + document.getElementById(`manual-${manualCitationSelection.children[i].attributes[0].value}`).style.display = 'none'; + } + +}); diff --git a/inc/tinymce-views/inline-citation.html b/inc/tinymce-views/inline-citation.html new file mode 100644 index 00000000..65c074a8 --- /dev/null +++ b/inc/tinymce-views/inline-citation.html @@ -0,0 +1,27 @@ + +
+
+
+
+ + +
+
+ +
+
+
+ + diff --git a/inc/tinymce-views/tinymce-views.css b/inc/tinymce-views/tinymce-views.css new file mode 100644 index 00000000..7a093da3 --- /dev/null +++ b/inc/tinymce-views/tinymce-views.css @@ -0,0 +1,103 @@ +.row { + margin-top: 10px; + margin-bottom: 10px; +} + +.btn { + background: #f7f7f7; + border-color: #ccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 1px 0 #ccc; + box-sizing: border-box; + color: #555; + cursor: pointer; + display: inline-block; + font-size: 13px; + height: 30px; + line-height: 31px; + margin: 0; + padding: 0 12px 2px; + vertical-align: top; + white-space: nowrap; + -moz-box-sizing: border-box; + -webkit-appearance: none; + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 0 #ccc; + -webkit-box-sizing: border-box; +} + +.btn:hover { + background: #fafafa; + border-color: #999; + color: #23282d; +} + +.btn:active { + background: #eee; + border-color: #999; + -webkit-box-shadow: inset 0 2px 5px -3px rgba(0,0,0,.5); + box-shadow: inset 0 2px 5px -3px rgba(0,0,0,.5); + -webkit-transform: translateY(1px); + -ms-transform: translateY(1px); + transform: translateY(1px); + outline: 0; +} + +.submit-btn { + background: #0085ba; + border-color: #0073aa #006799 #006799; + box-shadow: 0 1px 0 #006799; + color: #fff; + text-decoration: none; + text-shadow: 0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799,-1px 0 1px #006799; + -webkit-box-shadow: 0 1px 0 #006799; +} + +.submit-btn:hover { + background: #008ec2; + border-color: #006799; + color: #fff +} + +.submit-btn:active { + background: #0073aa; + border-color: #006799; + -webkit-box-shadow: inset 0 2px 0 #006799; + box-shadow: inset 0 2px 0 #006799; + vertical-align: top +} + +input, select { + border: 1px solid #ddd; + -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.07); + box-shadow: inset 0 1px 2px rgba(0,0,0,.07); + background-color: #fff; + color: #32373c; + outline: 0; + -webkit-transition: 50ms border-color ease-in-out; + transition: 50ms border-color ease-in-out; + margin: 1px; + padding: 5px; + font-size: 1em; +} + +input[type="checkbox"] { + height: 18px; + width: 18px; + vertical-align: middle; +} + +input:focus { + outline: none; +} + +select { + padding: 2px; + line-height: 28px; + height: 28px; + vertical-align: middle; + margin: 1px; + font-size: 1em; +} From 617a1e4510df5a22af982c558fdb7b7b54ae632a Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Fri, 25 Mar 2016 15:56:41 -0400 Subject: [PATCH 02/18] Finish gulp pipeline --- .gitignore | 2 + gulpfile.js | 60 +++++ inc/js/tinymce-buttons-bak.js | 464 ---------------------------------- package.json | 12 +- 4 files changed, 73 insertions(+), 465 deletions(-) create mode 100644 gulpfile.js delete mode 100644 inc/js/tinymce-buttons-bak.js diff --git a/.gitignore b/.gitignore index 85dcc16d..a89fd448 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .git node_modules +dist +npm-debug.log diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..5bf2cd6a --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,60 @@ +var gulp = require('gulp'), + uglify = require('gulp-uglify'), + sass = require('gulp-sass'), + autoprefixer = require('gulp-autoprefixer'), + cleanCSS = require('gulp-clean-css'), + browserSync = require('browser-sync').create(); + +gulp.task('build', ['js', 'css'], function() { + gulp.src([ + './academic-bloggers-toolkit.php', + './CHANGELOG.md', + './LICENSE', + './readme.txt', + './inc/**/*', + '!./inc/**/*.{ts,js,css,scss}' + ], { base: './' }) + .pipe(gulp.dest('./dist')); +}); + + +gulp.task('js', function() { + gulp.src([ + './inc/**/*.js' + ], { base: './' }) + .pipe(uglify()) + .pipe(gulp.dest('./dist')); +}); + +gulp.task('sass', function() { + gulp.src([ + './inc/**/*.scss' + ], { base: './' }) + .pipe(sass().on('error', sass.logError)) + .pipe(gulp.dest('./')) + .pipe(browserSync.stream()); +}); + +gulp.task('css', function() { + gulp.src([ + './inc/**/*.css' + ], { base: './' }) + .pipe(autoprefixer({ + browsers: ['last 2 versions'] + })) + .pipe(cleanCSS({compatibility: 'ie10'})) + .pipe(gulp.dest('./dist')) +}); + +gulp.task('serve', ['sass'], function() { + browserSync.init({ + proxy: 'localhost:8080' + }); + + gulp.watch('./inc/**/*.scss', ['sass']); + gulp.watch([ + './inc/**/*', + '!./inc/**/*.ts' + ]).on('change', browserSync.reload); + +}); diff --git a/inc/js/tinymce-buttons-bak.js b/inc/js/tinymce-buttons-bak.js deleted file mode 100644 index 976edd06..00000000 --- a/inc/js/tinymce-buttons-bak.js +++ /dev/null @@ -1,464 +0,0 @@ -(function() { - - tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function(editor, url) { - editor.addButton('abt_ref_id_parser_mce_button', { - type: 'menubutton', - image: url + '/../images/book.png', - title: "Academic Blogger's Toolkit", - icon: true, - menu: [{ - text: 'Bibliography Tools', - menu: [ - // Inline Citation Menu Item - { - text: 'Inline Citation', - onclick: function() { - editor.windowManager.open({ - title: 'Insert Citation', - width: 600, - height: 58, - body: [{ - type: 'textbox', - name: 'citation_number', - label: 'Citation Number', - value: '' - }, { - type: 'container', - html: 'Protip: Use the keyboard shortcut to access this menu
PC/Linux: (Ctrl+Alt+C) | Mac: (Cmd+Alt+C)' - }], - - onsubmit: function(e) { - editor.insertContent( - '[cite num="' + e.data.citation_number + '"]' - ); - } - }); - } - }, - // Separator - { - text: '-' - }, - // Single Reference Menu Item - { - text: 'Formatted Reference', - onclick: function() { - editor.windowManager.open({ - title: 'Insert Formatted Reference', - width: 600, - height: 125, - body: [{ - type: 'textbox', - name: 'ref_id_number', - label: 'PMID or URL (Beta)', - value: '' - }, { - type: 'listbox', - label: 'Citation Format', - name: 'ref_id_citation_type', - 'values': [{ - text: 'American Medical Association (AMA)', - value: 'AMA' - }, { - text: 'American Psychological Association (APA)', - value: 'APA' - }] - - }, { - type: 'checkbox', - name: 'ref_id_include_link', - label: 'Include link to PubMed?' - }, { - type: 'container', - html: 'Protip: Use the keyboard shortcut to access this menu
PC/Linux: (Ctrl+Alt+R) | Mac: (Cmd+Alt+R)' - }], - onsubmit: function(e) { - - editor.setProgressState(1); - var inputText = e.data.ref_id_number; - var citationFormat = e.data.ref_id_citation_type; - var includePubmedLink = e.data.ref_id_include_link; - var requestURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + inputText + '&version=2.0&retmode=json'; - var isPubmedCitation = true; - - var PMIDtest = new RegExp(/^[0-9]+$/); - if (!PMIDtest.test(inputText)) { - requestURL = inputText; - isPubmedCitation = false; - } - - var request = new XMLHttpRequest(); - request.open('GET', requestURL, true); - request.onload = function() { - if (request.readyState === 4) { - if (request.status === 200) { - output = parseRequestData(JSON.parse(request.responseText), inputText, citationFormat, includePubmedLink, isPubmedCitation); - editor.insertContent(output); - editor.setProgressState(0); - } else { - alert('ERROR: PMID not recognized.'); - editor.setProgressState(0); - return; - } - } - }; - request.send(null); - - } - }); - } - } - ] - }, { - text: 'Tracked Link', - onclick: function() { - var user_selection = tinyMCE.activeEditor.selection.getContent({ - format: 'text' - }); - editor.windowManager.open({ - title: 'Insert Tracked Link', - width: 600, - height: 160, - buttons: [{ - text: 'Insert', - onclick: 'submit' - }], - body: [{ - type: 'textbox', - name: 'tracked_url', - label: 'URL', - value: '' - }, { - type: 'textbox', - name: 'tracked_title', - label: 'Link Text', - value: user_selection - }, { - type: 'textbox', - name: 'tracked_tag', - label: 'Custom Tag ID', - tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', - value: '' - }, { - type: 'checkbox', - name: 'tracked_new_window', - label: 'Open link in a new window/tab' - }, ], - onsubmit: function(e) { - var trackedUrl = e.data.tracked_url; - var trackedTitle = e.data.tracked_title; - var trackedTag = e.data.tracked_tag; - var trackedLink; - - - if (e.data.tracked_new_window) { - trackedLink = '' + trackedTitle + ''; - } else { - trackedLink = '' + trackedTitle + ''; - } - - editor.execCommand('mceInsertContent', false, trackedLink); - } - }); - } - }, { - text: '-' - }, { - text: 'Request More Tools', - onclick: function() { - editor.windowManager.open({ - title: 'Request More Tools', - body: [ - - { - type: 'label', - text: "Have a feature or tool in mind that isn't available? Visit the link below to send a feature request. We'll do our best to make it happen." - }, { - type: 'button', - text: 'Send us your thoughts!', - onclick: function() { - window.open('https://github.com/dsifford/academic-bloggers-toolkit/issues', '_blank'); - }, - } - - ], - onsubit: function() { - return; - } - }); - } - } - - ] - }); - editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { - editor.windowManager.open({ - title: 'Insert Formatted Reference', - width: 600, - height: 125, - body: [{ - type: 'textbox', - name: 'ref_id_number', - label: 'PMID or URL (Beta)', - value: '' - }, { - type: 'listbox', - label: 'Citation Format', - name: 'ref_id_citation_type', - 'values': [{ - text: 'American Medical Association (AMA)', - value: 'AMA' - }, { - text: 'American Psychological Association (APA)', - value: 'APA' - }] - - }, { - type: 'checkbox', - name: 'ref_id_include_link', - label: 'Include link to PubMed?' - }], - onsubmit: function(e) { - - editor.setProgressState(1); - var PMID = e.data.ref_id_number; - var citationFormat = e.data.ref_id_citation_type; - var includePubmedLink = e.data.ref_id_include_link; - - var request = new XMLHttpRequest(); - request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); - request.onload = function() { - if (request.readyState === 4) { - if (request.status === 200) { - output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); - editor.insertContent(output); - editor.setProgressState(0); - } else { - alert('ERROR: PMID not recognized.'); - editor.setProgressState(0); - return; - } - } - }; - request.send(null); - - } - }); - }); - - editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { - editor.windowManager.open({ - title: 'Insert Citation', - width: 600, - height: 58, - body: [{ - type: 'textbox', - name: 'citation_number', - label: 'Citation Number', - value: '' - }], - onsubmit: function(e) { - editor.insertContent( - '[cite num="' + e.data.citation_number + '"]' - ); - } - }); - }); - - }); - - function parseRequestData(data, PMID, citationFormat, includePubmedLink, isPubmedCitation) { - - var authorsRaw = data.result[PMID].authors; - var title = data.result[PMID].title; - var journalName = data.result[PMID].source; - var pubYear = data.result[PMID].pubdate.substr(0, 4); - var volume = data.result[PMID].volume; - var issue = data.result[PMID].issue; - var pages = data.result[PMID].pages; - - var authors = ''; - var output, i; - - if (citationFormat === 'AMA') { - - /** - * AUTHOR PARSING - */ - - // 0 AUTHORS - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - // 1 AUTHOR - else if (authorsRaw.length === 1) { - authors = data.result[PMID].authors[0].name; - } - // 2 - 6 AUTHORS - else if (authorsRaw.length > 1 && authorsRaw.length < 7) { - - for (i = 0; i < authorsRaw.length - 1; i++) { - authors += authorsRaw[i].name + ', '; - } - authors += authorsRaw[authorsRaw.length - 1].name + '. '; - } - // >7 AUTHORS - else { - for (i = 0; i < 3; i++) { - authors += authorsRaw[i].name + ', '; - } - authors += 'et al. '; - } - - // NO VOLUME NUMBER - if (volume === '') { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } - // NO ISSUE NUMBER - else if (issue === '' || issue === undefined) { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } else { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + '(' + issue + '): ' + pages + '.'; - } - - - } else if (citationFormat === 'APA') { - - /** - * AUTHOR PARSING - */ - - // 0 AUTHORS - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - // 1 AUTHOR - else if (authorsRaw.length === 1) { - - // Check to see if both initials are listed - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; - } else { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; - } - - } - // 2 Authors - else if (authorsRaw.length === 2) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - - } else { - - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - - } - - if ((/( \w\w)/g).test(data.result[PMID].authors[1].name)) { - - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 3) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 2, data.result[PMID].authors[1].name.length - 1) + '. ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - - } else { - - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 2) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - - } - - } - // 3-7 AUTHORS - else if (authorsRaw.length > 2 && authorsRaw.length < 8) { - - for (i = 0; i < authorsRaw.length - 1; i++) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } else { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } - - } - - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } else { - - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } - - } - // >7 AUTHORS - else { - - for (i = 0; i < 6; i++) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } else { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } - - } - - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } else { - - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } - - - } - - output = authors + '(' + pubYear + '). ' + title + ' ' + journalName + ', ' + (volume !== '' ? volume : '') + (issue !== '' ? '(' + issue + '), ' : '') + pages + '.'; - - } - - // INCLUDE LINK TO PUBMED IF CHECKBOX IS CHECKED - if (includePubmedLink) { - output += ' PMID: ' + PMID + ''; - } - - return output; - - - } - -}) -(); diff --git a/package.json b/package.json index f1462074..c1a3d434 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ "description": "A plugin extending the functionality of WordPress for Academic Blogging.", "main": "index.js", "scripts": { + "build": "rm -rf ./dist && gulp build", + "serve": "gulp serve", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -15,5 +17,13 @@ "bugs": { "url": "https://github.com/dsifford/academic-bloggers-toolkit/issues" }, - "homepage": "https://github.com/dsifford/academic-bloggers-toolkit#readme" + "homepage": "https://github.com/dsifford/academic-bloggers-toolkit#readme", + "devDependencies": { + "browser-sync": "^2.11.2", + "gulp": "^3.9.1", + "gulp-autoprefixer": "^3.1.0", + "gulp-clean-css": "^2.0.4", + "gulp-sass": "^2.2.0", + "gulp-uglify": "^1.5.3" + } } From 218f08c1b001928dac56e1cf6bd595563730c290 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Sun, 27 Mar 2016 10:19:32 -0400 Subject: [PATCH 03/18] 2.4.0 Progress --- CHANGELOG.md | 9 + academic-bloggers-toolkit.php | 2 +- gulpfile.js | 2 +- inc/css/styles.css | 183 ++++++ inc/css/{shortcodes.css => styles.scss} | 61 +- inc/js/peer-review.js | 7 +- inc/js/peer-review.ts | 8 +- inc/js/tinymce-buttons.js | 383 ++++++------- inc/js/tinymce-buttons.ts | 629 ++++++++++++--------- inc/tinymce-views/formatted-reference.html | 316 ++++++----- inc/tinymce-views/formatted-reference.js | 164 +++++- inc/tinymce-views/formatted-reference.ts | 205 ++++++- inc/tinymce-views/inline-citation.html | 2 +- inc/tinymce-views/tinymce-views.css | 146 +++-- inc/tinymce-views/tinymce-views.scss | 108 ++++ readme.txt | 11 +- 16 files changed, 1457 insertions(+), 779 deletions(-) create mode 100644 inc/css/styles.css rename inc/css/{shortcodes.css => styles.scss} (78%) create mode 100644 inc/tinymce-views/tinymce-views.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e687921..d04a9250 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +### 2.4.0 +- Full rewrite. +- Parse multiple comma-separated PMIDs at once into an ordered list. +- Add ability to add citations manually for Journals, Websites, or Blogs. + +### 2.3.1 +- Fixed poor rendering of tooltip close icon on mobile. +- Increase size of toucharea for tooltip close icon on mobile. + ### 2.3.0 - Tooltips on desktop and mobile given a much-needed facelift. - Tooltips now appear above or below depending on page scroll position (prevents chopping). diff --git a/academic-bloggers-toolkit.php b/academic-bloggers-toolkit.php index 5054562f..15c51cde 100644 --- a/academic-bloggers-toolkit.php +++ b/academic-bloggers-toolkit.php @@ -21,7 +21,7 @@ function abt_enqueue_styles() { - wp_enqueue_style( 'abt_shortcodes_stylesheet', plugins_url('academic-bloggers-toolkit/inc/css/shortcodes.css') ); + wp_enqueue_style( 'abt_shortcodes_stylesheet', plugins_url('academic-bloggers-toolkit/inc/css/styles.css') ); } add_action( 'wp_enqueue_scripts', 'abt_enqueue_styles'); diff --git a/gulpfile.js b/gulpfile.js index 5bf2cd6a..619db6eb 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -54,7 +54,7 @@ gulp.task('serve', ['sass'], function() { gulp.watch('./inc/**/*.scss', ['sass']); gulp.watch([ './inc/**/*', - '!./inc/**/*.ts' + '!./inc/**/*.{ts,css}', ]).on('change', browserSync.reload); }); diff --git a/inc/css/styles.css b/inc/css/styles.css new file mode 100644 index 00000000..b3d6cf50 --- /dev/null +++ b/inc/css/styles.css @@ -0,0 +1,183 @@ +/* =========== TOOLTIP ============*/ +.abt_tooltip { + border: 1px solid #f1f1f1; + border-radius: 3px; + padding: 8px; + position: absolute; + margin: auto; + font-size: 0.75em; + background-color: #fff; + box-shadow: 0 0 50px rgba(0, 0, 0, 0.35); + z-index: 20; + animation: fadeInUp .2s; } + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translate3d(0, 10px, 0); } + to { + opacity: 1; + transform: none; } } + +.abt_tooltip_arrow { + content: ""; + position: absolute; + margin-left: -8px; + border-width: 8px; + border-style: solid; + pointer-events: none; } + +.abt_tooltip_touch_close-container { + width: 50px; + height: 50px; + position: absolute; + top: -10px; + right: -10px; + text-align: right; } + +.abt_tooltip_touch_close { + position: relative; + border-radius: 50%; + width: 26px; + height: 26px; + box-sizing: border-box; + display: inline-block; + vertical-align: middle; + font-style: normal; + color: #f1f1f1; + background: #555; + text-indent: -9999px; + transform: rotate(45deg); } + .abt_tooltip_touch_close:before, .abt_tooltip_touch_close:after { + content: ''; + left: 50%; + top: 50%; + box-shadow: inset 0 0 0 32px; + position: absolute; + transform: translate(-50%, -50%); } + .abt_tooltip_touch_close:before { + width: 14px; + pointer-events: none; + height: 2px; } + .abt_tooltip_touch_close:after { + height: 14px; + pointer-events: none; + width: 2px; } + +.noselect { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +/* =====Inline Citation Style===== */ +.cite:hover { + cursor: pointer; } + +/* =====Peer Review Box Style===== */ +#abt_PR_boxes h3 { + cursor: pointer; + border-bottom: 4px solid; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + background: #f5f5f5; + outline: 0; + /* Prevent div from being outlined on click */ + padding: 15px; + text-align: center; + margin-bottom: 10px; + margin-top: 10px; + /* Prevent text highlight on click*/ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +#abt_PR_boxes h3:hover { + background: #f1f1f1; } + +#abt_PR_boxes h3:active { + border-bottom: 1px solid; + padding-top: 18px; } + +.abt_PR_info { + display: inline-block; + float: left; + width: 30%; + position: relative; + top: 0px; + text-align: center; + font-size: 10px; + margin-bottom: 10px; + margin-right: 5px; } + +.abt_PR_info strong { + font-size: 14px; } + +.abt_PR_headshot { + display: block; + margin-left: auto; + margin-right: auto; } + +.abt_chat_bubble { + display: inline-block; + position: relative; + width: 63%; + height: auto; + min-height: 100px; + margin-right: 0px; + margin-left: 0px; + background: #F6F6F6; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + padding: 15px; + border-left: 1px solid #c7c7c7; + border-top: 1px solid #c7c7c7; + margin-bottom: 20px; + box-shadow: 1px 1px 1px #C7C7C7; } + +.abt_chat_bubble:after { + content: ''; + position: absolute; + background-color: #F6F6F6; + width: 20px; + height: 20px; + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + z-index: 1; + margin-top: -15px; + left: -11px; + top: 60px; + border-left: 1px solid #c7c7c7; + border-bottom: 1px solid #c7c7c7; } + +@media only screen and (max-width: 620px) { + .abt_PR_info { + display: block; + width: 100%; + padding-top: 10px; + padding-bottom: 20px; } + .abt_chat_bubble { + width: 100%; } + .abt_PR_info:before { + content: ''; + width: 20px; + height: 20px; + background-color: #F6F6F6; + border-right: 1px solid #c7c7c7; + border-bottom: 1px solid #c7c7c7; + position: absolute; + top: -30px; + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + z-index: 1; } + .abt_chat_bubble:after { + display: none; } } diff --git a/inc/css/shortcodes.css b/inc/css/styles.scss similarity index 78% rename from inc/css/shortcodes.css rename to inc/css/styles.scss index dada1c38..0cb694f8 100644 --- a/inc/css/shortcodes.css +++ b/inc/css/styles.scss @@ -33,29 +33,58 @@ pointer-events: none; } -.abt_tooltip_touch_close:before { +.abt_tooltip_touch_close-container { + width: 50px; + height: 50px; position: absolute; - color: #f1f1f1; - content: '✖'; top: -10px; - text-align: center; - background: #555; - width: 24px; - height: 24px; - border-radius: 50px; right: -10px; - font: 20px monospace; + text-align: right; } +.abt_tooltip_touch_close { + position: relative; + border-radius: 50%; + width: 26px; + height: 26px; + box-sizing: border-box; + display: inline-block; + vertical-align: middle; + font-style: normal; + color: #f1f1f1; + background: #555; + text-indent: -9999px; + transform: rotate(45deg); + + &:before,&:after { + content: ''; + left: 50%; + top: 50%; + box-shadow: inset 0 0 0 32px; + position: absolute; + transform: translate(-50%, -50%); + } + + &:before { + width: 14px; + pointer-events: none; + height: 2px; + } + + &:after { + height: 14px; + pointer-events: none; + width: 2px; + } +} .noselect { - -webkit-touch-callout: none; /* iOS Safari */ - -webkit-user-select: none; /* Chrome/Safari/Opera */ - -khtml-user-select: none; /* Konqueror */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE/Edge */ - user-select: none; /* non-prefixed version, currently - not supported by any browser */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } /* =====Inline Citation Style===== */ diff --git a/inc/js/peer-review.js b/inc/js/peer-review.js index 71540b16..e0a8b478 100644 --- a/inc/js/peer-review.js +++ b/inc/js/peer-review.js @@ -89,12 +89,15 @@ var ABT_Frontend; tooltipArrow.className = 'abt_tooltip_arrow'; if (this._isTouchDevice()) { var closeButton = document.createElement('div'); + var touchContainer = document.createElement('div'); + touchContainer.className = 'abt_tooltip_touch_close-container'; closeButton.className = 'abt_tooltip_touch_close'; - closeButton.addEventListener('touchend', function () { return tooltip.remove(); }); + touchContainer.addEventListener('touchend', function () { return tooltip.remove(); }); tooltip.style.left = '0'; tooltip.style.right = '0'; tooltip.style.maxWidth = '90%'; - tooltip.appendChild(closeButton); + touchContainer.appendChild(closeButton); + tooltip.appendChild(touchContainer); document.body.appendChild(tooltip); tooltip.appendChild(tooltipArrow); tooltipArrow.style.left = "calc(" + rect.left + "px - 5% + " + ((rect.right - rect.left) / 2) + "px - 3px)"; diff --git a/inc/js/peer-review.ts b/inc/js/peer-review.ts index 6bda53ce..b4eb6db0 100644 --- a/inc/js/peer-review.ts +++ b/inc/js/peer-review.ts @@ -131,13 +131,17 @@ module ABT_Frontend { if (this._isTouchDevice()) { let closeButton: HTMLDivElement = document.createElement('div'); + let touchContainer: HTMLDivElement = document.createElement('div'); + touchContainer.className = 'abt_tooltip_touch_close-container'; closeButton.className = 'abt_tooltip_touch_close'; - closeButton.addEventListener('touchend', () => tooltip.remove()); + touchContainer.addEventListener('touchend', () => tooltip.remove()); tooltip.style.left = '0'; tooltip.style.right = '0'; tooltip.style.maxWidth = '90%' - tooltip.appendChild(closeButton); + touchContainer.appendChild(closeButton); + tooltip.appendChild(touchContainer); + // tooltip.appendChild(closeButton); document.body.appendChild(tooltip); tooltip.appendChild(tooltipArrow); diff --git a/inc/js/tinymce-buttons.js b/inc/js/tinymce-buttons.js index de2b6c9f..84a2eb2e 100644 --- a/inc/js/tinymce-buttons.js +++ b/inc/js/tinymce-buttons.js @@ -1,3 +1,177 @@ +String.prototype.toTitleCase = function () { + var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; + return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function (match, index, title) { + if (index > 0 && index + match.length !== title.length && + match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && + (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && + title.charAt(index - 1).search(/[^\s-]/) < 0) { + return match.toLowerCase(); + } + if (match.substr(1).search(/[A-Z]|\../) > -1) { + return match; + } + return match.charAt(0).toUpperCase() + match.substr(1); + }); +}; +var ReferenceParser = (function () { + function ReferenceParser(data, editor) { + this.citationFormat = data['citation-format']; + this.PMIDquery = data['pmid-input'].replace(/\s/g, ''); + this.manualCitationType = data['manual-type-selection']; + this.includeLink = data['include-link']; + this.editor = editor; + } + ReferenceParser.prototype.fromPMID = function () { + var requestURL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=" + this.PMIDquery + "&version=2.0&retmode=json"; + var request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.addEventListener('load', this._parsePMID.bind(this)); + request.send(null); + }; + ReferenceParser.prototype._parsePMID = function (e) { + var req = e.target; + if (req.readyState !== 4 || req.status !== 200) { + this.editor.windowManager.alert('Your request could not be processed. Please try again.'); + return; + } + var res = JSON.parse(req.responseText); + if (res.error) { + var badPMID = res.error.match(/uid (\S+)/)[1]; + var badIndex = this.PMIDquery.split(',').indexOf(badPMID); + this.editor.windowManager.alert("PMID \"" + badPMID + "\" at index #" + (badIndex + 1) + " failed to process. Double check your list!"); + } + var payload; + switch (this.citationFormat) { + case 'ama': + payload = this._parseAMA(res.result); + break; + case 'apa': + payload = this._parseAPA(res.result); + break; + default: + this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + return; + } + if (payload.name === 'Error') { + this.editor.windowManager.alert(payload.message); + return; + } + if (payload.length === 1) { + this.editor.insertContent(payload.join()); + this.editor.setProgressState(0); + return; + } + var orderedList = '
    ' + payload.map(function (ref) { return ("
  1. " + ref + "
  2. "); }).join('') + '
'; + this.editor.insertContent(orderedList); + this.editor.setProgressState(0); + }; + ReferenceParser.prototype._parseAMA = function (data) { + var _this = this; + var pmidArray = data.uids; + var output; + try { + output = pmidArray.map(function (PMID) { + var ref = data[PMID]; + var year = ref.pubdate.substr(0, 4); + var link = _this.includeLink === true + ? " PMID: " + PMID + "" + : ''; + var authors = ''; + switch (ref.authors.length) { + case 0: + throw new Error("No authors were found for PMID " + PMID); + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + authors = ref.authors.map(function (author) { return author.name; }).join(', ') + '.'; + break; + default: + for (var i = 0; i < 3; i++) { + authors += ref.authors[i].name + ', '; + } + ; + authors += 'et al.'; + } + return (authors + " " + ref.title + " " + ref.source + ". " + year + "; ") + + ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + + ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ":") + + (ref.pages + "." + link); + }); + } + catch (e) { + return e; + } + return output; + }; + ReferenceParser.prototype._parseAPA = function (data) { + var _this = this; + var pmidArray = data.uids; + var output; + try { + output = pmidArray.map(function (PMID) { + var ref = data[PMID]; + var year = ref.pubdate.substr(0, 4); + var link = _this.includeLink === true + ? " PMID: " + PMID + "" + : ''; + var authors = ''; + switch (ref.authors.length) { + case 0: + throw new Error("No authors were found for PMID " + PMID); + case 1: + authors = ref.authors.map(function (author) { + return (author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "."); + }).join(); + break; + case 2: + authors = ref.authors.map(function (author) { + return (author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "."); + }).join(', & '); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + authors = ref.authors.map(function (author, i, arr) { + if (i === arr.length - 1) { + return (("& " + author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + ".")); + } + return ((author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "., ")); + }).join(''); + break; + default: + for (var i = 0; i < 6; i++) { + authors += + (ref.authors[i].name.split(' ')[0] + ", ") + + (ref.authors[i].name.split(' ')[1].split('').join('. ') + "., "); + } + authors += ". . . " + + (ref.lastauthor.split(' ')[0] + ", ") + + (ref.lastauthor.split(' ')[1].split('').join('. ') + "."); + break; + } + return (authors + " (" + year + "). " + ref.title + " ") + + ((ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()) + "., ") + + ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + + ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ", ") + + (ref.pages + "." + link); + }); + } + catch (e) { + return e; + } + return output; + }; + return ReferenceParser; +}()); tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) { var ABT_Button = { type: 'menubutton', @@ -100,207 +274,24 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) title: 'Insert Formatted Reference', url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', width: 600, - height: 'auto', + height: 100, onclose: function (e) { - console.log(e); + if (Object.keys(e.target.params).length === 0) { + return; + } + editor.setProgressState(1); + var payload = e.target.params.data; + var refparser = new ReferenceParser(payload, editor); + console.log(payload); + if (payload.hasOwnProperty('manual-type-selection')) { + editor.setProgressState(0); + } + refparser.fromPMID(); }, }); - } + }, }; bibToolsMenu.menu.push(inlineCitation, separator, formattedReference); ABT_Button.menu.push(bibToolsMenu, trackedLink, separator, requestTools); editor.addButton('abt_ref_id_parser_mce_button', ABT_Button); - editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function () { - editor.windowManager.open({ - title: 'Insert Formatted Reference', - width: 600, - height: 125, - body: [{ - type: 'textbox', - name: 'ref_id_number', - label: 'PMID', - value: '' - }, { - type: 'listbox', - label: 'Citation Format', - name: 'ref_id_citation_type', - 'values': [{ - text: 'American Medical Association (AMA)', - value: 'AMA' - }, { - text: 'American Psychological Association (APA)', - value: 'APA' - }] - }, { - type: 'checkbox', - name: 'ref_id_include_link', - label: 'Include link to PubMed?' - } - ], - onsubmit: function (e) { - editor.setProgressState(1); - var PMID = e.data.ref_id_number; - var citationFormat = e.data.ref_id_citation_type; - var includePubmedLink = e.data.ref_id_include_link; - var request = new XMLHttpRequest(); - request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); - request.onload = function () { - if (request.readyState === 4) { - if (request.status === 200) { - var output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); - editor.insertContent(output); - editor.setProgressState(0); - } - else { - alert('ERROR: PMID not recognized.'); - editor.setProgressState(0); - return; - } - } - }; - request.send(null); - } - }); - }); - editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function () { - editor.windowManager.open({ - title: 'Insert Citation', - width: 600, - height: 58, - body: [{ - type: 'textbox', - name: 'citation_number', - label: 'Citation Number', - value: '' - }], - onsubmit: function (e) { - editor.insertContent('[cite num="' + e.data.citation_number + '"]'); - } - }); - }); }); -function parseRequestData(data, PMID, citationFormat, includePubmedLink) { - var authorsRaw = data.result[PMID].authors; - var title = data.result[PMID].title; - var journalName = data.result[PMID].source; - var pubYear = data.result[PMID].pubdate.substr(0, 4); - var volume = data.result[PMID].volume; - var issue = data.result[PMID].issue; - var pages = data.result[PMID].pages; - var authors = ''; - var output, i; - if (citationFormat === 'AMA') { - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - else if (authorsRaw.length === 1) { - authors = data.result[PMID].authors[0].name; - } - else if (authorsRaw.length > 1 && authorsRaw.length < 7) { - for (i = 0; i < authorsRaw.length - 1; i++) { - authors += authorsRaw[i].name + ', '; - } - authors += authorsRaw[authorsRaw.length - 1].name + '. '; - } - else { - for (i = 0; i < 3; i++) { - authors += authorsRaw[i].name + ', '; - } - authors += 'et al. '; - } - if (volume === '') { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } - else if (issue === '' || issue === undefined) { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } - else { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + '(' + issue + '): ' + pages + '.'; - } - } - else if (citationFormat === 'APA') { - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - else if (authorsRaw.length === 1) { - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; - } - else { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; - } - } - else if (authorsRaw.length === 2) { - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - } - else { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - } - if ((/( \w\w)/g).test(data.result[PMID].authors[1].name)) { - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 3) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 2, data.result[PMID].authors[1].name.length - 1) + '. ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - } - else { - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 2) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - } - } - else if (authorsRaw.length > 2 && authorsRaw.length < 8) { - for (i = 0; i < authorsRaw.length - 1; i++) { - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - } - else { - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - } - } - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - } - else { - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - } - } - else { - for (i = 0; i < 6; i++) { - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - } - else { - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - } - } - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - } - else { - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - } - } - output = authors + '(' + pubYear + '). ' + title + ' ' + journalName + ', ' + (volume !== '' ? volume : '') + (issue !== '' ? '(' + issue + '), ' : '') + pages + '.'; - } - if (includePubmedLink) { - output += ' PMID: ' + PMID + ''; - } - return output; -} diff --git a/inc/js/tinymce-buttons.ts b/inc/js/tinymce-buttons.ts index 92628d77..dd70abf7 100644 --- a/inc/js/tinymce-buttons.ts +++ b/inc/js/tinymce-buttons.ts @@ -1,15 +1,26 @@ declare var tinymce, tinyMCE, AU_locationInfo -interface Author { - authtype: string - clusterid: string - name: string +interface String { + toTitleCase(): string } +String.prototype.toTitleCase = function(): string { + let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; + + return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ + if (index > 0 && index + match.length !== title.length && + match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && + (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && + title.charAt(index - 1).search(/[^\s-]/) < 0) { + return match.toLowerCase(); + } -interface AuthorObj { - [i: number]: Author - length: number -} + if (match.substr(1).search(/[A-Z]|\../) > -1) { + return match; + } + + return match.charAt(0).toUpperCase() + match.substr(1); + }); +}; interface TinyMCEMenuItem { text: string @@ -42,6 +53,231 @@ interface TinyMCEPluginButton { menu: TinyMCEMenuItem[] } +interface Author { + authtype: string + clusterid: string + name: string +} + +interface ReferenceFormData { + 'citation-format': string + 'pmid-input'?: string + 'include-link'?: boolean + 'manual-type-selection'?: string +} + +interface ReferenceObj { + authors: Author[] + title: string + source: string + pubdate: string + volume: string + issue: string + pages: string + lastauthor: string + fulljournalname?: string +} + +interface ReferencePayload { + [i: number]: ReferenceObj + uids?: string[] +} + + + + +class ReferenceParser { + + public citationFormat: string; + public includeLink: boolean; + public manualCitationType: string; + public PMIDquery: string; + public editor: any; + + constructor(data: ReferenceFormData, editor: Object) { + this.citationFormat = data['citation-format']; + this.PMIDquery = data['pmid-input'].replace(/\s/g, ''); + this.manualCitationType = data['manual-type-selection']; + this.includeLink = data['include-link']; + this.editor = editor; + } + + public fromPMID(): void { + let requestURL = `http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=${this.PMIDquery}&version=2.0&retmode=json`; + let request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.addEventListener('load', this._parsePMID.bind(this)); + request.send(null); + } + + + private _parsePMID(e: Event): void { + let req = e.target; + + // Handle bad request + if (req.readyState !== 4 || req.status !== 200) { + this.editor.windowManager.alert('Your request could not be processed. Please try again.'); + return; + } + + let res = JSON.parse(req.responseText); + + // Handle response errors + if (res.error) { + let badPMID = res.error.match(/uid (\S+)/)[1]; + let badIndex = this.PMIDquery.split(',').indexOf(badPMID); + this.editor.windowManager.alert( + `PMID "${badPMID}" at index #${badIndex + 1} failed to process. Double check your list!` + ); + } + + let payload: string[]|Error; + switch (this.citationFormat) { + case 'ama': + payload = this._parseAMA(res.result); + break; + case 'apa': + payload = this._parseAPA(res.result); + break; + default: + this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + return; + } + + if ((payload as Error).name === 'Error') { + this.editor.windowManager.alert((payload as Error).message); + return; + } + if ((payload as string[]).length === 1) { + this.editor.insertContent((payload as string[]).join()); + this.editor.setProgressState(0); + return; + } + + let orderedList: string = + '
    ' + (payload as string[]).map((ref: string) => `
  1. ${ref}
  2. `).join('') + '
'; + + this.editor.insertContent(orderedList); + this.editor.setProgressState(0); + + } + + + private _parseAMA(data: ReferencePayload): string[]|Error { + let pmidArray: string[] = data.uids; + let output: string[]; + + try { + output = pmidArray.map((PMID: string): string => { + let ref: ReferenceObj = data[PMID]; + let year: string = ref.pubdate.substr(0, 4); + let link = this.includeLink === true + ? ` PMID: ${PMID}` + : ''; + + let authors: string = ''; + switch (ref.authors.length) { + case 0: + throw new Error(`No authors were found for PMID ${PMID}`); + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + authors = ref.authors.map((author: Author) => author.name).join(', ') + '.'; + break; + default: + for (let i = 0; i < 3; i++) { authors+= ref.authors[i].name + ', ' }; + authors += 'et al.'; + } + + return `${authors} ${ref.title} ${ref.source}. ${year}; ` + + `${ref.volume === undefined || ref.volume === '' ? '' : ref.volume}` + + `${ref.issue === undefined || ref.issue === '' ? '' : '('+ref.issue+')'}:` + + `${ref.pages}.${link}`; + }); + } catch(e) { + return e; + } + + return output; + } + + private _parseAPA(data: ReferencePayload): string[]|Error { + let pmidArray: string[] = data.uids; + let output: string[]; + + try { + output = pmidArray.map((PMID: string): string => { + let ref: ReferenceObj = data[PMID]; + let year: string = ref.pubdate.substr(0, 4); + let link = this.includeLink === true + ? ` PMID: ${PMID}` + : ''; + + let authors: string = ''; + switch (ref.authors.length) { + case 0: + throw new Error(`No authors were found for PMID ${PMID}`); + case 1: + authors = ref.authors.map((author: Author) => + `${author.name.split(' ')[0]}, ` + // Last name + `${author.name.split(' ')[1].split('').join('. ')}.` // First Initial(s) + ).join(); + break; + case 2: + authors = ref.authors.map((author: Author) => + `${author.name.split(' ')[0]}, ` + // Last name + `${author.name.split(' ')[1].split('').join('. ')}.` // First Initial(s) + ).join(', & '); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + authors = ref.authors.map((author, i, arr) => { + if (i === arr.length - 1) { + return( + `& ${author.name.split(' ')[0]}, ` + + `${author.name.split(' ')[1].split('').join('. ')}.` + ); + } + return( + `${author.name.split(' ')[0]}, ` + + `${author.name.split(' ')[1].split('').join('. ')}., ` + ); + }).join(''); + break; + default: + for (let i = 0; i < 6; i++) { + authors += + `${ref.authors[i].name.split(' ')[0]}, ` + + `${ref.authors[i].name.split(' ')[1].split('').join('. ')}., ` + } + authors += `. . . ` + + `${ref.lastauthor.split(' ')[0]}, ` + + `${ref.lastauthor.split(' ')[1].split('').join('. ')}.`; + break; + } + + return `${authors} (${year}). ${ref.title} ` + + `${ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()}., ` + + `${ref.volume === undefined || ref.volume === '' ? '' : ref.volume}` + + `${ref.issue === undefined || ref.issue === '' ? '' : '('+ref.issue+')'}, ` + + `${ref.pages}.${link}`; + }); + } catch(e) { + return e; + } + + return output; + } + +} + + tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) => { let ABT_Button: TinyMCEPluginButton = { @@ -167,12 +403,32 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) title: 'Insert Formatted Reference', url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', width: 600, - height: 'auto', - onclose: (e) => { - console.log(e); + height: 100, + onclose: (e: any) => { + + // If the user presses the exit button, return. + if (Object.keys(e.target.params).length === 0) { + return; + } + + editor.setProgressState(1); + let payload: ReferenceFormData = e.target.params.data; + let refparser = new ReferenceParser(payload, editor); + + console.log(payload); + + if (payload.hasOwnProperty('manual-type-selection')) { + // do manual parsing + editor.setProgressState(0); + } + + // do pmid parsing + refparser.fromPMID(); + }, }); - } + }, + } // onsubmit: function(e) { // @@ -203,7 +459,7 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) // } // }); - } + bibToolsMenu.menu.push(inlineCitation, separator, formattedReference); ABT_Button.menu.push(bibToolsMenu, trackedLink, separator, requestTools); @@ -214,273 +470,82 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) - - editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { - editor.windowManager.open({ - title: 'Insert Formatted Reference', - width: 600, - height: 125, - body: [{ - type: 'textbox', - name: 'ref_id_number', - label: 'PMID', - value: '' - }, { - type: 'listbox', - label: 'Citation Format', - name: 'ref_id_citation_type', - 'values': [{ - text: 'American Medical Association (AMA)', - value: 'AMA' - }, { - text: 'American Psychological Association (APA)', - value: 'APA' - }] - - }, { - type: 'checkbox', - name: 'ref_id_include_link', - label: 'Include link to PubMed?' - } - ], - onsubmit: function(e) { - - editor.setProgressState(1); - var PMID = e.data.ref_id_number; - var citationFormat = e.data.ref_id_citation_type; - var includePubmedLink = e.data.ref_id_include_link; - - var request = new XMLHttpRequest(); - request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); - request.onload = function() { - if (request.readyState === 4) { - if (request.status === 200) { - let output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); - editor.insertContent(output); - editor.setProgressState(0); - } else { - alert('ERROR: PMID not recognized.'); - editor.setProgressState(0); - return; - } - } - }; - request.send(null); - - } - }); - }); - - editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { - editor.windowManager.open({ - title: 'Insert Citation', - width: 600, - height: 58, - body: [{ - type: 'textbox', - name: 'citation_number', - label: 'Citation Number', - value: '' - }], - onsubmit: function(e) { - editor.insertContent( - '[cite num="' + e.data.citation_number + '"]' - ); - } - }); - }); - +/* TODO: */ +// editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { +// editor.windowManager.open({ +// title: 'Insert Formatted Reference', +// width: 600, +// height: 125, +// body: [{ +// type: 'textbox', +// name: 'ref_id_number', +// label: 'PMID', +// value: '' +// }, { +// type: 'listbox', +// label: 'Citation Format', +// name: 'ref_id_citation_type', +// 'values': [{ +// text: 'American Medical Association (AMA)', +// value: 'AMA' +// }, { +// text: 'American Psychological Association (APA)', +// value: 'APA' +// }] +// +// }, { +// type: 'checkbox', +// name: 'ref_id_include_link', +// label: 'Include link to PubMed?' +// } +// ], +// onsubmit: function(e) { +// +// editor.setProgressState(1); +// var PMID = e.data.ref_id_number; +// var citationFormat = e.data.ref_id_citation_type; +// var includePubmedLink = e.data.ref_id_include_link; +// +// var request = new XMLHttpRequest(); +// request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); +// request.onload = function() { +// if (request.readyState === 4) { +// if (request.status === 200) { +// let output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); +// editor.insertContent(output); +// editor.setProgressState(0); +// } else { +// alert('ERROR: PMID not recognized.'); +// editor.setProgressState(0); +// return; +// } +// } +// }; +// request.send(null); +// +// } +// }); +// }); +// +// editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { +// editor.windowManager.open({ +// title: 'Insert Citation', +// width: 600, +// height: 58, +// body: [{ +// type: 'textbox', +// name: 'citation_number', +// label: 'Citation Number', +// value: '' +// }], +// onsubmit: function(e) { +// editor.insertContent( +// '[cite num="' + e.data.citation_number + '"]' +// ); +// } +// }); +// }); +// +// }); +// }); - -function parseRequestData(data, PMID, citationFormat, includePubmedLink): string { - - var authorsRaw: AuthorObj = data.result[PMID].authors; - var title: string = data.result[PMID].title; - var journalName: string = data.result[PMID].source; - var pubYear: string = data.result[PMID].pubdate.substr(0, 4); - var volume: string = data.result[PMID].volume; - var issue: string = data.result[PMID].issue; - var pages: string = data.result[PMID].pages; - - var authors = ''; - var output, i; - - if (citationFormat === 'AMA') { - - /** - * AUTHOR PARSING - */ - - // 0 AUTHORS - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - // 1 AUTHOR - else if (authorsRaw.length === 1) { - authors = data.result[PMID].authors[0].name; - } - // 2 - 6 AUTHORS - else if (authorsRaw.length > 1 && authorsRaw.length < 7) { - - for (i = 0; i < authorsRaw.length - 1; i++) { - authors += authorsRaw[i].name + ', '; - } - authors += authorsRaw[authorsRaw.length - 1].name + '. '; - } - // >7 AUTHORS - else { - for (i = 0; i < 3; i++) { - authors += authorsRaw[i].name + ', '; - } - authors += 'et al. '; - } - - // NO VOLUME NUMBER - if (volume === '') { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } - // NO ISSUE NUMBER - else if (issue === '' || issue === undefined) { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + ': ' + pages + '.'; - } else { - output = authors + ' ' + title + ' ' + journalName + '. ' + pubYear + '; ' + volume + '(' + issue + '): ' + pages + '.'; - } - - - } else if (citationFormat === 'APA') { - - /** - * AUTHOR PARSING - */ - - // 0 AUTHORS - if (authorsRaw.length === 0) { - alert('ERROR: No authors were found for this PMID.\n\nPlease double-check PMID or insert reference manually.'); - } - // 1 AUTHOR - else if (authorsRaw.length === 1) { - - // Check to see if both initials are listed - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; - } else { - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '. '; - } - - } - // 2 Authors - else if (authorsRaw.length === 2) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[0].name)) { - - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 3) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 2, data.result[PMID].authors[0].name.length - 1) + '. ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - - } else { - - authors += data.result[PMID].authors[0].name.substring(0, data.result[PMID].authors[0].name.length - 2) + ', ' + - data.result[PMID].authors[0].name.substring(data.result[PMID].authors[0].name.length - 1) + '., & '; - - } - - if ((/( \w\w)/g).test(data.result[PMID].authors[1].name)) { - - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 3) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 2, data.result[PMID].authors[1].name.length - 1) + '. ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - - } else { - - authors += data.result[PMID].authors[1].name.substring(0, data.result[PMID].authors[1].name.length - 2) + ', ' + - data.result[PMID].authors[1].name.substring(data.result[PMID].authors[1].name.length - 1) + '. '; - - } - - } - // 3-7 AUTHORS - else if (authorsRaw.length > 2 && authorsRaw.length < 8) { - - for (i = 0; i < authorsRaw.length - 1; i++) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } else { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } - - } - - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } else { - - authors += '& ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } - - } - // >7 AUTHORS - else { - - for (i = 0; i < 6; i++) { - - if ((/( \w\w)/g).test(data.result[PMID].authors[i].name)) { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 3) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 2, data.result[PMID].authors[i].name.length - 1) + '. ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } else { - - authors += data.result[PMID].authors[i].name.substring(0, data.result[PMID].authors[i].name.length - 2) + ', ' + - data.result[PMID].authors[i].name.substring(data.result[PMID].authors[i].name.length - 1) + '., '; - - } - - } - - if ((/( \w\w)/g).test(data.result[PMID].lastauthor)) { - - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 3) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 2, data.result[PMID].lastauthor.length - 1) + '. ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } else { - - authors += '. . . ' + data.result[PMID].lastauthor.substring(0, data.result[PMID].lastauthor.length - 2) + ', ' + - data.result[PMID].lastauthor.substring(data.result[PMID].lastauthor.length - 1) + '. '; - - } - - - } - - output = authors + '(' + pubYear + '). ' + title + ' ' + journalName + ', ' + (volume !== '' ? volume : '') + (issue !== '' ? '(' + issue + '), ' : '') + pages + '.'; - - } - - // INCLUDE LINK TO PUBMED IF CHECKBOX IS CHECKED - if (includePubmedLink) { - output += ' PMID: ' + PMID + ''; - } - - return output; - - -} diff --git a/inc/tinymce-views/formatted-reference.html b/inc/tinymce-views/formatted-reference.html index 0a7092f0..0a5bc436 100644 --- a/inc/tinymce-views/formatted-reference.html +++ b/inc/tinymce-views/formatted-reference.html @@ -1,159 +1,165 @@ - - -
- +
diff --git a/inc/tinymce-views/tinymce-views.css b/inc/tinymce-views/tinymce-views.css index 7a093da3..4b279879 100644 --- a/inc/tinymce-views/tinymce-views.css +++ b/inc/tinymce-views/tinymce-views.css @@ -1,103 +1,85 @@ .row { - margin-top: 10px; - margin-bottom: 10px; -} + margin-top: 10px; + margin-bottom: 10px; } -.btn { - background: #f7f7f7; - border-color: #ccc; - border-radius: 3px; - border-style: solid; - border-width: 1px; - box-shadow: 0 1px 0 #ccc; - box-sizing: border-box; - color: #555; - cursor: pointer; - display: inline-block; - font-size: 13px; - height: 30px; - line-height: 31px; - margin: 0; - padding: 0 12px 2px; - vertical-align: top; - white-space: nowrap; - -moz-box-sizing: border-box; - -webkit-appearance: none; - -webkit-border-radius: 3px; - -webkit-box-shadow: 0 1px 0 #ccc; - -webkit-box-sizing: border-box; -} +.manual-input-table { + width: 100%; } + .manual-input-table input { + width: 100%; } -.btn:hover { +.btn, .submit-btn { + background: #f7f7f7; + border-color: #ccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 1px 0 #ccc; + box-sizing: border-box; + color: #555; + cursor: pointer; + display: inline-block; + font-size: 13px; + height: 30px; + line-height: 31px; + margin: 0; + padding: 0 12px 2px; + vertical-align: top; + white-space: nowrap; + -webkit-appearance: none; } + .btn:hover, .submit-btn:hover { background: #fafafa; border-color: #999; - color: #23282d; -} - -.btn:active { + color: #23282d; } + .btn:active, .submit-btn:active { background: #eee; border-color: #999; - -webkit-box-shadow: inset 0 2px 5px -3px rgba(0,0,0,.5); - box-shadow: inset 0 2px 5px -3px rgba(0,0,0,.5); - -webkit-transform: translateY(1px); - -ms-transform: translateY(1px); + box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); transform: translateY(1px); - outline: 0; -} + outline: 0; } .submit-btn { - background: #0085ba; - border-color: #0073aa #006799 #006799; - box-shadow: 0 1px 0 #006799; - color: #fff; - text-decoration: none; - text-shadow: 0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799,-1px 0 1px #006799; - -webkit-box-shadow: 0 1px 0 #006799; -} - -.submit-btn:hover { + background: #0085ba; + border-color: #0073aa #006799 #006799; + box-shadow: 0 1px 0 #006799; + color: #fff; + text-decoration: none; + text-shadow: 0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799,-1px 0 1px #006799; } + .submit-btn:hover { background: #008ec2; border-color: #006799; - color: #fff -} - -.submit-btn:active { + color: #fff; } + .submit-btn:active { background: #0073aa; border-color: #006799; - -webkit-box-shadow: inset 0 2px 0 #006799; box-shadow: inset 0 2px 0 #006799; - vertical-align: top -} + vertical-align: top; } input, select { - border: 1px solid #ddd; - -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.07); - box-shadow: inset 0 1px 2px rgba(0,0,0,.07); - background-color: #fff; - color: #32373c; - outline: 0; - -webkit-transition: 50ms border-color ease-in-out; - transition: 50ms border-color ease-in-out; - margin: 1px; - padding: 5px; - font-size: 1em; -} - -input[type="checkbox"] { + border: 1px solid #ddd; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07); + background-color: #fff; + color: #32373c; + outline: 0; + height: 31px; + transition: 50ms border-color ease-in-out; + margin: 1px; + padding: 5px; + font-size: 1em; } + input:focus, select:focus { + border-color: #5b9dd9; + box-shadow: 0 0 2px rgba(30, 140, 190, 0.8); } + input[type="checkbox"], select[type="checkbox"] { height: 18px; width: 18px; - vertical-align: middle; -} - -input:focus { - outline: none; -} + vertical-align: middle; } select { - padding: 2px; - line-height: 28px; - height: 28px; - vertical-align: middle; - margin: 1px; - font-size: 1em; -} + padding: 2px; + vertical-align: middle; + margin: 1px; + font-size: 1em; } + +a { + color: #0073aa; } + a:hover { + color: #00a0d2; } diff --git a/inc/tinymce-views/tinymce-views.scss b/inc/tinymce-views/tinymce-views.scss new file mode 100644 index 00000000..9dfb867b --- /dev/null +++ b/inc/tinymce-views/tinymce-views.scss @@ -0,0 +1,108 @@ +.row { + margin-top: 10px; + margin-bottom: 10px; +} + +.manual-input-table { + width: 100%; + input { + width: 100%; + } +} + +.btn { + background: #f7f7f7; + border-color: #ccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 1px 0 #ccc; + box-sizing: border-box; + color: #555; + cursor: pointer; + display: inline-block; + font-size: 13px; + height: 30px; + line-height: 31px; + margin: 0; + padding: 0 12px 2px; + vertical-align: top; + white-space: nowrap; + -webkit-appearance: none; + + &:hover { + background: #fafafa; + border-color: #999; + color: #23282d; + } + + &:active { + background: #eee; + border-color: #999; + box-shadow: inset 0 2px 5px -3px rgba(0,0,0,.5); + transform: translateY(1px); + outline: 0; + } +} + +.submit-btn { + @extend .btn; + background: #0085ba; + border-color: #0073aa #006799 #006799; + box-shadow: 0 1px 0 #006799; + color: #fff; + text-decoration: none; + text-shadow: 0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799,-1px 0 1px #006799; + + &:hover { + background: #008ec2; + border-color: #006799; + color: #fff + } + + &:active { + background: #0073aa; + border-color: #006799; + box-shadow: inset 0 2px 0 #006799; + vertical-align: top; + } +} + +input, select { + border: 1px solid #ddd; + box-shadow: inset 0 1px 2px rgba(0,0,0,.07); + background-color: #fff; + color: #32373c; + outline: 0; + height: 31px; + transition: 50ms border-color ease-in-out; + margin: 1px; + padding: 5px; + font-size: 1em; + + &:focus { + border-color: #5b9dd9; + box-shadow: 0 0 2px rgba(30, 140, 190, .8); + } + + &[type="checkbox"] { + height: 18px; + width: 18px; + vertical-align: middle; + } +} + +select { + padding: 2px; + vertical-align: middle; + margin: 1px; + font-size: 1em; +} + +a { + color: #0073aa; + + &:hover { + color: #00a0d2; + } +} diff --git a/readme.txt b/readme.txt index be679da5..c0073ec8 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Donate link: https://cash.me/$dsifford Tags: academic, pmid, doi, peer-review, Google Tag Manager, citation, bibliography Requires at least: 4.2.2 Tested up to: 4.2.2 -Stable tag: 2.3.0 +Stable tag: 2.4.0 License: GPL3 or later License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -63,6 +63,15 @@ Yikes! I'm sorry about that. Please report all issues on the Academic Blogger's == Changelog == += 2.4.0 = +* Full rewrite. +* Parse multiple comma-separated PMIDs at once into an ordered list. +* Add ability to add citations manually for Journals, Websites, or Blogs. + += 2.3.1 = +* Fix poor rendering of tooltip close icon on mobile. +* Increase size of toucharea for tooltip close icon on mobile. + = 2.3.0 = * Tooltips on desktop and mobile given a much-needed facelift. * Tooltips now appear above or below depending on page scroll position (prevents chopping). From 55540e23197c29d7541a146d7a818a91d69bc731 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Sun, 27 Mar 2016 20:57:13 -0400 Subject: [PATCH 04/18] Finish early stages of data cleaning - committing before breaking code into modules --- inc/js/parsers.ts | 0 inc/js/tinymce-buttons.js | 35 ++++++++++++- inc/js/tinymce-buttons.ts | 58 +++++++++++++++++++--- inc/tinymce-views/formatted-reference.html | 18 +++---- inc/tinymce-views/formatted-reference.js | 15 +++++- inc/tinymce-views/formatted-reference.ts | 19 +++++-- 6 files changed, 122 insertions(+), 23 deletions(-) create mode 100644 inc/js/parsers.ts diff --git a/inc/js/parsers.ts b/inc/js/parsers.ts new file mode 100644 index 00000000..e69de29b diff --git a/inc/js/tinymce-buttons.js b/inc/js/tinymce-buttons.js index 84a2eb2e..86a10210 100644 --- a/inc/js/tinymce-buttons.js +++ b/inc/js/tinymce-buttons.js @@ -16,7 +16,9 @@ String.prototype.toTitleCase = function () { var ReferenceParser = (function () { function ReferenceParser(data, editor) { this.citationFormat = data['citation-format']; - this.PMIDquery = data['pmid-input'].replace(/\s/g, ''); + this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined + ? data['pmid-input'].replace(/\s/g, '') + : ''; this.manualCitationType = data['manual-type-selection']; this.includeLink = data['include-link']; this.editor = editor; @@ -28,6 +30,35 @@ var ReferenceParser = (function () { request.addEventListener('load', this._parsePMID.bind(this)); request.send(null); }; + ReferenceParser.prototype.cleanManualData = function (data) { + var output; + var type = this.manualCitationType; + var authors = data.authors; + var title = data[(type + "-title")].toTitleCase(); + var source = data[(type + "-source")]; + var pubdate = data[(type + "-date")] ? data[(type + "-date")] : ''; + var volume = data[(type + "-volume")] ? data[(type + "-volume")] : ''; + var issue = data[(type + "-issue")] ? data[(type + "-issue")] : ''; + var pages = data[(type + "-pages")] ? data[(type + "-pages")] : ''; + var lastauthor = data.authors[data.authors.length - 1].name; + var url = data[(type + "-url")] ? data[(type + "-url")] : ''; + var accessdate = data[(type + "-accessed")] ? data[(type + "-accessed")] : ''; + output = { + authors: authors, + title: title, + source: source, + pubdate: pubdate, + volume: volume, + issue: issue, + pages: pages, + lastauthor: lastauthor, + url: url, + accessdate: accessdate, + }; + console.log("OUTPUT:"); + console.log(output); + return output; + }; ReferenceParser.prototype._parsePMID = function (e) { var req = e.target; if (req.readyState !== 4 || req.status !== 200) { @@ -284,7 +315,9 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) var refparser = new ReferenceParser(payload, editor); console.log(payload); if (payload.hasOwnProperty('manual-type-selection')) { + refparser.cleanManualData(payload); editor.setProgressState(0); + return; } refparser.fromPMID(); }, diff --git a/inc/js/tinymce-buttons.ts b/inc/js/tinymce-buttons.ts index dd70abf7..e9220c4b 100644 --- a/inc/js/tinymce-buttons.ts +++ b/inc/js/tinymce-buttons.ts @@ -1,3 +1,4 @@ +/// declare var tinymce, tinyMCE, AU_locationInfo interface String { @@ -54,8 +55,8 @@ interface TinyMCEPluginButton { } interface Author { - authtype: string - clusterid: string + authtype?: string + clusterid?: string name: string } @@ -64,6 +65,7 @@ interface ReferenceFormData { 'pmid-input'?: string 'include-link'?: boolean 'manual-type-selection'?: string + authors?: Author[] } interface ReferenceObj { @@ -71,11 +73,17 @@ interface ReferenceObj { title: string source: string pubdate: string - volume: string - issue: string pages: string lastauthor: string + issue?: string + volume?: string fulljournalname?: string + url?: string + accessdate?: string +} + +interface ManualReference extends ReferenceObj { + /** FIXME */ } interface ReferencePayload { @@ -84,8 +92,6 @@ interface ReferencePayload { } - - class ReferenceParser { public citationFormat: string; @@ -96,7 +102,9 @@ class ReferenceParser { constructor(data: ReferenceFormData, editor: Object) { this.citationFormat = data['citation-format']; - this.PMIDquery = data['pmid-input'].replace(/\s/g, ''); + this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined + ? data['pmid-input'].replace(/\s/g, '') + : ''; this.manualCitationType = data['manual-type-selection']; this.includeLink = data['include-link']; this.editor = editor; @@ -110,6 +118,39 @@ class ReferenceParser { request.send(null); } + public cleanManualData(data: ReferenceFormData): ReferenceObj { + let output: ReferenceObj; + let type = this.manualCitationType; + + let authors: Author[] = data.authors; + let title: string = data[`${type}-title`].toTitleCase(); + let source: string = data[`${type}-source`]; + let pubdate: string = data[`${type}-date`] ? data[`${type}-date`] : ''; + let volume: string = data[`${type}-volume`] ? data[`${type}-volume`] : ''; + let issue: string = data[`${type}-issue`] ? data[`${type}-issue`] : ''; + let pages: string = data[`${type}-pages`] ? data[`${type}-pages`] : ''; + let lastauthor: string = data.authors[data.authors.length - 1].name; + let url: string = data[`${type}-url`] ? data[`${type}-url`] : ''; + let accessdate: string = data[`${type}-accessed`] ? data[`${type}-accessed`] : ''; + + output = { + authors, + title, + source, + pubdate, + volume, + issue, + pages, + lastauthor, + url, + accessdate, + } + + console.log(`OUTPUT:`); + console.log(output); + return output; + } + private _parsePMID(e: Event): void { let req = e.target; @@ -418,8 +459,9 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) console.log(payload); if (payload.hasOwnProperty('manual-type-selection')) { - // do manual parsing + refparser.cleanManualData(payload); editor.setProgressState(0); + return; } // do pmid parsing diff --git a/inc/tinymce-views/formatted-reference.html b/inc/tinymce-views/formatted-reference.html index 0a5bc436..3d9efbb6 100644 --- a/inc/tinymce-views/formatted-reference.html +++ b/inc/tinymce-views/formatted-reference.html @@ -46,13 +46,13 @@ Journal Abbreviation [?] - + Year Published - + @@ -80,13 +80,13 @@ Post Title - + Blog Title - + @@ -104,7 +104,7 @@ Access Date - + @@ -114,13 +114,13 @@ Page Title - + Website Name - + @@ -132,13 +132,13 @@ Year Published - + Access Date - + diff --git a/inc/tinymce-views/formatted-reference.js b/inc/tinymce-views/formatted-reference.js index fadc3a54..653227a4 100644 --- a/inc/tinymce-views/formatted-reference.js +++ b/inc/tinymce-views/formatted-reference.js @@ -121,7 +121,7 @@ var ReferenceWindow = (function () { var wm = top.tinymce.activeEditor.windowManager; var formElement = e.srcElement; var payload = {}; - var skippedFields = []; + var authorList = {}; for (var i = 0; i < formElement.length; i++) { var el = formElement[i]; if (el.type == 'button' @@ -134,9 +134,20 @@ var ReferenceWindow = (function () { payload[el.id] = el.checked; continue; } + if (el.id.search(/^author-fname/) > -1 || el.id.search(/^author-lname/) > -1) { + var capitalizedName = el.value[0].toUpperCase() + el.value.substr(1).toLowerCase(); + authorList[el.id] = capitalizedName; + continue; + } payload[el.id] = el.value; } - console.log(payload); + payload['authors'] = []; + for (var i = 0; i < (Object.keys(authorList).length / 2); i++) { + var author = { + name: authorList[("author-fname-" + (i + 1))] + ' ' + authorList[("author-lname-" + (i + 1))] + }; + payload['authors'].push(author); + } wm.setParams({ data: payload }); wm.close(); }; diff --git a/inc/tinymce-views/formatted-reference.ts b/inc/tinymce-views/formatted-reference.ts index cef91c4c..2e6a865b 100644 --- a/inc/tinymce-views/formatted-reference.ts +++ b/inc/tinymce-views/formatted-reference.ts @@ -168,8 +168,8 @@ class ReferenceWindow { let wm = top.tinymce.activeEditor.windowManager; let formElement: HTMLFormElement = e.srcElement; - let payload = {}; - let skippedFields: string[] = [] + let payload: Object = {}; + let authorList: Object = {}; for (let i = 0; i < formElement.length; i++) { let el = formElement[i]; @@ -183,10 +183,23 @@ class ReferenceWindow { continue; } + if (el.id.search(/^author-fname/) > -1 || el.id.search(/^author-lname/) > -1) { + let capitalizedName = el.value[0].toUpperCase() + el.value.substr(1).toLowerCase(); + authorList[el.id] = capitalizedName; + continue; + } + payload[el.id] = el.value; } - console.log(payload) + // Prepare author data + payload['authors'] = []; + for (let i = 0; i < (Object.keys(authorList).length / 2); i++) { + let author = { + name: authorList[`author-fname-${i + 1}`] + ' ' + authorList[`author-lname-${i + 1}`] + } + payload['authors'].push(author); + } wm.setParams({data: payload}); wm.close(); From 6d8633e4349648ec54cf6e54e51856d8bbd47395 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Mon, 28 Mar 2016 00:11:45 -0400 Subject: [PATCH 05/18] Finish modularizing code + begin working on manual citations --- inc/js/ABT.d.ts | 71 ++++ inc/js/parsers.ts | 0 inc/js/tinymce-buttons-bak.js | 335 ++++++++++++++++ inc/js/tinymce-buttons.js | 455 ++++++++++++--------- inc/js/tinymce-buttons.ts | 593 ---------------------------- inc/js/wp-editor/inc/toTitleCase.ts | 18 + inc/js/wp-editor/main-parser.ts | 139 +++++++ inc/js/wp-editor/parsers/ama.ts | 88 +++++ inc/js/wp-editor/parsers/apa.ts | 107 +++++ inc/js/wp-editor/tinymce-buttons.ts | 279 +++++++++++++ inc/js/wp-editor/tsconfig.json | 32 ++ tsconfig.json | 2 +- 12 files changed, 1340 insertions(+), 779 deletions(-) create mode 100644 inc/js/ABT.d.ts delete mode 100644 inc/js/parsers.ts create mode 100644 inc/js/tinymce-buttons-bak.js delete mode 100644 inc/js/tinymce-buttons.ts create mode 100644 inc/js/wp-editor/inc/toTitleCase.ts create mode 100644 inc/js/wp-editor/main-parser.ts create mode 100644 inc/js/wp-editor/parsers/ama.ts create mode 100644 inc/js/wp-editor/parsers/apa.ts create mode 100644 inc/js/wp-editor/tinymce-buttons.ts create mode 100644 inc/js/wp-editor/tsconfig.json diff --git a/inc/js/ABT.d.ts b/inc/js/ABT.d.ts new file mode 100644 index 00000000..a5dfc888 --- /dev/null +++ b/inc/js/ABT.d.ts @@ -0,0 +1,71 @@ +interface String { + toTitleCase(): string +} + +interface TinyMCEMenuItem { + text: string + menu?: TinyMCEMenuItem[] + onclick?: (e?: Event) => void +} + +interface TinyMCEWindowElement { + type: string + name: string + label: string + value: string + tooltip?: string +} + +interface TinyMCEWindowMangerObject { + title: string + width: number + height: any + body?: TinyMCEWindowElement[] + url?: string + onclose?: (e?: Event) => void +} + +interface TinyMCEPluginButton { + type: string + image: string + title: string + icon: boolean + menu: TinyMCEMenuItem[] +} + +interface Author { + authtype?: string + clusterid?: string + name: string +} + +interface ReferenceFormData { + 'citation-format': string + 'pmid-input'?: string + 'include-link'?: boolean + 'manual-type-selection'?: string + authors?: Author[] +} + +interface ReferenceObj { + authors: Author[] + title: string + source: string + pubdate: string + pages: string + lastauthor: string + issue?: string + volume?: string + fulljournalname?: string + url?: string + accessdate?: string +} + +interface ManualReference extends ReferenceObj { + /** FIXME */ +} + +interface ReferencePayload { + [i: number]: ReferenceObj + uids?: string[] +} diff --git a/inc/js/parsers.ts b/inc/js/parsers.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/inc/js/tinymce-buttons-bak.js b/inc/js/tinymce-buttons-bak.js new file mode 100644 index 00000000..d48cc63f --- /dev/null +++ b/inc/js/tinymce-buttons-bak.js @@ -0,0 +1,335 @@ +String.prototype.toTitleCase = function () { + var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; + return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function (match, index, title) { + if (index > 0 && index + match.length !== title.length && + match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && + (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && + title.charAt(index - 1).search(/[^\s-]/) < 0) { + return match.toLowerCase(); + } + if (match.substr(1).search(/[A-Z]|\../) > -1) { + return match; + } + return match.charAt(0).toUpperCase() + match.substr(1); + }); +}; +var Parsers; +(function (Parsers) { + var MainParser = (function () { + function MainParser(data, editor) { + this.citationFormat = data['citation-format']; + this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined + ? data['pmid-input'].replace(/\s/g, '') + : ''; + this.manualCitationType = data['manual-type-selection']; + this.includeLink = data['include-link']; + this.editor = editor; + } + MainParser.prototype.fromPMID = function () { + var requestURL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=" + this.PMIDquery + "&version=2.0&retmode=json"; + var request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.addEventListener('load', this._parsePMID.bind(this)); + request.send(null); + }; + MainParser.prototype.cleanManualData = function (data) { + var output; + var type = this.manualCitationType; + var authors = data.authors; + var title = data[(type + "-title")].toTitleCase(); + var source = data[(type + "-source")]; + var pubdate = data[(type + "-date")] ? data[(type + "-date")] : ''; + var volume = data[(type + "-volume")] ? data[(type + "-volume")] : ''; + var issue = data[(type + "-issue")] ? data[(type + "-issue")] : ''; + var pages = data[(type + "-pages")] ? data[(type + "-pages")] : ''; + var lastauthor = data.authors[data.authors.length - 1].name; + var url = data[(type + "-url")] ? data[(type + "-url")] : ''; + var accessdate = data[(type + "-accessed")] ? data[(type + "-accessed")] : ''; + output = { + authors: authors, + title: title, + source: source, + pubdate: pubdate, + volume: volume, + issue: issue, + pages: pages, + lastauthor: lastauthor, + url: url, + accessdate: accessdate, + }; + console.log("OUTPUT:"); + console.log(output); + return output; + }; + MainParser.prototype._parsePMID = function (e) { + var req = e.target; + if (req.readyState !== 4 || req.status !== 200) { + this.editor.windowManager.alert('Your request could not be processed. Please try again.'); + return; + } + var res = JSON.parse(req.responseText); + if (res.error) { + var badPMID = res.error.match(/uid (\S+)/)[1]; + var badIndex = this.PMIDquery.split(',').indexOf(badPMID); + this.editor.windowManager.alert("PMID \"" + badPMID + "\" at index #" + (badIndex + 1) + " failed to process. Double check your list!"); + } + var payload; + switch (this.citationFormat) { + case 'ama': + payload = this._parseAMA(res.result); + break; + case 'apa': + payload = this._parseAPA(res.result); + break; + default: + this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + return; + } + if (payload.name === 'Error') { + this.editor.windowManager.alert(payload.message); + return; + } + if (payload.length === 1) { + this.editor.insertContent(payload.join()); + this.editor.setProgressState(0); + return; + } + var orderedList = '
    ' + payload.map(function (ref) { return ("
  1. " + ref + "
  2. "); }).join('') + '
'; + this.editor.insertContent(orderedList); + this.editor.setProgressState(0); + }; + MainParser.prototype._parseAMA = function (data) { + var _this = this; + var pmidArray = data.uids; + var output; + try { + output = pmidArray.map(function (PMID) { + var ref = data[PMID]; + var year = ref.pubdate.substr(0, 4); + var link = _this.includeLink === true + ? " PMID: " + PMID + "" + : ''; + var authors = ''; + switch (ref.authors.length) { + case 0: + throw new Error("No authors were found for PMID " + PMID); + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + authors = ref.authors.map(function (author) { return author.name; }).join(', ') + '.'; + break; + default: + for (var i = 0; i < 3; i++) { + authors += ref.authors[i].name + ', '; + } + ; + authors += 'et al.'; + } + return (authors + " " + ref.title + " " + ref.source + ". " + year + "; ") + + ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + + ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ":") + + (ref.pages + "." + link); + }); + } + catch (e) { + return e; + } + return output; + }; + MainParser.prototype._parseAPA = function (data) { + var _this = this; + var pmidArray = data.uids; + var output; + try { + output = pmidArray.map(function (PMID) { + var ref = data[PMID]; + var year = ref.pubdate.substr(0, 4); + var link = _this.includeLink === true + ? " PMID: " + PMID + "" + : ''; + var authors = ''; + switch (ref.authors.length) { + case 0: + throw new Error("No authors were found for PMID " + PMID); + case 1: + authors = ref.authors.map(function (author) { + return (author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "."); + }).join(); + break; + case 2: + authors = ref.authors.map(function (author) { + return (author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "."); + }).join(', & '); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + authors = ref.authors.map(function (author, i, arr) { + if (i === arr.length - 1) { + return (("& " + author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + ".")); + } + return ((author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "., ")); + }).join(''); + break; + default: + for (var i = 0; i < 6; i++) { + authors += + (ref.authors[i].name.split(' ')[0] + ", ") + + (ref.authors[i].name.split(' ')[1].split('').join('. ') + "., "); + } + authors += ". . . " + + (ref.lastauthor.split(' ')[0] + ", ") + + (ref.lastauthor.split(' ')[1].split('').join('. ') + "."); + break; + } + return (authors + " (" + year + "). " + ref.title + " ") + + ((ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()) + "., ") + + ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + + ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ", ") + + (ref.pages + "." + link); + }); + } + catch (e) { + return e; + } + return output; + }; + return MainParser; + }()); + Parsers.MainParser = MainParser; +})(Parsers || (Parsers = {})); +tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) { + var ABT_Button = { + type: 'menubutton', + image: url + '/../images/book.png', + title: 'Academic Blogger\'s Toolkit', + icon: true, + menu: [], + }; + var separator = { text: '-' }; + var bibToolsMenu = { + text: 'Bibliography Tools', + menu: [], + }; + var trackedLink = { + text: 'Tracked Link', + onclick: function () { + var user_selection = tinyMCE.activeEditor.selection.getContent({ format: 'text' }); + editor.windowManager.open({ + title: 'Insert Tracked Link', + width: 600, + height: 160, + buttons: [{ + text: 'Insert', + onclick: 'submit' + }], + body: [ + { + type: 'textbox', + name: 'tracked_url', + label: 'URL', + value: '' + }, + { + type: 'textbox', + name: 'tracked_title', + label: 'Link Text', + value: user_selection + }, + { + type: 'textbox', + name: 'tracked_tag', + label: 'Custom Tag ID', + tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', + value: '' + }, + { + type: 'checkbox', + name: 'tracked_new_window', + label: 'Open link in a new window/tab' + }, + ], + onsubmit: function (e) { + var trackedUrl = e.data.tracked_url; + var trackedTitle = e.data.tracked_title; + var trackedTag = e.data.tracked_tag; + var trackedLink = ("" + trackedTitle + ""); + editor.execCommand('mceInsertContent', false, trackedLink); + } + }); + } + }; + var requestTools = { + text: 'Request More Tools', + onclick: function () { + editor.windowManager.open({ + title: 'Request More Tools', + body: [{ + type: 'container', + html: "
" + + "Have a feature or tool in mind that isn't available?
" + + "Open an issue on the GitHub repository and let me know!" + + "
", + }], + buttons: [], + }); + } + }; + var inlineCitation = { + text: 'Inline Citation', + onclick: function () { + editor.windowManager.open({ + title: 'Inline Citation', + url: AU_locationInfo.tinymceViewsURL + 'inline-citation.html', + width: 400, + height: 85, + onClose: function (e) { + editor.insertContent('[cite num="' + e.target.params.data + '"]'); + } + }); + } + }; + var formattedReference = { + text: 'Formatted Reference', + onclick: function () { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', + width: 600, + height: 100, + onclose: function (e) { + if (Object.keys(e.target.params).length === 0) { + return; + } + new Parsers.AMA; + editor.setProgressState(1); + var payload = e.target.params.data; + var refparser = new Parsers.MainParser(payload, editor); + console.log(payload); + if (payload.hasOwnProperty('manual-type-selection')) { + refparser.cleanManualData(payload); + editor.setProgressState(0); + return; + } + refparser.fromPMID(); + }, + }); + }, + }; + bibToolsMenu.menu.push(inlineCitation, separator, formattedReference); + ABT_Button.menu.push(bibToolsMenu, trackedLink, separator, requestTools); + editor.addButton('abt_ref_id_parser_mce_button', ABT_Button); +}); diff --git a/inc/js/tinymce-buttons.js b/inc/js/tinymce-buttons.js index 86a10210..2ab02811 100644 --- a/inc/js/tinymce-buttons.js +++ b/inc/js/tinymce-buttons.js @@ -13,196 +13,281 @@ String.prototype.toTitleCase = function () { return match.charAt(0).toUpperCase() + match.substr(1); }); }; -var ReferenceParser = (function () { - function ReferenceParser(data, editor) { - this.citationFormat = data['citation-format']; - this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined - ? data['pmid-input'].replace(/\s/g, '') - : ''; - this.manualCitationType = data['manual-type-selection']; - this.includeLink = data['include-link']; - this.editor = editor; - } - ReferenceParser.prototype.fromPMID = function () { - var requestURL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=" + this.PMIDquery + "&version=2.0&retmode=json"; - var request = new XMLHttpRequest(); - request.open('GET', requestURL, true); - request.addEventListener('load', this._parsePMID.bind(this)); - request.send(null); - }; - ReferenceParser.prototype.cleanManualData = function (data) { - var output; - var type = this.manualCitationType; - var authors = data.authors; - var title = data[(type + "-title")].toTitleCase(); - var source = data[(type + "-source")]; - var pubdate = data[(type + "-date")] ? data[(type + "-date")] : ''; - var volume = data[(type + "-volume")] ? data[(type + "-volume")] : ''; - var issue = data[(type + "-issue")] ? data[(type + "-issue")] : ''; - var pages = data[(type + "-pages")] ? data[(type + "-pages")] : ''; - var lastauthor = data.authors[data.authors.length - 1].name; - var url = data[(type + "-url")] ? data[(type + "-url")] : ''; - var accessdate = data[(type + "-accessed")] ? data[(type + "-accessed")] : ''; - output = { - authors: authors, - title: title, - source: source, - pubdate: pubdate, - volume: volume, - issue: issue, - pages: pages, - lastauthor: lastauthor, - url: url, - accessdate: accessdate, +var Parsers; +(function (Parsers) { + var MainParser = (function () { + function MainParser(data, editor) { + this.citationFormat = data['citation-format']; + this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined + ? data['pmid-input'].replace(/\s/g, '') + : ''; + MainParser.manualCitationType = data['manual-type-selection']; + MainParser.includeLink = data['include-link']; + this.editor = editor; + } + MainParser.prototype.fromPMID = function () { + var requestURL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=" + this.PMIDquery + "&version=2.0&retmode=json"; + var request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.addEventListener('load', this._parsePMID.bind(this)); + request.send(null); }; - console.log("OUTPUT:"); - console.log(output); - return output; - }; - ReferenceParser.prototype._parsePMID = function (e) { - var req = e.target; - if (req.readyState !== 4 || req.status !== 200) { - this.editor.windowManager.alert('Your request could not be processed. Please try again.'); + MainParser.prototype.fromManualInput = function (data) { + var cleanedData; + var type = MainParser.manualCitationType; + var authors = data.authors; + var title = data[(type + "-title")].toTitleCase(); + var source = data[(type + "-source")]; + var pubdate = data[(type + "-date")] ? data[(type + "-date")] : ''; + var volume = data[(type + "-volume")] ? data[(type + "-volume")] : ''; + var issue = data[(type + "-issue")] ? data[(type + "-issue")] : ''; + var pages = data[(type + "-pages")] ? data[(type + "-pages")] : ''; + var lastauthor = data.authors[data.authors.length - 1].name; + var url = data[(type + "-url")] ? data[(type + "-url")] : ''; + var accessdate = data[(type + "-accessed")] ? data[(type + "-accessed")] : ''; + cleanedData = { + authors: authors, + title: title, + source: source, + pubdate: pubdate, + volume: volume, + issue: issue, + pages: pages, + lastauthor: lastauthor, + url: url, + accessdate: accessdate, + }; + var payload; + switch (this.citationFormat) { + case 'ama': + var AMA_1 = new Parsers.AMA; + payload = AMA_1.parse([cleanedData]); + break; + case 'apa': + var APA_1 = new Parsers.APA; + payload = APA_1.parse([cleanedData]); + break; + default: + this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + this.editor.setProgressState(0); + return; + } + console.log("OUTPUT:"); + console.log(cleanedData); return; - } - var res = JSON.parse(req.responseText); - if (res.error) { - var badPMID = res.error.match(/uid (\S+)/)[1]; - var badIndex = this.PMIDquery.split(',').indexOf(badPMID); - this.editor.windowManager.alert("PMID \"" + badPMID + "\" at index #" + (badIndex + 1) + " failed to process. Double check your list!"); - } - var payload; - switch (this.citationFormat) { - case 'ama': - payload = this._parseAMA(res.result); - break; - case 'apa': - payload = this._parseAPA(res.result); - break; - default: - this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + }; + MainParser.prototype._parsePMID = function (e) { + var req = e.target; + if (req.readyState !== 4 || req.status !== 200) { + this.editor.windowManager.alert('Your request could not be processed. Please try again.'); + this.editor.setProgressState(0); return; - } - if (payload.name === 'Error') { - this.editor.windowManager.alert(payload.message); - return; - } - if (payload.length === 1) { - this.editor.insertContent(payload.join()); + } + var res = JSON.parse(req.responseText); + if (res.error) { + var badPMID = res.error.match(/uid (\S+)/)[1]; + var badIndex = this.PMIDquery.split(',').indexOf(badPMID); + this.editor.windowManager.alert("PMID \"" + badPMID + "\" at index #" + (badIndex + 1) + " failed to process. Double check your list!"); + } + var payload; + switch (this.citationFormat) { + case 'ama': + var AMA_2 = new Parsers.AMA; + payload = AMA_2.parse(res.result); + break; + case 'apa': + var APA_2 = new Parsers.APA; + payload = APA_2.parse(res.result); + break; + default: + this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + this.editor.setProgressState(0); + return; + } + if (payload.name === 'Error') { + this.editor.windowManager.alert(payload.message); + this.editor.setProgressState(0); + return; + } + if (payload.length === 1) { + this.editor.insertContent(payload.join()); + this.editor.setProgressState(0); + return; + } + var orderedList = '
    ' + payload.map(function (ref) { return ("
  1. " + ref + "
  2. "); }).join('') + '
'; + this.editor.insertContent(orderedList); this.editor.setProgressState(0); - return; - } - var orderedList = '
    ' + payload.map(function (ref) { return ("
  1. " + ref + "
  2. "); }).join('') + '
'; - this.editor.insertContent(orderedList); - this.editor.setProgressState(0); - }; - ReferenceParser.prototype._parseAMA = function (data) { - var _this = this; - var pmidArray = data.uids; - var output; - try { - output = pmidArray.map(function (PMID) { - var ref = data[PMID]; - var year = ref.pubdate.substr(0, 4); - var link = _this.includeLink === true - ? " PMID: " + PMID + "" - : ''; - var authors = ''; - switch (ref.authors.length) { - case 0: - throw new Error("No authors were found for PMID " + PMID); - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - authors = ref.authors.map(function (author) { return author.name; }).join(', ') + '.'; - break; - default: - for (var i = 0; i < 3; i++) { - authors += ref.authors[i].name + ', '; - } - ; - authors += 'et al.'; - } - return (authors + " " + ref.title + " " + ref.source + ". " + year + "; ") + - ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + - ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ":") + - (ref.pages + "." + link); - }); + }; + return MainParser; + }()); + Parsers.MainParser = MainParser; +})(Parsers || (Parsers = {})); +var Parsers; +(function (Parsers) { + var AMA = (function () { + function AMA() { } - catch (e) { - return e; + AMA.prototype.parse = function (data) { + var pmidArray = data.uids || false; + if (pmidArray) { + return this._fromPMID(data, pmidArray); + } + return this._fromManual(data); + }; + AMA.prototype._fromPMID = function (data, pmidArray) { + var _this = this; + var output; + try { + output = pmidArray.map(function (PMID) { + var ref = data[PMID]; + var year = ref.pubdate.substr(0, 4); + var link = Parsers.MainParser.includeLink === true + ? " PMID: " + PMID + "" + : ''; + var authors = _this._parseAuthors(ref.authors); + if (authors.name === 'Error') { + throw authors; + } + return (authors + " " + ref.title + " " + ref.source + ". " + year + "; ") + + ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + + ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ":") + + (ref.pages + "." + link); + }); + } + catch (e) { + return e; + } + return output; + }; + AMA.prototype._fromManual = function (data) { + switch (Parsers.MainParser.manualCitationType) { + case 'journal': + break; + case 'blog': + break; + case 'website': + break; + default: + } + console.log('MADE IT DO FROM MANUAL'); + console.log(data); + return ['unfinished']; + }; + AMA.prototype._parseAuthors = function (authorArr) { + var authors = ''; + switch (authorArr.length) { + case 0: + return new Error("No authors were found for given reference"); + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + authors = authorArr.map(function (author) { return author.name; }).join(', ') + '.'; + break; + default: + for (var i = 0; i < 3; i++) { + authors += authorArr[i].name + ', '; + } + ; + authors += 'et al.'; + } + return authors; + }; + return AMA; + }()); + Parsers.AMA = AMA; +})(Parsers || (Parsers = {})); +var Parsers; +(function (Parsers) { + var APA = (function () { + function APA() { } - return output; - }; - ReferenceParser.prototype._parseAPA = function (data) { - var _this = this; - var pmidArray = data.uids; - var output; - try { - output = pmidArray.map(function (PMID) { - var ref = data[PMID]; - var year = ref.pubdate.substr(0, 4); - var link = _this.includeLink === true - ? " PMID: " + PMID + "" - : ''; - var authors = ''; - switch (ref.authors.length) { - case 0: - throw new Error("No authors were found for PMID " + PMID); - case 1: - authors = ref.authors.map(function (author) { - return (author.name.split(' ')[0] + ", ") + - (author.name.split(' ')[1].split('').join('. ') + "."); - }).join(); - break; - case 2: - authors = ref.authors.map(function (author) { - return (author.name.split(' ')[0] + ", ") + - (author.name.split(' ')[1].split('').join('. ') + "."); - }).join(', & '); - break; - case 3: - case 4: - case 5: - case 6: - case 7: - authors = ref.authors.map(function (author, i, arr) { - if (i === arr.length - 1) { - return (("& " + author.name.split(' ')[0] + ", ") + - (author.name.split(' ')[1].split('').join('. ') + ".")); - } - return ((author.name.split(' ')[0] + ", ") + - (author.name.split(' ')[1].split('').join('. ') + "., ")); - }).join(''); - break; - default: - for (var i = 0; i < 6; i++) { - authors += - (ref.authors[i].name.split(' ')[0] + ", ") + - (ref.authors[i].name.split(' ')[1].split('').join('. ') + "., "); + APA.prototype.parse = function (data) { + var pmidArray = data.uids || false; + if (pmidArray) { + return this._fromPMID(data, pmidArray); + } + return this._fromManual(data); + }; + APA.prototype._fromPMID = function (data, pmidArray) { + var _this = this; + var output; + try { + output = pmidArray.map(function (PMID) { + var ref = data[PMID]; + var year = ref.pubdate.substr(0, 4); + var link = Parsers.MainParser.includeLink === true + ? " PMID: " + PMID + "" + : ''; + var authors = _this._parseAuthors(ref.authors, ref.lastauthor); + if (authors.name === 'Error') { + throw authors; + } + return (authors + " (" + year + "). " + ref.title + " ") + + ((ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()) + "., ") + + ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + + ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ", ") + + (ref.pages + "." + link); + }); + } + catch (e) { + return e; + } + return output; + }; + APA.prototype._fromManual = function (data) { + return ['unfinished']; + }; + APA.prototype._parseAuthors = function (authorArr, lastAuthor) { + var authors = ''; + switch (authorArr.length) { + case 0: + return new Error("No authors were found for given reference"); + case 1: + authors = authorArr.map(function (author) { + return (author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "."); + }).join(); + break; + case 2: + authors = authorArr.map(function (author) { + return (author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "."); + }).join(', & '); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + authors = authorArr.map(function (author, i, arr) { + if (i === arr.length - 1) { + return (("& " + author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + ".")); } - authors += ". . . " + - (ref.lastauthor.split(' ')[0] + ", ") + - (ref.lastauthor.split(' ')[1].split('').join('. ') + "."); - break; - } - return (authors + " (" + year + "). " + ref.title + " ") + - ((ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()) + "., ") + - ("" + (ref.volume === undefined || ref.volume === '' ? '' : ref.volume)) + - ((ref.issue === undefined || ref.issue === '' ? '' : '(' + ref.issue + ')') + ", ") + - (ref.pages + "." + link); - }); - } - catch (e) { - return e; - } - return output; - }; - return ReferenceParser; -}()); + return ((author.name.split(' ')[0] + ", ") + + (author.name.split(' ')[1].split('').join('. ') + "., ")); + }).join(''); + break; + default: + for (var i = 0; i < 6; i++) { + authors += + (authorArr[i].name.split(' ')[0] + ", ") + + (authorArr[i].name.split(' ')[1].split('').join('. ') + "., "); + } + authors += ". . . " + + (lastAuthor.split(' ')[0] + ", ") + + (lastAuthor.split(' ')[1].split('').join('. ') + "."); + break; + } + return authors; + }; + return APA; + }()); + Parsers.APA = APA; +})(Parsers || (Parsers = {})); tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) { var ABT_Button = { type: 'menubutton', @@ -312,10 +397,10 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) } editor.setProgressState(1); var payload = e.target.params.data; - var refparser = new ReferenceParser(payload, editor); + var refparser = new Parsers.MainParser(payload, editor); console.log(payload); if (payload.hasOwnProperty('manual-type-selection')) { - refparser.cleanManualData(payload); + refparser.fromManualInput(payload); editor.setProgressState(0); return; } diff --git a/inc/js/tinymce-buttons.ts b/inc/js/tinymce-buttons.ts deleted file mode 100644 index e9220c4b..00000000 --- a/inc/js/tinymce-buttons.ts +++ /dev/null @@ -1,593 +0,0 @@ -/// -declare var tinymce, tinyMCE, AU_locationInfo - -interface String { - toTitleCase(): string -} -String.prototype.toTitleCase = function(): string { - let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; - - return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ - if (index > 0 && index + match.length !== title.length && - match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && - (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && - title.charAt(index - 1).search(/[^\s-]/) < 0) { - return match.toLowerCase(); - } - - if (match.substr(1).search(/[A-Z]|\../) > -1) { - return match; - } - - return match.charAt(0).toUpperCase() + match.substr(1); - }); -}; - -interface TinyMCEMenuItem { - text: string - menu?: TinyMCEMenuItem[] - onclick?: (e?: Event) => void -} - -interface TinyMCEWindowElement { - type: string - name: string - label: string - value: string - tooltip?: string -} - -interface TinyMCEWindowMangerObject { - title: string - width: number - height: any - body?: TinyMCEWindowElement[] - url?: string - onclose?: (e?: Event) => void -} - -interface TinyMCEPluginButton { - type: string - image: string - title: string - icon: boolean - menu: TinyMCEMenuItem[] -} - -interface Author { - authtype?: string - clusterid?: string - name: string -} - -interface ReferenceFormData { - 'citation-format': string - 'pmid-input'?: string - 'include-link'?: boolean - 'manual-type-selection'?: string - authors?: Author[] -} - -interface ReferenceObj { - authors: Author[] - title: string - source: string - pubdate: string - pages: string - lastauthor: string - issue?: string - volume?: string - fulljournalname?: string - url?: string - accessdate?: string -} - -interface ManualReference extends ReferenceObj { - /** FIXME */ -} - -interface ReferencePayload { - [i: number]: ReferenceObj - uids?: string[] -} - - -class ReferenceParser { - - public citationFormat: string; - public includeLink: boolean; - public manualCitationType: string; - public PMIDquery: string; - public editor: any; - - constructor(data: ReferenceFormData, editor: Object) { - this.citationFormat = data['citation-format']; - this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined - ? data['pmid-input'].replace(/\s/g, '') - : ''; - this.manualCitationType = data['manual-type-selection']; - this.includeLink = data['include-link']; - this.editor = editor; - } - - public fromPMID(): void { - let requestURL = `http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=${this.PMIDquery}&version=2.0&retmode=json`; - let request = new XMLHttpRequest(); - request.open('GET', requestURL, true); - request.addEventListener('load', this._parsePMID.bind(this)); - request.send(null); - } - - public cleanManualData(data: ReferenceFormData): ReferenceObj { - let output: ReferenceObj; - let type = this.manualCitationType; - - let authors: Author[] = data.authors; - let title: string = data[`${type}-title`].toTitleCase(); - let source: string = data[`${type}-source`]; - let pubdate: string = data[`${type}-date`] ? data[`${type}-date`] : ''; - let volume: string = data[`${type}-volume`] ? data[`${type}-volume`] : ''; - let issue: string = data[`${type}-issue`] ? data[`${type}-issue`] : ''; - let pages: string = data[`${type}-pages`] ? data[`${type}-pages`] : ''; - let lastauthor: string = data.authors[data.authors.length - 1].name; - let url: string = data[`${type}-url`] ? data[`${type}-url`] : ''; - let accessdate: string = data[`${type}-accessed`] ? data[`${type}-accessed`] : ''; - - output = { - authors, - title, - source, - pubdate, - volume, - issue, - pages, - lastauthor, - url, - accessdate, - } - - console.log(`OUTPUT:`); - console.log(output); - return output; - } - - - private _parsePMID(e: Event): void { - let req = e.target; - - // Handle bad request - if (req.readyState !== 4 || req.status !== 200) { - this.editor.windowManager.alert('Your request could not be processed. Please try again.'); - return; - } - - let res = JSON.parse(req.responseText); - - // Handle response errors - if (res.error) { - let badPMID = res.error.match(/uid (\S+)/)[1]; - let badIndex = this.PMIDquery.split(',').indexOf(badPMID); - this.editor.windowManager.alert( - `PMID "${badPMID}" at index #${badIndex + 1} failed to process. Double check your list!` - ); - } - - let payload: string[]|Error; - switch (this.citationFormat) { - case 'ama': - payload = this._parseAMA(res.result); - break; - case 'apa': - payload = this._parseAPA(res.result); - break; - default: - this.editor.windowManager.alert('An error occurred while trying to parse the citation'); - return; - } - - if ((payload as Error).name === 'Error') { - this.editor.windowManager.alert((payload as Error).message); - return; - } - if ((payload as string[]).length === 1) { - this.editor.insertContent((payload as string[]).join()); - this.editor.setProgressState(0); - return; - } - - let orderedList: string = - '
    ' + (payload as string[]).map((ref: string) => `
  1. ${ref}
  2. `).join('') + '
'; - - this.editor.insertContent(orderedList); - this.editor.setProgressState(0); - - } - - - private _parseAMA(data: ReferencePayload): string[]|Error { - let pmidArray: string[] = data.uids; - let output: string[]; - - try { - output = pmidArray.map((PMID: string): string => { - let ref: ReferenceObj = data[PMID]; - let year: string = ref.pubdate.substr(0, 4); - let link = this.includeLink === true - ? ` PMID: ${PMID}` - : ''; - - let authors: string = ''; - switch (ref.authors.length) { - case 0: - throw new Error(`No authors were found for PMID ${PMID}`); - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - authors = ref.authors.map((author: Author) => author.name).join(', ') + '.'; - break; - default: - for (let i = 0; i < 3; i++) { authors+= ref.authors[i].name + ', ' }; - authors += 'et al.'; - } - - return `${authors} ${ref.title} ${ref.source}. ${year}; ` + - `${ref.volume === undefined || ref.volume === '' ? '' : ref.volume}` + - `${ref.issue === undefined || ref.issue === '' ? '' : '('+ref.issue+')'}:` + - `${ref.pages}.${link}`; - }); - } catch(e) { - return e; - } - - return output; - } - - private _parseAPA(data: ReferencePayload): string[]|Error { - let pmidArray: string[] = data.uids; - let output: string[]; - - try { - output = pmidArray.map((PMID: string): string => { - let ref: ReferenceObj = data[PMID]; - let year: string = ref.pubdate.substr(0, 4); - let link = this.includeLink === true - ? ` PMID: ${PMID}` - : ''; - - let authors: string = ''; - switch (ref.authors.length) { - case 0: - throw new Error(`No authors were found for PMID ${PMID}`); - case 1: - authors = ref.authors.map((author: Author) => - `${author.name.split(' ')[0]}, ` + // Last name - `${author.name.split(' ')[1].split('').join('. ')}.` // First Initial(s) - ).join(); - break; - case 2: - authors = ref.authors.map((author: Author) => - `${author.name.split(' ')[0]}, ` + // Last name - `${author.name.split(' ')[1].split('').join('. ')}.` // First Initial(s) - ).join(', & '); - break; - case 3: - case 4: - case 5: - case 6: - case 7: - authors = ref.authors.map((author, i, arr) => { - if (i === arr.length - 1) { - return( - `& ${author.name.split(' ')[0]}, ` + - `${author.name.split(' ')[1].split('').join('. ')}.` - ); - } - return( - `${author.name.split(' ')[0]}, ` + - `${author.name.split(' ')[1].split('').join('. ')}., ` - ); - }).join(''); - break; - default: - for (let i = 0; i < 6; i++) { - authors += - `${ref.authors[i].name.split(' ')[0]}, ` + - `${ref.authors[i].name.split(' ')[1].split('').join('. ')}., ` - } - authors += `. . . ` + - `${ref.lastauthor.split(' ')[0]}, ` + - `${ref.lastauthor.split(' ')[1].split('').join('. ')}.`; - break; - } - - return `${authors} (${year}). ${ref.title} ` + - `${ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()}., ` + - `${ref.volume === undefined || ref.volume === '' ? '' : ref.volume}` + - `${ref.issue === undefined || ref.issue === '' ? '' : '('+ref.issue+')'}, ` + - `${ref.pages}.${link}`; - }); - } catch(e) { - return e; - } - - return output; - } - -} - - -tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) => { - - let ABT_Button: TinyMCEPluginButton = { - type: 'menubutton', - image: url + '/../images/book.png', - title: 'Academic Blogger\'s Toolkit', - icon: true, - menu: [], - }; - - //================================================== - // MENU ITEMS - //================================================== - - let separator: TinyMCEMenuItem = { text: '-' }; - - - let bibToolsMenu: TinyMCEMenuItem = { - text: 'Bibliography Tools', - menu: [], - }; - - - let trackedLink: TinyMCEMenuItem = { - text: 'Tracked Link', - onclick: () => { - - let user_selection = tinyMCE.activeEditor.selection.getContent({format: 'text'}); - - /** TODO: Fix this so it doesn't suck */ - editor.windowManager.open({ - title: 'Insert Tracked Link', - width: 600, - height: 160, - buttons: [{ - text: 'Insert', - onclick: 'submit' - }], - body: [ - { - type: 'textbox', - name: 'tracked_url', - label: 'URL', - value: '' - }, - { - type: 'textbox', - name: 'tracked_title', - label: 'Link Text', - value: user_selection - }, - { - type: 'textbox', - name: 'tracked_tag', - label: 'Custom Tag ID', - tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', - value: '' - }, - { - type: 'checkbox', - name: 'tracked_new_window', - label: 'Open link in a new window/tab' - }, - ], - onsubmit: (e) => { - let trackedUrl = e.data.tracked_url; - let trackedTitle = e.data.tracked_title; - let trackedTag = e.data.tracked_tag; - let trackedLink = `${trackedTitle}`; - - editor.execCommand('mceInsertContent', false, trackedLink); - - } - }); - } - } - // End Tracked Link Menu Item - - let requestTools: TinyMCEMenuItem = { - text: 'Request More Tools', - onclick: () => { - editor.windowManager.open({ - title: 'Request More Tools', - body: [{ - type: 'container', - html: - `
` + - `Have a feature or tool in mind that isn't available?
` + - `Open an issue on the GitHub repository and let me know!` + - `
`, - }], - buttons: [], - }); - } - } - - - let inlineCitation: TinyMCEMenuItem = { - text: 'Inline Citation', - onclick: () => { - editor.windowManager.open({ - title: 'Inline Citation', - url: AU_locationInfo.tinymceViewsURL + 'inline-citation.html', - width: 400, - height: 85, - onClose: (e) => { - editor.insertContent( - '[cite num="' + e.target.params.data + '"]' - ); - } - }); - } - } - - let formattedReference: TinyMCEMenuItem = { - text: 'Formatted Reference', - onclick: () => { - editor.windowManager.open({ - title: 'Insert Formatted Reference', - url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', - width: 600, - height: 100, - onclose: (e: any) => { - - // If the user presses the exit button, return. - if (Object.keys(e.target.params).length === 0) { - return; - } - - editor.setProgressState(1); - let payload: ReferenceFormData = e.target.params.data; - let refparser = new ReferenceParser(payload, editor); - - console.log(payload); - - if (payload.hasOwnProperty('manual-type-selection')) { - refparser.cleanManualData(payload); - editor.setProgressState(0); - return; - } - - // do pmid parsing - refparser.fromPMID(); - - }, - }); - }, - } - - // onsubmit: function(e) { - // - // editor.setProgressState(1); - // var inputText = e.data.ref_id_number; - // var citationFormat = e.data.ref_id_citation_type; - // var includePubmedLink = e.data.ref_id_include_link; - // var requestURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + inputText + '&version=2.0&retmode=json'; - // - // var request = new XMLHttpRequest(); - // request.open('GET', requestURL, true); - // request.onload = function() { - // if (request.readyState === 4) { - // if (request.status === 200) { - // console.log(request.responseText) - // let output = parseRequestData(JSON.parse(request.responseText), inputText, citationFormat, includePubmedLink); - // editor.insertContent(output); - // editor.setProgressState(0); - // } else { - // alert('ERROR: PMID not recognized.'); - // editor.setProgressState(0); - // return; - // } - // } - // }; - // request.send(null); - // - // } - // }); - - - - bibToolsMenu.menu.push(inlineCitation, separator, formattedReference); - ABT_Button.menu.push(bibToolsMenu, trackedLink, separator, requestTools); - - - editor.addButton('abt_ref_id_parser_mce_button', ABT_Button); - - - - -/* TODO: */ -// editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { -// editor.windowManager.open({ -// title: 'Insert Formatted Reference', -// width: 600, -// height: 125, -// body: [{ -// type: 'textbox', -// name: 'ref_id_number', -// label: 'PMID', -// value: '' -// }, { -// type: 'listbox', -// label: 'Citation Format', -// name: 'ref_id_citation_type', -// 'values': [{ -// text: 'American Medical Association (AMA)', -// value: 'AMA' -// }, { -// text: 'American Psychological Association (APA)', -// value: 'APA' -// }] -// -// }, { -// type: 'checkbox', -// name: 'ref_id_include_link', -// label: 'Include link to PubMed?' -// } -// ], -// onsubmit: function(e) { -// -// editor.setProgressState(1); -// var PMID = e.data.ref_id_number; -// var citationFormat = e.data.ref_id_citation_type; -// var includePubmedLink = e.data.ref_id_include_link; -// -// var request = new XMLHttpRequest(); -// request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); -// request.onload = function() { -// if (request.readyState === 4) { -// if (request.status === 200) { -// let output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); -// editor.insertContent(output); -// editor.setProgressState(0); -// } else { -// alert('ERROR: PMID not recognized.'); -// editor.setProgressState(0); -// return; -// } -// } -// }; -// request.send(null); -// -// } -// }); -// }); -// -// editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { -// editor.windowManager.open({ -// title: 'Insert Citation', -// width: 600, -// height: 58, -// body: [{ -// type: 'textbox', -// name: 'citation_number', -// label: 'Citation Number', -// value: '' -// }], -// onsubmit: function(e) { -// editor.insertContent( -// '[cite num="' + e.data.citation_number + '"]' -// ); -// } -// }); -// }); -// -// }); -// -}); diff --git a/inc/js/wp-editor/inc/toTitleCase.ts b/inc/js/wp-editor/inc/toTitleCase.ts new file mode 100644 index 00000000..d76e0dc3 --- /dev/null +++ b/inc/js/wp-editor/inc/toTitleCase.ts @@ -0,0 +1,18 @@ +String.prototype.toTitleCase = function(): string { + let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; + + return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ + if (index > 0 && index + match.length !== title.length && + match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && + (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && + title.charAt(index - 1).search(/[^\s-]/) < 0) { + return match.toLowerCase(); + } + + if (match.substr(1).search(/[A-Z]|\../) > -1) { + return match; + } + + return match.charAt(0).toUpperCase() + match.substr(1); + }); +}; diff --git a/inc/js/wp-editor/main-parser.ts b/inc/js/wp-editor/main-parser.ts new file mode 100644 index 00000000..2aa158c9 --- /dev/null +++ b/inc/js/wp-editor/main-parser.ts @@ -0,0 +1,139 @@ +declare var tinymce, tinyMCE, AU_locationInfo + +namespace Parsers { + + export class MainParser { + + public citationFormat: string; + public static includeLink: boolean; + public static manualCitationType: string; + public PMIDquery: string; + public editor: any; + + constructor(data: ReferenceFormData, editor: Object) { + this.citationFormat = data['citation-format']; + this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined + ? data['pmid-input'].replace(/\s/g, '') + : ''; + MainParser.manualCitationType = data['manual-type-selection']; + MainParser.includeLink = data['include-link']; + this.editor = editor; + } + + public fromPMID(): void { + let requestURL = `http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=${this.PMIDquery}&version=2.0&retmode=json`; + let request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.addEventListener('load', this._parsePMID.bind(this)); + request.send(null); + } + + public fromManualInput(data: ReferenceFormData): void { + let cleanedData: ReferenceObj; + let type = MainParser.manualCitationType; + + let authors: Author[] = data.authors; + let title: string = data[`${type}-title`].toTitleCase(); + let source: string = data[`${type}-source`]; + let pubdate: string = data[`${type}-date`] ? data[`${type}-date`] : ''; + let volume: string = data[`${type}-volume`] ? data[`${type}-volume`] : ''; + let issue: string = data[`${type}-issue`] ? data[`${type}-issue`] : ''; + let pages: string = data[`${type}-pages`] ? data[`${type}-pages`] : ''; + let lastauthor: string = data.authors[data.authors.length - 1].name; + let url: string = data[`${type}-url`] ? data[`${type}-url`] : ''; + let accessdate: string = data[`${type}-accessed`] ? data[`${type}-accessed`] : ''; + + cleanedData = { + authors, + title, + source, + pubdate, + volume, + issue, + pages, + lastauthor, + url, + accessdate, + } + + let payload: string[]|Error; + switch (this.citationFormat) { + case 'ama': + let AMA = new Parsers.AMA; + payload = AMA.parse([cleanedData]); + break; + case 'apa': + let APA = new Parsers.APA; + payload = APA.parse([cleanedData]); + break; + default: + this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + this.editor.setProgressState(0); + return; + } + + console.log(`OUTPUT:`); + console.log(cleanedData); + return; + } + + + private _parsePMID(e: Event): void { + let req = e.target; + + // Handle bad request + if (req.readyState !== 4 || req.status !== 200) { + this.editor.windowManager.alert('Your request could not be processed. Please try again.'); + this.editor.setProgressState(0); + return; + } + + let res = JSON.parse(req.responseText); + + // Handle response errors + if (res.error) { + let badPMID = res.error.match(/uid (\S+)/)[1]; + let badIndex = this.PMIDquery.split(',').indexOf(badPMID); + this.editor.windowManager.alert( + `PMID "${badPMID}" at index #${badIndex + 1} failed to process. Double check your list!` + ); + } + + let payload: string[]|Error; + switch (this.citationFormat) { + case 'ama': + let AMA = new Parsers.AMA; + payload = AMA.parse(res.result); + break; + case 'apa': + let APA = new Parsers.APA; + payload = APA.parse(res.result); + break; + default: + this.editor.windowManager.alert('An error occurred while trying to parse the citation'); + this.editor.setProgressState(0); + return; + } + + if ((payload as Error).name === 'Error') { + this.editor.windowManager.alert((payload as Error).message); + this.editor.setProgressState(0); + return; + } + if ((payload as string[]).length === 1) { + this.editor.insertContent((payload as string[]).join()); + this.editor.setProgressState(0); + return; + } + + let orderedList: string = + '
    ' + (payload as string[]).map((ref: string) => `
  1. ${ref}
  2. `).join('') + '
'; + + this.editor.insertContent(orderedList); + this.editor.setProgressState(0); + + } + + } + +} diff --git a/inc/js/wp-editor/parsers/ama.ts b/inc/js/wp-editor/parsers/ama.ts new file mode 100644 index 00000000..cbf6b4bc --- /dev/null +++ b/inc/js/wp-editor/parsers/ama.ts @@ -0,0 +1,88 @@ +/// + +namespace Parsers { + + export class AMA { + + public parse(data: ReferencePayload): string[]|Error { + let pmidArray: string[]|boolean = data.uids || false; + + if (pmidArray) { + return this._fromPMID(data, (pmidArray as string[])); + } + + return this._fromManual(data); + } + + private _fromPMID(data: ReferencePayload, pmidArray: string[]): string[]|Error { + let output: string[]|Error; + try { + output = pmidArray.map((PMID: string): string => { + let ref: ReferenceObj = data[PMID]; + let year: string = ref.pubdate.substr(0, 4); + let link = MainParser.includeLink === true + ? ` PMID: ${PMID}` + : ''; + + let authors: string|Error = this._parseAuthors(ref.authors); + if ((authors as Error).name === 'Error') { + throw authors; + } + + return `${authors} ${ref.title} ${ref.source}. ${year}; ` + + `${ref.volume === undefined || ref.volume === '' ? '' : ref.volume}` + + `${ref.issue === undefined || ref.issue === '' ? '' : '('+ref.issue+')'}:` + + `${ref.pages}.${link}`; + }); + } catch(e) { + return e; + } + return output; + } + + private _fromManual(data: ReferencePayload): string[] { + /** TODO */ + + switch (MainParser.manualCitationType) { + case 'journal': + // do stuff + break; + case 'blog': + // do stuff + break; + case 'website': + // do stuff + break; + default: + // return an error + } + + console.log('MADE IT DO FROM MANUAL') + console.log(data); + + return ['unfinished']; + } + + private _parseAuthors(authorArr: Author[]): string|Error { + let authors: string = ''; + switch (authorArr.length) { + case 0: + return new Error(`No authors were found for given reference`); + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + authors = authorArr.map((author: Author) => author.name).join(', ') + '.'; + break; + default: + for (let i = 0; i < 3; i++) { authors+= authorArr[i].name + ', ' }; + authors += 'et al.'; + } + return authors; + } + + } + +} diff --git a/inc/js/wp-editor/parsers/apa.ts b/inc/js/wp-editor/parsers/apa.ts new file mode 100644 index 00000000..62ee17a0 --- /dev/null +++ b/inc/js/wp-editor/parsers/apa.ts @@ -0,0 +1,107 @@ +/// + +namespace Parsers { + + export class APA { + + public parse(data: ReferencePayload): string[]|Error { + let pmidArray: string[]|boolean = data.uids || false; + + if (pmidArray) { + return this._fromPMID(data, (pmidArray as string[])); + } + + return this._fromManual(data); + } + + private _fromPMID(data: ReferencePayload, pmidArray: string[]): string[]|Error { + + let output: string[]; + + try { + output = pmidArray.map((PMID: string): string => { + let ref: ReferenceObj = data[PMID]; + let year: string = ref.pubdate.substr(0, 4); + let link = MainParser.includeLink === true + ? ` PMID: ${PMID}` + : ''; + + let authors: string|Error = this._parseAuthors(ref.authors, ref.lastauthor); + if ((authors as Error).name === 'Error') { + throw authors; + } + + return `${authors} (${year}). ${ref.title} ` + + `${ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()}., ` + + `${ref.volume === undefined || ref.volume === '' ? '' : ref.volume}` + + `${ref.issue === undefined || ref.issue === '' ? '' : '('+ref.issue+')'}, ` + + `${ref.pages}.${link}`; + }); + } catch(e) { + return e; + } + + return output; + + } + + private _fromManual(data: ReferencePayload): string[] { + /** TODO */ + return ['unfinished'] + } + + private _parseAuthors(authorArr: Author[], lastAuthor: string): string|Error { + let authors: string = ''; + + switch (authorArr.length) { + case 0: + return new Error(`No authors were found for given reference`); + case 1: + authors = authorArr.map((author: Author) => + `${author.name.split(' ')[0]}, ` + // Last name + `${author.name.split(' ')[1].split('').join('. ')}.` // First Initial(s) + ).join(); + break; + case 2: + authors = authorArr.map((author: Author) => + `${author.name.split(' ')[0]}, ` + // Last name + `${author.name.split(' ')[1].split('').join('. ')}.` // First Initial(s) + ).join(', & '); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + authors = authorArr.map((author, i, arr) => { + if (i === arr.length - 1) { + return( + `& ${author.name.split(' ')[0]}, ` + + `${author.name.split(' ')[1].split('').join('. ')}.` + ); + } + return( + `${author.name.split(' ')[0]}, ` + + `${author.name.split(' ')[1].split('').join('. ')}., ` + ); + }).join(''); + break; + default: + for (let i = 0; i < 6; i++) { + authors += + `${authorArr[i].name.split(' ')[0]}, ` + + `${authorArr[i].name.split(' ')[1].split('').join('. ')}., ` + } + authors += `. . . ` + + `${lastAuthor.split(' ')[0]}, ` + + `${lastAuthor.split(' ')[1].split('').join('. ')}.`; + break; + } + return authors; + + + } + + } + +} diff --git a/inc/js/wp-editor/tinymce-buttons.ts b/inc/js/wp-editor/tinymce-buttons.ts new file mode 100644 index 00000000..47b4ac46 --- /dev/null +++ b/inc/js/wp-editor/tinymce-buttons.ts @@ -0,0 +1,279 @@ +/// +/// +/// +/// +/// +declare var tinymce, tinyMCE, AU_locationInfo + + +tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) => { + + let ABT_Button: TinyMCEPluginButton = { + type: 'menubutton', + image: url + '/../images/book.png', + title: 'Academic Blogger\'s Toolkit', + icon: true, + menu: [], + }; + + //================================================== + // MENU ITEMS + //================================================== + + let separator: TinyMCEMenuItem = { text: '-' }; + + + let bibToolsMenu: TinyMCEMenuItem = { + text: 'Bibliography Tools', + menu: [], + }; + + + let trackedLink: TinyMCEMenuItem = { + text: 'Tracked Link', + onclick: () => { + + let user_selection = tinyMCE.activeEditor.selection.getContent({format: 'text'}); + + /** TODO: Fix this so it doesn't suck */ + editor.windowManager.open({ + title: 'Insert Tracked Link', + width: 600, + height: 160, + buttons: [{ + text: 'Insert', + onclick: 'submit' + }], + body: [ + { + type: 'textbox', + name: 'tracked_url', + label: 'URL', + value: '' + }, + { + type: 'textbox', + name: 'tracked_title', + label: 'Link Text', + value: user_selection + }, + { + type: 'textbox', + name: 'tracked_tag', + label: 'Custom Tag ID', + tooltip: 'Don\'t forget to create matching tag in Google Tag Manager!', + value: '' + }, + { + type: 'checkbox', + name: 'tracked_new_window', + label: 'Open link in a new window/tab' + }, + ], + onsubmit: (e) => { + let trackedUrl = e.data.tracked_url; + let trackedTitle = e.data.tracked_title; + let trackedTag = e.data.tracked_tag; + let trackedLink = `${trackedTitle}`; + + editor.execCommand('mceInsertContent', false, trackedLink); + + } + }); + } + } + // End Tracked Link Menu Item + + let requestTools: TinyMCEMenuItem = { + text: 'Request More Tools', + onclick: () => { + editor.windowManager.open({ + title: 'Request More Tools', + body: [{ + type: 'container', + html: + `
` + + `Have a feature or tool in mind that isn't available?
` + + `Open an issue on the GitHub repository and let me know!` + + `
`, + }], + buttons: [], + }); + } + } + + + let inlineCitation: TinyMCEMenuItem = { + text: 'Inline Citation', + onclick: () => { + editor.windowManager.open({ + title: 'Inline Citation', + url: AU_locationInfo.tinymceViewsURL + 'inline-citation.html', + width: 400, + height: 85, + onClose: (e) => { + editor.insertContent( + '[cite num="' + e.target.params.data + '"]' + ); + } + }); + } + } + + let formattedReference: TinyMCEMenuItem = { + text: 'Formatted Reference', + onclick: () => { + editor.windowManager.open({ + title: 'Insert Formatted Reference', + url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', + width: 600, + height: 100, + onclose: (e: any) => { + + // If the user presses the exit button, return. + if (Object.keys(e.target.params).length === 0) { + return; + } + editor.setProgressState(1); + let payload: ReferenceFormData = e.target.params.data; + let refparser = new Parsers.MainParser(payload, editor); + + console.log(payload); + + if (payload.hasOwnProperty('manual-type-selection')) { + refparser.fromManualInput(payload); + editor.setProgressState(0); + return; + } + + // do pmid parsing + refparser.fromPMID(); + + }, + }); + }, + } + + // onsubmit: function(e) { + // + // editor.setProgressState(1); + // var inputText = e.data.ref_id_number; + // var citationFormat = e.data.ref_id_citation_type; + // var includePubmedLink = e.data.ref_id_include_link; + // var requestURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + inputText + '&version=2.0&retmode=json'; + // + // var request = new XMLHttpRequest(); + // request.open('GET', requestURL, true); + // request.onload = function() { + // if (request.readyState === 4) { + // if (request.status === 200) { + // console.log(request.responseText) + // let output = parseRequestData(JSON.parse(request.responseText), inputText, citationFormat, includePubmedLink); + // editor.insertContent(output); + // editor.setProgressState(0); + // } else { + // alert('ERROR: PMID not recognized.'); + // editor.setProgressState(0); + // return; + // } + // } + // }; + // request.send(null); + // + // } + // }); + + + + bibToolsMenu.menu.push(inlineCitation, separator, formattedReference); + ABT_Button.menu.push(bibToolsMenu, trackedLink, separator, requestTools); + + + editor.addButton('abt_ref_id_parser_mce_button', ABT_Button); + + + + +/* TODO: */ +// editor.addShortcut('meta+alt+r', 'Insert Formatted Reference', function() { +// editor.windowManager.open({ +// title: 'Insert Formatted Reference', +// width: 600, +// height: 125, +// body: [{ +// type: 'textbox', +// name: 'ref_id_number', +// label: 'PMID', +// value: '' +// }, { +// type: 'listbox', +// label: 'Citation Format', +// name: 'ref_id_citation_type', +// 'values': [{ +// text: 'American Medical Association (AMA)', +// value: 'AMA' +// }, { +// text: 'American Psychological Association (APA)', +// value: 'APA' +// }] +// +// }, { +// type: 'checkbox', +// name: 'ref_id_include_link', +// label: 'Include link to PubMed?' +// } +// ], +// onsubmit: function(e) { +// +// editor.setProgressState(1); +// var PMID = e.data.ref_id_number; +// var citationFormat = e.data.ref_id_citation_type; +// var includePubmedLink = e.data.ref_id_include_link; +// +// var request = new XMLHttpRequest(); +// request.open('GET', 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + PMID + '&version=2.0&retmode=json', true); +// request.onload = function() { +// if (request.readyState === 4) { +// if (request.status === 200) { +// let output = parseRequestData(JSON.parse(request.responseText), PMID, citationFormat, includePubmedLink); +// editor.insertContent(output); +// editor.setProgressState(0); +// } else { +// alert('ERROR: PMID not recognized.'); +// editor.setProgressState(0); +// return; +// } +// } +// }; +// request.send(null); +// +// } +// }); +// }); +// +// editor.addShortcut('meta+alt+c', 'Insert Inline Citation', function() { +// editor.windowManager.open({ +// title: 'Insert Citation', +// width: 600, +// height: 58, +// body: [{ +// type: 'textbox', +// name: 'citation_number', +// label: 'Citation Number', +// value: '' +// }], +// onsubmit: function(e) { +// editor.insertContent( +// '[cite num="' + e.data.citation_number + '"]' +// ); +// } +// }); +// }); +// +// }); +// +}); diff --git a/inc/js/wp-editor/tsconfig.json b/inc/js/wp-editor/tsconfig.json new file mode 100644 index 00000000..f1d4e071 --- /dev/null +++ b/inc/js/wp-editor/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "outFile": "../tinymce-buttons.js", + "moduleResolution": "node", + "isolatedModules": false, + "jsx": "react", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "declaration": false, + "noImplicitAny": false, + "noImplicitUseStrict": false, + "removeComments": true, + "noLib": false, + "preserveConstEnums": true, + "suppressImplicitAnyIndexErrors": true + }, + "files": [ + "./tinymce-buttons.ts" + ], + "exclude": [ + "node_modules", + "typings/browser", + "typings/browser.d.ts" + ], + "compileOnSave": false, + "buildOnSave": false, + "atom": { + "rewriteTsconfig": false + } +} diff --git a/tsconfig.json b/tsconfig.json index bf44b1a8..141823e7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,7 @@ "typings/browser", "typings/browser.d.ts" ], - "compileOnSave": true, + "compileOnSave": false, "buildOnSave": false, "atom": { "rewriteTsconfig": false From b8db1eeb1db383f6416f267a9419b8777f7f6ad7 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Mon, 28 Mar 2016 20:06:43 -0400 Subject: [PATCH 06/18] Finish manual reference insertion --- CHANGELOG.md | 2 +- academic-bloggers-toolkit.php | 2 +- inc/js/ABT.d.ts | 18 +- inc/js/tinymce-buttons.js | 155 +++++++++++++++--- inc/js/wp-editor/main-parser.ts | 46 ++++-- inc/js/wp-editor/parsers/ama.ts | 73 +++++++-- inc/js/wp-editor/parsers/apa.ts | 64 +++++++- inc/js/wp-editor/tinymce-buttons.ts | 6 +- inc/peer-review.php | 2 +- inc/tinymce-views/formatted-reference.html | 87 ++++++---- inc/tinymce-views/formatted-reference.js | 24 ++- inc/tinymce-views/formatted-reference.ts | 34 +++- inc/tinymce-views/tinymce-views.css | 6 + inc/tinymce-views/tinymce-views.scss | 10 ++ .../tinymce-views/tsconfig.json | 2 +- readme.txt | 2 +- 16 files changed, 432 insertions(+), 101 deletions(-) rename tsconfig.json => inc/tinymce-views/tsconfig.json (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d04a9250..00610f6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ### 2.4.0 - Full rewrite. - Parse multiple comma-separated PMIDs at once into an ordered list. -- Add ability to add citations manually for Journals, Websites, or Blogs. +- Add manual reference insertion for Journals, Websites, or Books. ### 2.3.1 - Fixed poor rendering of tooltip close icon on mobile. diff --git a/academic-bloggers-toolkit.php b/academic-bloggers-toolkit.php index 15c51cde..60e28510 100644 --- a/academic-bloggers-toolkit.php +++ b/academic-bloggers-toolkit.php @@ -4,7 +4,7 @@ * Plugin Name: Academic Blogger's Toolkit * Plugin URI: https://wordpress.org/plugins/academic-bloggers-toolkit/ * Description: A Wordpress plugin extending the functionality of Wordpress for Academic Blogging - * Version: 2.3.0 + * Version: 2.4.0 * Author: Derek P Sifford * Author URI: http://www.twitter.com/flightmed1 * License: GPL3 diff --git a/inc/js/ABT.d.ts b/inc/js/ABT.d.ts index a5dfc888..cfea4d6e 100644 --- a/inc/js/ABT.d.ts +++ b/inc/js/ABT.d.ts @@ -49,16 +49,20 @@ interface ReferenceFormData { interface ReferenceObj { authors: Author[] - title: string - source: string - pubdate: string - pages: string lastauthor: string - issue?: string - volume?: string + pages: string + pubdate: string + source: string + title: string + accessdate?: string + chapter?: string + edition?: string fulljournalname?: string + issue?: string + location?: string + updated?: string url?: string - accessdate?: string + volume?: string } interface ManualReference extends ReferenceObj { diff --git a/inc/js/tinymce-buttons.js b/inc/js/tinymce-buttons.js index 2ab02811..47b9b593 100644 --- a/inc/js/tinymce-buttons.js +++ b/inc/js/tinymce-buttons.js @@ -35,16 +35,25 @@ var Parsers; MainParser.prototype.fromManualInput = function (data) { var cleanedData; var type = MainParser.manualCitationType; - var authors = data.authors; + var authors = data.authors.map(function (author) { + var name = author.name.split(' ')[1] + " " + author.name.split(' ')[0][0]; + return { name: name }; + }); var title = data[(type + "-title")].toTitleCase(); var source = data[(type + "-source")]; - var pubdate = data[(type + "-date")] ? data[(type + "-date")] : ''; - var volume = data[(type + "-volume")] ? data[(type + "-volume")] : ''; - var issue = data[(type + "-issue")] ? data[(type + "-issue")] : ''; - var pages = data[(type + "-pages")] ? data[(type + "-pages")] : ''; - var lastauthor = data.authors[data.authors.length - 1].name; - var url = data[(type + "-url")] ? data[(type + "-url")] : ''; - var accessdate = data[(type + "-accessed")] ? data[(type + "-accessed")] : ''; + var pubdate = data[(type + "-date")] || ''; + var volume = data[(type + "-volume")] || ''; + var issue = data[(type + "-issue")] || ''; + var pages = data[(type + "-pages")] || ''; + var lastauthor = data.authors.length > 0 + ? data.authors[data.authors.length - 1].name + : ''; + var url = data[(type + "-url")] || ''; + var accessdate = data[(type + "-accessed")] || ''; + var updated = data[(type + "-updated")] || ''; + var location = data[(type + "-location")] || ''; + var chapter = data[(type + "-chapter")] || ''; + var edition = data[(type + "-edition")] || ''; cleanedData = { authors: authors, title: title, @@ -56,6 +65,10 @@ var Parsers; lastauthor: lastauthor, url: url, accessdate: accessdate, + updated: updated, + location: location, + chapter: chapter, + edition: edition, }; var payload; switch (this.citationFormat) { @@ -72,9 +85,7 @@ var Parsers; this.editor.setProgressState(0); return; } - console.log("OUTPUT:"); - console.log(cleanedData); - return; + this._deliverContent(payload); }; MainParser.prototype._parsePMID = function (e) { var req = e.target; @@ -104,6 +115,9 @@ var Parsers; this.editor.setProgressState(0); return; } + this._deliverContent(payload); + }; + MainParser.prototype._deliverContent = function (payload) { if (payload.name === 'Error') { this.editor.windowManager.alert(payload.message); this.editor.setProgressState(0); @@ -126,13 +140,15 @@ var Parsers; (function (Parsers) { var AMA = (function () { function AMA() { + this._isManual = true; } AMA.prototype.parse = function (data) { var pmidArray = data.uids || false; if (pmidArray) { + this._isManual = false; return this._fromPMID(data, pmidArray); } - return this._fromManual(data); + return [this._fromManual(data)]; }; AMA.prototype._fromPMID = function (data, pmidArray) { var _this = this; @@ -160,23 +176,27 @@ var Parsers; return output; }; AMA.prototype._fromManual = function (data) { + var payload; switch (Parsers.MainParser.manualCitationType) { case 'journal': - break; - case 'blog': + payload = this._parseJournal(data); break; case 'website': + payload = this._parseWebsite(data); + break; + case 'book': + payload = this._parseBook(data); break; - default: } - console.log('MADE IT DO FROM MANUAL'); - console.log(data); - return ['unfinished']; + return payload; }; AMA.prototype._parseAuthors = function (authorArr) { var authors = ''; switch (authorArr.length) { case 0: + if (this._isManual === true) { + break; + } return new Error("No authors were found for given reference"); case 1: case 2: @@ -195,6 +215,46 @@ var Parsers; } return authors; }; + AMA.prototype._parseJournal = function (data) { + var authors = this._parseAuthors(data[0].authors); + var year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); + var source = data[0].source.toTitleCase(); + var issue = "(" + data[0].issue + ")" || ''; + var volume = data[0].volume || ''; + return (authors + " " + data[0].title + ". " + source + ". " + year + "; ") + + ("" + volume + issue + ":" + data[0].pages + "."); + }; + AMA.prototype._parseWebsite = function (data) { + var authors = data[0].authors.length > 0 + ? this._parseAuthors(data[0].authors) + ' ' + : ''; + var pubdate = "Published " + new Date(data[0].pubdate).toLocaleDateString('en-us', { month: 'long', year: 'numeric' }) + ". "; + var updated = data[0].updated !== '' + ? "Updated " + new Date(data[0].updated).toLocaleDateString('en-us', { month: 'long', day: 'numeric', year: 'numeric' }) + ". " + : ''; + var accessed = data[0].accessdate !== '' + ? "Accessed " + new Date(data[0].accessdate).toLocaleDateString('en-us', { month: 'long', day: 'numeric', year: 'numeric' }) + ". " + : "Accessed " + new Date(Date.now()).toLocaleDateString('en-us', { month: 'long', day: 'numeric', year: 'numeric' }); + return ("" + authors + data[0].title + ". " + data[0].source + ". Available at: ") + + ("" + data[0].url + ". " + pubdate + updated + accessed); + }; + AMA.prototype._parseBook = function (data) { + console.log(data); + var authors = this._parseAuthors(data[0].authors); + var title = data[0].title; + var pubLocation = data[0].location !== '' + ? data[0].location + ":" + : ""; + var publisher = data[0].source; + var year = data[0].pubdate; + var chapter = data[0].chapter !== '' + ? " " + data[0].chapter + ". In:" + : ""; + var pages = data[0].pages !== '' + ? ": " + data[0].pages + "." + : "."; + return "" + authors + chapter + " " + title + ". " + pubLocation + publisher + "; " + year + pages; + }; return AMA; }()); Parsers.AMA = AMA; @@ -203,13 +263,15 @@ var Parsers; (function (Parsers) { var APA = (function () { function APA() { + this._isManual = true; } APA.prototype.parse = function (data) { var pmidArray = data.uids || false; if (pmidArray) { + this._isManual = false; return this._fromPMID(data, pmidArray); } - return this._fromManual(data); + return [this._fromManual(data)]; }; APA.prototype._fromPMID = function (data, pmidArray) { var _this = this; @@ -238,12 +300,27 @@ var Parsers; return output; }; APA.prototype._fromManual = function (data) { - return ['unfinished']; + var payload; + switch (Parsers.MainParser.manualCitationType) { + case 'journal': + payload = this._parseJournal(data); + break; + case 'website': + payload = this._parseWebsite(data); + break; + case 'book': + payload = this._parseBook(data); + break; + } + return payload; }; APA.prototype._parseAuthors = function (authorArr, lastAuthor) { var authors = ''; switch (authorArr.length) { case 0: + if (this._isManual === true) { + break; + } return new Error("No authors were found for given reference"); case 1: authors = authorArr.map(function (author) { @@ -284,6 +361,40 @@ var Parsers; } return authors; }; + APA.prototype._parseJournal = function (data) { + var authors = this._parseAuthors(data[0].authors, data[0].lastauthor); + var year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); + var source = data[0].source.toTitleCase(); + var issue = "(" + data[0].issue + ")" || ''; + var volume = data[0].volume || ''; + return (authors + " (" + year + "). " + data[0].title + ". ") + + (source + "., " + volume + issue + ", " + data[0].pages + "."); + }; + APA.prototype._parseWebsite = function (data) { + var authors = this._parseAuthors(data[0].authors, data[0].lastauthor); + var rawDate = new Date(data[0].pubdate); + var source = data[0].source.toTitleCase(); + var date = (rawDate.getFullYear() + ", ") + + ("" + rawDate.toLocaleDateString('en-us', { month: 'long', day: 'numeric' })); + return (authors + " (" + date + "). " + data[0].title + ". " + source + ". ") + + ("Retrieved from " + data[0].url + ""); + }; + APA.prototype._parseBook = function (data) { + var authors = this._parseAuthors(data[0].authors, data[0].lastauthor); + var year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); + var pubLocation = data[0].location !== '' + ? data[0].location + ":" + : ''; + var publisher = data[0].source; + var chapter = data[0].chapter !== '' + ? " " + data[0].chapter + ". In" + : ''; + var pages = data[0].pages !== '' + ? " (" + data[0].pages + ")" + : ''; + return (authors + " (" + year + ")." + chapter + " " + data[0].title + "" + pages + ". ") + + ("" + pubLocation + publisher + "."); + }; return APA; }()); Parsers.APA = APA; @@ -374,7 +485,7 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) onclick: function () { editor.windowManager.open({ title: 'Inline Citation', - url: AU_locationInfo.tinymceViewsURL + 'inline-citation.html', + url: ABT_locationInfo.tinymceViewsURL + 'inline-citation.html', width: 400, height: 85, onClose: function (e) { @@ -388,7 +499,7 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', function (editor, url) onclick: function () { editor.windowManager.open({ title: 'Insert Formatted Reference', - url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', + url: ABT_locationInfo.tinymceViewsURL + 'formatted-reference.html', width: 600, height: 100, onclose: function (e) { diff --git a/inc/js/wp-editor/main-parser.ts b/inc/js/wp-editor/main-parser.ts index 2aa158c9..6d3052f1 100644 --- a/inc/js/wp-editor/main-parser.ts +++ b/inc/js/wp-editor/main-parser.ts @@ -1,4 +1,4 @@ -declare var tinymce, tinyMCE, AU_locationInfo +declare var tinymce, tinyMCE, ABT_locationInfo namespace Parsers { @@ -32,16 +32,29 @@ namespace Parsers { let cleanedData: ReferenceObj; let type = MainParser.manualCitationType; - let authors: Author[] = data.authors; + // Reformat name to Last Name, First Initial + let authors: Author[] = data.authors.map((author: Author) => { + let name = + `${author.name.split(' ')[1]} ${author.name.split(' ')[0][0]}`; + return {name}; + }) + let title: string = data[`${type}-title`].toTitleCase(); let source: string = data[`${type}-source`]; - let pubdate: string = data[`${type}-date`] ? data[`${type}-date`] : ''; - let volume: string = data[`${type}-volume`] ? data[`${type}-volume`] : ''; - let issue: string = data[`${type}-issue`] ? data[`${type}-issue`] : ''; - let pages: string = data[`${type}-pages`] ? data[`${type}-pages`] : ''; - let lastauthor: string = data.authors[data.authors.length - 1].name; - let url: string = data[`${type}-url`] ? data[`${type}-url`] : ''; - let accessdate: string = data[`${type}-accessed`] ? data[`${type}-accessed`] : ''; + let pubdate: string = data[`${type}-date`] || ''; + let volume: string = data[`${type}-volume`] || ''; + let issue: string = data[`${type}-issue`] || ''; + let pages: string = data[`${type}-pages`] || ''; + let lastauthor: string = data.authors.length > 0 + ? data.authors[data.authors.length - 1].name + : ''; + let url: string = data[`${type}-url`] || ''; + let accessdate: string = data[`${type}-accessed`] || ''; + let updated: string = data[`${type}-updated`] || ''; + let location: string = data[`${type}-location`] || ''; + let chapter: string = data[`${type}-chapter`] || ''; + let edition: string = data[`${type}-edition`] || ''; + cleanedData = { authors, @@ -54,6 +67,10 @@ namespace Parsers { lastauthor, url, accessdate, + updated, + location, + chapter, + edition, } let payload: string[]|Error; @@ -72,9 +89,8 @@ namespace Parsers { return; } - console.log(`OUTPUT:`); - console.log(cleanedData); - return; + this._deliverContent(payload); + } @@ -115,6 +131,11 @@ namespace Parsers { return; } + this._deliverContent(payload); + + } + + private _deliverContent(payload: string[]|Error): void { if ((payload as Error).name === 'Error') { this.editor.windowManager.alert((payload as Error).message); this.editor.setProgressState(0); @@ -131,7 +152,6 @@ namespace Parsers { this.editor.insertContent(orderedList); this.editor.setProgressState(0); - } } diff --git a/inc/js/wp-editor/parsers/ama.ts b/inc/js/wp-editor/parsers/ama.ts index cbf6b4bc..b62f16e6 100644 --- a/inc/js/wp-editor/parsers/ama.ts +++ b/inc/js/wp-editor/parsers/ama.ts @@ -4,14 +4,17 @@ namespace Parsers { export class AMA { + private _isManual: boolean = true; + public parse(data: ReferencePayload): string[]|Error { let pmidArray: string[]|boolean = data.uids || false; if (pmidArray) { + this._isManual = false; return this._fromPMID(data, (pmidArray as string[])); } - return this._fromManual(data); + return [this._fromManual(data)]; } private _fromPMID(data: ReferencePayload, pmidArray: string[]): string[]|Error { @@ -40,33 +43,29 @@ namespace Parsers { return output; } - private _fromManual(data: ReferencePayload): string[] { - /** TODO */ + private _fromManual(data: ReferencePayload): string { + let payload: string; switch (MainParser.manualCitationType) { case 'journal': - // do stuff - break; - case 'blog': - // do stuff + payload = this._parseJournal(data); break; case 'website': - // do stuff + payload = this._parseWebsite(data); + break; + case 'book': + payload = this._parseBook(data); break; - default: - // return an error } - console.log('MADE IT DO FROM MANUAL') - console.log(data); - - return ['unfinished']; + return payload; } private _parseAuthors(authorArr: Author[]): string|Error { let authors: string = ''; switch (authorArr.length) { case 0: + if (this._isManual === true) { break; } return new Error(`No authors were found for given reference`); case 1: case 2: @@ -83,6 +82,52 @@ namespace Parsers { return authors; } + private _parseJournal(data: ReferencePayload): string { + let authors = this._parseAuthors(data[0].authors); + let year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); + let source = data[0].source.toTitleCase(); + let issue = `(${data[0].issue})` || ''; + let volume = data[0].volume || ''; + + return `${authors} ${data[0].title}. ${source}. ${year}; ` + + `${volume}${issue}:${data[0].pages}.`; + } + + private _parseWebsite(data: ReferencePayload): string { + let authors = data[0].authors.length > 0 + ? this._parseAuthors(data[0].authors) + ' ' + : ''; + let pubdate: string = `Published ${new Date(data[0].pubdate).toLocaleDateString('en-us', {month: 'long', year: 'numeric'})}. `; + let updated: string = data[0].updated !== '' + ? `Updated ${new Date(data[0].updated).toLocaleDateString('en-us', {month: 'long', day: 'numeric', year: 'numeric'})}. ` + : '' + let accessed: string = data[0].accessdate !== '' + ? `Accessed ${new Date(data[0].accessdate).toLocaleDateString('en-us', {month: 'long', day: 'numeric', year: 'numeric'})}. ` + : `Accessed ${new Date(Date.now()).toLocaleDateString('en-us', {month: 'long', day: 'numeric', year: 'numeric'})}`; + + return `${authors}${data[0].title}. ${data[0].source}. Available at: ` + + `${data[0].url}. ${pubdate}${updated}${accessed}`; + } + + private _parseBook(data: ReferencePayload): string { + console.log(data) + let authors = this._parseAuthors(data[0].authors); + let title = data[0].title; + let pubLocation = data[0].location !== '' + ? `${data[0].location}:` + : ``; + let publisher = data[0].source; + let year = data[0].pubdate; + let chapter = data[0].chapter !== '' + ? ` ${data[0].chapter}. In:` + : ``; + let pages = data[0].pages !== '' + ? `: ${data[0].pages}.` + : `.`; + + return `${authors}${chapter} ${title}. ${pubLocation}${publisher}; ${year}${pages}`; + } + } } diff --git a/inc/js/wp-editor/parsers/apa.ts b/inc/js/wp-editor/parsers/apa.ts index 62ee17a0..e87be730 100644 --- a/inc/js/wp-editor/parsers/apa.ts +++ b/inc/js/wp-editor/parsers/apa.ts @@ -4,14 +4,17 @@ namespace Parsers { export class APA { + private _isManual: boolean = true; + public parse(data: ReferencePayload): string[]|Error { let pmidArray: string[]|boolean = data.uids || false; if (pmidArray) { + this._isManual = false; return this._fromPMID(data, (pmidArray as string[])); } - return this._fromManual(data); + return [this._fromManual(data)]; } private _fromPMID(data: ReferencePayload, pmidArray: string[]): string[]|Error { @@ -45,9 +48,21 @@ namespace Parsers { } - private _fromManual(data: ReferencePayload): string[] { - /** TODO */ - return ['unfinished'] + private _fromManual(data: ReferencePayload): string { + let payload: string; + switch (MainParser.manualCitationType) { + case 'journal': + payload = this._parseJournal(data); + break; + case 'website': + payload = this._parseWebsite(data); + break; + case 'book': + payload = this._parseBook(data); + break; + } + + return payload; } private _parseAuthors(authorArr: Author[], lastAuthor: string): string|Error { @@ -55,6 +70,7 @@ namespace Parsers { switch (authorArr.length) { case 0: + if (this._isManual === true) { break; } return new Error(`No authors were found for given reference`); case 1: authors = authorArr.map((author: Author) => @@ -102,6 +118,46 @@ namespace Parsers { } + private _parseJournal(data: ReferencePayload): string { + let authors = this._parseAuthors(data[0].authors, data[0].lastauthor); + let year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); + let source = data[0].source.toTitleCase(); + let issue = `(${data[0].issue})` || ''; + let volume = data[0].volume || ''; + + return `${authors} (${year}). ${data[0].title}. ` + + `${source}., ${volume}${issue}, ${data[0].pages}.`; + } + + private _parseWebsite(data: ReferencePayload): string { + let authors = this._parseAuthors(data[0].authors, data[0].lastauthor); + let rawDate = new Date(data[0].pubdate); + let source = data[0].source.toTitleCase(); + let date = `${rawDate.getFullYear()}, ` + + `${rawDate.toLocaleDateString('en-us', {month: 'long', day: 'numeric'})}`; + + return `${authors} (${date}). ${data[0].title}. ${source}. ` + + `Retrieved from ${data[0].url}`; + } + + private _parseBook(data: ReferencePayload): string { + let authors = this._parseAuthors(data[0].authors, data[0].lastauthor); + let year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); + let pubLocation = data[0].location !== '' + ? `${data[0].location}:` + : ''; + let publisher = data[0].source; + let chapter = data[0].chapter !== '' + ? ` ${data[0].chapter}. In` + : ''; + let pages = data[0].pages !== '' + ? ` (${data[0].pages})` + : ''; + + return `${authors} (${year}).${chapter} ${data[0].title}${pages}. ` + + `${pubLocation}${publisher}.`; + } + } } diff --git a/inc/js/wp-editor/tinymce-buttons.ts b/inc/js/wp-editor/tinymce-buttons.ts index 47b4ac46..41df9cb2 100644 --- a/inc/js/wp-editor/tinymce-buttons.ts +++ b/inc/js/wp-editor/tinymce-buttons.ts @@ -3,7 +3,7 @@ /// /// /// -declare var tinymce, tinyMCE, AU_locationInfo +declare var tinymce, tinyMCE, ABT_locationInfo tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) => { @@ -112,7 +112,7 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) onclick: () => { editor.windowManager.open({ title: 'Inline Citation', - url: AU_locationInfo.tinymceViewsURL + 'inline-citation.html', + url: ABT_locationInfo.tinymceViewsURL + 'inline-citation.html', width: 400, height: 85, onClose: (e) => { @@ -129,7 +129,7 @@ tinymce.PluginManager.add('abt_ref_id_parser_mce_button', (editor, url: string) onclick: () => { editor.windowManager.open({ title: 'Insert Formatted Reference', - url: AU_locationInfo.tinymceViewsURL + 'formatted-reference.html', + url: ABT_locationInfo.tinymceViewsURL + 'formatted-reference.html', width: 600, height: 100, onclose: (e: any) => { diff --git a/inc/peer-review.php b/inc/peer-review.php index 51df472d..1aa947b6 100644 --- a/inc/peer-review.php +++ b/inc/peer-review.php @@ -365,7 +365,7 @@ function abt_image_enqueue() { 'button' => __( 'Use this image', 'abt-textdomain' ), ) ); - wp_localize_script( 'meta-box-image', 'AU_locationInfo', array( + wp_localize_script( 'meta-box-image', 'ABT_locationInfo', array( 'jsURL' => plugins_url('academic-bloggers-toolkit/inc/js/'), 'tinymceViewsURL' => plugins_url('academic-bloggers-toolkit/inc/tinymce-views/') )); diff --git a/inc/tinymce-views/formatted-reference.html b/inc/tinymce-views/formatted-reference.html index 3d9efbb6..d97712c8 100644 --- a/inc/tinymce-views/formatted-reference.html +++ b/inc/tinymce-views/formatted-reference.html @@ -15,6 +15,7 @@ + + diff --git a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts index 46131ab0..fdbb0e90 100644 --- a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts +++ b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts @@ -1,5 +1,6 @@ import { showHide } from '../../utils/HelperFunctions.ts'; import Modal from '../../components/Modal.ts'; +import PubmedWindow from '../../components/PubmedWindow.ts'; class ReferenceWindow { @@ -8,6 +9,7 @@ class ReferenceWindow { public buttons = { toggleAddManually: document.getElementById('add-manually'), addAuthor: document.getElementById('add-author'), + searchPubmed: document.getElementById('search-pubmed'), } public containers = { @@ -46,6 +48,10 @@ class ReferenceWindow { this.buttons.addAuthor.addEventListener('click', this._addAuthorRow.bind(this)); this.selections.manualCitationType.addEventListener('change', this._manualCitationChange.bind(this)); this.form.addEventListener('submit', this._submitForm.bind(this)); + this.buttons.searchPubmed.addEventListener('click', () => { + let wm = top.tinyMCE.activeEditor.windowManager; + new PubmedWindow(wm); + }); } private _manualCitationChange(e: Event): void { @@ -139,7 +145,7 @@ class ReferenceWindow { private _submitForm(e: Event) { e.preventDefault(); - let wm = top.tinymce.activeEditor.windowManager; + let wm = top.tinyMCE.activeEditor.windowManager; let formElement: HTMLFormElement = e.srcElement; let payload: Object = {}; let authorList: Object = {}; diff --git a/inc/js/tinymce-views/inline-citation/inline-citation.ts b/inc/js/tinymce-views/inline-citation/inline-citation.ts index b65db151..3071682c 100644 --- a/inc/js/tinymce-views/inline-citation/inline-citation.ts +++ b/inc/js/tinymce-views/inline-citation/inline-citation.ts @@ -1,53 +1,18 @@ - -class InlineCitationModal { - public outer: HTMLElement; - public inner: HTMLElement; - public mainRect: HTMLElement; - public initialSize: { - outer: number - inner: number - } - - constructor() { - this._getModal(); - this.initialSize = { - outer: parseInt(this.outer.style.height.substr(0, this.outer.style.height.length - 2)), - inner: parseInt(this.inner.style.height.substr(0, this.inner.style.height.length - 2)), - } - } - - public resize(): void { - let height = this.mainRect.getBoundingClientRect().height; - let position = `calc(50% - ${(height + 66) / 2}px)`; - this.outer.style.height = height + 66 + 'px'; - this.inner.style.height = height + 30 + 'px'; - this.outer.style.top = position; - }; - - private _getModal(): void { - let outerModalID: string = top.document.querySelector('div.mce-floatpanel[aria-label="Inline Citation"]').id; - let innerModalID: string = `${outerModalID}-body`; - this.outer = top.document.getElementById(outerModalID); - this.inner = top.document.getElementById(innerModalID); - this.mainRect = document.getElementById('main-container'); - } - -} - +import Modal from '../../components/Modal.ts'; class InlineCitationWindow { - private modal: InlineCitationModal = new InlineCitationModal; + private modal: Modal = new Modal('Inline Citation'); private editorDOM: HTMLDocument; public refList: HTMLOListElement|boolean; private smartBibRender: HTMLDivElement; constructor() { - this.editorDOM = top.tinymce.activeEditor.dom.doc; + this.editorDOM = top.tinyMCE.activeEditor.dom.doc; let smartBib = this.editorDOM.getElementById('abt-smart-bib'); this.refList = (smartBib as HTMLOListElement) || false; - this.smartBibRender = (document.getElementById('smart-bib-render') as HTMLDivElement); + this.smartBibRender = document.getElementById('smart-bib-render') as HTMLDivElement; if (this.refList) { let orderedList = document.createElement('OL'); diff --git a/inc/js/tsconfig.json b/inc/js/tsconfig.json index b2bf55d1..b15e39a5 100644 --- a/inc/js/tsconfig.json +++ b/inc/js/tsconfig.json @@ -33,6 +33,7 @@ "files": [ "ABT.d.ts", "components/Modal.ts", + "components/PubmedWindow.ts", "frontend.ts", "metaboxes.ts", "tinymce-entrypoint.ts", From 409f3d847a44d5cff0f862957c6652317e9ac61c Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Wed, 30 Mar 2016 22:31:14 -0400 Subject: [PATCH 14/18] Add React and begin pubmed query --- .gitignore | 1 + gulpfile.js | 2 +- inc/js/components/PubmedWindow.ts | 29 ---------- inc/js/tinymce-entrypoint.ts | 3 + .../formatted-reference.ts | 11 +++- .../pubmed-window/pubmed-window.html | 3 + .../pubmed-window/pubmed-window.tsx | 57 +++++++++++++++++++ inc/js/tsconfig.json | 47 --------------- package.json | 4 ++ tsconfig.json | 52 +++++++++++++++++ typings.json | 9 +++ webpack.config.js | 7 ++- 12 files changed, 143 insertions(+), 82 deletions(-) delete mode 100644 inc/js/components/PubmedWindow.ts create mode 100644 inc/js/tinymce-views/pubmed-window/pubmed-window.html create mode 100644 inc/js/tinymce-views/pubmed-window/pubmed-window.tsx delete mode 100644 inc/js/tsconfig.json create mode 100644 tsconfig.json create mode 100644 typings.json diff --git a/.gitignore b/.gitignore index a89fd448..a60329b0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules dist npm-debug.log +typings diff --git a/gulpfile.js b/gulpfile.js index ec949ef6..5b7337ae 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -46,7 +46,7 @@ gulp.task('serve', ['build'], function() { open: false, }); - gulp.watch('./inc/**/*.ts', ['webpack']).on('change', browserSync.reload); + gulp.watch(['./inc/**/*.ts', './inc/**/*.tsx'], ['webpack']).on('change', browserSync.reload); gulp.watch('./inc/**/*.scss', ['sass']); gulp.watch([ './inc/**/*', diff --git a/inc/js/components/PubmedWindow.ts b/inc/js/components/PubmedWindow.ts deleted file mode 100644 index 40119401..00000000 --- a/inc/js/components/PubmedWindow.ts +++ /dev/null @@ -1,29 +0,0 @@ - -export default class PubmedWindow { - - constructor(wm: any) { - console.log(wm) - wm.open( - { - title: 'Request More Tools', - body: [ - { - type: 'container', - html: x, - } - ], - buttons: [], - }); - } - -} - - -let x = -`
- Have a feature or tool in mind that isn't available?
- Open an issue on the GitHub repository and let me know! -
`; diff --git a/inc/js/tinymce-entrypoint.ts b/inc/js/tinymce-entrypoint.ts index f8b57607..6d38567f 100644 --- a/inc/js/tinymce-entrypoint.ts +++ b/inc/js/tinymce-entrypoint.ts @@ -43,6 +43,9 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { url: ABT_locationInfo.tinymceViewsURL + 'formatted-reference/formatted-reference.html', width: 600, height: 100, + params: { + baseUrl: ABT_locationInfo.tinymceViewsURL + }, onclose: (e: any) => { // If the user presses the exit button, return. diff --git a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts index fdbb0e90..03755d1e 100644 --- a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts +++ b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts @@ -1,6 +1,5 @@ import { showHide } from '../../utils/HelperFunctions.ts'; import Modal from '../../components/Modal.ts'; -import PubmedWindow from '../../components/PubmedWindow.ts'; class ReferenceWindow { @@ -50,7 +49,15 @@ class ReferenceWindow { this.form.addEventListener('submit', this._submitForm.bind(this)); this.buttons.searchPubmed.addEventListener('click', () => { let wm = top.tinyMCE.activeEditor.windowManager; - new PubmedWindow(wm); + console.log(wm) + wm.open({ + title: 'Search PubMed for Reference', + url: wm.windows[0].settings.params.baseUrl + 'pubmed-window/pubmed-window.html', + width: 600, + height: 100, + onclose: (e: any) => {}, + } + ); }); } diff --git a/inc/js/tinymce-views/pubmed-window/pubmed-window.html b/inc/js/tinymce-views/pubmed-window/pubmed-window.html new file mode 100644 index 00000000..fdf21d82 --- /dev/null +++ b/inc/js/tinymce-views/pubmed-window/pubmed-window.html @@ -0,0 +1,3 @@ + +
+ diff --git a/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx b/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx new file mode 100644 index 00000000..08108d37 --- /dev/null +++ b/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx @@ -0,0 +1,57 @@ +import * as React from 'react' +import * as ReactDOM from 'react-dom' +import Modal from '../../components/Modal.ts'; + +interface P { + +} + +interface S { + test: string +} + +class PubmedWindow extends React.Component { + + private modal: Modal = new Modal('Search PubMed for Reference'); + + constructor() { + super(); + this.state = { + test: '' + }; + } + + _handleSubmit(e) { + console.log(e); + this.modal.resize(); + } + + _changeHandler(e: Event) { + this.setState({ test: (e.target as HTMLInputElement).value }); + } + + render() { + return ( +
+
+
+ + +
+
+
{this.state.test}
+
+ ) + } +} + + + +ReactDOM.render( + , + document.getElementById('main-container') +); diff --git a/inc/js/tsconfig.json b/inc/js/tsconfig.json deleted file mode 100644 index b15e39a5..00000000 --- a/inc/js/tsconfig.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "moduleResolution": "node", - "isolatedModules": false, - "jsx": "react", - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "declaration": false, - "noImplicitAny": false, - "noImplicitUseStrict": false, - "removeComments": true, - "noLib": false, - "preserveConstEnums": true, - "suppressImplicitAnyIndexErrors": true - }, - "filesGlob": [ - "**/*.ts", - "!node_modules/**" - ], - "exclude": [ - "../../node_modules/", - "node_modules", - "typings/browser", - "typings/browser.d.ts" - ], - "compileOnSave": false, - "buildOnSave": false, - "atom": { - "rewriteTsconfig": true - }, - "files": [ - "ABT.d.ts", - "components/Modal.ts", - "components/PubmedWindow.ts", - "frontend.ts", - "metaboxes.ts", - "tinymce-entrypoint.ts", - "tinymce-views/formatted-reference/formatted-reference.ts", - "tinymce-views/inline-citation/inline-citation.ts", - "utils/Dispatcher.ts", - "utils/HelperFunctions-bak.ts", - "utils/HelperFunctions.ts", - "utils/Parsers.ts" - ] -} diff --git a/package.json b/package.json index 894294cf..5ddaa456 100644 --- a/package.json +++ b/package.json @@ -30,5 +30,9 @@ "typescript": "^1.8.9", "webpack": "^1.12.14", "webpack-stream": "^3.1.0" + }, + "dependencies": { + "react": "^0.14.8", + "react-dom": "^0.14.8" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..2ef55882 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,52 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "isolatedModules": false, + "jsx": "react", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "declaration": false, + "noImplicitAny": false, + "noImplicitUseStrict": false, + "removeComments": true, + "noLib": false, + "preserveConstEnums": true, + "suppressImplicitAnyIndexErrors": true + }, + "filesGlob": [ + "**/*.ts", + "**/*.tsx", + "!node_modules/**", + "../../typings/**" + ], + "exclude": [ + "node_modules", + "typings/browser", + "typings/browser.d.ts", + "dist" + ], + "compileOnSave": false, + "buildOnSave": false, + "atom": { + "rewriteTsconfig": true + }, + "files": [ + "inc/js/ABT.d.ts", + "inc/js/components/Modal.ts", + "inc/js/frontend.ts", + "inc/js/metaboxes.ts", + "inc/js/tinymce-entrypoint.ts", + "inc/js/tinymce-views/formatted-reference/formatted-reference.ts", + "inc/js/tinymce-views/inline-citation/inline-citation.ts", + "inc/js/utils/Dispatcher.ts", + "inc/js/utils/HelperFunctions-bak.ts", + "inc/js/utils/HelperFunctions.ts", + "inc/js/utils/Parsers.ts", + "typings/main.d.ts", + "typings/react-dom/index.d.ts", + "typings/react/index.d.ts", + "inc/js/tinymce-views/pubmed-window/pubmed-window.tsx" + ] +} diff --git a/typings.json b/typings.json new file mode 100644 index 00000000..e6b0fef7 --- /dev/null +++ b/typings.json @@ -0,0 +1,9 @@ +{ + "name": "academic-bloggers-toolkit", + "version": false, + "dependencies": {}, + "ambientDependencies": { + "react": "registry:dt/react#0.14.0+20160319053454", + "react-dom": "registry:dt/react-dom#0.14.0+20160316155526" + } +} diff --git a/webpack.config.js b/webpack.config.js index f2944c0b..314f2e7b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,6 +6,7 @@ module.exports = { 'inc/js/tinymce-views/formatted-reference/formatted-reference': './inc/js/tinymce-views/formatted-reference/formatted-reference.ts', 'inc/js/tinymce-views/inline-citation/inline-citation': './inc/js/tinymce-views/inline-citation/inline-citation.ts', 'inc/js/metaboxes': './inc/js/metaboxes.ts', + 'inc/js/tinymce-views/pubmed-window/pubmed-window': './inc/js/tinymce-views/pubmed-window/pubmed-window.tsx', }, output: { filename: '[name].js', @@ -14,13 +15,13 @@ module.exports = { module: { loaders: [ { - test: /\.(ts|tsx)$/, + test: /\.tsx?$/, exclude: /node_modules/, - loader: 'awesome-typescript-loader', + loader: 'ts-loader', } ], resolve: { - extensions: ['', '.ts', '.js'] + extensions: ['', '.ts', 'tsx', '.js'] } } } From 811d22b40a21d5ce0651d8de9bc6e805e08f0484 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Thu, 31 Mar 2016 18:17:21 -0400 Subject: [PATCH 15/18] Finish ground work with pubmed search --- .../formatted-reference.ts | 1 - .../pubmed-window/pubmed-window.tsx | 86 +++++++++++++++++-- inc/js/tinymce-views/tinymce-views.scss | 18 ++++ inc/js/utils/PubmedAPI.ts | 62 +++++++++++++ tsconfig.json | 1 + 5 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 inc/js/utils/PubmedAPI.ts diff --git a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts index 03755d1e..95dae03e 100644 --- a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts +++ b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts @@ -49,7 +49,6 @@ class ReferenceWindow { this.form.addEventListener('submit', this._submitForm.bind(this)); this.buttons.searchPubmed.addEventListener('click', () => { let wm = top.tinyMCE.activeEditor.windowManager; - console.log(wm) wm.open({ title: 'Search PubMed for Reference', url: wm.windows[0].settings.params.baseUrl + 'pubmed-window/pubmed-window.html', diff --git a/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx b/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx index 08108d37..aa16490d 100644 --- a/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx +++ b/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx @@ -1,13 +1,16 @@ import * as React from 'react' import * as ReactDOM from 'react-dom' import Modal from '../../components/Modal.ts'; +import { PubmedQuery } from '../../utils/PubmedAPI.ts'; interface P { } interface S { - test: string + query: string + results: Object[] + page: number } class PubmedWindow extends React.Component { @@ -17,17 +20,54 @@ class PubmedWindow extends React.Component { constructor() { super(); this.state = { - test: '' + query: '', + results: [], + page: 0, }; } - _handleSubmit(e) { - console.log(e); + componentDidMount() { this.modal.resize(); } + _handleSubmit(e: Event) { + e.preventDefault(); + PubmedQuery(this.state.query, (data) => { + console.log(data) + this.setState({ + query: '', + results: data, + page: 1, + }) + this.modal.resize(); + }); + + } + _changeHandler(e: Event) { - this.setState({ test: (e.target as HTMLInputElement).value }); + this.setState({ + query: (e.target as HTMLInputElement).value, + results: this.state.results, + page: this.state.page, + }); + } + + _handlePagination(e: Event) { + e.preventDefault(); + + let page: number = this.state.page; + page = (e.target as HTMLInputElement).id === 'next' + ? page + 1 + : page - 1; + + this.setState({ + query: this.state.query, + results: this.state.results, + page + }); + setTimeout(() => { + this.modal.resize(); + }, 200); } render() { @@ -40,15 +80,47 @@ class PubmedWindow extends React.Component { style={{flexGrow: '1'}} onChange={this._changeHandler.bind(this)} /> - + -
{this.state.test}
+ { + if ( i < (this.state.page * 5) && ((this.state.page * 5) - 6) < i ) { + return true; + } + })} /> + ) } } +const ResultList = ({ + results +}) => { + return( +
+
    + {results.map((result, i: number) =>
  1. {result.title}
  2. )} +
+
+ ) +} + +const Paginate = ({ + page, + onClick +}) => { + return ( +
+
+ +
+
+ 3} onClick={onClick} value='Next' /> +
+
+ ) +} ReactDOM.render( diff --git a/inc/js/tinymce-views/tinymce-views.scss b/inc/js/tinymce-views/tinymce-views.scss index 5f2b7697..82fe8041 100644 --- a/inc/js/tinymce-views/tinymce-views.scss +++ b/inc/js/tinymce-views/tinymce-views.scss @@ -43,6 +43,16 @@ transform: translateY(1px); outline: 0; } + + &:disabled { + color: #a0a5aa; + border-color: #ddd; + background: #f7f7f7; + box-shadow: none; + text-shadow: 0 1px 0 #fff; + cursor: default; + transform: none; + } } .submit-btn { @@ -66,6 +76,14 @@ box-shadow: inset 0 2px 0 #006799; vertical-align: top; } + + &:disabled { + background: #008ec2; + color: #66c6e4; + border-color: #007cb2; + text-shadow: 0 -1px 0 rgba(0,0,0,.1); + cursor: default; + } } input, select { diff --git a/inc/js/utils/PubmedAPI.ts b/inc/js/utils/PubmedAPI.ts new file mode 100644 index 00000000..cdb545a6 --- /dev/null +++ b/inc/js/utils/PubmedAPI.ts @@ -0,0 +1,62 @@ + + +export function PubmedQuery(query: string, callback: Function): void { + + let requestURL: string = `http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=${encodeURI(query)}&retmode=json` + let request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.onload = () => { + + // Handle bad request + if (request.readyState !== 4 || request.status !== 200) { + console.log('Error'); + return; + } + + let res = JSON.parse(request.responseText); + + // Handle response errors + if (res.error) { + console.log('error') + } + + console.log(res) + getData(res.esearchresult.idlist.join(), callback); + + }; + request.send(null); +} + +function getData(PMIDlist: string, callback: Function): void { + + let requestURL = `http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=${PMIDlist}&version=2.0&retmode=json`; + let request = new XMLHttpRequest(); + request.open('GET', requestURL, true); + request.onload = () => { + + // Handle bad request + if (request.readyState !== 4 || request.status !== 200) { + console.log('Error'); + return; + } + + let res = JSON.parse(request.responseText); + + // Handle response errors + if (res.error) { + console.log('error') + } + + + let iterable = []; + + for (let i in (res.result as Object)) { + iterable.push(res.result[i]); + } + + callback(iterable); + + }; + request.send(null); + +} diff --git a/tsconfig.json b/tsconfig.json index 2ef55882..e8121b3f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -44,6 +44,7 @@ "inc/js/utils/HelperFunctions-bak.ts", "inc/js/utils/HelperFunctions.ts", "inc/js/utils/Parsers.ts", + "inc/js/utils/PubmedAPI.ts", "typings/main.d.ts", "typings/react-dom/index.d.ts", "typings/react/index.d.ts", From f27afeea0044a68b6105d73954488b1a84ce8145 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Thu, 31 Mar 2016 23:46:45 -0400 Subject: [PATCH 16/18] Finish pubmed query + add attach inline --- inc/js/components/Modal.ts | 9 +- inc/js/tinymce-entrypoint.ts | 3 +- .../formatted-reference.html | 10 +- .../formatted-reference.ts | 17 ++- .../pubmed-window/pubmed-window.tsx | 115 ++++++++++++++---- inc/js/tinymce-views/tinymce-views.scss | 4 + inc/js/utils/Dispatcher.ts | 7 ++ inc/js/utils/Parsers.ts | 1 - inc/js/utils/PubmedAPI.ts | 2 +- 9 files changed, 131 insertions(+), 37 deletions(-) diff --git a/inc/js/components/Modal.ts b/inc/js/components/Modal.ts index eaa3296a..bafd12a5 100644 --- a/inc/js/components/Modal.ts +++ b/inc/js/components/Modal.ts @@ -3,6 +3,7 @@ export default class Modal { public title: string public outer: HTMLElement public inner: HTMLElement + public mceReset: HTMLElement public mainRect: HTMLElement public initialSize: { outer: number @@ -20,9 +21,8 @@ export default class Modal { public resize(): void { let height = this.mainRect.getBoundingClientRect().height; - let position = `calc(50% - ${(height + 66) / 2}px)`; - this.outer.style.height = height + 66 + 'px'; - this.inner.style.height = height + 30 + 'px'; + let position = `calc(50% - ${(height + 56) / 2}px)`; + this.outer.style.height = height + 56 + 'px'; this.outer.style.top = position; }; @@ -31,7 +31,10 @@ export default class Modal { let innerModalID: string = `${outerModalID}-body`; this.outer = top.document.getElementById(outerModalID); this.inner = top.document.getElementById(innerModalID); + this.mceReset = this.outer.children[0] as HTMLElement; this.mainRect = document.getElementById('main-container'); + this.mceReset.style.height = '100%'; + this.inner.style.height = '100%'; } } diff --git a/inc/js/tinymce-entrypoint.ts b/inc/js/tinymce-entrypoint.ts index 6d38567f..7c6ed288 100644 --- a/inc/js/tinymce-entrypoint.ts +++ b/inc/js/tinymce-entrypoint.ts @@ -44,7 +44,7 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { width: 600, height: 100, params: { - baseUrl: ABT_locationInfo.tinymceViewsURL + baseUrl: ABT_locationInfo.tinymceViewsURL, }, onclose: (e: any) => { @@ -70,7 +70,6 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { }; let generateSmartBib = function() { - console.log(this) let dom: HTMLDocument = editor.dom.doc; let existingSmartBib: HTMLOListElement = dom.getElementById('abt-smart-bib'); diff --git a/inc/js/tinymce-views/formatted-reference/formatted-reference.html b/inc/js/tinymce-views/formatted-reference/formatted-reference.html index 7980df05..b5ad2f56 100644 --- a/inc/js/tinymce-views/formatted-reference/formatted-reference.html +++ b/inc/js/tinymce-views/formatted-reference/formatted-reference.html @@ -12,7 +12,8 @@
-
+ + @@ -176,7 +177,7 @@
- +
+ +
diff --git a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts index 95dae03e..1c284490 100644 --- a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts +++ b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts @@ -15,6 +15,7 @@ class ReferenceWindow { mainContainer: document.getElementById('main-container'), pubmedContainer: document.getElementById('pubmed-container'), manualContainer: document.getElementById('manual-container'), + attachInline: document.getElementById('attach-inline-container'), } public form: HTMLFormElement = document.getElementById('main-form'); @@ -26,6 +27,7 @@ class ReferenceWindow { public inputs = { pmidInput: document.getElementById('pmid-input'), includeLink: document.getElementById('include-link'), + attachInline: document.getElementById('attach-inline'), } public manualComponents = { @@ -43,6 +45,11 @@ class ReferenceWindow { this.modal.resize(); this._addAuthorRow(); + let existingSmartBib = top.tinyMCE.activeEditor.dom.doc.getElementById('abt-smart-bib'); + if (existingSmartBib !== null) { + this.containers.attachInline.style.display = 'flex'; + } + this.buttons.toggleAddManually.addEventListener('click', this._toggleAddManually.bind(this)); this.buttons.addAuthor.addEventListener('click', this._addAuthorRow.bind(this)); this.selections.manualCitationType.addEventListener('change', this._manualCitationChange.bind(this)); @@ -54,7 +61,15 @@ class ReferenceWindow { url: wm.windows[0].settings.params.baseUrl + 'pubmed-window/pubmed-window.html', width: 600, height: 100, - onclose: (e: any) => {}, + onsubmit: (e: any) => { + if (this.inputs.pmidInput.value === '') { + this.inputs.pmidInput.value = (e.target as any).data.pmid; + return; + } + let combinedInput = this.inputs.pmidInput.value.split(','); + combinedInput.push((e.target as any).data.pmid) + this.inputs.pmidInput.value = combinedInput.join(','); + }, } ); }); diff --git a/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx b/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx index aa16490d..be17d329 100644 --- a/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx +++ b/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx @@ -3,19 +3,15 @@ import * as ReactDOM from 'react-dom' import Modal from '../../components/Modal.ts'; import { PubmedQuery } from '../../utils/PubmedAPI.ts'; -interface P { +declare var wm; -} - -interface S { - query: string - results: Object[] - page: number -} +/** TODO: Better handling of "next" button for paginator */ -class PubmedWindow extends React.Component { +class PubmedWindow extends React.Component +<{}, {query: string, results: Object[], page: number}> { private modal: Modal = new Modal('Search PubMed for Reference'); + private wm: any = top.window.tinyMCE.activeEditor.windowManager.windows[top.window.tinyMCE.activeEditor.windowManager.windows.length - 1]; constructor() { super(); @@ -33,7 +29,6 @@ class PubmedWindow extends React.Component { _handleSubmit(e: Event) { e.preventDefault(); PubmedQuery(this.state.query, (data) => { - console.log(data) this.setState({ query: '', results: data, @@ -41,7 +36,6 @@ class PubmedWindow extends React.Component { }) this.modal.resize(); }); - } _changeHandler(e: Event) { @@ -70,38 +64,85 @@ class PubmedWindow extends React.Component { }, 200); } + _insertPMID(e: Event) { + this.wm.data['pmid'] = (e.target as HTMLInputElement).dataset['pmid']; + this.wm.submit(); + } + render() { return (
-
-
+ +
- +
- { - if ( i < (this.state.page * 5) && ((this.state.page * 5) - 6) < i ) { - return true; - } - })} /> - + { this.state.results.length !== 0 && + { + if ( i < (this.state.page * 5) && ((this.state.page * 5) - 6) < i ) { + return true; + } + })} /> + } + { this.state.results.length !== 0 && + + }
) } } const ResultList = ({ - results + results, + onClick }) => { return(
-
    - {results.map((result, i: number) =>
  1. {result.title}
  2. )} -
+ {results.map((result, i: number) => +
+
+ +
+ {result.authors.filter((el, i) => i < 3).map(el => el.name).join(', ')} +
+
+ {result.source} | {result.pubdate} +
+
+
+ +
+
+ )}
) } @@ -111,18 +152,38 @@ const Paginate = ({ onClick }) => { return ( -
+
- 3} onClick={onClick} value='Next' /> + 3 || page === 0} onClick={onClick} value='Next' />
) } +function generatePlaceholder(): string { + + let options = [ + "Ioannidis JP[Author - First] AND meta research", + 'Brohi K[Author - First] AND "acute traumatic coagulopathy"', + "Dunning[Author] AND Kruger[Author] AND incompetence", + "parachute use AND death prevention AND BMJ[Journal]", + "obediance AND Milgram S[Author - First]", + "tranexamic acid AND trauma NOT arthroscopy AND Lancet[Journal]", + 'Watson JD[Author] AND Crick FH[Author] AND "nucleic acid"', + 'innovation OR ("machine learning" OR "deep learning") AND healthcare', + "injuries NOT orthopedic AND hemorrhage[MeSH]", + "resident OR student AND retention", + ]; + + return options[Math.ceil(Math.random() * 10) - 1]; + +} + + ReactDOM.render( , document.getElementById('main-container') diff --git a/inc/js/tinymce-views/tinymce-views.scss b/inc/js/tinymce-views/tinymce-views.scss index 82fe8041..1cc40189 100644 --- a/inc/js/tinymce-views/tinymce-views.scss +++ b/inc/js/tinymce-views/tinymce-views.scss @@ -1,3 +1,7 @@ +body { + overflow: hidden; +} + .row { margin-top: 10px; margin-bottom: 10px; diff --git a/inc/js/utils/Dispatcher.ts b/inc/js/utils/Dispatcher.ts index dc375512..94db34d5 100644 --- a/inc/js/utils/Dispatcher.ts +++ b/inc/js/utils/Dispatcher.ts @@ -4,6 +4,7 @@ import { AMA, APA } from './Parsers.ts'; export default class Dispatcher { public citationFormat: string; public includeLink: boolean; + public attachInline: boolean; public manualCitationType: string; public PMIDquery: string; public editor: any; @@ -16,6 +17,7 @@ export default class Dispatcher { : ''; this.manualCitationType = data['manual-type-selection']; this.includeLink = data['include-link']; + this.attachInline = data['attach-inline'] this.editor = editor; let smartBib = (this.editor.dom.doc as HTMLDocument) .getElementById('abt-smart-bib') as HTMLOListElement; @@ -145,11 +147,16 @@ export default class Dispatcher { } if (this.smartBib) { + let beforeLength: number = (this.smartBib as HTMLOListElement).children.length; for (let key in (payload as string[])) { let listItem = (this.editor.dom.doc as HTMLDocument).createElement('LI'); listItem.innerHTML = payload[key]; (this.smartBib as HTMLOListElement).appendChild(listItem); } + if (this.attachInline) { + let afterLength: number = (this.smartBib as HTMLOListElement).children.length; + this.editor.insertContent(`[cite num="${beforeLength + 1}-${afterLength}"]`); + } this.editor.setProgressState(0); return; } diff --git a/inc/js/utils/Parsers.ts b/inc/js/utils/Parsers.ts index 3e371fb0..6821078f 100644 --- a/inc/js/utils/Parsers.ts +++ b/inc/js/utils/Parsers.ts @@ -115,7 +115,6 @@ export class AMA { } private _parseBook(data: ReferencePayload): string { - console.log(data) let authors = this._parseAuthors(data[0].authors); let title = data[0].title; let pubLocation = data[0].location !== '' diff --git a/inc/js/utils/PubmedAPI.ts b/inc/js/utils/PubmedAPI.ts index cdb545a6..a95068d8 100644 --- a/inc/js/utils/PubmedAPI.ts +++ b/inc/js/utils/PubmedAPI.ts @@ -20,7 +20,6 @@ export function PubmedQuery(query: string, callback: Function): void { console.log('error') } - console.log(res) getData(res.esearchresult.idlist.join(), callback); }; @@ -51,6 +50,7 @@ function getData(PMIDlist: string, callback: Function): void { let iterable = []; for (let i in (res.result as Object)) { + if (i === 'uids') { continue; } iterable.push(res.result[i]); } From 5e66bea8f6f2f4c6362a6fc8cad42a7f1ba10fdd Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Sun, 3 Apr 2016 21:29:44 -0400 Subject: [PATCH 17/18] Commit prior to working on inline citation component --- CHANGELOG.md | 14 +- academic-bloggers-toolkit.php | 9 +- gulpfile.js | 48 +- inc/css/admin.scss | 18 + inc/css/{styles.scss => frontend.scss} | 63 +- inc/images/book.png | Bin 2512 -> 0 bytes inc/images/silhouette.png | Bin 1474 -> 0 bytes inc/js/ABT.d.ts | 51 +- .../inline-citation.ts | 4 +- .../pubmed-window.tsx | 37 +- inc/js/components/referenceWindow.tsx | 670 ++++++++++++++++++ inc/js/frontend.ts | 80 +-- inc/js/metaboxes.ts | 12 +- inc/js/tinymce-entrypoint.ts | 40 +- .../formatted-reference.html | 203 ------ .../formatted-reference.ts | 211 ------ .../inline-citation.html | 4 +- inc/js/tinymce-views/keyboard-shortcuts.html | 14 + inc/js/tinymce-views/pubmed-window.html | 3 + .../pubmed-window/pubmed-window.html | 3 - inc/js/tinymce-views/reference-window.html | 3 + .../{tinymce-views.scss => styles.scss} | 11 + inc/js/utils/Dispatcher.ts | 89 ++- inc/js/utils/HelperFunctions-bak.ts | 43 -- inc/js/utils/HelperFunctions.ts | 26 +- inc/js/{components => utils}/Modal.ts | 0 inc/js/utils/Parsers.ts | 21 +- inc/js/utils/PubmedAPI.ts | 14 +- inc/options-page-wrapper.php | 150 ++-- inc/peer-review.php | 89 ++- inc/shortcodes.php | 2 +- inc/tinymce-init.php | 24 +- package.json | 11 +- readme.txt | 47 +- tsconfig.json | 11 +- webpack.config.js | 18 +- 36 files changed, 1230 insertions(+), 813 deletions(-) create mode 100644 inc/css/admin.scss rename inc/css/{styles.scss => frontend.scss} (84%) delete mode 100644 inc/images/book.png delete mode 100644 inc/images/silhouette.png rename inc/js/{tinymce-views/inline-citation => components}/inline-citation.ts (92%) rename inc/js/{tinymce-views/pubmed-window => components}/pubmed-window.tsx (83%) create mode 100644 inc/js/components/referenceWindow.tsx delete mode 100644 inc/js/tinymce-views/formatted-reference/formatted-reference.html delete mode 100644 inc/js/tinymce-views/formatted-reference/formatted-reference.ts rename inc/js/tinymce-views/{inline-citation => }/inline-citation.html (88%) create mode 100644 inc/js/tinymce-views/keyboard-shortcuts.html create mode 100644 inc/js/tinymce-views/pubmed-window.html delete mode 100644 inc/js/tinymce-views/pubmed-window/pubmed-window.html create mode 100644 inc/js/tinymce-views/reference-window.html rename inc/js/tinymce-views/{tinymce-views.scss => styles.scss} (92%) delete mode 100644 inc/js/utils/HelperFunctions-bak.ts rename inc/js/{components => utils}/Modal.ts (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c652aa8..4a42b08b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,18 @@ # Changelog ### 2.4.0 -- Full rewrite. - Parse multiple comma-separated PMIDs at once into an ordered list. -- Add manual reference insertion for Journals, Websites, or Books. -- Add "Smart Bibliography" (see github repo for full details). +- Option to add references manually for Journals, Websites, or Books. +- Search PubMed from WordPress! + - References from your search are displayed in a list similar to native PubMed and, if you find one you like, click it and it'll be inserted into your post. +- Add optional "Smart Bibliography" feature which, if enabled, allows you to... + - Insert references directly to your bibliography without having to scroll down. + - Insert references and inline citations in one step. + - Choose from a visual list of references in your bibliography if you do not choose to add citations in one step. +- If Smart Bibliography not used, the last-occurring ordered list is automatically tagged with the HTML ID `abt-smart-bib` on load to allow for more reliable tooltip rendering. +- Details for nerds: + - Full rewrite; a majority of which is using React by Facebook. + - Speed improvements & resource minification. ### 2.3.1 - Fixed poor rendering of tooltip close icon on mobile. diff --git a/academic-bloggers-toolkit.php b/academic-bloggers-toolkit.php index 60e28510..eca01b85 100644 --- a/academic-bloggers-toolkit.php +++ b/academic-bloggers-toolkit.php @@ -7,9 +7,8 @@ * Version: 2.4.0 * Author: Derek P Sifford * Author URI: http://www.twitter.com/flightmed1 - * License: GPL3 - * License URI: https://www.gnu.org/licenses/gpl-3.0.html -*/ + * License: MIT + */ // Assign Global Variables @@ -20,9 +19,7 @@ // Enqueue Stylesheets function abt_enqueue_styles() { - - wp_enqueue_style( 'abt_shortcodes_stylesheet', plugins_url('academic-bloggers-toolkit/inc/css/styles.css') ); - + wp_enqueue_style( 'abt_frontend_styles', plugins_url('academic-bloggers-toolkit/inc/css/frontend.css') ); } add_action( 'wp_enqueue_scripts', 'abt_enqueue_styles'); diff --git a/gulpfile.js b/gulpfile.js index 5b7337ae..d39e6f7a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,55 +1,61 @@ -var gulp = require('gulp'), - uglify = require('gulp-uglify'), - sass = require('gulp-sass'), - autoprefixer = require('gulp-autoprefixer'), - cleanCSS = require('gulp-clean-css'), - browserSync = require('browser-sync').create(), - webpack = require('webpack-stream'); +var gulp = require('gulp'); +var uglify = require('gulp-uglify'); +var sass = require('gulp-sass'); +var autoprefixer = require('gulp-autoprefixer'); +var cleanCSS = require('gulp-clean-css'); +var browserSync = require('browser-sync').create(); +var webpack = require('webpack-stream'); +var del = require('del'); -// TODO: Static asset optimization // TODO: Better minifyer for js (one that doesn't break) -gulp.task('build', ['webpack', 'sass'], function() { +gulp.task('clean', function () { + return del([ + 'dist/inc/**/*', + ]); +}); + +gulp.task('build', ['clean', 'webpack', 'sass'], function () { gulp.src([ './academic-bloggers-toolkit.php', './CHANGELOG.md', './LICENSE', './readme.txt', './inc/**/*', - '!./inc/**/*.{ts,js,css,scss,json}' + '!./inc/**/*.{ts,js,css,scss,json}', ], { base: './' }) .pipe(gulp.dest('./dist')); }); -gulp.task('sass', function() { +gulp.task('sass', function () { gulp.src([ - './inc/**/*.scss' + './inc/**/*.scss', ], { base: './' }) .pipe(sass().on('error', sass.logError)) .pipe(autoprefixer({ - browsers: ['last 2 versions'] + browsers: ['last 2 versions'], })) - .pipe(cleanCSS({compatibility: 'ie10'})) + .pipe(cleanCSS({ compatibility: 'ie10' })) .pipe(gulp.dest('./dist')) .pipe(browserSync.stream()); }); -gulp.task('webpack', function() { +gulp.task('webpack', function () { return gulp.src('inc/js/frontend.ts') - .pipe(webpack( require('./webpack.config.js') )) + .pipe(webpack(require('./webpack.config.js'))) .pipe(gulp.dest('dist/')); -}) +}); -gulp.task('serve', ['build'], function() { +gulp.task('serve', ['build'], function () { browserSync.init({ proxy: 'localhost:8080', open: false, }); - gulp.watch(['./inc/**/*.ts', './inc/**/*.tsx'], ['webpack']).on('change', browserSync.reload); + gulp.watch(['./inc/**/*.tsx?'], ['webpack']).on('change', browserSync.reload); gulp.watch('./inc/**/*.scss', ['sass']); gulp.watch([ './inc/**/*', - '!./inc/**/*.{ts,scss}' + '!./inc/**/*.{tsx?,scss}', ], ['build']).on('change', browserSync.reload); -}) +}); diff --git a/inc/css/admin.scss b/inc/css/admin.scss new file mode 100644 index 00000000..957f16db --- /dev/null +++ b/inc/css/admin.scss @@ -0,0 +1,18 @@ + +i.mce-i-abt_menu { + font: normal 25px/1 'dashicons'; + padding: 0; + vertical-align: top; + speak: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + margin-left: -2px; + padding-right: 2px; +} + +#abt_menubutton:hover, +#abt_menubutton.mce-active, +#abt_menubutton:hover *, +#abt_menubutton.mce-active * { + color: rgb(50, 55, 60); +} diff --git a/inc/css/styles.scss b/inc/css/frontend.scss similarity index 84% rename from inc/css/styles.scss rename to inc/css/frontend.scss index 651a7339..46f59e63 100644 --- a/inc/css/styles.scss +++ b/inc/css/frontend.scss @@ -1,7 +1,6 @@ /* =========== TOOLTIP ============*/ .abt_tooltip { - border: 1px solid #f1f1f1; border-radius: 3px; padding: 8px; position: absolute; @@ -10,7 +9,7 @@ background-color: #fff; box-shadow: 0 0 50px rgba(0,0,0,.35); z-index: 20; - animation: fadeInUp .2s; + animation: fadeInDown .2s; } @keyframes fadeInUp { @@ -24,6 +23,17 @@ } } +@keyframes fadeInDown { + from { + opacity: 0; + transform: translate3d(0, -10px, 0); + } + to { + opacity: 1; + transform: none; + } +} + .abt_tooltip_arrow { content: ""; position: absolute; @@ -31,8 +41,21 @@ border-width: 8px; border-style: solid; pointer-events: none; + + &.abt_arrow_up { + border-color: transparent transparent #fff; + top: -15px; + } + + &.abt_arrow_down { + border-color: #fff transparent transparent; + bottom: -15px; + } + } + + .abt_tooltip_touch_close-container { width: 50px; height: 50px; @@ -89,27 +112,26 @@ /* =====Inline Citation Style===== */ -.cite:hover { - cursor: pointer; +.abt_cite { + white-space: nowrap; } +.abt_cite:hover { + cursor: pointer; +} /* =====Peer Review Box Style===== */ -#abt_PR_boxes h3 { +.abt_PR_heading { cursor: pointer; border-bottom: 4px solid; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; border-radius: 5px; background: #f5f5f5; - outline: 0; /* Prevent div from being outlined on click */ padding: 15px; text-align: center; - margin-bottom: 10px; - margin-top: 10px; - /* Prevent text highlight on click*/ + margin: 10px 0 !important; + // Prevent text highlight on click -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; @@ -119,11 +141,11 @@ } -#abt_PR_boxes h3:hover { +.abt_PR_heading:hover { background: #f1f1f1; } -#abt_PR_boxes h3:active { +.abt_PR_heading:active { border-bottom: 1px solid; padding-top: 18px; } @@ -133,7 +155,7 @@ float:left; width: 30%; position: relative; - top: 0px; + top: 0; text-align: center; font-size: 10px; margin-bottom: 10px; @@ -148,24 +170,21 @@ display: block; margin-left:auto; margin-right:auto; + height: auto; + min-width: 100px; } .abt_chat_bubble { display: inline-block; position: relative; width: 63%; - height: auto; min-height: 100px; - margin-right: 0px; - margin-left: 0px; + margin: auto 0 20px 0; background: #F6F6F6; - -webkit-border-radius: 8px; - -moz-border-radius: 8px; border-radius: 8px; padding: 15px; border-left: 1px solid #c7c7c7; border-top: 1px solid #c7c7c7; - margin-bottom: 20px; box-shadow: 1px 1px 1px #C7C7C7; } @@ -175,8 +194,6 @@ background-color: #F6F6F6; width: 20px; height: 20px; - -ms-transform: rotate(45deg); - -webkit-transform: rotate(45deg); transform: rotate(45deg); z-index: 1; margin-top: -15px; @@ -210,8 +227,6 @@ border-bottom: 1px solid #c7c7c7; position: absolute; top: -30px; - -ms-transform: rotate(45deg); - -webkit-transform: rotate(45deg); transform: rotate(45deg); z-index: 1; diff --git a/inc/images/book.png b/inc/images/book.png deleted file mode 100644 index 73a7d839e76e976897e31c2ad4997df29bb02dd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2512 zcmeHHSy0n=7yX3*2_a!A6cAK`1%$GNMK&b~OUfd$D2fD>ln`VotB4U(_=8k7B?zJk zB4CSvwn9KaAQ&mQ0J2%O2t^~ZiLz+W5`(1acamS#v zQ2+ppr-$1?DMJ4=5-y$Vf=ePP$ewUM;0!c4_7TRdJmzYx3&b&rv)k z+_=c7;}TcAxz&F2L}YZ#53_9=!v?MT_nN;c*wqw!_u>vt+_SHKxgekEAK#n*Q=a|n z#OwPObLEP2l#;XmK-TJvp5MEyc}$eb&Z-!>@$u^Eo_O@BKdmeu2p=3G zt@Q|e!&siHv{1LBHOJjw(#G_d(pzC+``z7Mg(8Ql0g&_YbaM`%PtHw=gVhgfA=V7^ zDMv!8+yZ9X&5wGiwrDXoug;UKpk13VSZOo$?WYMx*_|XbYVQ!ii`eaPF zK`9O5xlQ8++r5tl2m9H=a`uRDV++|K{DQlCm2JJs@)n@l43o+H=2vSN)gx~D*(z4P z%&^OZ?##M?b?@&a4+@!Kb<}Ij;g6;tPCUvJMcTe*Xh1=UImVP|-h0U5kPw5Ao!7yz ztnIM61J*W#<3-GQol;%HUU!9DPo9^LkEf@%_km{e9YsTvhgTx}@LqP}m{){T=j!7^ zn(Vt-jOXpf*7-?W1En8S`&#}O2yOHT#*<53?b6wg8Cgm3H&_)lPP)@x?@63Z+hx&W zN-D%QnWfruUwb8P&5%H|t4dNf17GogKG&C-Sypzqc+Rx!xBjsvm>vlwW}lSb5|uW0 z)qiCKTM5Z#$>i-<4~+`BVG0dSap+D%>IoC6C4XsKDD#OhKl0;WVYW*OMrMIe17!jr zSjpkrqMZ6GV5M5F_IXu#y=*H2Sv%bk;1ufHc|YO;<6-2li`a(-tu3$T_g{^y1s`0t!CUM(u%ch7s%uCG zin~Gze$rTxetCPL4Mv79hp?ffAw^z|E-tX)4Xreu`Ps@_Y?L4|taC*J1A6uNaKyV< z8ag4SClHJlo2%V4z{!U%{{rXxqH1H$!IU7FFGqf#CnBLxU4@ssM_{ZXh{9D`Rwz-d zEd|@gfm!Hz6y#b3eNxh@+=ixKQK~FfPuOr6hZch11rV@60$#p)p|c{93#L=a0fpzw^J7Yty-CyKVEdDS^fRHwP4|24 zp&FrEVT!$A)`Tvq_lZZ3zfd;=K5x*GE6QnKEM)$C2ql$ma>CguRPd=FtStovS&eP3 zW8jU;=i~u7)wl1SGS3inR6!%rr}t+MwyIBl0R`LF+LN}{bnxwpvul&a;Dut5geSI%;35|v{ZJ^AiLRri`{hriDWN%@ zyAcy=E8pO-R@m~;2BIq$i7mI^smz+5EeMX?!>8qI$-rgKXD@SSOw}~{OF3v} z1}tM_Dx9QLoBLBuH_)IvqH)f0f?7klG6@USDO9io@tGcXyav_a_?s&6%maD@cE>in z`8^peEkn(tnxvF;o=AXA(&#M~}FG|K@ z2(rC)7{&qQ#(dH6My!Fp&^)ABVmTp$CGQ4EA$}|cb^t9#DJS~M#Jbb zope}^(V^c*=oE;KPn8QRdi04E9MSItZ^yu8#{{q3-FMskh>RAF!IL>dOze!d(0@@4 zzdSQQb)RLzFSf?|x4BF#>0>)bS5*lk>Dq(!t4m8O`0FJBmv)Ctkt|J&m`GP}%&}mL@tEzd-`k69&u}l>s!K0@! z4#)>)S&C@{GzfQS?k|?BZ%ynmPxxZ_P=n&NHyAGu4>^z5BBVuJ59*GjQO3+*^S&!t zrG$It;`aSbcv_XQUUNJ`MA}&P%{4p;Ak~D diff --git a/inc/images/silhouette.png b/inc/images/silhouette.png deleted file mode 100644 index da78ec5ef5c3e1a71a383fb83f810a460f474817..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1474 zcmV;z1wHzSP)00009a7bBm000XU z000XU0RWnu7ytkO2XskIMF-#m6%{EPE;(Dn000GHNkl`P`kr3thSIGCG_g>CRn(&+0kq`L{&Q8lCsm2BYMeS{5QOM$(qC zx@a4QcF!l<-NC`+NKF_PBI<%y%9(N@JMF{NeRCK|fGRWpi!OkS!R~xeo zE13{G>m{MFrw>)It%NS#{&fPN&cM_~@SM|Mw&z13btlUdueauBFx?>pcDKr*4{MqF z-p+!ufL;--wdH(5*JO;GFtm-8{7k`ea+bWoi}}=pLXfG3Rm@vda@f80!a@17Q93LH zSYF6Uf6f}3##!`XA*#vd7^l&nh6rlPDHue58mf%rVp!v9%+f^+3qVQM6E9fAuwqy- ztQb}dD^?6Eh84rQUjfFs;rMqVzqTP4RuG^NOw9rxAtaDoc#yjkwzFQcvq?3U<>XAh z!S)Z&qiR{Y&Q(sswB$;>Tv%?qr_yc7_V99H5m4HX5ClPlVGTV`C9Ip`+VcG*sIaRI9fl46Ac9M1`%zo*!k)VwAM5d#XqU{ec%@SO8G1U8#Zf@zj-_@koc& zA9{ZuNpH~`jr`i#^(-XPP4`yzPh4DeDIv1}YcTXZUv9WqKX0qZs1(%$WIm^Y0A;&& zm9U^clz1~E&sWoXqNwoCo*Ford*O9nfe2s6@E%U-c%AqmmD zBh2j6FbEI`FdEt~GD=YGK`W|u-xK(CXF&)aZaotb-|p9MdZU@LEGKIkx)yrnmk_eC zQkb=An6_l~w@^xFYL7G`fMF>3c)Qfv9i@bQk;UiNAYpI--S|gux zQbB;T0L$}(a!Kw^K%p@qScGBSIbA!Oe6zdAne@M8Z+oF!NDGZgjl9B-vk)<1XyszM zXj=-l;(itPA~st$=Z&u0?#Y<=VK&J60os{F$+4WAIgvB@C?N&gD%h6i1;_PP!@V62 zy%4V?1j|B1&Y7J_tS;plo35Hq)4i>ox}ENTkPx8pCt?zUFVE+Sjy0Xt&wMtS&nA68 zIJs!o>Mr7wnh_sqS%{D_MP)9N&zTS%9oOB9X16~WJBj+DfYpyz7me=y4F>nYGIYMX zS=KZL&qKZ+93C~B?(O%|0RFvsxAn51Z1>xgh%vhPvM?NZf4n>I4Mt<-hITgb=Jn!p zBlSgE&i7s|ROT{2wybh7^>Q%}&tA(5IY#Nx*A0vG%Q&+#mx)PzR;8RN=B@vSl}#H8 z4(E%O)?YaK7ts>^T-?}Labh~(>ZjG>=Q8XkSP5Md8jsO@D>EsK|8{zRf~DqA)QBo= c8Fw%K1y)?be1tM8YybcN07*qoM6N<$f-v#AW&i*H diff --git a/inc/js/ABT.d.ts b/inc/js/ABT.d.ts index a08e2512..b05ceb0a 100644 --- a/inc/js/ABT.d.ts +++ b/inc/js/ABT.d.ts @@ -88,15 +88,54 @@ interface TinyMCEPluginButton { interface Author { authtype?: string clusterid?: string - name: string + name?: string + firstname?: string + lastname?: string + middleinitial?: string +} + +interface CommonMeta { + title: string + source: string + pubdate: string +} + +interface BookMeta extends CommonMeta { + chapter: string + edition: string + location: string + pages: string +} + +interface JournalMeta extends CommonMeta { + volume: string + issue: string + pages: string +} + +interface WebsiteMeta extends CommonMeta { + url: string + updated: string + accessed: string +} + +interface ManualDataObj { + authors: Author[] + meta: { + book: BookMeta + journal: JournalMeta + website: WebsiteMeta + } + type: 'journal'|'website'|'book' } interface ReferenceFormData { - 'citation-format': string - 'pmid-input'?: string - 'include-link'?: boolean - 'manual-type-selection'?: string - authors?: Author[] + addManually: boolean + attachInline: boolean + citationFormat: string + includeLink: boolean + manualData: ManualDataObj + pmidList: string } interface ReferenceObj { diff --git a/inc/js/tinymce-views/inline-citation/inline-citation.ts b/inc/js/components/inline-citation.ts similarity index 92% rename from inc/js/tinymce-views/inline-citation/inline-citation.ts rename to inc/js/components/inline-citation.ts index 3071682c..48030b53 100644 --- a/inc/js/tinymce-views/inline-citation/inline-citation.ts +++ b/inc/js/components/inline-citation.ts @@ -1,4 +1,6 @@ -import Modal from '../../components/Modal.ts'; +/** TODO: Smart bibliography insertion */ + +import Modal from '../utils/Modal.ts'; class InlineCitationWindow { diff --git a/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx b/inc/js/components/pubmed-window.tsx similarity index 83% rename from inc/js/tinymce-views/pubmed-window/pubmed-window.tsx rename to inc/js/components/pubmed-window.tsx index be17d329..f5bd1584 100644 --- a/inc/js/tinymce-views/pubmed-window/pubmed-window.tsx +++ b/inc/js/components/pubmed-window.tsx @@ -1,11 +1,10 @@ import * as React from 'react' import * as ReactDOM from 'react-dom' -import Modal from '../../components/Modal.ts'; -import { PubmedQuery } from '../../utils/PubmedAPI.ts'; +import Modal from '../utils/Modal.ts'; +import { PubmedQuery } from '../utils/PubmedAPI.ts'; declare var wm; -/** TODO: Better handling of "next" button for paginator */ class PubmedWindow extends React.Component <{}, {query: string, results: Object[], page: number}> { @@ -28,10 +27,14 @@ class PubmedWindow extends React.Component _handleSubmit(e: Event) { e.preventDefault(); - PubmedQuery(this.state.query, (data) => { + PubmedQuery(this.state.query, (data: Object[]|Error) => { + if ((data as Error).name == 'Error') { + top.tinyMCE.activeEditor.windowManager.alert((data as Error).message); + return; + } this.setState({ query: '', - results: data, + results: (data as Object[]), page: 1, }) this.modal.resize(); @@ -93,7 +96,10 @@ class PubmedWindow extends React.Component })} /> } { this.state.results.length !== 0 && - + }
) @@ -149,15 +155,28 @@ const ResultList = ({ const Paginate = ({ page, - onClick + onClick, + resultLength, }) => { return (
- +
- 3 || page === 0} onClick={onClick} value='Next' /> + 3 || page === 0 || ((page + 1) * 5) > resultLength } + onClick={onClick} + value='Next' />
) diff --git a/inc/js/components/referenceWindow.tsx b/inc/js/components/referenceWindow.tsx new file mode 100644 index 00000000..af5c423e --- /dev/null +++ b/inc/js/components/referenceWindow.tsx @@ -0,0 +1,670 @@ +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import Modal from '../utils/Modal.ts'; + +interface Author { + firstname: string + lastname: string + middleinitial: string +} + +interface CommonMeta { + title: string + source: string + pubdate: string +} + +interface JournalMeta extends CommonMeta { + volume: string + issue: string + pages: string +} + +interface WebsiteMeta extends CommonMeta { + url: string + updated: string + accessed: string +} + +interface BookMeta extends CommonMeta { + chapter: string + edition: string + location: string + pages: string +} + +interface ManualMeta { + journal: JournalMeta, + website: WebsiteMeta, + book: BookMeta, +} + +interface ManualPayload { + type: 'journal'|'website'|'book' + authors: Author[] + meta: ManualMeta +} + +interface State { + pmidList: string + citationFormat: string + includeLink: boolean + attachInline: boolean + addManually: boolean + manualData: ManualPayload +} + + +class ReferenceWindow extends React.Component<{}, State> { + + private modal: Modal = new Modal('Insert Formatted Reference'); + private smartBibIsEnabled = + (top.tinyMCE.activeEditor.dom.doc as Document).getElementById('abt-smart-bib'); + + constructor() { + super(); + this.state = { + pmidList: '', + citationFormat: top.tinyMCE.activeEditor.windowManager.windows[0].settings.params.preferredStyle || 'ama', + includeLink: false, + attachInline: false, + addManually: false, + manualData: { + type: 'journal', + authors: [ + { firstname: '', lastname: '', middleinitial: '', }, + ], + meta: { + journal: { + title: '', + source: '', + pubdate: '', + volume: '', + issue: '', + pages: '', + }, + website: { + title: '', + source: '', + pubdate: '', + url: '', + updated: '', + accessed: '', + }, + book: { + title: '', + source: '', + pubdate: '', + chapter: '', + edition: '', + location: '', + pages: '', + }, + } + }, + } + } + + componentDidMount() { + this.modal.resize(); + } + + componentDidUpdate() { + this.modal.resize(); + } + + handleButtonClick(e: MouseEvent) { + let id = (e.target as HTMLInputElement).id; + + switch(id) { + case 'searchPubmed': + let wm = top.tinyMCE.activeEditor.windowManager; + wm.open({ + title: 'Search PubMed for Reference', + url: wm.windows[0].settings.params.baseUrl + 'pubmed-window.html', + width: 600, + height: 100, + onsubmit: (e: any) => { + let newList: string = e.target.data.pmid; + + // If the current PMID List is not empty, add PMID to it + if (this.state.pmidList !== '') { + let combinedInput = this.state.pmidList.split(','); + combinedInput.push(e.target.data.pmid); + newList = combinedInput.join(','); + } + + this.setState(Object.assign({}, this.state, { pmidList: newList })); + }} + ); + break; + case 'addManually': + this.setState(Object.assign({}, this.state, { addManually: !this.state.addManually })); + break; + } + + } + + handleSubmit(e: Event) { + e.preventDefault(); + let wm = top.tinyMCE.activeEditor.windowManager; + wm.setParams({ data: this.state }); + wm.close(); + } + + consumeChange(e: Event) { + + // Switch on the type of input element and create a new, non-mutated + // state object to apply the result of the state change. + let id: string = (e.target as HTMLElement).id; + let tagName: string = (e.target as HTMLElement).tagName; + let newState = {}; + + switch (tagName) { + case 'INPUT': + let type: string = (e.target as HTMLInputElement).type; + + switch(type) { + case 'text': + newState[id] = (e.target as HTMLInputElement).value; + break; + case 'checkbox': + newState[id] = (e.target as HTMLInputElement).checked; + break; + } + break; + case 'SELECT': + newState[id] = (e.target as HTMLSelectElement).value; + break; + } + + this.setState(Object.assign({}, this.state, newState)); + } + + consumeManualDataChange(e: Event) { + + let type: string = e.type; + let newData = Object.assign({}, this.state.manualData); + + switch(type) { + case 'AUTHOR_DATA_CHANGE': + newData.authors = (e as CustomEvent).detail; + break; + case 'ADD_AUTHOR': + newData.authors = [...newData.authors, { firstname: '', lastname: '', middleinitial: '', }]; + break + case 'REMOVE_AUTHOR': + let removeNum: number = parseInt((e as CustomEvent).detail); + newData.authors = [ + ...newData.authors.slice(0, removeNum), + ...newData.authors.slice(removeNum + 1), + ]; + break; + case 'TYPE_CHANGE': + newData.type = (e as CustomEvent).detail; + break; + case 'META_CHANGE': + newData.meta = (e as CustomEvent).detail; + break; + } + + this.setState(Object.assign({}, this.state, { manualData: newData })); + + } + + render() { + return( +
+
+ { !this.state.addManually && + + } + { this.state.addManually && + + } + + + +
+ ); + } + +} + + +class PMIDInput extends React.Component<{pmidList: string, onChange: Function},{}> { + + refs: { + [key: string]: Element + pmidInput: HTMLInputElement + } + + componentDidMount() { + (ReactDOM.findDOMNode(this.refs.pmidInput) as HTMLInputElement).focus() + } + + render() { + let sharedStyle = { + padding: '5px', + } + return( +
+
+ +
+ +
+ +
+
+ +
+
+ ) + } + +} + + +const RefOptions = ({ + attachInline, + citationFormat, + onChange, + smartBibIsEnabled, +}) => { + let commonStyle = { padding: '5px' } + return( +
+
+
+ +
+
+ +
+
+ { smartBibIsEnabled && +
+
+ +
+
+ +
+
+ } +
+ ); +} + + +const ActionButtons = ({ + addManually, + onClick +}) => { + + const rowStyle = { + textAlign: 'center', + display: 'flex', + alignItems: 'center', + justifyContent: 'space-around', + }; + + const spanStyle = { + borderRight: 'solid 2px #ccc', + height: 25, + margin: '0 15px 0 10px', + }; + + const buttonStyle = { margin: '0 5px' }; + + const submitStyle = { + flexGrow: 1, + margin: '0 15px 0 0' + }; + + return( +
+ + + + + +
+ ) +} + + + + +class ManualEntryContainer extends React.Component<{ + manualData: ManualPayload, + onChange +},{}> { + + constructor(props) { + super(props); + } + + + typeChange(e) { + let event = new CustomEvent('TYPE_CHANGE', { detail: e.target.value }); + this.props.onChange(event); + } + + authorChange(e) { + let type = e.target.dataset['nametype']; + let authNumber: number = parseInt(e.target.dataset['authornum']); + let newAuthorList = [...this.props.manualData.authors]; + newAuthorList[authNumber][type] = e.target.value; + let event = new CustomEvent('AUTHOR_DATA_CHANGE', {detail: newAuthorList}) + this.props.onChange(event); + + } + + addAuthor(e) { + let event = new CustomEvent('ADD_AUTHOR'); + this.props.onChange(event); + } + + removeAuthor(e) { + let authornum = e.target.dataset['authornum']; + let event = new CustomEvent('REMOVE_AUTHOR', { detail: authornum }); + this.props.onChange(event); + } + + handleMetaChange(e) { + let newMeta = Object.assign({}, this.props.manualData.meta); + newMeta[this.props.manualData.type][e.target.dataset['metakey']] = e.target.value; + let event = new CustomEvent('META_CHANGE', { detail: newMeta }); + this.props.onChange(event); + } + + render() { + return( +
+ + + +
+ ) + } + +} + +const ManualSelection = ({ + value, + onChange, +}) => { + const commonStyle = { padding: '5px' }; + return( +
+
+ +
+
+ +
+
+ ) +} + +const Authors = ({ + authorList, + removeAuthor, + onChange, + addAuthor, + type, +}) => { + const inputStyle = { + flex: 1, + padding: '0 5px', + }; + const commonStyle = { + padding: '0 5px' + } + return( +
+
+ Author Name(s) +
+ {authorList.map((author: Author, i: number) => +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ )} +
+ +
+
+ ) +} + + +const MetaFields = ({type, meta, onChange,} : +{ + type: string + meta: ManualMeta + onChange: Function +}) => { + + const outerFlex = { + display: 'flex', + flexDirection: 'column', + } + + const innerFlex = { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + } + + let displayMeta: Object[] = []; + let title: string = type[0].toUpperCase() + type.substring(1, type.length); + + switch(type) { + case 'journal': + displayMeta = [ + { meta: meta.journal.title, key: 'title', label: 'Title', required: true }, + { meta: meta.journal.source, key: 'source', label: 'Journal Name', required: true }, + { meta: meta.journal.pubdate, key: 'pubdate', label: 'Year Published', pattern: '[1-2][0-9]{3}', required: true }, + { meta: meta.journal.volume, key: 'volume', label: 'Volume', pattern: '[0-9]{1,5}', required: false }, + { meta: meta.journal.issue, key: 'issue', label: 'Issue', pattern: '^[0-9]{1,4}', required: false }, + { meta: meta.journal.pages, key: 'pages', label: 'Pages', pattern: '^([0-9]{1,4}(?:-[0-9]{1,4}$)?)', required: true } + ]; + break; + case 'website': + displayMeta = [ + { meta: meta.website.title, key: 'title', label: 'Content Title', required: true }, + { meta: meta.website.source, key: 'source', label: 'Website Title', required: true }, + { meta: meta.website.pubdate, key: 'pubdate', label: 'Published Date', placeholder: 'MM/DD/YYYY', pattern: '[0-1][0-9][-/][0-3][0-9][-/][1-2][0-9]{3}', required: true }, + { meta: meta.website.url, key: 'url', label: 'URL', required: true }, + { meta: meta.website.updated, key: 'updated', label: 'Updated Date', placeholder: 'MM/DD/YYYY', pattern: '[0-1][0-9][-/][0-3][0-9][-/][1-2][0-9]{3}', required: false }, + { meta: meta.website.accessed, key: 'accessed', label: 'Accessed Date', placeholder: 'MM/DD/YYYY', pattern: '[0-1][0-9][-/][0-3][0-9][-/][1-2][0-9]{3}', required: false }, + ]; + break; + case 'book': + displayMeta = [ + { meta: meta.book.title, key: 'title', label: 'Book Title', required: true }, + { meta: meta.book.source, key: 'source', label: 'Publisher', required: true }, + { meta: meta.book.pubdate, key: 'pubdate', label: 'Copyright Year', pattern: '[1-2][0-9]{3}', required: true }, + { meta: meta.book.chapter, key: 'chapter', label: 'Chapter/Section', required: false }, + { meta: meta.book.edition, key: 'edition', label: 'Edition', required: false }, + { meta: meta.book.location, key: 'location', label: 'Publisher Location', required: false }, + { meta: meta.book.pages, key: 'pages', label: 'Pages', pattern: '^([0-9]{1,4}(?:-[0-9]{1,4}$)?)', required: false }, + ]; + break; + } + + return( +
+
+ {title} Information +
+
+ {displayMeta.map((item, i: number) => +
+
+ +
+
+ +
+
+ )} +
+
+ ) +} + + + +ReactDOM.render( + , + document.getElementById('main-container') +) diff --git a/inc/js/frontend.ts b/inc/js/frontend.ts index b4eb6db0..8a8c71ca 100644 --- a/inc/js/frontend.ts +++ b/inc/js/frontend.ts @@ -2,28 +2,29 @@ declare var DocumentTouch; -module ABT_Frontend { +namespace ABT_Frontend { export class Accordion { - private _headings: NodeList; + private _headings: NodeListOf; constructor() { - this._headings = document.querySelectorAll('#abt_PR_boxes > h3'); + this._headings = (document.getElementsByClassName('abt_PR_heading') as NodeListOf); - for (let heading of (this._headings)) { - let reviewContent: HTMLElement = heading.nextSibling; - reviewContent.style.display = 'none'; + for (let i = 0; i < this._headings.length; i++) { + let currentHeading = this._headings[i]; + let reviewContent = (currentHeading.nextElementSibling as HTMLDivElement); - heading.addEventListener('click', this._clickHandler); + reviewContent.style.display = 'none'; + currentHeading.addEventListener('click', this._clickHandler); } } private _clickHandler(e: Event): void { - let targetContent = e.srcElement.nextSibling; + let targetContent = (e.srcElement.nextSibling as HTMLDivElement); // If targetContent already visible, hide it and exit if (targetContent.style.display != 'none') { @@ -31,16 +32,20 @@ module ABT_Frontend { return; } - let accordionNodes = e.srcElement.parentElement.childNodes; - let element: HTMLElement; + let accordionChildren = e.srcElement.parentElement.children; + + for (let i = 0; i < accordionChildren.length; i++) { + + let currentElement = accordionChildren[i] as HTMLElement; - for (element of accordionNodes) { - if (element.tagName != 'DIV') { continue; } - if (element.previousSibling === e.srcElement) { - element.style.display = ''; + if (currentElement.tagName != 'DIV') { continue; } + + if (currentElement.previousSibling === e.srcElement) { + currentElement.style.display = ''; continue; } - element.style.display = 'none'; + + currentElement.style.display = 'none'; } } @@ -53,13 +58,12 @@ module ABT_Frontend { public static timer: number; constructor() { - let referenceList: HTMLOListElement = this._getReferenceList(); - let citationList: NodeListOf = document.querySelectorAll('span.cite'); - let citation: HTMLSpanElement; + let referenceList = (document.getElementById('abt-smart-bib') as HTMLOListElement); + let citationList = document.getElementsByClassName('abt_cite') - for (citation of citationList) { + for (let i = 0; i < citationList.length; i++) { - let citeNums: number[] = JSON.parse(citation.dataset['reflist']); + let citeNums: number[] = JSON.parse((citationList[i] as HTMLSpanElement).dataset['reflist']); let citationHTML = citeNums.map((citeNum: number): string => { // Correct for zero-based index citeNum--; @@ -78,14 +82,14 @@ module ABT_Frontend { }); // Save CSV string of citenums as data attr 'citations' - citation.dataset['citations'] = citationHTML.join(''); + (citationList[i] as HTMLSpanElement).dataset['citations'] = citationHTML.join(''); // Conditionally create tooltip based on device if (this._isTouchDevice()) { - citation.addEventListener('touchstart', this._createTooltip.bind(this)); + citationList[i].addEventListener('touchstart', this._createTooltip.bind(this)); } else { - citation.addEventListener('mouseover', this._createTooltip.bind(this)); - citation.addEventListener('mouseout', this._destroyTooltip); + citationList[i].addEventListener('mouseover', this._createTooltip.bind(this)); + citationList[i].addEventListener('mouseout', this._destroyTooltip); } } @@ -93,23 +97,13 @@ module ABT_Frontend { } - private _getReferenceList(): HTMLOListElement { - let orderedLists: NodeListOf = document.getElementsByTagName('ol'); - for (let i = (orderedLists.length - 1); i >= 0; i--){ - if (orderedLists[i].parentElement.className !== 'abt_chat_bubble') { - return orderedLists[i]; - } - } - } - - private _isTouchDevice(): boolean { return true == ("ontouchstart" in window || (window).DocumentTouch && document instanceof DocumentTouch); } private _createTooltip(e: Event): void { - + e.preventDefault(); clearTimeout(Citations.timer); let preExistingTooltip: HTMLElement = document.getElementById('abt_tooltip'); @@ -132,6 +126,7 @@ module ABT_Frontend { let closeButton: HTMLDivElement = document.createElement('div'); let touchContainer: HTMLDivElement = document.createElement('div'); + touchContainer.className = 'abt_tooltip_touch_close-container'; closeButton.className = 'abt_tooltip_touch_close'; touchContainer.addEventListener('touchend', () => tooltip.remove()); @@ -139,9 +134,9 @@ module ABT_Frontend { tooltip.style.left = '0'; tooltip.style.right = '0'; tooltip.style.maxWidth = '90%' + touchContainer.appendChild(closeButton); tooltip.appendChild(touchContainer); - // tooltip.appendChild(closeButton); document.body.appendChild(tooltip); tooltip.appendChild(tooltipArrow); @@ -162,13 +157,14 @@ module ABT_Frontend { // Set tooltip above or below based on window position + set arrow position if ((rect.top - tooltip.offsetHeight) < 0) { + // On bottom - Upwards arrow tooltip.style.top = (rect.bottom + window.scrollY + 5) + 'px'; - tooltipArrow.style.top = '-15px'; - tooltipArrow.style.borderColor = 'transparent transparent #fff'; + tooltip.style.animation = 'fadeInUp .2s'; + tooltipArrow.classList.add('abt_arrow_up'); } else { + // On top - Downwards arrow tooltip.style.top = (rect.top + window.scrollY - tooltip.offsetHeight - 5) + 'px'; - tooltipArrow.style.bottom = '-15px'; - tooltipArrow.style.borderColor = '#fff transparent transparent'; + tooltipArrow.classList.add('abt_arrow_down'); } tooltip.style.visibility = ''; @@ -196,7 +192,7 @@ if (document.readyState != 'loading'){ function frontendJS() { - new ABT_Frontend.Citations(); - new ABT_Frontend.Accordion(); + new ABT_Frontend.Citations; + new ABT_Frontend.Accordion; } diff --git a/inc/js/metaboxes.ts b/inc/js/metaboxes.ts index 7692eff5..f1d15edc 100644 --- a/inc/js/metaboxes.ts +++ b/inc/js/metaboxes.ts @@ -1,4 +1,4 @@ -declare var wp; +declare var wp, ABT_locationInfo; class PeerReviewMetabox { @@ -69,9 +69,7 @@ class PeerReviewMetabox { el.style.display = 'none'; } - if (!e) { return; } - - let selectBox = e.srcElement as HTMLSelectElement + let selectBox = document.getElementById('reviewer_selector') as HTMLSelectElement switch (selectBox.value) { case '3': this.containers.reviews[2].style.display = ''; @@ -136,7 +134,9 @@ class PeerReviewMetabox { } if (document.readyState != 'loading'){ - new PeerReviewMetabox + if (ABT_locationInfo.postType !== 'page') { new PeerReviewMetabox; } } else { - document.addEventListener('DOMContentLoaded', () => new PeerReviewMetabox); + document.addEventListener('DOMContentLoaded', () => { + if (ABT_locationInfo.postType !== 'page') { new PeerReviewMetabox } + }); } diff --git a/inc/js/tinymce-entrypoint.ts b/inc/js/tinymce-entrypoint.ts index 7c6ed288..3c24cf0f 100644 --- a/inc/js/tinymce-entrypoint.ts +++ b/inc/js/tinymce-entrypoint.ts @@ -10,11 +10,12 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { // MAIN BUTTON //================================================== - let ABT_Button: TinyMCEPluginButton = { + let ABT_Button: any = { + id: 'abt_menubutton', type: 'menubutton', - image: url + '/../images/book.png', + icon: 'abt_menu dashicons-welcome-learn-more', title: 'Academic Blogger\'s Toolkit', - icon: true, + // icon: true, menu: [], }; @@ -25,7 +26,7 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { let openInlineCitationWindow = () => { editor.windowManager.open({ title: 'Inline Citation', - url: ABT_locationInfo.tinymceViewsURL + 'inline-citation/inline-citation.html', + url: ABT_locationInfo.tinymceViewsURL + 'inline-citation.html', width: 400, height: 85, onClose: (e) => { @@ -40,11 +41,12 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { let openFormattedReferenceWindow = () => { editor.windowManager.open({ title: 'Insert Formatted Reference', - url: ABT_locationInfo.tinymceViewsURL + 'formatted-reference/formatted-reference.html', + url: ABT_locationInfo.tinymceViewsURL + 'reference-window.html', width: 600, - height: 100, + height: 10, params: { baseUrl: ABT_locationInfo.tinymceViewsURL, + preferredStyle: ABT_locationInfo.preferredCitationStyle, }, onclose: (e: any) => { @@ -52,17 +54,17 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { if (Object.keys(e.target.params).length === 0) { return; } + editor.setProgressState(1); let payload: ReferenceFormData = e.target.params.data; let refparser = new Dispatcher(payload, editor); - if (payload.hasOwnProperty('manual-type-selection')) { + if (payload.addManually === true) { refparser.fromManualInput(payload); - editor.setProgressState(0); + // editor.setProgressState(0); return; } - // do pmid parsing refparser.fromPMID(); }, @@ -126,15 +128,15 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { } + /** NOTE: THIS WILL BE DEPRECIATED NEXT RELEASE! */ let trackedLink: TinyMCEMenuItem = { text: 'Tracked Link', onclick: () => { let user_selection = tinyMCE.activeEditor.selection.getContent({format: 'text'}); - /** TODO: Fix this so it doesn't suck */ editor.windowManager.open({ - title: 'Insert Tracked Link', + title: 'Insert Tracked Link === Depreciating Next Release! ===', width: 600, height: 160, buttons: [{ @@ -203,6 +205,20 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { } } + + let keyboardShortcuts: TinyMCEMenuItem = { + text: 'Keyboard Shortcuts', + onclick: () => { + editor.windowManager.open({ + title: 'Keyboard Shortcuts', + url: ABT_locationInfo.tinymceViewsURL + 'keyboard-shortcuts.html', + width: 400, + height: 90, + }); + } + } + + // Workaround for checking to see if a smart bib exists. setTimeout(() => { let dom: HTMLDocument = editor.dom.doc; let existingSmartBib: HTMLOListElement = dom.getElementById('abt-smart-bib'); @@ -213,7 +229,7 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { }, 500); bibToolsMenu.menu.push(trackedLink, separator, requestTools); - ABT_Button.menu.push(smartBib, inlineCitation, formattedReference, bibToolsMenu); + ABT_Button.menu.push(smartBib, inlineCitation, formattedReference, bibToolsMenu, separator, keyboardShortcuts); editor.addButton('abt_main_menu', ABT_Button); diff --git a/inc/js/tinymce-views/formatted-reference/formatted-reference.html b/inc/js/tinymce-views/formatted-reference/formatted-reference.html deleted file mode 100644 index b5ad2f56..00000000 --- a/inc/js/tinymce-views/formatted-reference/formatted-reference.html +++ /dev/null @@ -1,203 +0,0 @@ - -
-
-
-
-
- -
-
-
-
- -
-
- -
-
-
- - - -
-
-
- -
-
- -
- - -
-
-
- - - - -
-
-
- diff --git a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts b/inc/js/tinymce-views/formatted-reference/formatted-reference.ts deleted file mode 100644 index 1c284490..00000000 --- a/inc/js/tinymce-views/formatted-reference/formatted-reference.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { showHide } from '../../utils/HelperFunctions.ts'; -import Modal from '../../components/Modal.ts'; - -class ReferenceWindow { - - private modal: Modal = new Modal('Insert Formatted Reference'); - - public buttons = { - toggleAddManually: document.getElementById('add-manually'), - addAuthor: document.getElementById('add-author'), - searchPubmed: document.getElementById('search-pubmed'), - } - - public containers = { - mainContainer: document.getElementById('main-container'), - pubmedContainer: document.getElementById('pubmed-container'), - manualContainer: document.getElementById('manual-container'), - attachInline: document.getElementById('attach-inline-container'), - } - - public form: HTMLFormElement = document.getElementById('main-form'); - - public tables = { - authorTable: document.getElementById('author-table'), - } - - public inputs = { - pmidInput: document.getElementById('pmid-input'), - includeLink: document.getElementById('include-link'), - attachInline: document.getElementById('attach-inline'), - } - - public manualComponents = { - journal: document.getElementById('manual-journal'), - website: document.getElementById('manual-website'), - book: document.getElementById('manual-book'), - } - - public selections = { - manualCitationType: document.getElementById('manual-type-selection'), - } - - constructor() { - - this.modal.resize(); - this._addAuthorRow(); - - let existingSmartBib = top.tinyMCE.activeEditor.dom.doc.getElementById('abt-smart-bib'); - if (existingSmartBib !== null) { - this.containers.attachInline.style.display = 'flex'; - } - - this.buttons.toggleAddManually.addEventListener('click', this._toggleAddManually.bind(this)); - this.buttons.addAuthor.addEventListener('click', this._addAuthorRow.bind(this)); - this.selections.manualCitationType.addEventListener('change', this._manualCitationChange.bind(this)); - this.form.addEventListener('submit', this._submitForm.bind(this)); - this.buttons.searchPubmed.addEventListener('click', () => { - let wm = top.tinyMCE.activeEditor.windowManager; - wm.open({ - title: 'Search PubMed for Reference', - url: wm.windows[0].settings.params.baseUrl + 'pubmed-window/pubmed-window.html', - width: 600, - height: 100, - onsubmit: (e: any) => { - if (this.inputs.pmidInput.value === '') { - this.inputs.pmidInput.value = (e.target as any).data.pmid; - return; - } - let combinedInput = this.inputs.pmidInput.value.split(','); - combinedInput.push((e.target as any).data.pmid) - this.inputs.pmidInput.value = combinedInput.join(','); - }, - } - ); - }); - } - - private _manualCitationChange(e: Event): void { - let selection = this.selections.manualCitationType.value; - for (let key in this.manualComponents) { - if (key == selection || key == '') { continue; } - showHide(this.manualComponents[key], 'hide'); - } - if (selection !== '' ) { - showHide(this.manualComponents[selection], 'show'); - } - this._adjustRequiredFields(selection); - this.modal.resize(); - } - - private _toggleAddManually(): void { - showHide(this.containers.pubmedContainer); - showHide(this.containers.manualContainer); - - this.inputs.pmidInput.disabled = !this.inputs.pmidInput.disabled; - this.inputs.includeLink.disabled = !this.inputs.includeLink.disabled; - this.selections.manualCitationType.disabled = !this.selections.manualCitationType.disabled; - - // Make all fields not required - if (this.selections.manualCitationType.disabled === true) { - this._adjustRequiredFields('REQUIRE NONE'); - } else { - this._adjustRequiredFields(this.selections.manualCitationType.value); - } - - this.buttons.toggleAddManually.value = - this.buttons.toggleAddManually.value === 'Add Reference Manually' - ? 'Add Reference with PMID' - : 'Add Reference Manually'; - - this.modal.resize(); - } - - private _adjustRequiredFields(selection: string): void { - - for (let key in this.manualComponents) { - - let fields = document.querySelectorAll(`input[id^=${key}-][data-required]`); - let required: boolean = key === selection ? true : false; - - for (let i = 0; i < fields.length; i++) { - (document.getElementById(fields[i].id) as HTMLInputElement).required = required; - } - - } - - } - - private _addAuthorRow(): void { - let newRow = this.tables.authorTable.insertRow(); - newRow.insertCell().appendChild( - document.createTextNode('First Name') - ); - - let rowNum: number = this.tables.authorTable.rows.length; - - let firstNameInput = document.createElement('input'); - firstNameInput.type = 'text'; - firstNameInput.id = `author-fname-${rowNum}`; - newRow.insertCell().appendChild(firstNameInput); - - newRow.insertCell().appendChild( - document.createTextNode('Last Name') - ); - - let lastNameInput = document.createElement('input'); - lastNameInput.type = 'text'; - lastNameInput.id = `author-lname-${rowNum}`; - newRow.insertCell().appendChild(lastNameInput); - - let removeRowButton = document.createElement('input'); - removeRowButton.type = 'button'; - removeRowButton.className = 'btn'; - removeRowButton.value = 'x'; - removeRowButton.addEventListener('click', (e: Event) => { - let row = e.srcElement.parentElement.parentElement; - row.remove(); - this.modal.resize(); - }); - newRow.insertCell().appendChild(removeRowButton); - - this.modal.resize(); - - } - - private _submitForm(e: Event) { - e.preventDefault(); - - let wm = top.tinyMCE.activeEditor.windowManager; - let formElement: HTMLFormElement = e.srcElement; - let payload: Object = {}; - let authorList: Object = {}; - - for (let i = 0; i < formElement.length; i++) { - let el = formElement[i]; - if(el.type == 'button' - || el.type == 'submit' - || el.value == '' - || el.disabled ) { continue; } - - if (el.type == 'checkbox') { - payload[el.id] = el.checked; - continue; - } - - if (el.id.search(/^author-fname/) > -1 || el.id.search(/^author-lname/) > -1) { - let capitalizedName = el.value[0].toUpperCase() + el.value.substr(1).toLowerCase(); - authorList[el.id] = capitalizedName; - continue; - } - - payload[el.id] = el.value; - } - - // Prepare author data - payload['authors'] = []; - for (let i = 0; i < (Object.keys(authorList).length / 2); i++) { - let author = { - name: authorList[`author-fname-${i + 1}`] + ' ' + authorList[`author-lname-${i + 1}`] - } - payload['authors'].push(author); - } - - wm.setParams({data: payload}); - wm.close(); - - } - -} - -new ReferenceWindow; diff --git a/inc/js/tinymce-views/inline-citation/inline-citation.html b/inc/js/tinymce-views/inline-citation.html similarity index 88% rename from inc/js/tinymce-views/inline-citation/inline-citation.html rename to inc/js/tinymce-views/inline-citation.html index e706a9cc..7d22cb65 100644 --- a/inc/js/tinymce-views/inline-citation/inline-citation.html +++ b/inc/js/tinymce-views/inline-citation.html @@ -1,4 +1,4 @@ - +

@@ -20,7 +20,7 @@
- + diff --git a/inc/js/tinymce-views/pubmed-window/pubmed-window.html b/inc/js/tinymce-views/pubmed-window/pubmed-window.html deleted file mode 100644 index fdf21d82..00000000 --- a/inc/js/tinymce-views/pubmed-window/pubmed-window.html +++ /dev/null @@ -1,3 +0,0 @@ - -
- diff --git a/inc/js/tinymce-views/reference-window.html b/inc/js/tinymce-views/reference-window.html new file mode 100644 index 00000000..22534339 --- /dev/null +++ b/inc/js/tinymce-views/reference-window.html @@ -0,0 +1,3 @@ + +
+ diff --git a/inc/js/tinymce-views/tinymce-views.scss b/inc/js/tinymce-views/styles.scss similarity index 92% rename from inc/js/tinymce-views/tinymce-views.scss rename to inc/js/tinymce-views/styles.scss index 1cc40189..4bf59426 100644 --- a/inc/js/tinymce-views/tinymce-views.scss +++ b/inc/js/tinymce-views/styles.scss @@ -120,6 +120,7 @@ input, select { &:invalid { background: #f6c9cc; color: #dc3232; + border: solid #E58383 1px; } } @@ -138,3 +139,13 @@ a { color: #00a0d2; } } + +kbd { + font-family: monospace; + padding: 2px 7px 3px; + font-weight: 400; + margin: 0; + font-size: 15px; + background: #eaeaea; + background: rgba(0,0,0,.08) +} diff --git a/inc/js/utils/Dispatcher.ts b/inc/js/utils/Dispatcher.ts index 94db34d5..34153bac 100644 --- a/inc/js/utils/Dispatcher.ts +++ b/inc/js/utils/Dispatcher.ts @@ -1,5 +1,5 @@ import { AMA, APA } from './Parsers.ts'; - +import './HelperFunctions.ts'; export default class Dispatcher { public citationFormat: string; @@ -11,13 +11,13 @@ export default class Dispatcher { public smartBib: HTMLOListElement|boolean constructor(data: ReferenceFormData, editor: Object) { - this.citationFormat = data['citation-format']; - this.PMIDquery = data['pmid-input'] !== '' && data['pmid-input'] !== undefined - ? data['pmid-input'].replace(/\s/g, '') + this.citationFormat = data.citationFormat; + this.PMIDquery = data.pmidList !== '' + ? data.pmidList.replace(/\s/g, '') : ''; - this.manualCitationType = data['manual-type-selection']; - this.includeLink = data['include-link']; - this.attachInline = data['attach-inline'] + this.manualCitationType = data.manualData.type; + this.includeLink = data.includeLink; + this.attachInline = data.attachInline; this.editor = editor; let smartBib = (this.editor.dom.doc as HTMLDocument) .getElementById('abt-smart-bib') as HTMLOListElement; @@ -36,29 +36,51 @@ export default class Dispatcher { let cleanedData: ReferenceObj; let type = this.manualCitationType; - // Reformat name to Last Name, First Initial - let authors: Author[] = data.authors.map((author: Author) => { - let name = - `${author.name.split(' ')[1]} ${author.name.split(' ')[0][0]}`; - return {name}; - }) - - let title: string = data[`${type}-title`].toTitleCase(); - let source: string = data[`${type}-source`]; - let pubdate: string = data[`${type}-date`] || ''; - let volume: string = data[`${type}-volume`] || ''; - let issue: string = data[`${type}-issue`] || ''; - let pages: string = data[`${type}-pages`] || ''; - let lastauthor: string = data.authors.length > 0 - ? data.authors[data.authors.length - 1].name + // Reformat name to + let authors: Author[] = data.manualData.authors.map((author: any) => { + let name = this._prepareName(author); + return { name }; + }); + + let meta: JournalMeta|BookMeta|WebsiteMeta = data.manualData.meta[type]; + + let title: string = meta.title.toTitleCase(); + let source: string = meta.source; + let pubdate: string = meta.pubdate; + let lastauthor: string = data.manualData.authors.length > 0 + ? this._prepareName(data.manualData.authors[data.manualData.authors.length - 1]) : ''; - let url: string = data[`${type}-url`] || ''; - let accessdate: string = data[`${type}-accessed`] || ''; - let updated: string = data[`${type}-updated`] || ''; - let location: string = data[`${type}-location`] || ''; - let chapter: string = data[`${type}-chapter`] || ''; - let edition: string = data[`${type}-edition`] || ''; + let volume: string; + let issue: string; + let pages: string; + + let url: string; + let accessdate: string; + let updated: string; + + let location: string; + let chapter: string; + let edition: string; + + switch (type) { + case 'journal': + volume = (meta as JournalMeta).volume; + issue = (meta as JournalMeta).issue; + pages = (meta as JournalMeta).pages; + break; + case 'website': + url = (meta as WebsiteMeta).url; + accessdate = (meta as WebsiteMeta).accessed; + updated = (meta as WebsiteMeta).updated; + break; + case 'book': + pages = (meta as BookMeta).pages; + location = (meta as BookMeta).location; + chapter = (meta as BookMeta).chapter; + edition = (meta as BookMeta).edition; + break; + } cleanedData = { authors, @@ -97,6 +119,13 @@ export default class Dispatcher { } + private _prepareName(author: Author): string { + return( author.lastname[0].toUpperCase() + + author.lastname.substring(1, author.lastname.length) + ' ' + + author.firstname[0].toUpperCase() + author.middleinitial.toUpperCase() + ) + } + private _parsePMID(e: Event): void { let req = e.target; @@ -147,7 +176,7 @@ export default class Dispatcher { } if (this.smartBib) { - let beforeLength: number = (this.smartBib as HTMLOListElement).children.length; + let beforeLength: number = (this.smartBib as HTMLOListElement).children.length + 1; for (let key in (payload as string[])) { let listItem = (this.editor.dom.doc as HTMLDocument).createElement('LI'); listItem.innerHTML = payload[key]; @@ -155,7 +184,7 @@ export default class Dispatcher { } if (this.attachInline) { let afterLength: number = (this.smartBib as HTMLOListElement).children.length; - this.editor.insertContent(`[cite num="${beforeLength + 1}-${afterLength}"]`); + this.editor.insertContent(`[cite num="${beforeLength}${afterLength > beforeLength ? '-' + afterLength : ''}"]`); } this.editor.setProgressState(0); return; diff --git a/inc/js/utils/HelperFunctions-bak.ts b/inc/js/utils/HelperFunctions-bak.ts deleted file mode 100644 index 9c8795bd..00000000 --- a/inc/js/utils/HelperFunctions-bak.ts +++ /dev/null @@ -1,43 +0,0 @@ -export default {}; - -declare global { - interface String { - toTitleCase(): string - } - interface HTMLElement { - showHide(option?: 'show'|'hide'): string - } -} - -String.prototype.toTitleCase = function(): string { - let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; - - return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ - if (index > 0 && index + match.length !== title.length && - match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && - (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && - title.charAt(index - 1).search(/[^\s-]/) < 0) { - return match.toLowerCase(); - } - - if (match.substr(1).search(/[A-Z]|\../) > -1) { - return match; - } - - return match.charAt(0).toUpperCase() + match.substr(1); - }); -}; - -HTMLElement.prototype.showHide = function(option?: 'show' | 'hide'): string { - switch(option) { - case 'show': - this.style.display = ''; - break; - case 'hide': - this.style.display = 'none'; - break; - default: - this.style.display = this.style.display == 'none' ? '' : 'none'; - } - return this.style.display; -} diff --git a/inc/js/utils/HelperFunctions.ts b/inc/js/utils/HelperFunctions.ts index faa86484..6a780374 100644 --- a/inc/js/utils/HelperFunctions.ts +++ b/inc/js/utils/HelperFunctions.ts @@ -1,7 +1,15 @@ -export function toTitleCase(s: string): string { +export default {}; + +declare global { + interface String { + toTitleCase(): string + } +} + +String.prototype.toTitleCase = function(): string { let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; - return s.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ + return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ if (index > 0 && index + match.length !== title.length && match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && @@ -16,17 +24,3 @@ export function toTitleCase(s: string): string { return match.charAt(0).toUpperCase() + match.substr(1); }); }; - -export function showHide(el: HTMLElement, option?: 'show' | 'hide'): string { - switch(option) { - case 'show': - el.style.display = ''; - break; - case 'hide': - el.style.display = 'none'; - break; - default: - el.style.display = el.style.display == 'none' ? '' : 'none'; - } - return el.style.display; -} diff --git a/inc/js/components/Modal.ts b/inc/js/utils/Modal.ts similarity index 100% rename from inc/js/components/Modal.ts rename to inc/js/utils/Modal.ts diff --git a/inc/js/utils/Parsers.ts b/inc/js/utils/Parsers.ts index 6821078f..ed93e1bc 100644 --- a/inc/js/utils/Parsers.ts +++ b/inc/js/utils/Parsers.ts @@ -1,4 +1,3 @@ -import { toTitleCase } from './HelperFunctions.ts'; export class AMA { @@ -12,14 +11,16 @@ export class AMA { } public parse(data: ReferencePayload): string[]|Error { - let pmidArray: string[]|boolean = data.uids || false; - if (pmidArray) { - this._isManual = false; - return this._fromPMID(data, (pmidArray as string[])); + if (data.uids) { + this._isManual = false } - return [this._fromManual(data)]; + if (this._isManual) { + return [this._fromManual(data)]; + } + + return this._fromPMID(data, data.uids); } private _fromPMID(data: ReferencePayload, pmidArray: string[]): string[]|Error { @@ -90,7 +91,7 @@ export class AMA { private _parseJournal(data: ReferencePayload): string { let authors = this._parseAuthors(data[0].authors); let year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); - let source = toTitleCase(data[0].source); + let source = data[0].source.toTitleCase(); let issue = `(${data[0].issue})` || ''; let volume = data[0].volume || ''; @@ -175,7 +176,7 @@ export class APA { } return `${authors} (${year}). ${ref.title} ` + - `${ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : toTitleCase(ref.fulljournalname)}., ` + + `${ref.fulljournalname === undefined || ref.fulljournalname === '' ? ref.source : ref.fulljournalname.toTitleCase()}., ` + `${ref.volume === undefined || ref.volume === '' ? '' : ref.volume}` + `${ref.issue === undefined || ref.issue === '' ? '' : '('+ref.issue+')'}, ` + `${ref.pages}.${link}`; @@ -261,7 +262,7 @@ export class APA { private _parseJournal(data: ReferencePayload): string { let authors = this._parseAuthors(data[0].authors, data[0].lastauthor); let year = (new Date(data[0].pubdate).getFullYear() + 1).toString(); - let source = toTitleCase(data[0].source); + let source = data[0].source.toTitleCase(); let issue = `(${data[0].issue})` || ''; let volume = data[0].volume || ''; @@ -272,7 +273,7 @@ export class APA { private _parseWebsite(data: ReferencePayload): string { let authors = this._parseAuthors(data[0].authors, data[0].lastauthor); let rawDate = new Date(data[0].pubdate); - let source = toTitleCase(data[0].source); + let source = data[0].source.toTitleCase(); let date = `${rawDate.getFullYear()}, ` + `${rawDate.toLocaleDateString('en-us', {month: 'long', day: 'numeric'})}`; diff --git a/inc/js/utils/PubmedAPI.ts b/inc/js/utils/PubmedAPI.ts index a95068d8..2ae99f3e 100644 --- a/inc/js/utils/PubmedAPI.ts +++ b/inc/js/utils/PubmedAPI.ts @@ -9,7 +9,8 @@ export function PubmedQuery(query: string, callback: Function): void { // Handle bad request if (request.readyState !== 4 || request.status !== 200) { - console.log('Error'); + let error = new Error('Error: PubMed Query, Phase 1 - PubMed returned a non-200 status code.'); + callback(error); return; } @@ -17,7 +18,9 @@ export function PubmedQuery(query: string, callback: Function): void { // Handle response errors if (res.error) { - console.log('error') + let error = new Error('Error: PubMed Query, Phase 1 - Unknown response error.'); + callback(error); + return; } getData(res.esearchresult.idlist.join(), callback); @@ -35,7 +38,8 @@ function getData(PMIDlist: string, callback: Function): void { // Handle bad request if (request.readyState !== 4 || request.status !== 200) { - console.log('Error'); + let error = new Error('Error: PubMed Query, Phase 2 - PubMed returned a non-200 status code.'); + callback(error); return; } @@ -43,7 +47,9 @@ function getData(PMIDlist: string, callback: Function): void { // Handle response errors if (res.error) { - console.log('error') + let error = new Error('Error: PubMed Query, Phase 2 - Unknown response error.'); + callback(error); + return; } diff --git a/inc/options-page-wrapper.php b/inc/options-page-wrapper.php index 65211426..9134ce10 100644 --- a/inc/options-page-wrapper.php +++ b/inc/options-page-wrapper.php @@ -1,22 +1,12 @@
-

- +

-
- -
-
- - -
- -

- +

@@ -29,63 +19,71 @@ - + - + - + - +
Classes / IDs used in this plugin:CSS classes used in this plugin:
Inline Citations:.cite.abt_cite
Peer Review Boxes:#abt_PR_boxes h3, .abt_PR_info, .abt_PR_headshot, .abt_chat_bubble.abt_PR_heading, .abt_PR_info, .abt_PR_headshot, .abt_chat_bubble
Citation Tooltips:.abt_tooltip, .abt_tooltip_arrow.abt_tooltip, .abt_tooltip_arrow, .abt_tooltip_touch_close
- - -
- - - - -
- -

- +

- - - - - - - - - +
+
+

Make my tooltips a different color?

+
.abt_tooltip { +   background-color: magenta; +   border: solid lime 2px; + } + .abt_arrow_up { +   border-color: transparent transparent magenta; + } + .abt_arrow_down { +   border-color: magenta transparent transparent; + } +
+
+
+

Make my citations superscript?

+
.abt_cite { +   vertical-align: super; +   font-size: 0.8em; + } +
+
+
+

Apply style to the bibliography list?

+
.abt-smart-bib { +   vertical-align: super; +   font-size: 0.8em; +   list-style-type: upper-roman; +   padding: 20px 40px; +   border: solid; +   border-radius: 3px; + } +
+
+
- -
- - - - -
- -

- +

@@ -149,52 +147,40 @@
- -
- - -
- -
- - - -
-
-
-

- + 'Please send your feedback!', 'wp_admin_style' + ); ?>

GitHub Repository and leave a comment. I'll do my best to get it handled in a timely manner.

Comments can also be sent to me on twitter @flightmed1.", - 'wp_admin_style' - ); ?>

+ "If you experience a bug or would like to request a new feature, please visit my GitHub Repository and leave a comment. I'll do my best to get it handled in a timely manner.

Comments can also be sent to me on twitter @flightmed1.", + 'wp_admin_style' + ); ?>

+
+
+
+
+
+

+
+
+ + + +
- -
- -
- -
- -
- -
- - -
+
diff --git a/inc/peer-review.php b/inc/peer-review.php index e4cb55cd..376a6da8 100644 --- a/inc/peer-review.php +++ b/inc/peer-review.php @@ -6,7 +6,6 @@ function abt_peer_review_meta() { add_action( 'add_meta_boxes', 'abt_peer_review_meta' ); - function abt_peer_review_callback( $post ) { wp_nonce_field( basename( __file__ ), 'abt_nonce' ); @@ -48,7 +47,6 @@ function abt_peer_review_callback( $post ) { - @@ -85,7 +83,7 @@ function abt_peer_review_callback( $post ) { - +
@@ -216,6 +214,28 @@ function abt_meta_save( $post_id ) { add_action( 'save_post', 'abt_meta_save' ); +function tag_ordered_list( $content ) { + + if ( is_single() || is_page() ) { + + $smart_bib_exists = preg_match('
    ', $content); + + if (!$smart_bib_exists) { + + $lastOLPosition = strrpos($content, '' . - '
    ' . - '' . ${'author_name_' . $i} . '
    ' . - ${'author_background_' . $i} . '
    ' . - ${'author_twitter_' . $i} . + '
    ' . + '
    ' . + ( + ${'author_headshot_image_' . $i} !== '' + ? '' + : '' + ) . + '
    ' . + '
    ' . + '' . ${'author_name_' . $i} . '' . + '
    ' . + '
    ' . + '
    ' . + ${'author_background_' . $i} . + '
    ' . + ${'author_twitter_' . $i} . + '
    ' . '
    '; } @@ -300,13 +333,26 @@ function insert_the_meta( $text ) { if ( ${'reviewer_name_' . $i} != '' ) { ${'reviewer_block_' . $i} = - '

    ' . ${'peer_review_box_heading_' . $i} . '

    ' . + '

    ' . ${'peer_review_box_heading_' . $i} . '

    ' . '
    ' . '
    ' . ${'peer_review_content_' . $i} . '
    ' . - '
    ' . - '' . ${'reviewer_name_' . $i} . '
    ' . - ${'reviewer_background_' . $i} . '
    ' . - ${'reviewer_twitter_' . $i} . + '
    ' . + '
    ' . + ( + ${'reviewer_headshot_image_' . $i} !== '' + ? '' + : '' + ) . + '
    ' . + '
    ' . + '' . ${'reviewer_name_' . $i} . '' . + '
    ' . + '
    ' . + '
    ' . + ${'reviewer_background_' . $i} . + '
    ' . + ${'reviewer_twitter_' . $i} . + '
    ' . '
    ' . ( isset(${'author_block_' . $i}) ? ${'author_block_' . $i} : '' ) . '
    '; @@ -352,18 +398,23 @@ function abt_peer_review_js_enqueue() { /** * Loads the image management javascript */ -function abt_image_enqueue() { - global $typenow; - if( $typenow == 'post' ) { - wp_enqueue_media(); +function abt_image_enqueue( $hook ) { + + global $typenow; + + if( $hook == 'post.php' ) { + + wp_enqueue_media(); + $abt_options = get_option( 'abt_options' ); // Registers and enqueues the required javascript. - wp_register_script( 'abt-metaboxes', plugins_url('academic-bloggers-toolkit/inc/js/metaboxes.js') ); + wp_enqueue_script( 'abt-metaboxes', plugins_url('academic-bloggers-toolkit/inc/js/metaboxes.js') ); wp_localize_script( 'abt-metaboxes', 'ABT_locationInfo', array( 'jsURL' => plugins_url('academic-bloggers-toolkit/inc/js/'), - 'tinymceViewsURL' => plugins_url('academic-bloggers-toolkit/inc/js/tinymce-views/') + 'tinymceViewsURL' => plugins_url('academic-bloggers-toolkit/inc/js/tinymce-views/'), + 'preferredCitationStyle' => $abt_options['abt_citation_style'], + 'postType' => $typenow, )); - wp_enqueue_script( 'abt-metaboxes' ); } } add_action( 'admin_enqueue_scripts', 'abt_image_enqueue' ); diff --git a/inc/shortcodes.php b/inc/shortcodes.php index 98588b21..7a9fd813 100644 --- a/inc/shortcodes.php +++ b/inc/shortcodes.php @@ -48,7 +48,7 @@ function inline_citation ( $atts ) { $nums = implode(', ', $nums); - return '[' . $nums . ']'; + return '[' . $nums . ']'; } add_shortcode( 'cite', 'inline_citation' ); diff --git a/inc/tinymce-init.php b/inc/tinymce-init.php index 84deb769..5b917539 100644 --- a/inc/tinymce-init.php +++ b/inc/tinymce-init.php @@ -1,36 +1,36 @@ diff --git a/package.json b/package.json index 5ddaa456..b15a4b83 100644 --- a/package.json +++ b/package.json @@ -19,20 +19,21 @@ }, "homepage": "https://github.com/dsifford/academic-bloggers-toolkit#readme", "devDependencies": { - "awesome-typescript-loader": "^0.17.0-rc.3", + "babel-core": "^6.7.4", + "babel-loader": "^6.2.4", + "babel-preset-es2015": "^6.6.0", "browser-sync": "^2.11.2", + "del": "^2.2.0", "gulp": "^3.9.1", "gulp-autoprefixer": "^3.1.0", "gulp-clean-css": "^2.0.4", "gulp-sass": "^2.2.0", "gulp-uglify": "^1.5.3", + "react": "^0.14.8", + "react-dom": "^0.14.8", "ts-loader": "^0.8.1", "typescript": "^1.8.9", "webpack": "^1.12.14", "webpack-stream": "^3.1.0" - }, - "dependencies": { - "react": "^0.14.8", - "react-dom": "^0.14.8" } } diff --git a/readme.txt b/readme.txt index 9d79bbd2..88a5c5d4 100644 --- a/readme.txt +++ b/readme.txt @@ -14,30 +14,15 @@ A WordPress plugin extending the functionality of WordPress for Academic Bloggin Academic Blogger's toolkit is an **open source** WordPress plugin providing an all-in-one solution for effective academic blogging. -= Automatically parse references on the fly using PMID = -- Option to add hyperlink to PubMed. - -= Inline citations with hover tooltips showing full reference = -- **Requirements**: - - A bibliography ordered list must be present **AND** the ordered list must be last one in your blog post. -- **How to use**: - - Select `Bibliography Tools -> inline citation` from the options menu located on the editor and insert a list of one or more citation numbers from your bibliography list in the form of `1-4,7,9`. - -= Append up to 3 formatted Peer Reviews to blog posts via a Frontend UI integrated on the post edit screen = -- Input areas for the Peer Review section include... - 1. Reviewer Name - 2. Reviewer Background (optional) - 3. Reviewer Twitter Handle (optional) - 4. Peer Review - 5. Reviewer Photo (interfaces with WordPress's Media Uploader) -- Option to add Author Response to Peer Reviews. - -= Integration with Google Tag Manager = -- Google's newest [analytics powerhouse](http://www.google.com/tagmanager/)! -- Track individual link clicks to see who is interacting with or downloading your content and much more! - -= Customizable Options = -* CSS override area to adjust the look of any content that doesn't fit your site's style. += Feature List = +* Insert formatted references on the fly using PMID. +* Search and insert references from PubMed directly within WordPress. +* **Smart Bibliography** - Insert references to a bibliography and append inline citations without breaking focus of your writing. +* References inserted using this plugin are displayed as tooltips on hover in the post. No need to scroll down to the reference list to check the reference (unless you want to!). +* Append up to 3 formatted Peer Reviews to blog posts via a Frontend UI integrated on the post edit screen. + += Want to learn more? = +Check out this plugin's [GitHub Repository](https://github.com/dsifford/academic-bloggers-toolkit) for more details or to ask questions. == Installation == @@ -64,10 +49,18 @@ Yikes! I'm sorry about that. Please report all issues on the Academic Blogger's == Changelog == = 2.4.0 = -* Full rewrite. * Parse multiple comma-separated PMIDs at once into an ordered list. -* Add manual reference insertion for Journals, Websites, or Books. -* Add "Smart Bibliography" (see github repo for full details). +* Option to add references manually for Journals, Websites, or Books. +* Search PubMed from WordPress! + * References from your search are displayed in a list similar to native PubMed and, if you find one you like, click it and it'll be inserted into your post. +* Add optional "Smart Bibliography" feature which, if enabled, allows you to... + * Insert references directly to your bibliography without having to scroll down. + * Insert references and inline citations in one step. + * Choose from a visual list of references in your bibliography if you do not choose to add citations in one step. +* If Smart Bibliography not used, the last-occurring ordered list is automatically tagged with the HTML ID `abt-smart-bib` on load to allow for more reliable tooltip rendering. +* Details for nerds: + * Full rewrite; a majority of which is using React by Facebook. + * Speed improvements & resource minification. = 2.3.1 = * Fix poor rendering of tooltip close icon on mobile. diff --git a/tsconfig.json b/tsconfig.json index e8121b3f..0e8b3e6d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "module": "commonjs", "moduleResolution": "node", "isolatedModules": false, @@ -34,20 +34,19 @@ }, "files": [ "inc/js/ABT.d.ts", - "inc/js/components/Modal.ts", + "inc/js/components/inline-citation.ts", "inc/js/frontend.ts", "inc/js/metaboxes.ts", "inc/js/tinymce-entrypoint.ts", - "inc/js/tinymce-views/formatted-reference/formatted-reference.ts", - "inc/js/tinymce-views/inline-citation/inline-citation.ts", "inc/js/utils/Dispatcher.ts", - "inc/js/utils/HelperFunctions-bak.ts", "inc/js/utils/HelperFunctions.ts", + "inc/js/utils/Modal.ts", "inc/js/utils/Parsers.ts", "inc/js/utils/PubmedAPI.ts", "typings/main.d.ts", "typings/react-dom/index.d.ts", "typings/react/index.d.ts", - "inc/js/tinymce-views/pubmed-window/pubmed-window.tsx" + "inc/js/components/pubmed-window.tsx", + "inc/js/components/referenceWindow.tsx" ] } diff --git a/webpack.config.js b/webpack.config.js index 314f2e7b..e2919227 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,10 +3,10 @@ module.exports = { entry: { 'inc/js/tinymce-entrypoint': './inc/js/tinymce-entrypoint.ts', 'inc/js/frontend': './inc/js/frontend.ts', - 'inc/js/tinymce-views/formatted-reference/formatted-reference': './inc/js/tinymce-views/formatted-reference/formatted-reference.ts', - 'inc/js/tinymce-views/inline-citation/inline-citation': './inc/js/tinymce-views/inline-citation/inline-citation.ts', + 'inc/js/components/referenceWindow': './inc/js/components/referenceWindow.tsx', + 'inc/js/components/inline-citation': './inc/js/components/inline-citation.ts', 'inc/js/metaboxes': './inc/js/metaboxes.ts', - 'inc/js/tinymce-views/pubmed-window/pubmed-window': './inc/js/tinymce-views/pubmed-window/pubmed-window.tsx', + 'inc/js/components/pubmed-window': './inc/js/components/pubmed-window.tsx', }, output: { filename: '[name].js', @@ -17,11 +17,11 @@ module.exports = { { test: /\.tsx?$/, exclude: /node_modules/, - loader: 'ts-loader', - } + loader: 'babel?presets[]=es2015!ts', + }, ], resolve: { - extensions: ['', '.ts', 'tsx', '.js'] - } - } -} + extensions: ['', '.ts', 'tsx', '.js'], + }, + }, +}; From 7776043fdb35f9b5ca9c828aefd3132552198be2 Mon Sep 17 00:00:00 2001 From: Derek P Sifford Date: Mon, 4 Apr 2016 18:23:08 -0400 Subject: [PATCH 18/18] Finish release 2.4.0 --- academic-bloggers-toolkit.php | 6 +- gulpfile.js | 54 +++--- inc/js/components/CitationWindow.tsx | 173 ++++++++++++++++++ .../{pubmed-window.tsx => PubmedWindow.tsx} | 4 +- ...eferenceWindow.tsx => ReferenceWindow.tsx} | 2 +- inc/js/components/inline-citation.ts | 35 ---- inc/js/tinymce-entrypoint.ts | 37 ++-- inc/js/tinymce-views/citation-window.html | 3 + inc/js/tinymce-views/inline-citation.html | 31 ---- inc/js/tinymce-views/pubmed-window.html | 2 +- inc/js/tinymce-views/reference-window.html | 2 +- inc/js/tinymce-views/styles.scss | 28 ++- inc/js/utils/Dispatcher.ts | 4 +- inc/js/utils/HelperFunctions.ts | 80 ++++++-- inc/js/utils/PrototypeFunctions.ts | 26 +++ jestPreprocessor.js | 19 ++ package.json | 19 +- readme.txt | 13 +- tsconfig.json | 10 +- typings.json | 5 +- webpack.config.js | 12 +- 21 files changed, 407 insertions(+), 158 deletions(-) create mode 100644 inc/js/components/CitationWindow.tsx rename inc/js/components/{pubmed-window.tsx => PubmedWindow.tsx} (98%) rename inc/js/components/{referenceWindow.tsx => ReferenceWindow.tsx} (99%) delete mode 100644 inc/js/components/inline-citation.ts create mode 100644 inc/js/tinymce-views/citation-window.html delete mode 100644 inc/js/tinymce-views/inline-citation.html create mode 100644 inc/js/utils/PrototypeFunctions.ts create mode 100644 jestPreprocessor.js diff --git a/academic-bloggers-toolkit.php b/academic-bloggers-toolkit.php index eca01b85..64548f3b 100644 --- a/academic-bloggers-toolkit.php +++ b/academic-bloggers-toolkit.php @@ -3,11 +3,11 @@ /* * Plugin Name: Academic Blogger's Toolkit * Plugin URI: https://wordpress.org/plugins/academic-bloggers-toolkit/ - * Description: A Wordpress plugin extending the functionality of Wordpress for Academic Blogging + * Description: A plugin extending the functionality of Wordpress for academic blogging * Version: 2.4.0 * Author: Derek P Sifford - * Author URI: http://www.twitter.com/flightmed1 - * License: MIT + * Author URI: https://github.com/dsifford + * License: GPL3 or later */ // Assign Global Variables diff --git a/gulpfile.js b/gulpfile.js index d39e6f7a..3f75b366 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -7,34 +7,16 @@ var browserSync = require('browser-sync').create(); var webpack = require('webpack-stream'); var del = require('del'); -// TODO: Better minifyer for js (one that doesn't break) - gulp.task('clean', function () { return del([ 'dist/inc/**/*', ]); }); -gulp.task('build', ['clean', 'webpack', 'sass'], function () { - gulp.src([ - './academic-bloggers-toolkit.php', - './CHANGELOG.md', - './LICENSE', - './readme.txt', - './inc/**/*', - '!./inc/**/*.{ts,js,css,scss,json}', - ], { base: './' }) - .pipe(gulp.dest('./dist')); -}); - gulp.task('sass', function () { - gulp.src([ - './inc/**/*.scss', - ], { base: './' }) + return gulp.src(['./inc/**/*.scss'], { base: './' }) .pipe(sass().on('error', sass.logError)) - .pipe(autoprefixer({ - browsers: ['last 2 versions'], - })) + .pipe(autoprefixer({ browsers: ['last 2 versions'] })) .pipe(cleanCSS({ compatibility: 'ie10' })) .pipe(gulp.dest('./dist')) .pipe(browserSync.stream()); @@ -42,8 +24,22 @@ gulp.task('sass', function () { gulp.task('webpack', function () { return gulp.src('inc/js/frontend.ts') - .pipe(webpack(require('./webpack.config.js'))) - .pipe(gulp.dest('dist/')); + .pipe(webpack(require('./webpack.config.js'))) + .pipe(gulp.dest('dist/')); +}); + +gulp.task('build', ['clean', 'webpack', 'sass'], function () { + gulp.src([ + './academic-bloggers-toolkit.php', + './CHANGELOG.md', + './LICENSE', + './readme.txt', + './inc/**/*', + '!./inc/**/*.{ts,tsx,js,css,scss,json}', + '!./**/__tests__', + '!./inc/js/utils', + ], { base: './' }) + .pipe(gulp.dest('./dist')); }); gulp.task('serve', ['build'], function () { @@ -57,5 +53,19 @@ gulp.task('serve', ['build'], function () { gulp.watch([ './inc/**/*', '!./inc/**/*.{tsx?,scss}', + '!__tests__/**/*', ], ['build']).on('change', browserSync.reload); }); + +gulp.task('remove-mapfiles', function (cb) { + del(['./dist/**/*.map']); + cb(); +}); + +gulp.task('minify-js', ['remove-mapfiles'], function () { + gulp.src(['./dist/**/*.js']) + .pipe(uglify()) + .pipe(gulp.dest('./dist/')); +}); + +gulp.task('deploy', ['remove-mapfiles', 'minify-js']); diff --git a/inc/js/components/CitationWindow.tsx b/inc/js/components/CitationWindow.tsx new file mode 100644 index 00000000..5940ca70 --- /dev/null +++ b/inc/js/components/CitationWindow.tsx @@ -0,0 +1,173 @@ +import * as React from 'react' +import * as ReactDOM from 'react-dom' +import Modal from '../utils/Modal' +import { + parseInlineCitationString, + parseCitationNumArray +} from '../utils/HelperFunctions'; + +interface State { + citeText: string + citeArray: number[] +} + +export default class CitationWindow extends React.Component<{}, State> { + + private modal: Modal = new Modal('Inline Citation'); + private editorDOM: HTMLDocument = top.tinyMCE.activeEditor.dom.doc; + private wm = top.tinyMCE.activeEditor.windowManager; + private refList: HTMLOListElement|boolean; + + constructor() { + super(); + let smartBib = this.editorDOM.getElementById('abt-smart-bib'); + this.refList = (smartBib as HTMLOListElement) || false; + this.state = { + citeText: '', + citeArray: [], + } + } + + componentDidMount() { + this.modal.resize(); + } + + parser(input: number[]|string): string|number[] { + if (Array.isArray(input)) { + return parseInlineCitationString(input); + } + return parseCitationNumArray(input as string); + } + + handleSubmit(e: Event) { + e.preventDefault(); + this.wm.setParams({ data: this.state.citeArray.sort((a, b) => a - b) }); + this.wm.close(); + } + + handleChange(e: Event) { + let val = (e.currentTarget as HTMLInputElement).value; + let newStateArr = Array.from(new Set(this.parser(val) as number[])); + this.setState(Object.assign({}, this.state, { citeText: val, citeArray: newStateArr })); + } + + handleClick(e: Event) { + let selected = e.currentTarget as HTMLDivElement; + let selectedNum: number = parseInt(selected.dataset['citenum']); + let indexOfNum: number = this.state.citeArray.indexOf(selectedNum); + let newStateArray: number[]; + let newStateString: string; + + // Take care of the number array first + switch (indexOfNum) { + case -1: + newStateArray = + this.state.citeArray + .concat(selectedNum) + .sort((a, b) => a - b ); + break; + default: + newStateArray = [ + ...this.state.citeArray.slice(0, indexOfNum), + ...this.state.citeArray.slice(indexOfNum + 1) + ]; + } + + // Parse new input string + newStateString = this.parser(newStateArray) as string; + + this.setState({ + citeText: newStateString, + citeArray: newStateArray, + }); + } + + render() { + return( +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    + + { this.refList && + + } +
    + ) + } + +} + +interface RefListProps { + list: HTMLCollection + modal: Modal + clickHandler: Function + citeArray: number[] +} + +class ReferenceList extends React.Component { + + constructor(props) { + super(props); + } + + componentDidMount() { + this.props.modal.resize(); + } + + render() { + + return( +
    + {Object.keys(this.props.list).map((key, i) => { + + let thisClass: string = 'cite-row'; + thisClass += i % 2 === 0 ? ' even' : ''; + thisClass += this.props.citeArray.indexOf(i+1) !== -1 ? ' cite-selected' : ''; + + return( +
    ${i+1}. ` + + (this.props.list[key] as HTMLLIElement).innerHTML} + } + onClick={this.props.clickHandler} + data-citenum={i+1} /> + ) + })} +
    + ) + } + +} + + + +ReactDOM.render( + , + document.getElementById('main-container') +); diff --git a/inc/js/components/pubmed-window.tsx b/inc/js/components/PubmedWindow.tsx similarity index 98% rename from inc/js/components/pubmed-window.tsx rename to inc/js/components/PubmedWindow.tsx index f5bd1584..75d86074 100644 --- a/inc/js/components/pubmed-window.tsx +++ b/inc/js/components/PubmedWindow.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as ReactDOM from 'react-dom' -import Modal from '../utils/Modal.ts'; -import { PubmedQuery } from '../utils/PubmedAPI.ts'; +import Modal from '../utils/Modal'; +import { PubmedQuery } from '../utils/PubmedAPI'; declare var wm; diff --git a/inc/js/components/referenceWindow.tsx b/inc/js/components/ReferenceWindow.tsx similarity index 99% rename from inc/js/components/referenceWindow.tsx rename to inc/js/components/ReferenceWindow.tsx index af5c423e..39f978b1 100644 --- a/inc/js/components/referenceWindow.tsx +++ b/inc/js/components/ReferenceWindow.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import Modal from '../utils/Modal.ts'; +import Modal from '../utils/Modal'; interface Author { firstname: string diff --git a/inc/js/components/inline-citation.ts b/inc/js/components/inline-citation.ts deleted file mode 100644 index 48030b53..00000000 --- a/inc/js/components/inline-citation.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** TODO: Smart bibliography insertion */ - -import Modal from '../utils/Modal.ts'; - -class InlineCitationWindow { - - private modal: Modal = new Modal('Inline Citation'); - private editorDOM: HTMLDocument; - public refList: HTMLOListElement|boolean; - private smartBibRender: HTMLDivElement; - - constructor() { - this.editorDOM = top.tinyMCE.activeEditor.dom.doc; - - let smartBib = this.editorDOM.getElementById('abt-smart-bib'); - this.refList = (smartBib as HTMLOListElement) || false; - this.smartBibRender = document.getElementById('smart-bib-render') as HTMLDivElement; - - if (this.refList) { - let orderedList = document.createElement('OL'); - for (let i = 0; i < (this.refList as HTMLOListElement).childElementCount; i++) { - let liContent = (this.refList as HTMLOListElement).children[i].innerHTML; - let listItem = document.createElement('li'); - listItem.innerHTML = liContent; - orderedList.appendChild(listItem); - } - this.smartBibRender.appendChild(orderedList); - } - - this.modal.resize(); - - } -} - -new InlineCitationWindow; diff --git a/inc/js/tinymce-entrypoint.ts b/inc/js/tinymce-entrypoint.ts index 3c24cf0f..55dc8134 100644 --- a/inc/js/tinymce-entrypoint.ts +++ b/inc/js/tinymce-entrypoint.ts @@ -1,9 +1,8 @@ -/// -import Dispatcher from './utils/Dispatcher.ts'; +import Dispatcher from './utils/Dispatcher'; +import { parseInlineCitationString } from './utils/HelperFunctions'; declare var tinyMCE, ABT_locationInfo - tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { //================================================== @@ -15,7 +14,6 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { type: 'menubutton', icon: 'abt_menu dashicons-welcome-learn-more', title: 'Academic Blogger\'s Toolkit', - // icon: true, menu: [], }; @@ -24,19 +22,19 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { //================================================== let openInlineCitationWindow = () => { - editor.windowManager.open({ - title: 'Inline Citation', - url: ABT_locationInfo.tinymceViewsURL + 'inline-citation.html', - width: 400, - height: 85, - onClose: (e) => { - if (!e.target.params.data) { return; } - editor.insertContent( - '[cite num="' + e.target.params.data + '"]' - ); - } - }); - } + editor.windowManager.open({ + title: 'Inline Citation', + url: ABT_locationInfo.tinymceViewsURL + 'citation-window.html', + width: 400, + height: 85, + onClose: (e) => { + if (!e.target.params.data) { return; } + editor.insertContent( + '[cite num="' + parseInlineCitationString(e.target.params.data) + '"]' + ); + } + }); + } let openFormattedReferenceWindow = () => { editor.windowManager.open({ @@ -61,12 +59,10 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { if (payload.addManually === true) { refparser.fromManualInput(payload); - // editor.setProgressState(0); return; } refparser.fromPMID(); - }, }); }; @@ -91,8 +87,6 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { } - - //================================================== // MENU ITEMS //================================================== @@ -112,7 +106,6 @@ tinyMCE.PluginManager.add('abt_main_menu', (editor, url: string) => { } editor.addShortcut('meta+alt+c', 'Insert Inline Citation', openInlineCitationWindow); - let formattedReference: TinyMCEMenuItem = { text: 'Formatted Reference', onclick: openFormattedReferenceWindow, diff --git a/inc/js/tinymce-views/citation-window.html b/inc/js/tinymce-views/citation-window.html new file mode 100644 index 00000000..d6d6c8ff --- /dev/null +++ b/inc/js/tinymce-views/citation-window.html @@ -0,0 +1,3 @@ + +
    + diff --git a/inc/js/tinymce-views/inline-citation.html b/inc/js/tinymce-views/inline-citation.html deleted file mode 100644 index 7d22cb65..00000000 --- a/inc/js/tinymce-views/inline-citation.html +++ /dev/null @@ -1,31 +0,0 @@ - -
    -
    -
    -
    -
    - - -
    -
    - -
    -
    - -
    -
    - - - diff --git a/inc/js/tinymce-views/pubmed-window.html b/inc/js/tinymce-views/pubmed-window.html index 43aca755..e92505c0 100644 --- a/inc/js/tinymce-views/pubmed-window.html +++ b/inc/js/tinymce-views/pubmed-window.html @@ -1,3 +1,3 @@
    - + diff --git a/inc/js/tinymce-views/reference-window.html b/inc/js/tinymce-views/reference-window.html index 22534339..09161edf 100644 --- a/inc/js/tinymce-views/reference-window.html +++ b/inc/js/tinymce-views/reference-window.html @@ -1,3 +1,3 @@
    - + diff --git a/inc/js/tinymce-views/styles.scss b/inc/js/tinymce-views/styles.scss index 4bf59426..9b048b7b 100644 --- a/inc/js/tinymce-views/styles.scss +++ b/inc/js/tinymce-views/styles.scss @@ -28,7 +28,7 @@ body { font-size: 13px; height: 30px; line-height: 31px; - margin: 0; + margin: 2px 0; padding: 0 12px 2px; vertical-align: top; white-space: nowrap; @@ -149,3 +149,29 @@ kbd { background: #eaeaea; background: rgba(0,0,0,.08) } + +.cite-row { + padding: 5px; + font-size: 0.8em; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + &.even { + background: #fafafa; + border: 1px solid #ccc; + border-left: none; + border-right: none; + } + + &:hover { + cursor: pointer; + } +} + +.cite-selected { + background: rgba(0, 133, 186, 0.5)!important; +} diff --git a/inc/js/utils/Dispatcher.ts b/inc/js/utils/Dispatcher.ts index 34153bac..13e70103 100644 --- a/inc/js/utils/Dispatcher.ts +++ b/inc/js/utils/Dispatcher.ts @@ -1,5 +1,5 @@ -import { AMA, APA } from './Parsers.ts'; -import './HelperFunctions.ts'; +import { AMA, APA } from './Parsers'; +import './PrototypeFunctions'; export default class Dispatcher { public citationFormat: string; diff --git a/inc/js/utils/HelperFunctions.ts b/inc/js/utils/HelperFunctions.ts index 6a780374..8ebca34b 100644 --- a/inc/js/utils/HelperFunctions.ts +++ b/inc/js/utils/HelperFunctions.ts @@ -1,26 +1,68 @@ -export default {}; -declare global { - interface String { - toTitleCase(): string + +/** + * Function that takes a sorted array of integers as input and returns + * an inline citation string representation of the numbers. + * + * Example: [1,3,4,5,10] => "1,3-5,10" + * + * @param {number[]} numArr Sorted array of integers. + * @returns {string} A formatted inline citation string. + */ +export function parseInlineCitationString(numArr: number[]): string { + if (numArr.length === 0) { return ''; } + + let output: string = numArr[0].toString(); + + for (let i = 1; i < numArr.length; i++) { + switch (output[output.length - 1]) { + case ',': + output += numArr[i]; + break; + case '-': + if (numArr[i+1] === numArr[i] + 1) { break; } + if (i === numArr.length - 1) { output += numArr[i]; break;} + output += numArr[i] + ','; + break; + default: + let lastNum = parseInt(output.split(',')[output.split(',').length - 1]); + if (lastNum === numArr[i] - 1 && numArr[i + 1] === numArr[i] + 1) { + output += '-'; + break; + } + output += ',' + numArr[i]; + } } + + return output; } -String.prototype.toTitleCase = function(): string { - let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; +/** + * Function that takes an inline citation string and returns an array of + * integers for that string. + * + * Example: "1-3,6,8-10" => [1,2,3,6,8,9,10] + * + * @param {string} input An inline citation string. + * @returns {number[]} An array of integers that represent the input string. + */ +export function parseCitationNumArray(input: string): number[] { + let x = input.split(','); + let output: number[] = []; - return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ - if (index > 0 && index + match.length !== title.length && - match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && - (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && - title.charAt(index - 1).search(/[^\s-]/) < 0) { - return match.toLowerCase(); - } + if (x.length === 0 || (x.length === 1 && x[0] === '')) { return []; } - if (match.substr(1).search(/[A-Z]|\../) > -1) { - return match; - } + for (let i = 0; i < x.length; i++) { + switch (x[i].match('-')) { + case null: + output.push(parseInt(x[i])); + break; + default: + for (let j = parseInt(x[i].split('-')[0]); j <= parseInt(x[i].split('-')[1]); j++) { + output.push(j); + } + } + } - return match.charAt(0).toUpperCase() + match.substr(1); - }); -}; + return output; +} diff --git a/inc/js/utils/PrototypeFunctions.ts b/inc/js/utils/PrototypeFunctions.ts new file mode 100644 index 00000000..6a780374 --- /dev/null +++ b/inc/js/utils/PrototypeFunctions.ts @@ -0,0 +1,26 @@ +export default {}; + +declare global { + interface String { + toTitleCase(): string + } +} + +String.prototype.toTitleCase = function(): string { + let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; + + return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){ + if (index > 0 && index + match.length !== title.length && + match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && + (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && + title.charAt(index - 1).search(/[^\s-]/) < 0) { + return match.toLowerCase(); + } + + if (match.substr(1).search(/[A-Z]|\../) > -1) { + return match; + } + + return match.charAt(0).toUpperCase() + match.substr(1); + }); +}; diff --git a/jestPreprocessor.js b/jestPreprocessor.js new file mode 100644 index 00000000..02504a79 --- /dev/null +++ b/jestPreprocessor.js @@ -0,0 +1,19 @@ +const tsc = require('typescript'); + +module.exports = { + process(src, path) { + if (path.endsWith('.ts') || path.endsWith('.tsx')) { + return tsc.transpile( + src, + { + module: tsc.ModuleKind.CommonJS, + jsx: tsc.JsxEmit.React, + }, + path, + [] + ); + } + + return src; + }, +}; diff --git a/package.json b/package.json index b15a4b83..efba9027 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,17 @@ { "name": "academic-bloggers-toolkit", - "version": "2.3.0", + "version": "2.4.0", "description": "A plugin extending the functionality of WordPress for Academic Blogging.", "main": "index.js", "scripts": { - "build": "gulp build", - "serve": "gulp serve", - "deploy": "gulp build && find ./dist -type d -empty -delete && find ./dist -name '*.map' -type f -delete" + "test": "jest" }, "repository": { "type": "git", "url": "git+https://github.com/dsifford/academic-bloggers-toolkit.git" }, "author": "Derek P Sifford", - "license": "MIT", + "license": "GPL3 or later", "bugs": { "url": "https://github.com/dsifford/academic-bloggers-toolkit/issues" }, @@ -29,11 +27,22 @@ "gulp-clean-css": "^2.0.4", "gulp-sass": "^2.2.0", "gulp-uglify": "^1.5.3", + "jest-cli": "^0.10.0", "react": "^0.14.8", + "react-addons-test-utils": "^0.14.8", "react-dom": "^0.14.8", "ts-loader": "^0.8.1", "typescript": "^1.8.9", "webpack": "^1.12.14", "webpack-stream": "^3.1.0" + }, + "jest": { + "scriptPreprocessor": "jestPreprocessor.js", + "testFileExtensions": ["ts", "tsx", "js"], + "unmockedModulePathPatterns": [ + "/node_modules/react", + "/node_modules/react-dom", + "/node_modules/react-addons-test-utils" + ] } } diff --git a/readme.txt b/readme.txt index 88a5c5d4..7e2e8e9e 100644 --- a/readme.txt +++ b/readme.txt @@ -1,14 +1,14 @@ === Academic Blogger's Toolkit === Contributors: dsifford Donate link: https://cash.me/$dsifford -Tags: academic, pmid, doi, peer-review, Google Tag Manager, citation, bibliography +Tags: academic, pmid, doi, peer-review, pubmed, citation, bibliography, reference Requires at least: 4.2.2 -Tested up to: 4.2.2 +Tested up to: 4.5 Stable tag: 2.4.0 License: GPL3 or later License URI: https://www.gnu.org/licenses/gpl-3.0.html -A WordPress plugin extending the functionality of WordPress for Academic Blogging. +A plugin extending the functionality of Wordpress for academic blogging. == Description == @@ -62,6 +62,13 @@ Yikes! I'm sorry about that. Please report all issues on the Academic Blogger's * Full rewrite; a majority of which is using React by Facebook. * Speed improvements & resource minification. +Documentation improvements will be added within the next few days. + +**Note:** Due to the magnitude of this update, there may be bugs that I have not encountered (although, I did test this pretty heavily). +If you run into any problems, have any questions, or experience a bug, please file an issue [here](https://github.com/dsifford/academic-bloggers-toolkit/issues). + +A special thanks to @metallikat36 for the great suggestions that led directly to the features added in this update. + = 2.3.1 = * Fix poor rendering of tooltip close icon on mobile. * Increase size of toucharea for tooltip close icon on mobile. diff --git a/tsconfig.json b/tsconfig.json index 0e8b3e6d..0ca2d971 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -34,7 +34,6 @@ }, "files": [ "inc/js/ABT.d.ts", - "inc/js/components/inline-citation.ts", "inc/js/frontend.ts", "inc/js/metaboxes.ts", "inc/js/tinymce-entrypoint.ts", @@ -42,11 +41,16 @@ "inc/js/utils/HelperFunctions.ts", "inc/js/utils/Modal.ts", "inc/js/utils/Parsers.ts", + "inc/js/utils/PrototypeFunctions.ts", "inc/js/utils/PubmedAPI.ts", "typings/main.d.ts", + "typings/main/ambient/jest/index.d.ts", + "typings/main/ambient/react-addons-test-utils/index.d.ts", + "typings/main/ambient/require/index.d.ts", "typings/react-dom/index.d.ts", "typings/react/index.d.ts", - "inc/js/components/pubmed-window.tsx", - "inc/js/components/referenceWindow.tsx" + "inc/js/components/CitationWindow.tsx", + "inc/js/components/PubmedWindow.tsx", + "inc/js/components/ReferenceWindow.tsx" ] } diff --git a/typings.json b/typings.json index e6b0fef7..b2c9af28 100644 --- a/typings.json +++ b/typings.json @@ -3,7 +3,10 @@ "version": false, "dependencies": {}, "ambientDependencies": { + "jest": "registry:dt/jest#0.9.0+20160319033628", "react": "registry:dt/react#0.14.0+20160319053454", - "react-dom": "registry:dt/react-dom#0.14.0+20160316155526" + "react-addons-test-utils": "registry:dt/react-addons-test-utils#0.14.0+20160316155526", + "react-dom": "registry:dt/react-dom#0.14.0+20160316155526", + "require": "registry:dt/require#2.1.20+20160316155526" } } diff --git a/webpack.config.js b/webpack.config.js index e2919227..1bea1c69 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,10 +3,10 @@ module.exports = { entry: { 'inc/js/tinymce-entrypoint': './inc/js/tinymce-entrypoint.ts', 'inc/js/frontend': './inc/js/frontend.ts', - 'inc/js/components/referenceWindow': './inc/js/components/referenceWindow.tsx', - 'inc/js/components/inline-citation': './inc/js/components/inline-citation.ts', + 'inc/js/components/ReferenceWindow': './inc/js/components/ReferenceWindow.tsx', + 'inc/js/components/CitationWindow': './inc/js/components/CitationWindow.tsx', 'inc/js/metaboxes': './inc/js/metaboxes.ts', - 'inc/js/components/pubmed-window': './inc/js/components/pubmed-window.tsx', + 'inc/js/components/PubmedWindow': './inc/js/components/PubmedWindow.tsx', }, output: { filename: '[name].js', @@ -20,8 +20,8 @@ module.exports = { loader: 'babel?presets[]=es2015!ts', }, ], - resolve: { - extensions: ['', '.ts', 'tsx', '.js'], - }, + }, + resolve: { + extensions: ['', '.ts', '.tsx', '.js'], }, };