Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
dev:translators:coding [2018/12/26 06:49] – Add proxy: false attachment flag dstillmandev:translators:coding [2021/11/18 18:29] – Mention translator template, improve code style, formatting abejellinek
Line 1: Line 1:
 ====== Writing Translator Code ====== ====== Writing Translator Code ======
  
-Below we will describe how the ''detect*'' and ''do*'' functions of Zotero [[dev/translators]] can and should be coded. If you are unfamiliar with JavaScript, make sure to check out a [[https://developer.mozilla.org/en/JavaScript/A_re-introduction_to_JavaScript|JavaScript tutorial]] to get familiar with the syntax. In addition to the information on this page, it can often be very informative to look at existing translators to see how things are done. A [[https://www.mediawiki.org/wiki/Citoid/Creating_Zotero_translators|particularly helpful guide]] with up-to-date recommendation on best coding practices is provided by the wikimedia foundation, whose tool Citoid uses Zotero translators.+Below we will describe how the ''detect*'' and ''do*'' functions of Zotero [[dev/translators]] can and should be coded. If you are unfamiliar with JavaScript, make sure to check out a [[https://developer.mozilla.org/en/JavaScript/A_re-introduction_to_JavaScript|JavaScript tutorial]] to get familiar with the syntax. In addition to the information on this page, it can often be very informative to look at existing translators to see how things are done. A [[https://www.mediawiki.org/wiki/Citoid/Creating_Zotero_translators|particularly helpful guide]] with up-to-date recommendation on best coding practices is provided by the Wikimedia Foundation, whose tool Citoid uses Zotero translators.
  
-While translators can be written with any text editor, the Zotero add-on [[dev/translators/scaffold|Scaffold]] can make writing them much easier, as it provides the option to test and troubleshoot translators relatively quickly.+While translators can be written with any text editor, the built-in [[dev/translators/scaffold|Translator Editor]] can make writing them much easier, as it provides the option to test and troubleshoot translators relatively quickly.
  
 +New web translators should use the Translator Editor's web translator template as a starting point. The template can be inserted in the Code tab: click the green plus dropdown and choose "Add web translator template".
  
 ====== Web Translators ====== ====== Web Translators ======
Line 10: Line 11:
 ===== detectWeb ===== ===== detectWeb =====
  
-''detectWeb'' is run to determine whether item metadata can indeed be retrieved from the webpage. The return value of this function should be the detected item type (e.g. "journalArticle", see the [[https://aurimasv.github.io/z2csl/typeMap.xml|overview of Zotero item types]]), or, if multiple items are found, "multiple".+''detectWeb'' is run to determine whether item metadata can indeed be retrieved from the webpage. The return value of this function should be the detected item type (e.g. "journalArticle", see the [[https://aurimasv.github.io/z2csl/typeMap.xml|overview of Zotero item types]]), or, if multiple items are found, "multiple". If no item(s) can be detected on the current page, return false.
  
-''detectWeb'' receives two argumentsthe webpage document object and URL (typically named ''doc'' and ''url''). In some cases, the URL provides all the information needed to determine whether item metadata is available, allowing for a simple ''detectWeb'' function, e.g. (example from ''Cell Press.js''):+''detectWeb'' receives two argumentsthe webpage document object and URL (typically named ''doc'' and ''url''). In some cases, the URL provides all the information needed to determine whether item metadata is available, allowing for a simple ''detectWeb'' function, e.g. (example from ''Cell Press.js''):
  
 <code javascript>function detectWeb(doc, url) { <code javascript>function detectWeb(doc, url) {
-  
  if (url.indexOf("search/results") != -1) {  if (url.indexOf("search/results") != -1) {
  return "multiple";  return "multiple";
- } else if (url.indexOf("content/article") != -1) {+ } 
 + else if (url.indexOf("content/article") != -1) {
  return "journalArticle";  return "journalArticle";
  }  }
 + return false;
 }</code> }</code>
  
Line 53: Line 55:
 Attachments may be saved alongside item metadata via the item object's ''attachments'' property. Common attachment types are full-text PDFs, links and snapshots. An example from "Pubmed Central.js": Attachments may be saved alongside item metadata via the item object's ''attachments'' property. Common attachment types are full-text PDFs, links and snapshots. An example from "Pubmed Central.js":
  
-<code javascript>var linkurl = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" + ids[i] + "/";+<code javascript>var linkURL = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" + ids[i] + "/";
 newItem.attachments = [{ newItem.attachments = [{
- url: linkurl,+ url: linkURL,
  title: "PubMed Central Link",  title: "PubMed Central Link",
  mimeType: "text/html",  mimeType: "text/html",
Line 61: Line 63:
 }]; }];
  
-var pdfurl = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" + ids[i] + "/pdf/" + pdfFileName;+var pdfURL = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" + ids[i] + "/pdf/" + pdfFileName;
 newItem.attachments.push({ newItem.attachments.push({
- title:"Full Text PDF", + title: "Full Text PDF", 
- mimeType:"application/pdf", + mimeType: "application/pdf", 
- url:pdfurl+ url: pdfURL
 });</code> });</code>
  
Line 73: Line 75:
 <code javascript> <code javascript>
 newItem.attachments.push({ newItem.attachments.push({
-title:"Snapshot", + title: "Snapshot", 
-document:doc});</code>+ document: doc 
 +});</code> 
 + 
 +When ''document'' is set, the MIME type will be set automatically.
  
 Zotero will automatically use proxied versions of attachment URLs returned from translators when the original page was proxied, which allows translators to construct and return attachment URLs without needing to know whether proxying is in use. However, some sites expect unproxied PDF URLs at all times, causing PDF downloads to potentially fail if requested via a proxy. If a PDF URL is extracted directly from the page, it's already a functioning link that's proxied or not as appropriate, and a translator should include ''proxy: false'' in the attachment metadata to indicate that further proxying should not be performed: Zotero will automatically use proxied versions of attachment URLs returned from translators when the original page was proxied, which allows translators to construct and return attachment URLs without needing to know whether proxying is in use. However, some sites expect unproxied PDF URLs at all times, causing PDF downloads to potentially fail if requested via a proxy. If a PDF URL is extracted directly from the page, it's already a functioning link that's proxied or not as appropriate, and a translator should include ''proxy: false'' in the attachment metadata to indicate that further proxying should not be performed:
Line 80: Line 85:
 <code javascript> <code javascript>
 item.attachments.push({ item.attachments.push({
- url:realpdf,+ url: realPDF,
  title: "EBSCO Full Text",  title: "EBSCO Full Text",
- mimeType:"application/pdf",+ mimeType: "application/pdf",
  proxy: false  proxy: false
 }); });
Line 89: Line 94:
 === Notes === === Notes ===
  
-Notes are saved similarly to attachments. The content of the note, which should consist of a string, should be stored in the ''note'' property of the item's ''notes'' property. A title, stored in the ''title'' property, is optional. E.g.:+Notes are saved similarly to attachments. The content of the note, which should consist of a string, should be stored in the ''note'' property of the item's ''notes'' property. E.g.:
  
-<code javascript>bbCite = "Bluebook citation: " + bbCite + "."; +<code javascript>let bbCite = "Bluebook citation: " + bbCite + "."; 
-newItem.notes.push({note:bbCite});</code>+newItem.notes.push({ note: bbCite });</code>
  
 === Related === === Related ===
Line 144: Line 149:
 === Item Selection === === Item Selection ===
  
-To present the user with a selection window that shows all the items that have been found on the webpage, a JavaScript object should be created. Then, for each item, an item ID and label should be stored in the object as a property/value pair. The item ID is used internally by the translator, and can be a URL, DOI, or any other identifier, whereas the label is shown to the user (this will usually be the item's title). Passing the object to the ''Zotero.selectItems'' function will trigger the selection window, and the function passed as the second argument will receive an object with the selected items, as in this example from the IMDb translator+To present the user with a selection window that shows all the items that have been found on the webpage, a JavaScript object should be created. Then, for each item, an item ID and label should be stored in the object as a property/value pair. The item ID is used internally by the translator, and can be a URL, DOI, or any other identifier, whereas the label is shown to the user (this will usually be the item's title). Passing the object to the ''Zotero.selectItems'' function will trigger the selection window, and the function passed as the second argument will receive an object with the selected items, as in this example: 
-<code javascript>Zotero.selectItems(items, function(items) { +<code javascript>Zotero.selectItems(getSearchResults(doc, false), function (items) { 
- if(!items) return true+    if (!items) return; 
- for (var i in items) { +    ZU.processDocuments(Object.keys(items), scrape);
- ids.push(i)+
-+
- apiFetch(ids);+
 });</code> });</code>
 Here, ''Zotero.selectItems(..)'' is called with an anonymous function as the callback. As in many translators, the selected items are simply loaded into an array and passed off to a processing function that makes requests for each of them. Here, ''Zotero.selectItems(..)'' is called with an anonymous function as the callback. As in many translators, the selected items are simply loaded into an array and passed off to a processing function that makes requests for each of them.
Line 156: Line 158:
 === Batch Saving === === Batch Saving ===
  
-You will often need to make additional requests to fetch all the metadata needed, either to make multiple items, or to get additional information on a single item. The most common and reliable way to make such requests is with the utility functions ''Zotero.Utilities.doGet'', ''Zotero.Utilities.doPost'', ''Zotero.Utilities.processDocuments''.+You will often need to make additional requests to fetch all the metadata needed, either to make multiple items, or to get additional information on a single item. The most common and reliable way to make such requests is with the utility functions ''Zotero.Utilities.doGet'', ''Zotero.Utilities.doPost'', and ''Zotero.Utilities.processDocuments''.
  
 ''Zotero.Utilities.doGet(url, callback, onDone, charset)'' sends a GET request to the specified URL or to each in an array of URLs, and then calls function ''callback'' with three arguments: response string, response object, and the URL. This function is frequently used to fetch standard representations of items in formats like RIS and BibTeX. The function ''onDone'' is called when the input URLs have all been processed. The optional ''charset'' argument forces the response to be interpreted in the specified character set. ''Zotero.Utilities.doGet(url, callback, onDone, charset)'' sends a GET request to the specified URL or to each in an array of URLs, and then calls function ''callback'' with three arguments: response string, response object, and the URL. This function is frequently used to fetch standard representations of items in formats like RIS and BibTeX. The function ''onDone'' is called when the input URLs have all been processed. The optional ''charset'' argument forces the response to be interpreted in the specified character set.
Line 171: Line 173:
 <code javascript> <code javascript>
 var line; var line;
-while((line = Zotero.read()) !== false)) {+while ((line = Zotero.read()) !== false)) {
       // Do something       // Do something
 } }
Line 210: Line 212:
 If ''configOptions'' in [[dev:translators#metadata|the translator metadata]] has the ''getCollections'' attribute set to ''true'', the ''Zotero.nextCollection()'' call will be available. It provides collection objects like those created on import. If ''configOptions'' in [[dev:translators#metadata|the translator metadata]] has the ''getCollections'' attribute set to ''true'', the ''Zotero.nextCollection()'' call will be available. It provides collection objects like those created on import.
 <code javascript> <code javascript>
-while(collection = Zotero.nextCollection()) {+while (collection = Zotero.nextCollection()) {
         // Do something         // Do something
 } }
Line 227: Line 229:
 <code javascript> <code javascript>
 function detectSearch(item) { function detectSearch(item) {
-        if(item.itemType === "journalArticle" || item.DOI) {+        if (item.itemType === "journalArticle" || item.DOI) {
                 return true;                 return true;
         }         }
Line 238: Line 240:
 ===== Utility Functions ===== ===== Utility Functions =====
  
-Zotero provides several [[https://github.com/zotero/zotero/blob/4.0/chrome/content/zotero/xpcom/utilities.js|utility functions]] for translators to use. Some of them are used for asynchronous and synchronous HTTP requests; those are [[#batch_saving|discussed above]]. In addition to those HTTP functions and the many standard functions provided by JavaScript, Zotero provides:+Zotero provides several [[https://github.com/zotero/zotero/blob/master/chrome/content/zotero/xpcom/utilities.js|utility functions]] for translators to use. Some of them are used for asynchronous and synchronous HTTP requests; those are [[#batch_saving|discussed above]]. In addition to those HTTP functions and the many standard functions provided by JavaScript, Zotero provides:
   * ''Zotero.Utilities.capitalizeTitle(title, ignorePreference)''\\ Applies English-style title case to the string, if the capitalizeTitles [[/support/hidden_prefs|hidden preference]] is set. If ''ignorePreference'' is true, title case will be applied even if the preference is set to false. This function is often useful for fixing capitalization of personal names, in conjunction with the built-in string method ''text.toLowerCase()''.   * ''Zotero.Utilities.capitalizeTitle(title, ignorePreference)''\\ Applies English-style title case to the string, if the capitalizeTitles [[/support/hidden_prefs|hidden preference]] is set. If ''ignorePreference'' is true, title case will be applied even if the preference is set to false. This function is often useful for fixing capitalization of personal names, in conjunction with the built-in string method ''text.toLowerCase()''.
   * ''Zotero.Utilities.cleanAuthor(author, creatorType, hasComma)''\\ Attempts to split the given string into firstName and lastName components, splitting on a comma if desired and performs some clean-up (e.g. removes unnecessary white-spaces and punctuation). The creatorType (see the [[http://gimranov.com/research/zotero/creator-types|list of valid creator types]] for each item type) will be just passed trough. Returns a creator object of the form: ''{ lastName: , firstName: , creatorType: }'', which can for example used directly in ''item.creators.push()'' as argument.   * ''Zotero.Utilities.cleanAuthor(author, creatorType, hasComma)''\\ Attempts to split the given string into firstName and lastName components, splitting on a comma if desired and performs some clean-up (e.g. removes unnecessary white-spaces and punctuation). The creatorType (see the [[http://gimranov.com/research/zotero/creator-types|list of valid creator types]] for each item type) will be just passed trough. Returns a creator object of the form: ''{ lastName: , firstName: , creatorType: }'', which can for example used directly in ''item.creators.push()'' as argument.
dev/translators/coding.txt · Last modified: 2023/08/04 01:14 by dstillman