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:client_coding:javascript_api [2019/01/22 00:34] – [Zotero JavaScript API] dstillmandev:client_coding:javascript_api [2019/01/22 04:37] dstillman
Line 1: Line 1:
-<html><p id="zotero-5-update-warning" style="color: red; font-weight: bold">We’re 
-in the process of updating the documentation for 
-<a href="https://www.zotero.org/blog/zotero-5-0">Zotero 5.0</a>. Some documentation 
-may be outdated in the meantime. Thanks for your understanding.</p></html> 
- 
- 
 ====== Zotero JavaScript API ====== ====== Zotero JavaScript API ======
  
Line 11: Line 5:
 Note that the (mostly user-contributed) documentation of the JavaScript API is not comprehensive. If you use the JavaScript API in ways beyond what's described here, please consider expanding this wiki page. Note that the (mostly user-contributed) documentation of the JavaScript API is not comprehensive. If you use the JavaScript API in ways beyond what's described here, please consider expanding this wiki page.
  
-===== Helpful Resources ===== 
  
-For this section, you’ll likely find the following helpful:+===== Running Ad Hoc JavaScript in Zotero =====
  
-  * A basic understanding of how to create a Firefox extension +Zotero 5.0.61 and later include an option to run arbitrary privileged JavaScript:
-    * [[http://developer.mozilla.org|The Mozilla Developer Center]] (including [[http://developer.mozilla.org/en/docs/Building_an_Extension|Building an Extension]]) +
-    * [[https://developer.mozilla.org/en/Setting_up_extension_development_environment|Setting up an extension development environment]] +
-  * A decent grasp of object-oriented JavaScript +
-    * [[http://javascript.crockford.com/private.html|public, private and privileged methods and members]]; object literal notation; closures +
-    * [[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference|MDC Core JavaScript 1.5 Reference]] (also note [[http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6|New in JavaScript 1.6]] and [[http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7|New in JavaScript 1.7]])+
  
-===== An Easy Debugging Environment =====+  - In the Advanced pane of the Zotero preferences, select Config Editor, and then set ''devtools.chrome.enabled'' to ''true'' and restart Zotero. 
 +  - In the Tools menu, select Run JavaScript. Open the Error Console, which also appears in Tools, will also be helpful. 
 +  - In the window that opens, enter JavaScript in the Code textbox and click Run or press Cmd-R/Ctrl-R.
  
-Various Firefox extensions create servers within Firefox that expose the internal Firefox environmentincluding Zotero internalsThese can be used as shells for easy experimentationThese include:+To run asynchronous code, check the "Run as async function" checkbox. This runs the entered code wrapped in an [[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function|async function]]allowing you to use ''await'' to wait for the resolution of promises returned by functions. Most Zotero functions that access the database, disk, or network are asynchronousIn this mode, the value of a ''return'' statement will be displayed in the right-hand pane upon successful completion.
  
-  * [[https://addons.mozilla.org/en-US/firefox/addon/execute-js/|ExecuteJS]] +In synchronous mode, the value of the final line will appear in the right-hand pane.
-  * [[http://davidkellogg.com/wiki/Main_Page|Plain Old Webserver]] (POW) - [[http://github.com/singingfish/zotero-browser|Zotero Browser]] is an example of getting POW to interact with Zotero to create rich annotated bibliographies. +
-  * [[http://wiki.github.com/bard/mozrepl/|MozRepl]] - interactive shellavailable by telnetting to localhost on port 4242 (by default). Linux and Mac OS X users can use the built in telnet client. Windows users should use [[http://www.chiark.greenend.org.uk/~sgtatham/putty/|Putty]]. There is also a Firefox plugin to provide MozRepl access [[http://ubik.cc/2009/09/mozrepl-in-a-panel.html|directly inside Firefox]]. +
-    * **Potential MozRepl Problems**: Longer scripts can time out non-deterministically. A solution to this is to either send the code to the terminal application in smaller sized chunks, or to keep pasting the code in until it works.  Use an external library (like CPAN's MozRepl module) for finer grained control.   Syntax errors can cause silent failure. Avoid this by avoiding excessively long blocks of procedural code factor everything into smaller functions wherever possible.+
  
-Perl programmers should be aware of the [[http://search.cpan.org/perldoc?MozRepl|MozRepl]] CPAN moduleand the closely related [[http://search.cpan.org/perldoc?MozRepl::RemoteObject|MozRepl::RemoteObject]] which allows you to access JavaScript objects from inside Perl programs.+(Before Zotero 5.0.61 is releasedyou'll need to install the [[:dev_builds|Zotero beta]] to use this feature.)
  
 +===== Zotero Code Architecture =====
  
-===== The Zotero Object ====+==== Window Scope vs. Non-Window Scope ===
  
-Zotero exposes an object-oriented JavaScript API that can be used to access and modify Zotero data. Within Zotero itself, most SQL statements are limited to the data layer, with all other elements (including the entire UI) using the data API to access the data. Through the base Zotero XPCOM service, this functionality is available to all privileged code in Firefox, including other loaded extensions.+Zotero code exists in either window scope and non-window scope.
  
-==== XPCOM ====+Window scope applies to code that runs within either the main Zotero window or a secondary window (e.g., the Advanced Search window). It has access to the window's DOM and can interact with the UI. The main window-scope object in Zotero is ''ZoteroPane'', from zoteroPane.js, which controls most interactions triggered in the main Zotero window.
  
-A common problem in developing Mozilla extensions is figuring out how to pass data between different windows, which have their own scopes and do not by default share the same variables and code. While there are various mechanisms to get around this, the [[http://developer.mozilla.org/en/docs/Working_with_windows_in_chrome_code#Using_an_XPCOM_singleton_component|recommended method]], and the method used by Zotero, is to use an XPCOM singleton component to store common data, which can then be accessed from any window that imports the component(XPCOM is the //cross-platform component object model//---the framework---that forms the basis for the Mozilla application environment.)+Non-window scope applies to lower-level code that doesn'have access to the DOMThis includes the core ''Zotero'' object, which contains all other non-window code, including the data layer used for retrieving and modifying library dataIn Zotero, non-window code is contained within the ''xpcom'' subdirectory.
  
-The base Zotero service is an XPCOM component written in JavaScript. While normally XPCOM components implement various predefined interfaces themselves, in Zotero the data layer and most of the core functionality are stored within a JavaScript object that is then stuffed into the special ''wrappedJSObject'' property of the component. The component itself does not define any XPCOM interfaces. (This is vaguely a hack, but it addresses our needs sufficiently and is an approach used by several other extensions.) Chrome overlays and windows in Zotero import the core object via the script include.js, which calls ''getService()'' on the component and assigns the wrapped object to the variable ''Zotero''. Zotero methods can then be called from anywhere within the windows scope simply by calling, for example, ''var item = Zotero.Items.get(1)''.+Overlays and windows in Zotero can import the core ''Zotero'' object via the include.js script. Zotero methods can then be called from anywhere within the window's scope simply by calling, for example, ''var item = Zotero.Items.get(1);''.
  
-Access to the Zotero service is not limited to Zotero itself, howeverAs a standard XPCOM component, the Zotero service---and, specifically, the wrapped JavaScript object---can be accessed from anywhere within privileged code, including other loaded extensions.+To access Zotero functionality from your own extension, you will need access to the core ''Zotero'' objectIf your extension operates within the main browser overlayyou already have access to the ''Zotero'' object and don’t need to take further steps. Otherwiseyou can import the Zotero object into other windows by including the script %%chrome://zotero/content/include.js%% within an HTML or XUL file:
  
-To access the data API in your own extension, you will need access to the core Zotero JavaScript object. If your extension operates within the main browser overlay, you already have access to the ''Zotero'' object and don’t need to take further steps. Otherwise, you can import the Zotero object into other windows either by including the script %%chrome://zotero/content/include.js%% within a XUL file (recommended) or by manually calling ''getService()'' directly on the Zotero XPCOM service and assigning the wrapped JS object to a variable.+<code html> 
 +<script src="chrome://zotero/content/include.js"><script> 
 +</code>
  
-%%chrome://zotero/content/include.js:%%+Once you have ''Zotero'', you can get the current ''ZoteroPane'' object:
 <code javascript> <code javascript>
-var Zotero Components.classes["@zotero.org/Zotero;1"] +var zp = Zotero.getActiveZoteroPane(); 
- .getService(Components.interfaces.nsISupports+var items = zp.getSelectedItems()
- .wrappedJSObject+</code>  
-</code>+(The Zotero pane will always be available unless the main window is closed, as is possible on macOS.)
  
-===== Notification System =====+==== Notification System ====
  
-Zotero has a built-in notification system that allows other privileged code to be notified when a change is made via the data layer---for example, when an item is added to the library. Within Zotero itself, this is used mostly to update the UI when items change, but external extensions can use the system to perform additional operations when specific events occur---say, to sync item metadata with a web-based tool.+Zotero has a built-in notification system that allows other privileged code to be notified when a change is made via the data layer — for example, when an item is added to the library. Within Zotero itself, this is used mostly to update the UI when items change, but extensions can use the system to perform additional operations when specific events occur — say, to sync item metadata with a web-based API.
  
 Available events: Available events:
Line 74: Line 64:
  
 //The Zotero JavaScript API is under-documented, and at present requires a lot of looking around in the source code.  The most useful parts of the source code are in chrome/content/zotero/xpcom and xpcom/data, and the chrome/content/zotero (particularly zoteroPane.js and fileInterface.js).// //The Zotero JavaScript API is under-documented, and at present requires a lot of looking around in the source code.  The most useful parts of the source code are in chrome/content/zotero/xpcom and xpcom/data, and the chrome/content/zotero (particularly zoteroPane.js and fileInterface.js).//
- 
-Once you have access to the core Zotero object, you can use the objects and methods provided by the Zotero JavaScript API. 
- 
-Zotero uses a combination of instantiatable objects (e.g. ''Zotero.Item = function(){...}'') and singletons (''Zotero.Items = **new** function(){...}''). The most important example of the former is ''Zotero.Item'', which represents a single item in the database. Singletons are used mostly to group related static methods into a single namespace. 
  
 ==== Adding items and modifying data ==== ==== Adding items and modifying data ====
  
-A typical operation might include a call to ''Items.get()'' to retrieve an ''Item'' instance, calls to ''Item'' methods on the retrieved object to modify data, and finally a ''save()'' to save the modified data to the database.+A typical operation might include a call to ''Zotero.Items.get()'' to retrieve ''Zotero.Item'' instance, calls to ''Zotero.Item'' methods on the retrieved object to modify data, and finally a ''save()'' (within a transaction) or ''saveTx()'' (outside a transaction) to save the modified data to the database.
  
 <code javascript> <code javascript>
-var creator = new Zotero.Creator; +var item = new Zotero.Item('book');
-creator.firstName = 'William'; +
-creator.lastName = 'Shakespeare'; +
-creator.save(); +
- +
-var item = new Zotero.Item+
-item.setType(Zotero.ItemTypes.getID('book'));+
 item.setField('title', 'Much Ado About Nothing'); item.setField('title', 'Much Ado About Nothing');
-item.setCreator(0creator'author'); +item.setCreators( 
-var itemID = item.save();+    [ 
 +        { 
 +            firstName: "William", 
 +            lastName: "Shakespeare", 
 +            creatorType: "author
 +        } 
 +    ] 
 +); 
 +var itemID = await item.save()
 +return itemID;
 </code> </code>
  
Line 105: Line 94:
 alert(item.getCreator(0)); // {'firstName'=>'William', 'lastName'=>'Shakespeare', alert(item.getCreator(0)); // {'firstName'=>'William', 'lastName'=>'Shakespeare',
                            //   'creatorTypeID'=>1, 'fieldMode'=>0}                            //   'creatorTypeID'=>1, 'fieldMode'=>0}
 +// Alternative format
 +alert(item.getCreatorJSON(0)); // {'firstName'=>'William', 'lastName'=>'Shakespeare',
 +                           //   'creatorType'=>'author'}
 +
 item.setField('place', 'England'); item.setField('place', 'England');
 item.setField('date', 1599); item.setField('date', 1599);
-item.save(); // update database with new data+await item.saveTx(); // update database with new data
  
 </code> </code>
  
-==== Create new Zotero object ==== +==== Get the Zotero Pane to interact with the Zotero UI ====
- +
-This is the first thing that you need to do when interacting with Zotero'+
-internals.  The code to do so is:+
  
 <code javascript> <code javascript>
-var Zotero Components.classes["@zotero.org/Zotero;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;+var ZoteroPane = Zotero.getActiveZoteroPane();
 </code> </code>
  
-==== Get the Zotero Pane to interact with the Zotero GUI ====+Then grab the currently selected items from the Zotero pane:
  
 <code javascript> <code javascript>
-var ZoteroPane = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow("navigator:browser").ZoteroPane; +// Get first selected item 
-</code> +var selectedItems = ZoteroPane.getSelectedItems(); 
- +var item = selectedItems[0];
-Then grab the currently selected items from the zotero pane: +
- +
-<code javascript> +
-//get first selected item +
-var selected_items = ZoteroPane.getSelectedItems(); +
-var item = selected_items[0];+
  
-// proced if selected item is neither a collection nor a note +// Proceed if an item is selected and it isn'a note 
-if ( item.isCollection() & ! item.isNote()) {+if (item && !item.isNote()) {
     if (item.isAttachment()) {     if (item.isAttachment()) {
         // find out about attachment         // find out about attachment
     }     }
     if (item.isRegularItem()) {     if (item.isRegularItem()) {
-        // we could grab attachments: +        // We could grab attachments: 
-        // var att_ids = item.getAttachments(false); +        // let attachmentIDs = item.getAttachments(); 
-        // if (att_ids.length>1) exit(); // bailout +        // let attachment = Zotero.Items.get(attachmentIDs[0]);
-        // item_att=Zotero.Items.get(att_ids[0]);+
     }     }
     alert(item.id);     alert(item.id);
Line 148: Line 131:
 </code> </code>
  
-==== Setup a Zotero search ====+==== Collection Operations ====
  
-If you are focused on data access, then the first thing you will want to do +=== Get the items in the selected collection ===
-will be to retrieve items from your Zotero.  Creating an in-memory search is a +
-good start.+
  
-<code javascript>    var search new z.Search(); </code>+<code javascript> 
 +var collection ZoteroPane.getSelectedCollection(); 
 +var items = collection.getChildItems(); 
 +// or you can obtain an array of itemIDs instead: 
 +var itemIDs = collection.getChildItems(true); 
 +</code>
  
-====  Search for items containing specific tag ====+=== Create subcollection of the selected collection ===
  
-Starting with the code from "Setup a Zotero search" we then use the following +<code javascript> 
-code to retrieve items with a particular tag:+var currentCollection = ZoteroPane.getSelectedCollection(); 
 +var collection = new Zotero.Collection(); 
 +collection.name = name; 
 +collection.parentID = currentCollection.id; 
 +var collectionID = await collection.saveTx(); 
 +return collectionID; 
 +</code>
  
-<code javascript>    search.addCondition('tag', 'is', 'tag name here');</code>+==== Zotero Search Basics ====
  
-==== Zotero Collection Operations ==== +If you are focused on data access, the first thing you will want to do 
- +will be to retrieve items from your Zotero library. Creating an in-memory search is a 
-=== Get the collection tree and display as a series of nested ordered lists === +good start.
- +
-This code was developed in the Firefox extension Plain Old Webserver server side JavaScript.  Note that it'recursive function. With a bit of jQuery the nested ordered list can be easily transformed into a tree widget.+
  
 <code javascript> <code javascript>
-var Zotero Components.classes["@zotero.org/Zotero;1".getService(Components.interfaces.nsISupports).wrappedJSObject+var new Zotero.Search(); 
- +s.libraryID = Zotero.Libraries.userLibraryID;
-var render_collection = function(coll) { +
-    if (!coll) {  +
-        coll = null;  +
-    } +
-    var collections = Zotero.getCollections(coll); +
-    document.writeln("<ul>"); +
-    for (c in collections) { +
-        document.writeln('<li>' + '<a href="view_collection.sjs?name=' + encodeURI(collections[c].name) + '&id=' + collections[c].id + '">' + collections[c].name  + '</a></li>'); +
-        if (collections[c].hasChildCollections) { +
-    var childCol = render_collection(collections[c].id); +
-        } +
-    }    +
-    document.writeln("</ul>"); +
-+
- +
-render_collection();+
 </code> </code>
  
-=== Get the items for a particular collection ===+=== Search for items containing specific tag ===
  
-<code javascript> +Starting with the above code, we then use the following code to retrieve items in My Library with particular tag:
-var Zotero = Components.classes["@zotero.org/Zotero;1"] .getService(Components.interfaces.nsISupports).wrappedJSObject; +
-var collectionid = pow_server.GET.id; // or some other way of finding the collectionID here +
-var collection = z.Collections.get(collectionid); +
-var items = collection.getChildItems(); +
-// or you can obtain an array of itemIDs instead: +
-var itemids = collection.getChildItems(true); +
-</code+
- +
-=== Create a New Collection in a function ===+
  
 <code javascript> <code javascript>
-async function createCollection(name) { +s.addCondition('tag', 'is', 'tag name here'); 
-    var currentCollection = ZoteroPane.getSelectedCollection(); +var itemIDs = await s.search();
-    var collection = new Zotero.Collection(); +
-    collection.name = name; +
-    collection.parentID = currentCollection.id; +
-    var collectionID = await collection.saveTx(); +
-    return collectionID; +
-}+
 </code> </code>
  
-This function creates a new collection with a given name and makes +=== Advanced searches ===
-it a subcollection of the currently selected one. Since the saving +
-will result in a Promise object, we add the ''await'' before the +
-function call and make sure that this is within an ''async'' function. +
- +
-==== Zotero Search Basics ==== +
- +
-=== Set up the search ===+
  
 <code javascript> <code javascript>
 var s = new Zotero.Search(); var s = new Zotero.Search();
 +s.libraryID = Zotero.Libraries.userLibraryID;
 s.addCondition('joinMode', 'any'); // joinMode defaults to 'all' as per the  s.addCondition('joinMode', 'any'); // joinMode defaults to 'all' as per the 
-                                        // advanced search GUI+                                        // advanced search UI
 </code> </code>
  
-To add the other conditions available in the advanced search GUI, use the following:+To add the other conditions available in the advanced search UI, use the following:
  
 <code javascript> <code javascript>
Line 247: Line 200:
 === Search by collection === === Search by collection ===
  
-To search for a collection or a saved search you need to know the ID:+To search for a collection or a saved search you need to know the ID or key:
  
 <code javascript> <code javascript>
-s.addCondition('collectionID', 'is', collectionID);+s.addCondition('collectionID', 'is', collectionID); // e.g., 52
 s.addCondition('savedSearchID', 'is', savedSearchID); s.addCondition('savedSearchID', 'is', savedSearchID);
 +</code>
 +
 +<code javascript>
 +s.addCondition('collection', 'is', collectionKey); // e.g., 'C72FDAP2'
 +s.addCondition('savedSearch', 'is', savedSearchKey);
 </code> </code>
  
Line 259: Line 217:
  
 <code javascript> <code javascript>
-    var tagname = 'something'; +var tagName = 'something'; 
-    search.addCondition('tag', 'is', tagname);+s.addCondition('tag', 'is', tagName);
 </code> </code>
  
Line 272: Line 230:
 results: results:
  
-<code javascript>var results = search.search();</code>+<code javascript>var results = await s.search();</code>
  
-This returns the item ids in the search as an array [I could be wrong ... ]. +This returns the item ids in the search as an array. The next thing to do is to get the Zotero items for the array of IDs:
-The next thing to do is to get the Zotero items for the array of IDs:+
  
-<code javascript>var items = z.Items.get(results);</code>+<code javascript>var items = await Zotero.Items.getAsync(results);</code>
  
 ===== Managing citations and bibliographies ===== ===== Managing citations and bibliographies =====
Line 290: Line 247:
 First we start with a list of as in the previous entry. First we start with a list of as in the previous entry.
  
-<code javascript>  var qc = z.QuickCopy; +<code javascript>var qc = Zotero.QuickCopy; 
-  var biblio = qc.getContentFromItems(new Array(item), +var biblio = qc.getContentFromItems([item]Zotero.Prefs.get("export.quickCopy.setting")); 
-                                      z.Prefs.get("export.quickCopy.setting")); +var biblio_html_format = cite.html; 
-    var biblio_html_format = cite.html; +var biblio_txt  = cite.text; 
-    var biblio_txt         = cite.text; +
 </code> </code>
  
Line 300: Line 256:
  
 <code javascript>  <code javascript> 
-      var styles = zotero.Styles.getVisible(); +await Zotero.Schema.schemeUpdatePromise; 
-      var style_info = []; +var styles = Zotero.Styles.getVisible(); 
-      for each var s in styles) { +var styleInfo = []; 
-           style_info.push( { "ids.styleID, "names.title } ); +for (let style of styles) { 
-       +    styleInfo.push({ id: style.styleID, name: style.title }); 
-      JSON.stringify(style_info)// e.g. to return json from the mozrepl+
 +return styleInfo;
 </code> </code>
  
Line 318: Line 275:
 To get an item's abstract, we get the 'abstractNote' field from the Zotero item: To get an item's abstract, we get the 'abstractNote' field from the Zotero item:
  
-<code javascript>    var abstract = item.getField('abstractNote'); </code>+<code javascript>var abstract = item.getField('abstractNote');</code>
  
 ==== Get child notes for an item ==== ==== Get child notes for an item ====
Line 324: Line 281:
 To get the child notes for an item, we use the following code: To get the child notes for an item, we use the following code:
  
-<code javascript>     var notes = item.getNotes(); </code>+<code javascript>var noteIDs = item.getNotes();</code>
  
-This returns an array of notes.  Each note is in HTML format To get each note +This returns an array of ids of note items. To get each note in turn we just iterate through the array:
-in turn we just iterate through the array:+
  
 <code javascript> <code javascript>
-    for (var j=0;j<notes.length;j++) { +for (let id of noteIDs) { 
-        var note = z.Items.get(notes[j]); +    let note = Zotero.Items.get(id); 
-        var note_html = note.getNote(); +    let noteHTML = note.getNote(); 
-    +
 </code> </code>
  
 ==== Get an item's related items ==== ==== Get an item's related items ====
  
-This technique works for anything that can have related items attached within +<code javascript>var relatedItems = item.relatedItems;</code>
-the Zotero database.  This includes items and notes. +
- +
-<code javascript>  var related_items = item.relatedItems</code>+
  
 ==== Set two items as related to each other  ==== ==== Set two items as related to each other  ====
Line 354: Line 307:
  
  
-==== Get an Item'Attachments ===+==== Get an item'attachments ===
  
-Here's some example code to get the full text of HTML and PDF items in storage and puts the data in an array:+Here's some example code to get the full text of HTML and PDF items in storage and put the data in an array:
  
 <code javascript> <code javascript>
-var item = 'some item' // some Zotero Item obtained previously +var item = ZoteroPane.getSelectedItems()[0]
-var fulltext = new Array;+var fulltext = [];
 if (item.isRegularItem()) { // not an attachment already if (item.isRegularItem()) { // not an attachment already
-    var attachments selected_items[item].getAttachments(false); +    let attachmentIDs = item.getAttachments(); 
-    for (a in attachments) { +    for (let id of attachmentIDs) { 
-        var a_item = Zotero.Items.get(attachments[a]); +        let attachment = Zotero.Items.get(id); 
-        if (a_item.attachmentMIMEType == 'application/pdf' +        if (attachment.attachmentContentType == 'application/pdf' 
-            || a_item.attachmentMIMEType == 'text/html') { +                || attachment.attachmentContentType == 'text/html') { 
-            fulltext.push(a_item.attachmentText);+            fulltext.push(await attachment.attachmentText);
         }         }
     }     }
 } }
 +return fulltext;
 </code> </code>
  
Line 387: Line 341:
 The JavaScript API can provide a powerful way to script changes to your Zotero library. The common case of search-and-replace is accomplished easily using a basic script. The JavaScript API can provide a powerful way to script changes to your Zotero library. The common case of search-and-replace is accomplished easily using a basic script.
  
-Firstinstall the [[https://addons.mozilla.org/en-US/firefox/addon/execute-js/|Execute JS]] Firefox extension to interact with Zotero via JavaScript. (Advanced users can also use the Firefox Browser Console or Scratchpad in Browser mode after enable chrome/add-on debugging in the Web Console settings.) Back up your database first, and temporarily disable auto-sync in the Sync pane of the Zotero preferences+Before proceedingback up your [[:zotero_data|Zotero data directory]] and temporarily disable auto-sync in the Sync pane of the Zotero preferences.
- +
-In Execute JS, switch the target window to an open browser window, paste the relevant code into the "JS-Code to execute" box, make any necessary changes, and click "Execute".+
  
 ==== Example: Item Field Changes ==== ==== Example: Item Field Changes ====
Line 400: Line 352:
  
 var fieldID = Zotero.ItemFields.getID(fieldName); var fieldID = Zotero.ItemFields.getID(fieldName);
-var s = new Zotero.Search;+var s = new Zotero.Search(); 
 +s.libraryID = Zotero.Libraries.userLibraryID;
 s.addCondition(fieldName, 'is', oldValue); s.addCondition(fieldName, 'is', oldValue);
-var ids = s.search(); +var ids = await s.search(); 
-if (ids) { +if (!ids.length) { 
- for(var i in ids) { +    return "No items found";
- var item = Zotero.Items.get(ids[i]); +
- var mappedFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(item.itemTypeID, fieldName); +
- item.setField(mappedFieldID ? mappedFieldID : fieldID, newValue); +
- item.save(); +
-+
- alert(ids.length + " items updated");+
 } }
-else +await Zotero.DB.executeTransaction(async function () 
- alert("No items found"); +    for (let id of ids) { 
-}</code> +        let item = await Zotero.Items.getAsync(id); 
- +        let mappedFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(item.itemTypeID, fieldName); 
-The list of field names to use can be retrieved via the server API: https://api.zotero.org/itemFields?pprint=1.+        item.setField(mappedFieldID ? mappedFieldID : fieldID, newValue); 
 +        await item.save(); 
 +    
 +}); 
 +return ids.length + " item(s) updated";</code>
  
-==== ExampleDelete All Automatic Tags ====+The list of field names to use can be retrieved via the web API:
  
-<code javascript>var tagType = 1; // automatic +https://api.zotero.org/itemFields?pprint=1.
-Zotero.Tags.erase(Object.keys(Zotero.Tags.getAll([tagType])))</code>+
  
 ==== Example: Delete Tags By Name ==== ==== Example: Delete Tags By Name ====
 +
 +<html><p id="zotero-5-update-warning" style="color: red; font-weight: bold">This example has not been updated for Zotero 5 and should not currently be used.</p></html>
  
 <code javascript>var tags = ["foo", "bar", "baz"]; <code javascript>var tags = ["foo", "bar", "baz"];
Line 438: Line 390:
  
 ==== Example: Delete Tags By Part of Name ==== ==== Example: Delete Tags By Part of Name ====
 +
 +<html><p id="zotero-5-update-warning" style="color: red; font-weight: bold">This example has not been updated for Zotero 5 and should not currently be used.</p></html>
  
 <code javascript>var tags = ["foo", "bar", "baz"]; <code javascript>var tags = ["foo", "bar", "baz"];
dev/client_coding/javascript_api.txt · Last modified: 2022/07/02 18:22 by dstillman