From 4e140af68966072c832ab132ed1c7bf940387cec Mon Sep 17 00:00:00 2001 From: Yusra Haider Date: Thu, 5 Mar 2020 14:06:56 +0000 Subject: [PATCH 01/23] base modal implementation with citation text, copy to clipboard and email implemented. The citation text is dynamically generated depending on which page of the website the user is currently on --- templates/favourite/citation-query.js | 212 ++++++++++++++++++++++++ templates/favourite/index.php | 51 +++++- templates/favourite/js/clipboard.min.js | 7 + 3 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 templates/favourite/citation-query.js create mode 100644 templates/favourite/js/clipboard.min.js diff --git a/templates/favourite/citation-query.js b/templates/favourite/citation-query.js new file mode 100644 index 000000000..d07365f37 --- /dev/null +++ b/templates/favourite/citation-query.js @@ -0,0 +1,212 @@ + +// to-do: write parser for the various URL / URI +// write the endpoint / implement the code for download page and citation page +// implement the copy to clipboard button +// make the modal and button responsive +// finalize the color scheme and stuff +// consider generating the modal programmatically / on call +// implement the email functionality +// I could potentially call and save the citation in one format if the cite-me module exists: https://gomakethings.com/conditionally-loading-javascript-only-when-the-browser-supports-it/#feature-testing +// implement on pathway browser as well + + +// potentially helpful later: +// https://deepasp.wordpress.com/2015/10/18/dynamically-creating-and-showing-bootstrap-modal/ +// https://www.ovais.me/javascript/bootstrap-3-modal-easy-way/ + + +// to ask -- could use const here, +var EUROPE_PMC_BASE_URL = "https://www.ebi.ac.uk/europepmc/webservices/rest/search?"; +var EUROPE_PMC_RESPONSE_FORMAT = "dc"; +var EUROPE_PMC_XML_CITATION_TAG = "dcterms:bibliographicCitation"; +var DOI_BASE_URL = " https://doi.org/" +var PATHWAY_CITATION_ENDPOINT = "/ContentService/citation/pathway/"; +var QUERY_ENDPOINT = "/ContentService/data/query/"; +var QUERY_ATTRIBUTE = "/schemaClass"; +var DOWNLOAD_CITATION_ENDPOINT = "/ContentService/citation/download/"; + + +var GENERAL_CITATION_ID = 31691815 +var ICON_CITATION_ID = 29077811 +var PATHWAY_ANALYSIS_CITATION_ID = 28249561 +var FIVIZ_CITATION_ID = 28150241 +var GRAPH_DATABASE_CITATION_ID = 29377902 + + +// for your regex needs: https://stackoverflow.com/questions/30114238/match-any-all-of-multiple-words-in-a-string --- good alternative +// this is noice: https://stackoverflow.com/questions/10152650/javascript-match-regular-expression-against-the-array-of-items +// should I stick to an array of regexes or do `or` in regex? +// or use substring ops? +var generalCitation = [/what-is-reactome/, /about/, /sab/, /license/, /orcid/, /community/]; // checked on these pages +var downloadCitation = [/download-data/]; +var iconCitation = [/icon-lib/, /R-ICO/]; // checked here +var pathwayAnalysisCitation = [/AnalysisService/]; +var fivizCitation = [/reactome-fiviz/]; // checked here +var graphDatabaseCitation = [/ContentService/, /graph-database/]; // checked +var pathwayCitation = [/content\/detail\/R-/]; + +// analysis service, content service have issues wrt menu modal assignment +// icon-lib acting weirdly + +// instantiating the clipboard button here +jQuery(document).ready(function() { + // refactor this code here + var clipboard = new ClipboardJS('#clipboardButton', { + container: jQuery('#myModal') + }); + + var clipboardButton = jQuery('#clipboardButton'); + + clipboard.on('success', function(e) { + clipboardButton.find("i").removeClass("fa fa-clipboard").addClass("fa fa-check"); + clipboardButton.attr("disabled", true); + + // clears selection and changes icon back to the copy icon after 2 seconds have passed + setTimeout(function() { + clipboardButton.attr("disabled", false); + // clipboardButton.find("i").removeClass("fas fa-check").addClass("fas fa-copy"); + clipboardButton.find("i").removeClass("fa fa-check").addClass("fa fa-clipboard"); + + e.clearSelection(); + }, 2000); + }); + + clipboard.on('error', function(e) { + console.error("Whoops.Couldn't copy"); + }); +}); + + + +/* main method that gets called when the modal button is clicked +event order: + 1) someone clicks on the button + 2) we check what page we are on + 3) we call the appropriate function to get citation data +*/ +function getCitation() { + var modal = jQuery('#myModal'); + // passing the current page url to parseURL which will give us a citation promise + // that we can resolve + var d = parseURL(window.location.href); + + d.then( + // on success + function(citation) { + modal.modal('show'); + modal.find('.modal-body').text(citation); + }, + // on failure + function() { + // hide the copy to clipboard and mail buttons + modal.find(".modal-header").find("#clipboardButton").hide(); + modal.find(".modal-header").find("#mailButton").hide(); + modal.modal('show'); + // make `help@reactome.org` a mailto link + var helpEmail = jQuery(""); + helpEmail.attr("href", "mailto:help@reactome.org"); + helpEmail.text("help@reactome.org"); + // show the error message + modal.find(".modal-body").text("Sorry, we could not process your request. Please email the error code to ").append(helpEmail); + } + ); +} + + +// function that does the heavy lifting of figuring out which page we are on, +// and returning the approriate citation promise +function parseURL(url) { + if (generalCitation.some(function(regex) {return regex.test(url)})) { + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID, EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + } + + else if (downloadCitation.some(function(regex) {return regex.test(url)})) { + var d = jQuery.get(window.location.origin.concat(DOWNLOAD_CITATION_ENDPOINT)).then(function(response) { return response + " (" + new Date().toDateString() + ")";}) + return d; + + } + + else if (iconCitation.some(function(regex) {return regex.test(url)})) { + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, ICON_CITATION_ID, EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + } + + else if (pathwayAnalysisCitation.some(function(regex) {return regex.test(url)})) { + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, PATHWAY_ANALYSIS_CITATION_ID, EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + } + + else if (fivizCitation.some(function(regex) {return regex.test(url)})) { + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, FIVIZ_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + } + + else if (graphDatabaseCitation.some(function(regex) {return regex.test(url)})) { + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GRAPH_DATABASE_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + } + + else if (pathwayCitation.some(function(regex) {return regex.test(url)})) { + + var pathwayStId = window.location.href.split("/").pop(); + return jQuery.get(QUERY_ENDPOINT.concat(pathwayStId, QUERY_ATTRIBUTE)).then( + function(response) { + if (response.toLowerCase().indexOf("pathway") != -1) { + // return the promise for pathway citation + return getPathwayCitationObj(PATHWAY_CITATION_ENDPOINT, pathwayStId); + } + else { + // return promise for general citation + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + } + }); + } + + // default case + else { + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + } +} + + +// helper functions + +// returns promise with the citation from Europe PMC and how to parse that response +function getCitationFromEuropePMC(baseUrl, searchId, format, tagName) { + var d = jQuery.get(baseUrl.concat(jQuery.param({query:searchId, format: format}))).then(function(response) {return response.getElementsByTagName(tagName)[0].childNodes[0].nodeValue;}); + return d; +} + + +//returns promise with the pathway citation response and how to parse that response +function getPathwayCitationObj(pathwayCitationEndpoint, pathwayStId) { + var windowLocation = window.location; + + var d = jQuery.get(windowLocation.origin.concat(pathwayCitationEndpoint, pathwayStId)).then(function(response) { + var authors = response["authors"]; + // checking that authors key exists, the value is not undefined or null and the list is not empty + var authorCitation = (authors && authors.length != 0) ? authors.slice(0, authors.length-1).join(" , ").concat(" & ", authors[authors.length-1]) : "The Reactome Consortium"; + + var doi = response["doi"]; + // checking that doi key exists and the value is not undefined or null + var urls = doi ? [windowLocation.href, DOI_BASE_URL.concat(doi)] : [windowLocation.href]; + + var dateOfAccess = new Date().toDateString(); + var commonCitation = response["pathwayTitle"].concat(". Reactome, ", response["releaseVersion"], ", ", urls.join(", ")," (", dateOfAccess, ")"); + var pathwayCitation = "Pathway Citation".concat(": ", authorCitation, " (", response["publicationYear"], "). ", commonCitation); + var imageCitation = "Image Citation".concat(": ", commonCitation); + + // line break not working + return pathwayCitation.concat("
", imageCitation); + }); + + return d; + +} +// helper functions end + + +// handles the mail-to functionality +function sendMail() { + window.location = "mailto:?subject=Reactome Citation&body=" + encodeURIComponent(jQuery('#myModal').find('.modal-body').text()); +} + + + + diff --git a/templates/favourite/index.php b/templates/favourite/index.php index d91dc84e6..5eb1ee9a8 100644 --- a/templates/favourite/index.php +++ b/templates/favourite/index.php @@ -26,6 +26,9 @@ JHtml::_('jquery.framework'); $doc->addStyleSheet($this->baseurl. '/templates/' .$this->template. '/bootstrap/favth-bootstrap.css'); $doc->addScript($this->baseurl. '/templates/' .$this->template. '/bootstrap/favth-bootstrap.js'); +// adding the js files for the citation project +$doc->addScript($this->baseurl. '/templates/' .$this->template. '/js/clipboard.min.js'); +$doc->addScript($this->baseurl. '/templates/' .$this->template. '/citation-query.js'); // Custom: Adding autocomplete javascript JHtml::_('script', 'jui/jquery.autocomplete.min.js', array('version' => 'auto', 'relative' => true)); @@ -85,7 +88,7 @@ - + @@ -522,6 +525,52 @@ function gtag(){dataLayer.push(arguments)}; + + countModules('cite-me')) { ?> + + + + + + +
+ + + + + + Date: Tue, 10 Mar 2020 11:11:47 +0000 Subject: [PATCH 02/23] added export functionality to modal --- templates/favourite/citation-query.js | 396 +++++++++++++++++++++----- templates/favourite/css/custom.css | 24 ++ templates/favourite/index.php | 44 +-- 3 files changed, 379 insertions(+), 85 deletions(-) diff --git a/templates/favourite/citation-query.js b/templates/favourite/citation-query.js index d07365f37..c7454d32e 100644 --- a/templates/favourite/citation-query.js +++ b/templates/favourite/citation-query.js @@ -1,25 +1,76 @@ +//TO-DO: +// refactor code so that the dom indentifiers are less generic +// work on the CSS, mode code from html to proper style sheets -// to-do: write parser for the various URL / URI -// write the endpoint / implement the code for download page and citation page -// implement the copy to clipboard button -// make the modal and button responsive -// finalize the color scheme and stuff -// consider generating the modal programmatically / on call -// implement the email functionality -// I could potentially call and save the citation in one format if the cite-me module exists: https://gomakethings.com/conditionally-loading-javascript-only-when-the-browser-supports-it/#feature-testing -// implement on pathway browser as well +// constants declaration +var EUROPE_PMC_BASE_URL = "https://www.ebi.ac.uk/europepmc/webservices/rest/search?"; +var EUROPE_PMC_QUERY_MODES = { + EXPORT: "export", + TEXT: "text" +} +var EUROPE_PMC_REQUEST_RESPONSE = { + // for the export functionality of the citations we querying Europe PMC's api with format `json` and + // resultType `core` so that we get all the data, specifically so that we get the author names + // in full detail + export : { + format: "json", + resultType: "core", + parseResponse: function(response) {return response["resultList"]["result"][0];} + }, + + // for the textual citation, we are querying Europe PMC's api with format `dc` so to get citation related metadata + // and use the `dcterms:bibliographicCitation` tag + // the `dc` format by default uses `resultType` = `core`. I specified that here for clarity + text: { + format: "dc", + resultType: "core", + parseResponse: function(response) {return response.getElementsByTagName("dcterms:bibliographicCitation")[0].childNodes[0].nodeValue;} + } +} +var PATHWAY_CITATION_REQUEST_RESPONSE = { + export: { + parseResponse: function(response) {return response;} + }, + text: { + parseResponse: function(response) { + var windowLocation = window.location; + var authors = response["authorsxf"].map(function(author) { + return author["lastName"] + "," + " " + author["initials"]; + }); + // checking that authors key exists, the value is not undefined or null and the list is not empty + var authorCitation = ""; -// potentially helpful later: -// https://deepasp.wordpress.com/2015/10/18/dynamically-creating-and-showing-bootstrap-modal/ -// https://www.ovais.me/javascript/bootstrap-3-modal-easy-way/ + if (authors && authors.length > 0) { + authorCitation = authors[authors.length-1]; + if (authors.length > 1) { + authors.slice(0, authors.length-1).join(" , ").concat(" & ", authorCitation); + } -// to ask -- could use const here, -var EUROPE_PMC_BASE_URL = "https://www.ebi.ac.uk/europepmc/webservices/rest/search?"; -var EUROPE_PMC_RESPONSE_FORMAT = "dc"; -var EUROPE_PMC_XML_CITATION_TAG = "dcterms:bibliographicCitation"; -var DOI_BASE_URL = " https://doi.org/" + } + else { + authorCitation = "The Reactome Consortium"; + } + + + + var doi = response["doi"]; + // checking that doi key exists and the value is not undefined or null + var urls = doi ? [windowLocation.href, DOI_BASE_URL.concat(doi)] : [windowLocation.href]; + + var dateOfAccess = new Date().toDateString(); + var commonCitation = response["pathwayTitle"].concat(". Reactome, ", response["releaseVersion"], ", ", urls.join(", ")," (", dateOfAccess, ")"); + var pathwayCitation = "Pathway Citation".concat(": ", authorCitation, " (", response["publicationYear"], "). ", commonCitation); + var imageCitation = "Image Citation".concat(": Image Citation for ", commonCitation); + + // line break not working + return pathwayCitation.concat("\n", imageCitation); + } + } +} + +var DOI_BASE_URL = "https://doi.org/" var PATHWAY_CITATION_ENDPOINT = "/ContentService/citation/pathway/"; var QUERY_ENDPOINT = "/ContentService/data/query/"; var QUERY_ATTRIBUTE = "/schemaClass"; @@ -32,27 +83,33 @@ var PATHWAY_ANALYSIS_CITATION_ID = 28249561 var FIVIZ_CITATION_ID = 28150241 var GRAPH_DATABASE_CITATION_ID = 29377902 +// export formats +var EXPORT_FORMATS = { + BIBTEX: {fileExt: "bib", mimeType: "application/x-bibtex", web: "misc", journal: "article"}, + TEXT: {fileExt: "txt", mimeType: "text/plain"}, + // for pathways, the Type in the RIS files ahas been set as `ELEC`, and the type for static citations + //has been set as + RIS: {fileExt: "ris", mimeType: "application/x-research-info-systems", web: "ELEC", journal: "JOUR"} +}; + -// for your regex needs: https://stackoverflow.com/questions/30114238/match-any-all-of-multiple-words-in-a-string --- good alternative -// this is noice: https://stackoverflow.com/questions/10152650/javascript-match-regular-expression-against-the-array-of-items -// should I stick to an array of regexes or do `or` in regex? -// or use substring ops? -var generalCitation = [/what-is-reactome/, /about/, /sab/, /license/, /orcid/, /community/]; // checked on these pages +// constants declaration end + +var generalCitation = [/what-is-reactome/, /about/, /sab/, /license/, /orcid/, /community/]; var downloadCitation = [/download-data/]; -var iconCitation = [/icon-lib/, /R-ICO/]; // checked here +var iconCitation = [/icon-lib/, /R-ICO/]; var pathwayAnalysisCitation = [/AnalysisService/]; -var fivizCitation = [/reactome-fiviz/]; // checked here -var graphDatabaseCitation = [/ContentService/, /graph-database/]; // checked +var fivizCitation = [/reactome-fiviz/]; +var graphDatabaseCitation = [/ContentService/, /graph-database/]; var pathwayCitation = [/content\/detail\/R-/]; -// analysis service, content service have issues wrt menu modal assignment -// icon-lib acting weirdly -// instantiating the clipboard button here +// event based work: jQuery(document).ready(function() { - // refactor this code here + + // instantiating the clipboard button here var clipboard = new ClipboardJS('#clipboardButton', { - container: jQuery('#myModal') + container: jQuery('#myModal').find(".modal-body").find("#citationText") }); var clipboardButton = jQuery('#clipboardButton'); @@ -76,7 +133,7 @@ jQuery(document).ready(function() { }); }); - +// functions being called from the html file /* main method that gets called when the modal button is clicked event order: @@ -88,13 +145,15 @@ function getCitation() { var modal = jQuery('#myModal'); // passing the current page url to parseURL which will give us a citation promise // that we can resolve - var d = parseURL(window.location.href); + var d = parseURL(url=window.location.href, mode=EUROPE_PMC_QUERY_MODES["TEXT"]); d.then( // on success function(citation) { - modal.modal('show'); - modal.find('.modal-body').text(citation); + // clearing any radio button selection before modal gets opened + jQuery("input[name=exportOption]:checked").prop("checked", false); + modal.modal("show"); + modal.find(".modal-body").find("#citationText").text(citation); }, // on failure function() { @@ -107,39 +166,91 @@ function getCitation() { helpEmail.attr("href", "mailto:help@reactome.org"); helpEmail.text("help@reactome.org"); // show the error message - modal.find(".modal-body").text("Sorry, we could not process your request. Please email the error code to ").append(helpEmail); + modal.find(".modal-body").find("#citationText").text("Sorry, we could not process your request. Please email the error code to ").append(helpEmail); } ); } +// handles the mail-to functionality +function sendMail() { + window.location = "mailto:?subject=Reactome Citation&body=" + encodeURIComponent(jQuery('#myModal').find('.modal-body').find("#citationText").text()); +} + + +// exports the citation in the selected format +function exportCitation() { + + var exportFormat = jQuery("input[name=exportOption]:checked", "#exportCitationForm").val(); + var filename = "reactome_citation." + exportFormat; + var data = "This is a Reactome Citation"; // putting in a default citation + + if (!exportFormat) { + return; + } + + var modal = jQuery('#myModal'); + // passing the current page url to parseURL which will give us a citation promise + // that we can resolve + var d = parseURL(url=window.location.href, mode=EUROPE_PMC_QUERY_MODES["EXPORT"]); + d.then( + //on success + function(citation) { + switch(exportFormat) { + case EXPORT_FORMATS["BIBTEX"]["fileExt"]: + data = convertJSONToBibTeX(preprocessForExport(citation)); + downloadFile(data, format=EXPORT_FORMATS["BIBTEX"]["mimeType"], filename); + break; + case EXPORT_FORMATS["RIS"]["fileExt"]: + data = convertJSONToRIS(preprocessForExport(citation)); + downloadFile(data, format=EXPORT_FORMATS["RIS"]["mimeType"], filename); + break; + default: + data = jQuery('#myModal').find(".modal-body").find("#citationText").text(); + downloadFile(data, format=exportFormat, filename); + } + }); +} + + +// enables the export citation button when one of the citation formats is selected +function enableExportCitationButton() { + jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].disabled = false; + // refactor code so that so that a custom css class can get made for disabled and enabled buttons + jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].style["cursor"] = "default"; + +} + +// functions being called from html end + // function that does the heavy lifting of figuring out which page we are on, // and returning the approriate citation promise -function parseURL(url) { +function parseURL(url, mode) { if (generalCitation.some(function(regex) {return regex.test(url)})) { - return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID, EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID, mode); } else if (downloadCitation.some(function(regex) {return regex.test(url)})) { + document.getElementById("exportCitationForm").style.display="none"; var d = jQuery.get(window.location.origin.concat(DOWNLOAD_CITATION_ENDPOINT)).then(function(response) { return response + " (" + new Date().toDateString() + ")";}) return d; } else if (iconCitation.some(function(regex) {return regex.test(url)})) { - return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, ICON_CITATION_ID, EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, ICON_CITATION_ID, mode); } else if (pathwayAnalysisCitation.some(function(regex) {return regex.test(url)})) { - return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, PATHWAY_ANALYSIS_CITATION_ID, EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, PATHWAY_ANALYSIS_CITATION_ID, mode); } else if (fivizCitation.some(function(regex) {return regex.test(url)})) { - return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, FIVIZ_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, FIVIZ_CITATION_ID, mode); } else if (graphDatabaseCitation.some(function(regex) {return regex.test(url)})) { - return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GRAPH_DATABASE_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GRAPH_DATABASE_CITATION_ID, mode); } else if (pathwayCitation.some(function(regex) {return regex.test(url)})) { @@ -149,18 +260,18 @@ function parseURL(url) { function(response) { if (response.toLowerCase().indexOf("pathway") != -1) { // return the promise for pathway citation - return getPathwayCitationObj(PATHWAY_CITATION_ENDPOINT, pathwayStId); + return getPathwayCitationObj(PATHWAY_CITATION_ENDPOINT, pathwayStId, mode); } else { // return promise for general citation - return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID, mode); } }); } // default case else { - return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID,EUROPE_PMC_RESPONSE_FORMAT, EUROPE_PMC_XML_CITATION_TAG); + return getCitationFromEuropePMC(EUROPE_PMC_BASE_URL, GENERAL_CITATION_ID, mode); } } @@ -168,45 +279,194 @@ function parseURL(url) { // helper functions // returns promise with the citation from Europe PMC and how to parse that response -function getCitationFromEuropePMC(baseUrl, searchId, format, tagName) { - var d = jQuery.get(baseUrl.concat(jQuery.param({query:searchId, format: format}))).then(function(response) {return response.getElementsByTagName(tagName)[0].childNodes[0].nodeValue;}); - return d; +function getCitationFromEuropePMC(baseUrl, searchId, mode) { + var settings = EUROPE_PMC_REQUEST_RESPONSE[mode]; + var d = jQuery.get(baseUrl.concat(jQuery.param({query:searchId, format: settings["format"],resultType: settings["resultType"]}))).then(settings["parseResponse"]); + return d; } //returns promise with the pathway citation response and how to parse that response -function getPathwayCitationObj(pathwayCitationEndpoint, pathwayStId) { - var windowLocation = window.location; +function getPathwayCitationObj(pathwayCitationEndpoint, pathwayStId, mode) { + var settings = PATHWAY_CITATION_REQUEST_RESPONSE[mode]; + var d = jQuery.get(window.location.origin.concat(pathwayCitationEndpoint, pathwayStId)).then(function(response) {return settings["parseResponse"](response);}); + return d; - var d = jQuery.get(windowLocation.origin.concat(pathwayCitationEndpoint, pathwayStId)).then(function(response) { - var authors = response["authors"]; - // checking that authors key exists, the value is not undefined or null and the list is not empty - var authorCitation = (authors && authors.length != 0) ? authors.slice(0, authors.length-1).join(" , ").concat(" & ", authors[authors.length-1]) : "The Reactome Consortium"; +} - var doi = response["doi"]; - // checking that doi key exists and the value is not undefined or null - var urls = doi ? [windowLocation.href, DOI_BASE_URL.concat(doi)] : [windowLocation.href]; - var dateOfAccess = new Date().toDateString(); - var commonCitation = response["pathwayTitle"].concat(". Reactome, ", response["releaseVersion"], ", ", urls.join(", ")," (", dateOfAccess, ")"); - var pathwayCitation = "Pathway Citation".concat(": ", authorCitation, " (", response["publicationYear"], "). ", commonCitation); - var imageCitation = "Image Citation".concat(": ", commonCitation); +// takes json, that is either the response from Europe PMC's endpoint or the response from the +// pathway citation and makes a dictionary that the export functions can use +function preprocessForExport(json) { - // line break not working - return pathwayCitation.concat("
", imageCitation); - }); + // all the checks here follow the order: are we getting the citation from Europe PMC? or are we getting it from our pathway citation endpoint? citationDetails gets populated accordingly + var citationDetails = {}; + citationDetails["id"] = json["id"] || json["stid"]; // the id. compulsory field + citationDetails["title"] = json["title"] || json["pathwayTitle"]; //title of article. compulsory field - return d; + citationDetails["journal"] = ((json["journalInfo"] || {})["journal"] || {})["title"]; + citationDetails["year"] = (json["journalInfo"] || {})["yearOfPublication"] || json["publicationYear"]; // publication year. compulsory field + citationDetails["month"] = (json["journalInfo"] || {})["monthOfPublication"] || json["publicationMonth"]; // publication month + citationDetails["number"] = (json["journalInfo"] || {})["issue"]; + citationDetails["volume"] = (json["journalInfo"] || {})["volume"] + citationDetails["issn"] = ((json["journalInfo"] || {})["journal"] || {})["issn"]; // ISSN number + citationDetails["pages"] = json["pageInfo"]; // pages + + if (json["doi"]) { + citationDetails["doi"] = json["doi"]; + citationDetails["urls"] = [DOI_BASE_URL.concat(json["doi"])]; + } + else if (json["stid"]) + citationDetails["urls"] = (citationDetails["urls"]) ? citationDetails.push(window.location.href) : [].push(window.location.href); + citationDetails["authors"] = (json["authorList"] || {})["author"] || json["authors"] || "The Reactome Consortium"; + citationDetails["type"] = (!!json["isPathway"]) ? EXPORT_FORMATS["BIBTEX"]["web"] : EXPORT_FORMATS["BIBTEX"]["journal"]; + + return citationDetails; } -// helper functions end -// handles the mail-to functionality -function sendMail() { - window.location = "mailto:?subject=Reactome Citation&body=" + encodeURIComponent(jQuery('#myModal').find('.modal-body').text()); +// download file code taken from here: https://stackoverflow.com/a/33542499/3240056 +// there are other export options worth evaluating +// browser compaability will have to be more throughly checked +function downloadFile(data, format, filename) { + var blob = new Blob([data], {type: format}); + if(window.navigator.msSaveOrOpenBlob) { + window.navigator.msSaveBlob(blob, filename); + } + else { + var elem = window.document.createElement('a'); + elem.href = window.URL.createObjectURL(blob); + elem.download = filename; + document.body.appendChild(elem); + elem.click(); + document.body.removeChild(elem); + } } +// helper functions end + +// export functions + +// takes a json and converts that to RIS string +// RIS file specs were taken from: +// https://web.archive.org/web/20100704171416/http://www.refman.com/support/risformat_intro.asp +// https://en.wikipedia.org/wiki/RIS_(file_format) +function convertJSONToRIS(json) { + var doubleSpace = " "; + var space = " "; + var dash = "-"; + var keyValueSeparator = doubleSpace + dash + space; + var comma = ","; + var newline = "\n"; + + // start the RIS document + var ris = "TY" + keyValueSeparator + json["type"] + newline; + + // adding the title + ris += "TI" + keyValueSeparator + json["title"] + newline + + // adding the authors + var authorString = ""; + if (json["authors"] instanceof Array) { + json["authors"].forEach(function(author) { + authorString += "AU" + keyValueSeparator + + author["lastName"] + comma + space + (author["firstName"] || author["initials"]) + + newline; + }) + } + else { + authorString = json["authors"]; + } + ris += authorString; + + + // adding unique identifiers + // Accession Number + ris += "AN" + keyValueSeparator + (json["id"] || json["stid"]) + newline; + // DOI + if (json["doi"]) ris += "DO" + keyValueSeparator + json["doi"] + newline; + // URL + if (json["urls"] && json["urls"].length != 0) { + var urlstring = "" + json["urls"].forEach(function(url){ urlstring += "UR" + keyValueSeparator + url.trim() + newline}); + ris += urlstring; + } + + //all the pub time related info + // publishing year + ris += "PY" + keyValueSeparator + json["year"] + newline; + if (json["month"]) ris += "DA" + keyValueSeparator + json["year"] + "/" + json["month"] + "//" + newline; + + // all the journal related fields + if (json["journal"]) ris += "JO" + keyValueSeparator + json["journal"] + newline; + if (json["number"]) ris += "IS" + keyValueSeparator + json["number"] + newline; + if (json["volume"]) ris += "VL" + keyValueSeparator + json["volume"] + newline; + if (json["issn"]) ris += "SN" + keyValueSeparator + json["issn"] + newline; + if (json["pages"]) ris += "SP" + keyValueSeparator + json["pages"] + newline; + + // end of RIS document + ris += "ER" + keyValueSeparator + newline; + + return ris; +} + +// takes a json and converts that into a BibTeX string +// BibTe files specs were taken from: +// LaTeX - User's Guide and Reference Manual-lamport94.pdf, Appendix B +// https://www.economics.utoronto.ca/osborne/latex/BIBTEX.HTM +// https://en.wikipedia.org/wiki/BibTeX +function convertJSONToBibTeX(json) { + var newline = "\n" + var openBracket = "{" + var closeBracket = "}"; + var comma = "," + var endLine = closeBracket + comma + newline; + var space = " "; + var and = "and"; + + // start bibtex document + // IMPORTANT: DISCUSS THE TYPE WRT PATHWAY. WOULD THE TYPE BE ARTICLE FOR PATHWAY AS WELL? + // https://tex.stackexchange.com/questions/3587/how-can-i-use-bibtex-to-cite-a-web-page + var bibtex = "@" + json["type"] + openBracket + json["id"] + comma + newline; + + bibtex += "Title = " + openBracket + json["title"] + endLine; // added title + + // prepping author string + var authorString = ""; + if (json["authors"] instanceof Array) { + var authors = json["authors"].map(function(author) { + return author["lastName"] + comma + space + (author["firstName"] || author["initials"]); + }) + + authorString = authors.join(space + and + space) + } + else { + authorString = json["authors"]; + } + + bibtex += "Author = " + openBracket + authorString + endLine; + + // all the journal related info + if (json["journal"]) bibtex += "Journal = " + openBracket + json["journal"] + endLine; + if (json["number"]) bibtex += "Number = " + openBracket + json["number"] + endLine; + if (json["volume"]) bibtex += "Volume = " + openBracket + json["volume"] + endLine; + if (json["issn"]) bibtex += "ISSN = " + openBracket + json["issn"] + endLine; + if (json["pages"]) bibtex += "Pages = " + openBracket + json["pages"] + endLine; + + // all the pub time related info + bibtex += "Year = " + openBracket + json["year"] + endLine; + if (json["month"]) bibtex += "Month = " + openBracket + json["month"] + endLine; + + // any unique identifiers + if (json["doi"]) bibtex += "DOI = " + openBracket + json["doi"] + endLine; + if (json["urls"] && json["urls"].length != 0) bibtex += "URL = " + openBracket + json["urls"][0] + endLine; + + // end bibtex document + bibtex += closeBracket; + + return bibtex; +} diff --git a/templates/favourite/css/custom.css b/templates/favourite/css/custom.css index f09c2799b..fe53bcb95 100644 --- a/templates/favourite/css/custom.css +++ b/templates/favourite/css/custom.css @@ -792,6 +792,30 @@ video.responsive-vid { color: red !important; } + +fieldset { + overflow: hidden + } + + .list-radio-button-class { + float: left; + clear: none; + } + + label { + float: left; + clear: none; + display: block; + padding: 0px 1em 0px 8px; + } + + input[type=radio], + input.radio { + float: left; + clear: none; + margin: 2px 0 0 2px; + } + @media only screen and (min-width: 992px) and (max-width: 1200px) { .twitter-timeline { height: 568px !important; diff --git a/templates/favourite/index.php b/templates/favourite/index.php index 5eb1ee9a8..4b8a2d6e6 100644 --- a/templates/favourite/index.php +++ b/templates/favourite/index.php @@ -526,19 +526,7 @@ function gtag(){dataLayer.push(arguments)}; - countModules('cite-me')) { ?> - - - + countModules('cite-us')) { ?> @@ -552,19 +540,41 @@ function gtag(){dataLayer.push(arguments)};
- +
- + From f03d0d54cb9945e6e3f8de15992eaaddc8b184f2 Mon Sep 17 00:00:00 2001 From: Yusra Haider Date: Tue, 10 Mar 2020 11:25:54 +0000 Subject: [PATCH 03/23] fixed an accidental typo --- templates/favourite/citation-query.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/favourite/citation-query.js b/templates/favourite/citation-query.js index c7454d32e..ab6ee3217 100644 --- a/templates/favourite/citation-query.js +++ b/templates/favourite/citation-query.js @@ -35,7 +35,7 @@ var PATHWAY_CITATION_REQUEST_RESPONSE = { text: { parseResponse: function(response) { var windowLocation = window.location; - var authors = response["authorsxf"].map(function(author) { + var authors = response["authors"].map(function(author) { return author["lastName"] + "," + " " + author["initials"]; }); // checking that authors key exists, the value is not undefined or null and the list is not empty @@ -216,7 +216,7 @@ function exportCitation() { function enableExportCitationButton() { jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].disabled = false; // refactor code so that so that a custom css class can get made for disabled and enabled buttons - jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].style["cursor"] = "default"; + //jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].style["cursor"] = "default"; } From 3de57c98a8e19758a95efe62c12d6951d7ce9852 Mon Sep 17 00:00:00 2001 From: Yusra Haider Date: Tue, 10 Mar 2020 11:26:43 +0000 Subject: [PATCH 04/23] uncommented an loc --- templates/favourite/citation-query.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/favourite/citation-query.js b/templates/favourite/citation-query.js index ab6ee3217..b5102bd90 100644 --- a/templates/favourite/citation-query.js +++ b/templates/favourite/citation-query.js @@ -216,7 +216,7 @@ function exportCitation() { function enableExportCitationButton() { jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].disabled = false; // refactor code so that so that a custom css class can get made for disabled and enabled buttons - //jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].style["cursor"] = "default"; + jQuery("#myModal").find(".modal-body").find("#exportCitationForm").find("#exportCitationButton")[0].style["cursor"] = "default"; } From 8658199f1da55b1e10d973d151e0a48b1800dde8 Mon Sep 17 00:00:00 2001 From: Yusra Haider Date: Tue, 10 Mar 2020 16:26:28 +0000 Subject: [PATCH 05/23] fixed a few bugs --- templates/favourite/citation-query.js | 35 ++++++++++++--------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/templates/favourite/citation-query.js b/templates/favourite/citation-query.js index b5102bd90..e67a5e672 100644 --- a/templates/favourite/citation-query.js +++ b/templates/favourite/citation-query.js @@ -35,25 +35,23 @@ var PATHWAY_CITATION_REQUEST_RESPONSE = { text: { parseResponse: function(response) { var windowLocation = window.location; - var authors = response["authors"].map(function(author) { - return author["lastName"] + "," + " " + author["initials"]; - }); + + // default value + var authorCitation = "The Reactome Consortium";; + // checking that authors key exists, the value is not undefined or null and the list is not empty - var authorCitation = ""; + if (response["authors"] && response["authors"].length > 0) { + var authors = response["authors"].map(function(author) { + return author["lastName"] + "," + " " + author["initials"]; + }); - if (authors && authors.length > 0) { authorCitation = authors[authors.length-1]; if (authors.length > 1) { - authors.slice(0, authors.length-1).join(" , ").concat(" & ", authorCitation); + authorCitation = authors.slice(0, authors.length-1).join(" , ").concat(" & ", authorCitation); } } - else { - authorCitation = "The Reactome Consortium"; - } - - var doi = response["doi"]; // checking that doi key exists and the value is not undefined or null @@ -316,11 +314,11 @@ function preprocessForExport(json) { citationDetails["doi"] = json["doi"]; citationDetails["urls"] = [DOI_BASE_URL.concat(json["doi"])]; } - else if (json["stid"]) - citationDetails["urls"] = (citationDetails["urls"]) ? citationDetails.push(window.location.href) : [].push(window.location.href); + if (json["stid"]) + (citationDetails["urls"]) ? citationDetails["urls"].push(window.location.href) : citationDetails["urls"] = [window.location.href]; citationDetails["authors"] = (json["authorList"] || {})["author"] || json["authors"] || "The Reactome Consortium"; - citationDetails["type"] = (!!json["isPathway"]) ? EXPORT_FORMATS["BIBTEX"]["web"] : EXPORT_FORMATS["BIBTEX"]["journal"]; + citationDetails["isPathway"] = json["isPathway"]; return citationDetails; } @@ -362,7 +360,7 @@ function convertJSONToRIS(json) { var newline = "\n"; // start the RIS document - var ris = "TY" + keyValueSeparator + json["type"] + newline; + var ris = "TY" + keyValueSeparator + (!!json["isPathway"] ? EXPORT_FORMATS["RIS"]["web"] : EXPORT_FORMATS["RIS"]["journal"]) + newline; // adding the title ris += "TI" + keyValueSeparator + json["title"] + newline @@ -372,12 +370,11 @@ function convertJSONToRIS(json) { if (json["authors"] instanceof Array) { json["authors"].forEach(function(author) { authorString += "AU" + keyValueSeparator + - author["lastName"] + comma + space + (author["firstName"] || author["initials"]) + - newline; + author["lastName"] + comma + space + (author["firstName"] || author["initials"]) + newline; }) } else { - authorString = json["authors"]; + authorString = "AU" + keyValueSeparator + json["authors"] + newline; } ris += authorString; @@ -429,7 +426,7 @@ function convertJSONToBibTeX(json) { // start bibtex document // IMPORTANT: DISCUSS THE TYPE WRT PATHWAY. WOULD THE TYPE BE ARTICLE FOR PATHWAY AS WELL? // https://tex.stackexchange.com/questions/3587/how-can-i-use-bibtex-to-cite-a-web-page - var bibtex = "@" + json["type"] + openBracket + json["id"] + comma + newline; + var bibtex = "@" + (!!json["isPathway"] ? EXPORT_FORMATS["BIBTEX"]["web"] : EXPORT_FORMATS["BIBTEX"]["journal"]) + openBracket + json["id"] + comma + newline; bibtex += "Title = " + openBracket + json["title"] + endLine; // added title From d82c548b2c7104a92f1d31051f2a57d046ae9c5b Mon Sep 17 00:00:00 2001 From: Yusra Haider Date: Thu, 12 Mar 2020 16:20:06 +0000 Subject: [PATCH 06/23] added an important fix for a bug where the modal was interfering with the menu --- templates/favourite/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/favourite/index.php b/templates/favourite/index.php index 4b8a2d6e6..6b4fc6f9d 100644 --- a/templates/favourite/index.php +++ b/templates/favourite/index.php @@ -530,7 +530,7 @@ function gtag(){dataLayer.push(arguments)}; -