Skip to content

{ zotero“” } Search Results

Zotz and the limitations of the Zotero plugin framework

Zotz Developer's Guide – SIMILE has a useful warning to all who work on developing Zotero plugins:

Zotz is a Zotero add-on, but it's written as a regular Firefox extension: the nature of firefox extensions all living in the same address space allows extensions to invoke each other internal methods, which means that Zotz can extend Zotero without Zotero having to expose special APIs for this.

While this is a very powerful mechanism, it is also insecure and fragile.

Insecure because it allows potentially malicious extensions to do act uncontrolled inside your browser (stealing your data and/or altering the browser or the extensions' own activities) and fragile because Zotero might change internal APIs not knowing that Zotz dependend on them and would immediately break Zotz functionality.

There is currently no better way to do things so we're stuck with it for the time being, but being aware of the situation helps forecast future development needs and potential issues that could arise.

Tagged , ,

copying to clipboard Zotero citations as HTML w/ chickenfoot

Here's a first pass at a Chickenfoot script that copies selected Zotero items as HTML to the clipboard.  (I couldn't find anything in the Zotero interface to do exactly this function.  There is a  Create Bibliography from Selected Item(s)->Copy to Clipboard but that seems to copy citations as RTF for me.)

var Zotero = chromeWindow.Zotero;
var ZoteroPane = chromeWindow.ZoteroPane;
var zfi = chromeWindow.Zotero_File_Interface;

// zfi.bibliographyFromItems();

// create the bibliography out of the default style 
// and copy directly to clipboard w/o any popup windows.

// get the default style
var style=Zotero.Prefs.get("export.lastStyle");

// e.g., http://www.zotero.org/styles/chicago-note-bibliographystyle

var items = ZoteroPane.getSelectedItems();
zfi.copyItemsToClipboard(items, style);

For more details, you can look at how Zotero_File_Interface is defined in v 1.0.9 to study copyItemsToClipboard.

Tagged ,

studying sync.js to (start) to understand how Zotero does synchronization

This morning I was studying how Zotero performs synchronization among libraries distributed in different Firefox profiles via Zotero sync server. Specifically, I printed out /extension/tags/1.5-sync3.5/chrome/content/zotero/xpcom/sync.js to decipher some off its workings. My goal wasn't to understand all the code, which gets pretty complicated, because of the complexities of things like conflict resolution. Rather, my focus is on how collections and items are serialized.

Here are couple of things I figured out:

  • When you hit the sync button, you invoke Zotero.Sync.Runner.sync
  • Because I hadn't seen the use of __defineGetter__ and __defineSetter__ in the Zotero 1.0.7 code, I didn't realize that these functions are actually part of JavaScript 1.5 — but according to Defining Getters and Setters – MDC, "Prior to Firefox 3.0, getter and setter are not supported for DOM Elements. Older versions of Firefox silently fail. If exceptions are needed for those, changing the prototype of HTMLElement (HTMLElement.prototype.__define[SG]etter__) and throwing an exception is a workaround. "
  • Zotero.Item.prototype.serialize is worthwhile studying for how to package up Zotero items in preparation for serialization (to, say, XML)
  • sync.js was the first time I had seen the use of [https://developer.mozilla.org/en/E4X E4X] to process XML in JavaScript. ("E4X is implemented (at least partially) in SpiderMonkey (Gecko's JavaScript engine) and in Rhino (JavaScript engine written in Java)."
  • Zotero.Sync.Server.Data..itemToXML shows how Zotero items are serialized to XML interpreted by the Zotero sync server.
Tagged ,

Range of creator types in Zotero

One thing that I didn't know about Zotero was the range of creator types in Zotero. Here's a Chickenfoot script that you can run to list them:

// to explore the range of creatorTypes
// to do:  figure out how to get localized string for different creator types

var Zotero = chromeWindow.Zotero;
var creatorTypes = Zotero.CreatorTypes.getTypes()
for (var i=0; i<creatorTypes.length; i++) {
  output(creatorTypes[i].id + ": " + Zotero.CreatorTypes.getName(creatorTypes[i].id));
}

The results (in Zotero 1.0.7):

22: artist
15: attorneyAgent
1: author
20: cartographer
11: castMember
23: commenter
18: composer
2: contributor
13: counsel
8: director
3: editor
25: guest
6: interviewee
7: interviewer
14: inventor
17: performer
26: podcaster
24: presenter
10: producer
21: programmer
16: recipient
27: reviewedAuthor
9: scriptwriter
5: seriesEditor
12: sponsor
4: translator
19: wordsBy

Tagged ,

Accessing attributes of Zotero Items

The following Chickenfoot script demonstrates how to access attributes related to Zotero items. (I've run this script on both Zotero 1.0.7 and the latest named release of  Zotero 1.5 Sync Preview (1.5-sync3.5))):

// zotero_item_show_pieces.js
// code to extract elements of the first selected item
// Dec 16, 2008

var Zotero = chromeWindow.Zotero;
var ZoteroPane = chromeWindow.ZoteroPane;
var items = ZoteroPane.getSelectedItems();
var item = items[0];

// get item ID

output("item ID: " + item.id);

// get named type

var iType = item.getType();
output("type: " + Zotero.ItemTypes.getName(iType));

// figure out whether this is a top level item, note, etc.
// if not, is it a  note or attachment
output("isRegularItem: " + item.isRegularItem());
output("isAttachment: " + item.isAttachment());
output("isNote: " + item.isNote()); // or just check type == note

// get all possible fields for the type and their value
var fields = Zotero.ItemFields.getItemTypeFields(iType);
for (var i=0; i<fields.length; i++) {
  fieldName = Zotero.ItemFields.getName(fields[i]);
  fieldVal = item.getField(fieldName);
  fieldLocalName = Zotero.ItemFields.getLocalizedString(iType,fields[i])
  output(fieldLocalName + ": " + fieldVal);
}
//fields;

// get creators

var creators = item.getCreators();

for (var i=0; i<creators.length; i++) {
  // Zoteo 1.5 +
  if (creators[i].ref) {
    output (Zotero.CreatorTypes.getName(creators[i].creatorTypeID) + ": " +creators[i].ref.lastName + ", " + creators[i].ref.firstName);  }
  // Zotero 1.0.x
  else {
    output (Zotero.CreatorTypes.getName(creators[i].creatorTypeID) + ": " +creators[i].lastName + ", " + creators[i].firstName);
  }
}

// date added and date modified
output("Date Added: " + item.getField('dateAdded'));
output("Date Modified: " + item.getField('dateModified'));

// Notes -- return ids for the notes

var notes = item.getNotes();
output("notes: " + notes);

// Attachments -- there are more details to take care of
// https://www.zotero.org/trac/browser/extension/tags/1.5-sync3.5/chrome/content/zotero/xpcom/data/item.js#L3469

var attachments = item.getAttachments();
output("attachments: " + attachments);

// Tags -- Z 1.5.x has more complex structures than Z 1.0.7

var tags = item.getTags();
output("tags:");
for (var i=0; i<tags.length; i++) {
  if (tags[i].name) {
    output("|" + tags[i].name + "|");
  }
  else {
  output("|" + tags[i]['tag'] + "|");
  }
}

// Related

// https://www.zotero.org/trac/browser/extension/tags/1.0.7/chrome/content/zotero/xpcom/data_access.js#L2180

if (item.getSeeAlso) {
  var related = item.getSeeAlso();
} else if (item.relatedItems) {
  var related = item.relatedItems;
}

output("related: " + related);

// Collections -- get which collections the item belongs in.
output("collections: " + item.getCollections());

A few notes:

  • Some of the conditionals in the script reflect differences in how Zotero 1.0.x and the upcoming Zotero 1.5+ Zotero object model work.
  • For Zotero 1.5+,  you can learn a lot about how to access attributes related to a Zotero item by studying Zotero.Item.serialize (v 1.5-sync3.5)
Tagged ,

Adding all tabs to Zotero Version 2 — scraping translatable sites

In a previous post adding all Firefox tabs to Zotero using Chickenfoot, I showed how to write a Chickenfoot script to loop through all Firefox  tabs and add each of them as an item into Zotero.  A limitation of the script was that it used only ZoteroPane.addItemFromPage for every tab, even if a given tab had a translator that could be used to save the item. As explained in Adding items to Zotero with Chickenfoot, you can use Zotero_Browser.scrapeThisPage to invoke the appropriate translator for tab. The reason I didn't use Zotero_Browser.scrapeThisPage in my Chickenfoot script to add items is that I didn't know how to write a function to determine suitable translator exists.

Now, I think I've come up with a way of determining whether a translator exists — though I'm not highly confident that the solution is fullproof.    I'll share my  Chickenfoot script here, explain the logic behind it, and write about its possible limitations.  First the script:

// add_each_tab_to_Zotero_2.js
// R. Yee

var Zotero = chromeWindow.Zotero;
var ZoteroPane = chromeWindow.ZoteroPane;
var Zotero_Browser = chromeWindow.Zotero_Browser;
var tabBrowser = getTabBrowser(chromeWindow);

// getIcon returns a link to the translator icon for the current
// tab and false if there is no suitable
// translator and 'chrome://zotero/skin/treesource-collection.png'
// if there are multiple savable elements on a page

function getIcon() {

  var browser = Zotero_Browser.tabbrowser.selectedBrowser;
  var tab0 = new Zotero_Browser.Tab(browser);

  // need to figure out whether doc is HTMLDocument
  // doc instanceof HTMLDocument doesn't seem to work here

  var doc = browser.contentWindow.document;

  // in emulation of
  // https://www.zotero.org/trac/browser/extension/tags/1.0.7/chrome/content/zotero/browser.js#L311

  var rootDoc = doc;
  if (rootDoc.defaultView) {
    while(rootDoc.defaultView.frameElement) {
      rootDoc = rootDoc.defaultView.frameElement.ownerDocument;
    }
  }

  // detect possible translators and return the corresponding icon
  tab0.detectTranslators(rootDoc,doc);
  return tab0.getCaptureIcon();

} // getIcon()

// create a new collection with current date
var new_Collection = Zotero.Collections.add("_Saved " + (new Date()).toLocaleString());

// output # tabs
output(tabBrowser.browsers.length);

// loop through tabs, selecting each one in turn
for (var i=0; i < tabBrowser.browsers.length; i++) {
  tabBrowser.mTabContainer.advanceSelectedTab(1, true);
  output(tabBrowser.selectedBrowser.contentWindow.location);
  var icon = getIcon();
  // if icon is not false and not representing multiple items -- scrape page
  if (icon && icon != 'chrome://zotero/skin/treesource-collection.png') {
    Zotero_Browser.scrapeThisPage(new_Collection.id);
  // otherwise add item as a generic web page
  } else {
   ZoteroPane.addItemFromPage(new_Collection.id);
  }
}

A few points about the script:

When I ran the script with 3 tabs, it seemed to work fine. When I had 20+ tabs, all the tabs were saved — but only the first one ended up in the right collection. (I don't know why….) Also, the code is not terribly elegant — for example, it depends on creating a new Zotero_Browser.Tab for each tab; I figure there should be some way to read off whether an icon exists in the interface already without having to recalculate possible translators.

Getting primary and secondary item types in Zotero

A Chickenfoot script for calculating the primary and secondary Zotero items (which draws upon the code in overlay.js->onLoad():


// based on https://www.zotero.org/trac/browser/extension/tags/1.0.7/chrome/content/zotero/overlay.js#L153

var Zotero = chromeWindow.Zotero;

var itemTypes = Zotero.ItemTypes.getPrimaryTypes();

for(var i = 0; i<itemTypes.length; i++) {
  output (itemTypes[i]['name'] + ":" + itemTypes[i]['id']);
}

var itemTypes = Zotero.ItemTypes.getSecondaryTypes();

for(var i = 0; i<itemTypes.length; i++) {
  output (itemTypes[i]['name'] + ":" + itemTypes[i]['id']);
}

The output of the script is (for Zotero 1.0.7):

book:2
bookSection:3
document:34
journalArticle:4
magazineArticle:5
newspaperArticle:6
artwork:12
audioRecording:26
bill:16
blogPost:23
case:17
computerProgram:32
conferencePaper:33
dictionaryEntry:36
email:21
encyclopediaArticle:35
film:11
forumPost:25
hearing:18
instantMessage:24
interview:10
letter:8
manuscript:9
map:22
patent:19
podcast:31
presentation:27
radioBroadcast:30
report:15
statute:20
thesis:7
tvBroadcast:29
videoRecording:28

When you hit "New Item" button in Zotero, you are given the option of creating a new item of one of a given type:

primary and secondary Zotero item types

Furthermore, you can use Zotero.ItemTypes to map between item types and IDs:

Zotero.ItemTypes.getID('book'); yields 2

and

Zotero.ItemTypes.getName(2); returns book

Tagged ,

A screencast to show Chickenfoot scripting of Zotero

Several weeks ago, I wrote (a blog post and a post on the zotero-dev group) on how to use Chickenfoot to script Zotero. I'm starting to experiment with creating little videos that I hope will make my technical posts easier to understand. Here's one I just made to illustrate what I wrote about in the previous post:

Please forgive my video-newbie level of craft — I'm still learning to make my way around Camtasia Studio 6. (One fault is that I produced the video for 640×480, which is not the optimal setting for YouTube.)

Enjoy!

Tagged , ,

adding all Firefox tabs to Zotero using Chickenfoot

We can now build on what was presented in the previous blog post: Adding items to Zotero with Chickenfoot.

The end goal is to loop through all the tabs and add Each of them as items into Zotero. So we need to figure out how to access the tabs. I would do so here by presenting a series of code fragments that you can try out using Chickenfoot and Zotero.

But let's first work through some code to manipulate tabs in Firefox, drawn from two reference documents:

  • tabbrowser – MDC: a reference to the tabbrowser object
  • Tabbed browser – MDC has some nice sample code, which seems to work best in Firefox 3.x, — something seemed to fail in Firefox 2.x (I should put an example here)

For example, one example of code doesn't work in 2.x — using addTab:

var tabBrowser = getTabBrowser(chromeWindow);
tabBrowser.addTab("http://yahoo.com");

Since I've had some problems using Firefox 2.x, I recommend running the following code fragments in Firefox 3.x.

First, let's get the tabbrowser object:

var tabBrowser = getTabBrowser(chromeWindow);
tabBrowser;

You can show the URL of the currently selected tab:

var tabBrowser = getTabBrowser(chromeWindow);
tabBrowser.selectedBrowser.contentWindow.location;

The following code advances selects the tab to the right of the currently tab — and loops around if needed:

var tabBrowser = getTabBrowser(chromeWindow);
tabBrowser.mTabContainer.advanceSelectedTab(1, true);

We can write out the current number of open tabs:

var tabBrowser = getTabBrowser(chromeWindow);
output(tabBrowser.browsers.length);

Here's code to select each tab in turn and output its location:

var tabBrowser = getTabBrowser(chromeWindow);
output(tabBrowser.browsers.length);
for (var i=0; i < tabBrowser.browsers.length; i++) {
  tabBrowser.mTabContainer.advanceSelectedTab(1, true);
  output(tabBrowser.selectedBrowser.contentWindow.location);
}

how to create a new collection in Zotero:

var Zotero = chromeWindow.Zotero;
var new_Collection = Zotero.Collections.add("testing");
new_Collection;

Here's code to create a new collection and add an item to it. (In my tries, the code crashes in FF 2.0.x but seems to work in FF 3.0.3):

var Zotero = chromeWindow.Zotero;
var ZoteroPane = chromeWindow.ZoteroPane;

var new_Collection = Zotero.Collections.add("testing");
var new_item = ZoteroPane.addItemFromPage(new_Collection.id);

Here's code that pulls it altogether — it loops through the tabs and adds the document of each tab to Zotero in a new collection:

var Zotero = chromeWindow.Zotero;
var ZoteroPane = chromeWindow.ZoteroPane;
var tabBrowser = getTabBrowser(chromeWindow);

var new_Collection = Zotero.Collections.add("Saved from tabs");
output(tabBrowser.browsers.length);

for (var i=0; i < tabBrowser.browsers.length; i++) {
  tabBrowser.mTabContainer.advanceSelectedTab(1, true);
  output(tabBrowser.selectedBrowser.contentWindow.location);
  var new_item = ZoteroPane.addItemFromPage(new_Collection.id);
}
Tagged ,

Adding items to Zotero with Chickenfoot

Here I report a few code fragments that you can try in Chickenfoot to create a Zotero item from the contents in the selected tab of your browser. (For a bit of context for what I'm talking about here, see my previous post Data Unbound » Accessing Zotero via Chickenfoot: a warm up exercise.)

There's a difference between the Zotero function that is invoked if an appropriate translator is found verses when there is no translator (and you have to then "create a new item from current page". (It would be helpful to show you how I deduced what these code fragments should be — I hope to do so later.)

When there is an appropriate translator, you invoke Zotero_Browser.scrapeThisPage:

var Zotero_Browser = chromeWindow.Zotero_Browser;
Zotero_Browser.scrapeThisPage();

When there isn't — and you add the page to Zotero as a web page using ZoteroPane.addItemFromPage:

var ZoteroPane = chromeWindow.ZoteroPane;
ZoteroPane.addItemFromPage();

Yet to figure out: How to ask Zotero whether for the selected tab there is an appropriate translator to use.

Tagged ,