commit 453fed88bd175d3b1b0cefe7f349cd92fcdb5dcb
parent a678cfa5b98828a3a6ef56c7e7716cd575e2cd5c
Author: Dan Stillman <dstillman@zotero.org>
Date: Tue, 27 Apr 2010 08:03:08 +0000
Zotero Commons updates:
- Store one item per IA bucket, with attachments stored as objects
- Use proper mediatype field based on Zotero item type
- Commons list is now pulled dynamically based on RDF stored at IA, without need for corresponding local item (which may have been deleted, etc.)
- Once available, OCRed PDFs can be pulled down by right-clicking on Commons and selecting Refresh
- Downloaded OCRed PDFs are now named the same as the existing attachment, with "(OCR)" appended
- The relations table is used to link downloaded OCRed PDFs to the IA file, so the downloaded file can be renamed without triggering another download
- The Commons view is marked for automatic refresh after an item is uploaded
- Added some progress notifications, though more are probably needed
- Other things
Also:
- Added Zotero.File.getBinaryContents(file)
- Erase an item's relations when the item is deleted, and purge orphaned ones
- Zotero.URI.eraseByPathPrefix(prefix) no longer prepends 'http://zotero.org' (which has been moved to Zotero.URI.defaultPrefix)
- New function Zotero.URI.eraseByURI(prefix)
Known Issues:
- Slow (some IA changes should be able to speed it up)
- Identifier format is likely temporary
- Sometimes it stops during setTimeout() calls for no apparent reason whatsoever
- Didn't test items with multiple attachments
- Not sure if Commons view will auto-refresh if you switch to it before the upload is done
- IA translator not yet updated
- Deleting items not supported by IA
- Date Added/Date Modified don't show up properly in Zotero for Commons items
Diffstat:
12 files changed, 1069 insertions(+), 688 deletions(-)
diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js
@@ -1343,7 +1343,7 @@ var ZoteroPane = new function()
}
var itemGroup = this.itemsView._itemGroup;
- if (!itemGroup.isTrash() && !this.canEdit()) {
+ if (!itemGroup.isTrash() && !itemGroup.isCommons() && !this.canEdit()) {
this.displayCannotEditLibraryMessage();
return;
}
@@ -1383,6 +1383,9 @@ var ZoteroPane = new function()
else if (itemGroup.isShare()) {
return;
}
+ else if (itemGroup.isCommons()) {
+ var prompt = toDelete;
+ }
// Do nothing in trash view if any non-deleted items are selected
else if (itemGroup.isTrash()) {
var start = {};
@@ -1462,47 +1465,25 @@ var ZoteroPane = new function()
}
}
- this.createCommonsBucket = function() {
- var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
- .getService(Components.interfaces.nsIPromptService);
-
- var bucketName = { value: '' };
- // TODO localize
- var result = promptService.prompt(window,
- "New Bucket",
- "Enter a name for this bucket:", bucketName, "", {});
-
- if (result && bucketName.value) {
- Zotero.Commons.createBucket(bucketName.value);
- }
- }
-
- this.refreshCommonsBucket = function() {
+ this.refreshCommons = function() {
if (this.collectionsView
&& this.collectionsView.selection
- && this.collectionsView.selection.count > 0
+ && this.collectionsView.selection.count == 1
&& this.collectionsView.selection.currentIndex != -1) {
- var bucket = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
- if (bucket && bucket.isBucket()) {
- this.itemsView._itemGroup.ref._items = null;
- this.itemsView.refresh();
- }
- }
- }
-
- this.removeCommonsBucket = function() {
- if (this.collectionsView
- && this.collectionsView.selection
- && this.collectionsView.selection.count > 0
- && this.collectionsView.selection.currentIndex != -1) {
- var bucket = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
- if (bucket && bucket.isBucket()) {
- Zotero.Commons.removeBucket(bucket.getName());
+ var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
+ if (itemGroup && itemGroup.isCommons()) {
+ var self = this;
+ Zotero.Commons.syncBucketList(function () {
+ self.itemsView.refresh();
+ self.itemsView.sort();
+
+ // On a manual refresh, also check for new OCRed files
+ Zotero.Commons.syncFiles();
+ });
}
}
}
-
function editSelectedCollection()
{
if (!this.canEdit()) {
@@ -1802,10 +1783,7 @@ var ZoteroPane = new function()
exportFile: 9,
loadReport: 10,
emptyTrash: 11,
- createCommonsBucket: 12,
- syncBucketList: 13,
- removeCommonsBucket: 14,
- refreshCommonsBucket: 15
+ refreshCommons: 12
};
var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
@@ -1873,14 +1851,8 @@ var ZoteroPane = new function()
else if (itemGroup.isTrash()) {
show = [m.emptyTrash];
}
- // Header
- else if (itemGroup.isHeader()) {
- if (itemGroup.ref.id == 'commons-header') {
- show = [m.createCommonsBucket, m.syncBucketList];
- }
- }
- else if (itemGroup.isBucket()) {
- show = [m.removeCommonsBucket, m.refreshCommonsBucket];
+ else if (itemGroup.isCommons()) {
+ show = [m.refreshCommons];
}
// Group
else if (itemGroup.isGroup()) {
@@ -2261,7 +2233,7 @@ var ZoteroPane = new function()
return;
}
- if (tree.id == 'zotero-collections-tree') {
+ if (tree.id == 'zotero-collections-tree') {
// Ignore triple clicks for collections
if (event.detail != 2) {
return;
@@ -2295,15 +2267,12 @@ var ZoteroPane = new function()
ZoteroPane.loadURI(uri);
event.stopPropagation();
}
- else if(itemGroup.ref.id == 'commons-header') {
- ZoteroPane.loadURI(Zotero.Commons.uri);
- event.stopPropagation();
- }
return;
}
- if (itemGroup.isBucket()) {
- ZoteroPane.loadURI(itemGroup.ref.uri);
+ if (itemGroup.isCommons()) {
+ // TODO: take to a search of the user's buckets?
+ //ZoteroPane.loadURI(itemGroup.ref.uri);
event.stopPropagation();
}
}
@@ -2325,6 +2294,18 @@ var ZoteroPane = new function()
var item = ZoteroPane.getSelectedItems()[0];
if (item) {
if (item.isRegularItem()) {
+ // Double-click on Commons item should load IA page
+ var itemGroup = ZoteroPane.collectionsView._getItemAtRow(
+ ZoteroPane.collectionsView.selection.currentIndex
+ );
+
+ if (itemGroup.isCommons()) {
+ var bucket = Zotero.Commons.getBucketFromItem(item);
+ ZoteroPane.loadURI(bucket.uri);
+ event.stopPropagation();
+ return;
+ }
+
if (!viewOnDoubleClick) {
return;
}
@@ -2879,6 +2860,8 @@ var ZoteroPane = new function()
return this.addItemFromPage(itemType, saveSnapshot, row);
}
+ var self = this;
+
Zotero.MIME.getMIMETypeFromURL(url, function (mimeType, hasNativeHandler) {
// If native type, save using a hidden browser
if (hasNativeHandler) {
@@ -2943,7 +2926,16 @@ var ZoteroPane = new function()
var collectionID = false;
}
- Zotero.Attachments.importFromURL(url, false, false, false, collectionID, null, libraryID);
+ var attachmentItem = Zotero.Attachments.importFromURL(url, false, false, false, collectionID, mimeType, libraryID);
+
+ // importFromURL() doesn't trigger the notifier until
+ // after download is complete
+ //
+ // TODO: add a callback to importFromURL()
+ setTimeout(function () {
+ self.selectItem(attachmentItem.id);
+ }, 1001);
+
return;
}
}
diff --git a/chrome/content/zotero/overlay.xul b/chrome/content/zotero/overlay.xul
@@ -107,10 +107,7 @@
<menuitem label="&zotero.toolbar.export.label;" oncommand="Zotero_File_Interface.exportFile()"/>
<menuitem oncommand="Zotero_Report_Interface.loadCollectionReport()"/>
<menuitem label="&zotero.toolbar.emptyTrash.label;" oncommand="ZoteroPane.emptyTrash();"/>
- <menuitem label="Create Bucket" oncommand="ZoteroPane.createCommonsBucket();"/><!--TODO localize -->
- <menuitem label="Sync Bucket List with IA" oncommand="Zotero.Commons.syncBucketList();"/><!--TODO localize -->
- <menuitem label="Remove Bucket from List" oncommand="ZoteroPane.removeCommonsBucket();"/><!--TODO localize -->
- <menuitem label="Refresh Bucket" oncommand="ZoteroPane.refreshCommonsBucket();"/><!--TODO localize -->
+ <menuitem label="Refresh" oncommand="ZoteroPane.refreshCommons();"/><!--TODO localize -->
</popup>
<popup id="zotero-itemmenu" onpopupshowing="ZoteroPane.buildItemContextMenu();">
<menuitem label="&zotero.items.menu.showInLibrary;" oncommand="ZoteroPane.selectItem(this.parentNode.getAttribute('itemID'), true)"/>
diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js
@@ -39,7 +39,7 @@ Zotero.CollectionTreeView = function()
this._treebox = null;
this.itemToSelect = null;
this._highlightedRows = {};
- this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share', 'group', 'bucket']);
+ this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share', 'group', 'commons']);
this.showDuplicates = false;
}
@@ -194,7 +194,7 @@ Zotero.CollectionTreeView.prototype.refresh = function()
var groups = Zotero.Groups.getAll();
if (groups.length) {
- this._showItem(new Zotero.ItemGroup('separator', false));
+ this._showItem(new Zotero.ItemGroup('separator'));
var header = {
id: "group-libraries-header",
label: "Group Libraries", // TODO: localize
@@ -234,30 +234,15 @@ Zotero.CollectionTreeView.prototype.refresh = function()
var shares = Zotero.Zeroconf.instances;
if (shares.length) {
- this._showItem(new Zotero.ItemGroup('separator', false));
+ this._showItem(new Zotero.ItemGroup('separator'));
for each(var share in shares) {
this._showItem(new Zotero.ItemGroup('share', share));
}
}
- var buckets = Zotero.Commons.buckets;
- if(buckets) {
- this._showItem(new Zotero.ItemGroup('separator', false));
- var header = {
- id: "commons-header",
- label: "Commons", // TODO: localize
- expand: function (buckets) {
- if (!buckets) {
- var buckets = Zotero.Commons.buckets;
- }
-
- for(var i = 0, len = buckets.length; i < len; i++) {
- self._showItem(new Zotero.ItemGroup('bucket', buckets[i]), 1);
- }
- }
- };
- this._showItem(new Zotero.ItemGroup('header', header), null, null, true);
- header.expand(buckets);
+ if (Zotero.Commons.enabled) {
+ this._showItem(new Zotero.ItemGroup('separator'));
+ this._showItem(new Zotero.ItemGroup('commons'), null, null, true);
}
this._refreshHashMap();
@@ -278,7 +263,11 @@ Zotero.CollectionTreeView.prototype.reload = function()
for (var i=0; i<this.rowCount; i++) {
if (this.isContainer(i) && this.isContainerOpen(i)) {
- openCollections.push(this._getItemAtRow(i).ref.id);
+ var itemGroup = this._getItemAtRow(i);
+ if (!itemGroup.isCollection()) {
+ continue;
+ }
+ openCollections.push(itemGroup.ref.id);
}
}
@@ -387,7 +376,7 @@ Zotero.CollectionTreeView.prototype.notify = function(action, type, ids)
this.rememberSelection(savedSelection);
}
else if (action == 'modify' || action == 'refresh') {
- if (type != 'bucket') {
+ if (type != 'commons') {
this.reload();
}
this.rememberSelection(savedSelection);
@@ -433,7 +422,7 @@ Zotero.CollectionTreeView.prototype.notify = function(action, type, ids)
this.rememberSelection(savedSelection);
break;
- case 'bucket':
+ case 'commons':
this.reload();
}
}
@@ -522,14 +511,15 @@ Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
if (source.ref.id == 'group-libraries-header') {
collectionType = 'groups';
}
- else if (source.ref.id == 'commons-header') {
- collectionType = 'commons';
- }
break;
case 'group':
collectionType = 'library';
break;
+
+ case 'commons':
+ collectionType = 'commons';
+ break;
}
return "chrome://zotero/skin/treesource-" + collectionType + ".png";
}
@@ -537,7 +527,7 @@ Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
Zotero.CollectionTreeView.prototype.isContainer = function(row)
{
var itemGroup = this._getItemAtRow(row);
- return itemGroup.isLibrary(true) || itemGroup.isCollection() || itemGroup.isHeader() || itemGroup.isBucket();
+ return itemGroup.isLibrary(true) || itemGroup.isCollection() || itemGroup.isHeader() || itemGroup.isCommons();
}
Zotero.CollectionTreeView.prototype.isContainerOpen = function(row)
@@ -557,9 +547,6 @@ Zotero.CollectionTreeView.prototype.isContainerEmpty = function(row)
if (itemGroup.isHeader()) {
return false;
}
- if (itemGroup.isBucket()) {
- return true;
- }
if (itemGroup.isGroup()) {
return !itemGroup.ref.hasCollections();
}
@@ -617,8 +604,6 @@ Zotero.CollectionTreeView.prototype.toggleOpenState = function(row)
if (itemGroup.type == 'header') {
itemGroup.ref.expand();
}
- else if(itemGroup.type == 'bucket') {
- }
else {
if (itemGroup.isLibrary()) {
count = itemGroup.ref.expand();
@@ -1063,12 +1048,14 @@ Zotero.CollectionTreeView.prototype.canDrop = function(row, orient, dragData)
{
var itemGroup = this._getItemAtRow(row); //the collection we are dragging over
- if (!itemGroup.editable) {
+ if (!itemGroup.editable
+ // Commons can be dropped on but not edited
+ && !itemGroup.isCommons()) {
return false;
}
if (dataType == 'zotero/item') {
- if(itemGroup.isBucket()) {
+ if(itemGroup.isCommons()) {
return true;
}
@@ -1236,8 +1223,8 @@ Zotero.CollectionTreeView.prototype.drop = function(row, orient)
var targetLibraryID = null;
}
- if(itemGroup.isBucket()) {
- itemGroup.ref.uploadItems(ids);
+ if(itemGroup.isCommons()) {
+ Zotero.Commons.uploadItems(ids);
return;
}
@@ -1638,9 +1625,9 @@ Zotero.ItemGroup.prototype.isShare = function()
return this.type == 'share';
}
-Zotero.ItemGroup.prototype.isBucket = function()
+Zotero.ItemGroup.prototype.isCommons = function()
{
- return this.type == 'bucket';
+ return this.type == 'commons';
}
Zotero.ItemGroup.prototype.isTrash = function()
@@ -1667,7 +1654,7 @@ Zotero.ItemGroup.prototype.isWithinGroup = function () {
}
Zotero.ItemGroup.prototype.__defineGetter__('editable', function () {
- if (this.isTrash() || this.isShare()) {
+ if (this.isTrash() || this.isShare() || this.isCommons()) {
return false;
}
if (!this.isWithinGroup()) {
@@ -1726,9 +1713,6 @@ Zotero.ItemGroup.prototype.getName = function()
case 'share':
return this.ref.name;
-
- case 'bucket':
- return this.ref.name;
case 'trash':
return Zotero.getString('pane.collections.trash');
@@ -1739,6 +1723,9 @@ Zotero.ItemGroup.prototype.getName = function()
case 'header':
return this.ref.label;
+ case 'commons':
+ return "Commons";
+
default:
return "";
}
@@ -1751,8 +1738,8 @@ Zotero.ItemGroup.prototype.getChildItems = function()
case 'share':
return this.ref.getAll();
- case 'bucket':
- return this.ref.getItems();
+ case 'commons':
+ return Zotero.Commons.getItems();
case 'header':
return [];
@@ -1865,7 +1852,7 @@ Zotero.ItemGroup.prototype.getChildTags = function() {
case 'share':
return false;
- case 'bucket':
+ case 'commons':
return false;
case 'header':
diff --git a/chrome/content/zotero/xpcom/commons.js b/chrome/content/zotero/xpcom/commons.js
@@ -27,196 +27,515 @@
Zotero.Commons = new function() {
this.uri = 'http://www.archive.org/';
this.apiUrl = 'http://s3.us.archive.org';
-
- this.__defineGetter__('buckets', function () {
- if(!Zotero.Prefs.get("commons.enabled")) {
- return false;
- }
-
- var accessKey = Zotero.Prefs.get("commons.accessKey");
- var secretKey = Zotero.Prefs.get("commons.secretKey");
- var buckets = [];
- var bucketNames = Zotero.Prefs.get("commons.buckets").split(',');
- for(var i = 0, len = bucketNames.length; i < len; i++) {
- if(bucketNames[i]) {
- buckets.push(new Zotero.Commons.Bucket(bucketNames[i], accessKey, secretKey));
- }
- }
- return buckets;
+ this.postCreateBucketDelay = 2000;
+
+ this.__defineGetter__('enabled', function () {
+ return Zotero.Prefs.get("commons.enabled");
});
-
- this.createBucket = function (bucketName) {
- var accessKey = Zotero.Prefs.get("commons.accessKey");
- var secretKey = Zotero.Prefs.get("commons.secretKey");
-
+
+ this.__defineGetter__('userIdentifier', function () {
+ return Zotero.Prefs.get("commons.accessKey");
+ });
+
+ this.__defineGetter__('accessKey', function () {
+ return Zotero.Prefs.get("commons.accessKey");
+ });
+
+ this.__defineGetter__('secretKey', function () {
+ return Zotero.Prefs.get("commons.secretKey");
+ });
+
+ this.RDF_TRANSLATOR = {
+ 'label': 'Zotero RDF',
+ 'target': 'rdf',
+ 'translatorID': '14763d24-8ba0-45df-8f52-b8d1108e7ac9',
+ 'displayOptions': {
+ 'exportFileData': true,
+ 'exportNotes': true
+ }
+ };
+
+ this.RDF_IMPORT_TRANSLATOR = {
+ 'translatorID': '5e3ad958-ac79-463d-812b-a86a9235c28f',
+ }
+
+ this.ERROR_BUCKET_EXISTS = 1;
+
+ this.refreshNeeded = true;
+
+ var _buckets = {};
+ var _bucketsLoading = false;
+ var _requestingItems = false;
+
+
+ this.createBucket = function (item, onBucketQueued, onBucketCreated, waitForCreation) {
var headers = {
"x-archive-auto-make-bucket":"1",
"x-archive-meta01-collection":"scholarworkspaces",
"x-archive-meta02-collection":"zoterocommons",
- "x-archive-meta-mediatype":"texts",
"x-archive-meta-sponsor":"Andrew W. Mellon Foundation",
"x-archive-meta01-language":"eng"
};
-
- var callback = function (req) {
+
+ var itemTitle = item.getDisplayTitle();
+ if (itemTitle) {
+ headers["x-archive-meta-title"] = itemTitle;
+ }
+
+ var itemLanguage = item.getField('language');
+ // TODO: use proper language code?
+ if (itemLanguage) {
+ headers["x-archive-meta01-language"] = itemLanguage;
+ }
+
+ var itemType = Zotero.ItemTypes.getName(item.itemTypeID);
+ switch (itemType) {
+ case 'artwork':
+ case 'map':
+ headers["x-archive-meta-mediatype"] = "image";
+ break;
+
+ case 'radioBroadcast':
+ case 'audioRecording':
+ headers["x-archive-meta-mediatype"] = "audio";
+ break;
+
+ case 'tvBroadcast':
+ case 'videoRecording':
+ headers["x-archive-meta-mediatype"] = "movies";
+ break;
+
+ default:
+ headers["x-archive-meta-mediatype"] = "texts";
+ }
+
+ var requestCallback = function (req, id, tries) {
+ Zotero.debug(req.status);
+
if (req.status == 201) {
- // add bucketName to preference if isn't already there
- var prefBucketNames = Zotero.Prefs.get("commons.buckets").split(',');
- if(!Zotero.inArray(bucketName, prefBucketNames)) {
- prefBucketNames.push(bucketName);
- prefBucketNames.sort();
- Zotero.Prefs.set("commons.buckets", prefBucketNames.join(','));
- Zotero.Notifier.trigger('add', 'bucket', true);
+ var bucket = new Zotero.Commons.Bucket(id);
+
+ if (waitForCreation) {
+ Zotero.debug('Waiting for bucket creation');
+
+
+ Zotero.debug('-------');
+ Zotero.debug(setTimeout);
+
+ setTimeout(function () {
+ var tries = 15;
+ bucket.exists(function (found) {
+ if (found == 1) {
+ onBucketCreated(bucket);
+ }
+ else if (!found) {
+ alert("Commons: Bucket " + bucket.name + " not found after creation");
+ }
+ else {
+ alert("Commons: Error checking for bucket " + bucket.name + " after creation");
+ }
+ }, tries);
+ }, Zotero.Commons.postCreateBucketDelay);
+
+ if (onBucketQueued) {
+ onBucketQueued();
+ }
+ }
+ else {
+ if (onBucketQueued) {
+ onBucketQueued();
+ }
+ if (onBucketCreated) {
+ onBucketCreated(bucket);
+ }
}
}
else {
- Zotero.debug(req.status);
Zotero.debug(req.responseText);
- if (req.status == 403) {
- alert("Bucket creation failed: authentication failed.");
- }
- else if (req.status == 409) {
- alert("Bucket creation failed: bucket name already taken.");
- }
- else if (req.status == 503) {
- alert("Bucket creation failed: server unavailable.");
+ // DEBUG: What is this for?
+ if (req.status == 409) {
+ tries++;
+ // Max tries
+ if (tries > 3) {
+ alert("Upload failed");
+ return;
+ }
+
+ id = Zotero.Commons.getNewBucketName();
+ Zotero.Commons.createAuthenticatedRequest(
+ "PUT", "/" + id, headers, this.accessKey, this.secretKey,
+ function (req) {
+ requestCallback(req, id, tries);
+ }
+ );
+
}
else {
- alert("Bucket creation failed: server error " + req.status);
+ Zotero.debug(req.status);
+ Zotero.debug(req.responseText);
+
+ alert("Upload failed");
}
}
- }
+ };
- var req = this.createAuthenticatedRequest(
- "PUT", "/" + bucketName, headers, accessKey, secretKey, callback
+ var id = Zotero.Commons.getNewBucketName();
+ Zotero.Commons.createAuthenticatedRequest(
+ "PUT", "/" + id, headers, this.accessKey, this.secretKey,
+ function (req) {
+ requestCallback(req, id, 1);
+ }
);
}
-
- this.syncBucketList = function () {
+
+
+ this.syncBucketList = function (callback) {
var accessKey = Zotero.Prefs.get("commons.accessKey");
var secretKey = Zotero.Prefs.get("commons.secretKey");
-
- // get list of buckets from IA
- var callback = function (req) {
+
+ if (_bucketsLoading) {
+ Zotero.debug("Already loading buckets");
+ return;
+ }
+
+ _bucketsLoading = true;
+
+ var syncCallback = function (req) {
// Error
if (req.status != 200) {
Zotero.debug(req.status);
Zotero.debug(req.responseText);
if (req.status == 503) {
- alert("Bucket list sync failed: server unavailable.");
+ alert("Unable to retrieve items list from the Internet Archive: server unavailable.");
}
else {
- alert("Bucket list sync failed: server error " + req.status);
+ alert("Unable to retrieve items list from the Internet Archive: server error " + req.status);
}
+ _bucketsLoading = false;
+
return;
}
Zotero.debug(req.responseText);
- var zu = new Zotero.Utilities;
- var prompt = Components.classes["@mozilla.org/network/default-prompt;1"]
- .getService(Components.interfaces.nsIPrompt);
+ var currentBuckets = [];
+ var IABuckets = [];
- var prefChanged = false;
- var prefBuckets = Zotero.Prefs.get("commons.buckets");
- var prefBucketNames = prefBuckets ? prefBuckets.split(',').sort() : [];
-
- // Remove any duplicate buckets that got into the pref somehow
- var len = prefBucketNames.length;
- var hash = {};
- for each(var val in prefBucketNames) {
- hash[val] = true;
- }
- for (var key in hash) {
- prefBucketNames.push(key);
- }
- if (prefBucketNames.length != len) {
- prefChanged = true;
+ for (var name in _buckets) {
+ currentBuckets.push(name);
}
+ currentBuckets.sort();
+
+ Zotero.debug('==========');
+ Zotero.debug("CURRENT BUCKETS");
+ Zotero.debug(currentBuckets);
+
- var newPrefBucketNames = [];
- var iaBucketNames = [];
var buckets = req.responseXML.getElementsByTagName("Bucket");
- for(var i = 0, len = buckets.length; i < len; i++) {
+ for (var i=0, len=buckets.length; i<len; i++) {
var bucketName = buckets[i].getElementsByTagName('Name')[0].textContent;
- iaBucketNames.push(bucketName);
- if (prefBucketNames.indexOf(bucketName) != -1) {
- newPrefBucketNames.push(bucketName);
- }
+ IABuckets.push(bucketName);
}
- iaBucketNames.sort();
+ IABuckets.sort();
- // newPrefBucketNames currently contains intersection
- // of prefBucketNames and iaBucketNames
- var askToAddBuckets = zu.arrayDiff(prefBucketNames, iaBucketNames);
- var askToRemoveBuckets = zu.arrayDiff(iaBucketNames, prefBucketNames);
+ Zotero.debug("IA BUCKETS");
+ Zotero.debug(IABuckets);
- // prompt user about adding buckets
- for(var i = 0, len = askToAddBuckets.length; i < len; i++) {
- var result = prompt.confirm("", "'" + askToAddBuckets[i] + "' is associated with "
- + "your IA account but is not in your list of buckets in Zotero.\n\n"
- + "Add bucket '" + askToAddBuckets[i] + "'?");
- if (result) {
- newPrefBucketNames.push(askToAddBuckets[i]);
- prefChanged = true;
- }
+ var addBuckets = Zotero.Utilities.prototype.arrayDiff(IABuckets, currentBuckets);
+ var removeBuckets = Zotero.Utilities.prototype.arrayDiff(currentBuckets, IABuckets);
+
+ Zotero.debug("ADD");
+ Zotero.debug(addBuckets);
+ Zotero.debug("REMOVE");
+ Zotero.debug(removeBuckets);
+
+ for each(var name in removeBuckets) {
+ delete _buckets[name];
}
- // prompt user about removing buckets
- for(var i = 0, len = askToRemoveBuckets.length; i < len; i++) {
- var result = prompt.confirm("", "'" + askToRemoveBuckets[i] + "' is in your "
- + "list of buckets in Zotero but is not associated with your IA account.\n\n"
- + "Remove bucket '" + askToRemoveBuckets[i] + "' from Zotero?");
- if (result) {
- prefChanged = true;
- }
- else {
- newPrefBucketNames.push(askToRemoveBuckets[i]);
- }
+ for each(var name in addBuckets) {
+ _buckets[name] = new Zotero.Commons.Bucket(name);
}
- newPrefBucketNames.sort();
- Zotero.Prefs.set("commons.buckets", newPrefBucketNames.join(','));
-
+
// refresh left pane if local bucket list changed
- if(prefChanged) {
- Zotero.Notifier.trigger('add', 'bucket', true);
- }
-
- // give user feedback if no difference between lists
- // (don't leave user wondering if nothing happened)
- if(askToAddBuckets.length == 0 && askToRemoveBuckets.length == 0) {
- alert("Your list of buckets in Zotero is up-to-date.");
+ //if(prefChanged) {
+ //Zotero.Notifier.trigger('add', 'bucket', true);
+ //}
+
+ _bucketsLoading = false;
+
+ if (callback) {
+ callback();
}
- }
+ };
var req = this.createAuthenticatedRequest(
- "GET", "/", {}, accessKey, secretKey, callback
+ "GET", "/", {}, accessKey, secretKey, syncCallback, null, false, true
);
}
- // remove bucketName from preference, and refresh left pane in Zotero
- this.removeBucket = function (bucketName) {
- var prefBucketNames = Zotero.Prefs.get("commons.buckets").split(',');
- var newPrefBucketNames = [];
- for(var i = 0, len = prefBucketNames.length; i < len; i++) {
- if(bucketName != prefBucketNames[i]) {
- newPrefBucketNames.push(prefBucketNames[i]);
+ this.getNewBucketName = function () {
+ return "zc-" + this.accessKey + "-" + Zotero.ID.getBigInt(9999999999);
+ }
+
+
+ this.getBucketFromItem = function (item) {
+ return this.getBucketFromItemID(item.id);
+ }
+
+
+ this.getBucketFromItemID = function (itemID) {
+ for each(var bucket in _buckets) {
+ if (bucket.item.id == itemID) {
+ return bucket;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Return an array of items belonging to this user
+ */
+ this.getItems = function() {
+ Zotero.debug('========');
+ Zotero.debug('calling getItems()');
+
+ if (!this.refreshNeeded) {
+ Zotero.debug("Commons: Buckets already loaded. Returing existing item set");
+ return _getItemsFromBuckets();
+ }
+
+ if (_requestingItems) {
+ Zotero.debug("Commons: Already requesting items in Zotero.Commons.getItem()", 2);
+ return;
+ }
+
+ _requestingItems = true;
+
+ // First update the list of buckets
+ var req = this.syncBucketList(function () {
+ Zotero.Commons.refreshNeeded = false;
+ Zotero.Notifier.trigger('refresh', 'commons', []);
+ _requestingItems = false;
+ });
+
+ // Browser offline
+ if (!req) {
+ _requestingItems = false;
+ }
+
+ // List isn't yet available
+ return [];
+ }
+
+
+ this.syncFiles = function () {
+ if (Zotero.Commons.refreshNeeded) {
+ throw ("Buckets must be loaded before syncing files in Zotero.Commons.syncFiles()");
+ }
+
+ Zotero.debug("Getting updated files from all buckets");
+
+ var progressWin = null;
+ var icon = 'chrome://zotero/skin/treeitem-attachment-pdf.png';
+
+ for each(var bucket in _buckets) {
+ bucket.syncFiles(function (attachment) {
+ if (!progressWin) {
+ progressWin = new Zotero.ProgressWindow();
+ progressWin.changeHeadline("Downloading OCRed PDFs"); // TODO: localize
+ }
+ progressWin.addLines([attachment.getField('title')], [icon]);
+ progressWin.show();
+ progressWin.startCloseTimer(8000);
+ });
+ }
+ }
+
+
+ this.uploadItems = function (ids) {
+ var items = Zotero.Items.get(ids);
+ if (!items) {
+ Zotero.debug("No items to upload");
+ return;
+ }
+
+ var itemsToUpload = false;
+ for (var i=0, len=items.length; i<len; i++) {
+ if (items[i].isRegularItem()) {
+ itemsToUpload = true;
+ break;
}
}
- newPrefBucketNames.sort();
- Zotero.Prefs.set("commons.buckets", newPrefBucketNames.join(','));
- Zotero.Notifier.trigger('add', 'bucket', true);
+
+ var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
+ .getService(Components.interfaces.nsIPrompt);
+
+ if (!itemsToUpload) {
+ Zotero.debug("No regular items to upload");
+ pr.alert("", "Only items with bibliographic metadata can be added to the Zotero Commons.");
+ return;
+ }
+
+ var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
+ + (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL);
+ var index = pr.confirmEx(
+ "Zotero Commons Upload",
+ "By uploading items to Zotero Commons you agree to the terms of use at zotero.org and archive.org. "
+ + "Please make sure metadata for your item(s) is set properly."
+ + "\n\n "
+ + "Continue to upload items to the Internet Archive?",
+ buttonFlags,
+ "Upload",
+ null, null, null, {}
+ );
+
+ // if user chooses 'cancel', exit
+ if (index != 0) return;
+
+
+ var progressWin = new Zotero.ProgressWindow();
+
+ var tmpDir = Zotero.getTempDirectory();
+
+ // Create buckets one at a time, pulling items off a stack
+ var process = function (items) {
+ if (!items.length) {
+ Zotero.debug("Commons: No more items to upload");
+ return;
+ }
+
+ let item = items.shift();
+
+ // Skip notes and attachments
+ if (!item.isRegularItem()) {
+ process(items);
+ return;
+ }
+
+ // TODO: check relations table to see if this item already has a bucket
+
+ // TODO: localize
+ progressWin.changeHeadline("Uploading items to IA");
+ progressWin.addLines([item.getField('title')], [item.getImageSrc()]);
+ progressWin.show();
+
+ Zotero.Commons.createBucket(
+ item,
+ // onBucketQueued
+ function () {
+ // Start next item while waiting for bucket creation
+ process(items);
+ },
+ // onBucketCreated
+ function (bucket) {
+ // Link item to new bucket
+ var url1 = Zotero.URI.getItemURI(item);
+ var predicate = bucket.relationPredicate;
+ var url2 = bucket.uri;
+ Zotero.Relations.add(null, url1, predicate, url2);
+
+ //
+ // Export item and attachments to RDF and files
+ //
+
+ var key = Zotero.ID.getKey();
+
+ var outputDir = Zotero.getTempDirectory();
+ // TEMP
+ //outputDir.append(bucket.name);
+ outputDir.append(key);
+
+ var translation = new Zotero.Translate("export");
+ translation.setItems([item]);
+ translation.setTranslator(Zotero.Commons.RDF_TRANSLATOR.translatorID);
+ translation.setDisplayOptions(Zotero.Commons.RDF_TRANSLATOR.displayOptions);
+ translation.setHandler("done", function (translation, success) {
+ if (!success) {
+ alert("Commons: Translation failed for " + translation);
+ return;
+ }
+
+ try {
+ // Upload RDF file
+ var rdfFile = outputDir.clone();
+ // TEMP
+ //rdfFile.append(bucket.name + ".rdf");
+ rdfFile.append(key + ".rdf");
+ rdfFile.moveTo(null, bucket.name + ".rdf");
+ bucket.putFile(rdfFile, "application/rdf+xml", function (uri) {
+ // TEMP
+ rdfFile.moveTo(null, key + ".rdf");
+
+ // Then create ZIP file from item
+ var zipFile = Zotero.getTempDirectory();
+ // TEMP
+ //zipFile.append(outputDir.leafName + '.zip');
+ zipFile.append(key + '.zip');
+
+ var zw = Components.classes["@mozilla.org/zipwriter;1"]
+ .createInstance(Components.interfaces.nsIZipWriter);
+ zw.open(zipFile, 0x04 | 0x08 | 0x20); // open rw, create, truncate
+
+ bucket.zipDirectory(outputDir, outputDir, zw);
+
+ // Upload file after zipping
+ var observer = new Zotero.Commons.ZipWriterObserver(zw, function () {
+ bucket.putFile(zipFile, "application/zip", function (uri) {
+ // TODO: localize
+ Zotero.debug('-=-=-=-=-=');
+ Zotero.debug(items.length);
+ if (!items.length) {
+ progressWin.startCloseTimer(5000);
+ }
+
+ Zotero.Commons.refreshNeeded = true;
+ });
+ });
+ zw.processQueue(observer, null);
+ });
+ }
+ catch (e) {
+ alert("Zotero Commons upload failed:\n\n" + e);
+ }
+ });
+ translation.setLocation(outputDir);
+ translation.translate(); // synchronous
+ },
+ true
+ );
+ }
+
+ process(items);
+ }
+
+
+ this.deleteItems = function (ids) {
+ Zotero.debug("Unimplemented");
+ return;
+
+ // TODO: Confirm
+
+ for each(var id in ids) {
+ var bucket = this.getBucketFromItemID(id);
+ bucket.erase();
+ }
}
- this.createAuthenticatedRequest = function (method, resource, headers, accessKey, secretKey, callback, data, sendAsBinary) {
+ this.createAuthenticatedRequest = function (method, resource, headers, accessKey, secretKey, callback, data, sendAsBinary, noCache) {
+ var url = Zotero.Commons.apiUrl + resource;
+
+ Zotero.debug("Commons HTTP " + method + ": " + url);
+
var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest);
- req.open(method, Zotero.Commons.apiUrl + resource, true);
+ req.open(method, url, true);
var d = new Date();
headers["Date"] = d.toUTCString();
@@ -244,6 +563,10 @@ Zotero.Commons = new function() {
req.setRequestHeader(header, headers[header]);
}
+ if (noCache) {
+ req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
+ }
+
if (data) {
if (sendAsBinary) {
req.sendAsBinary(data);
@@ -278,119 +601,360 @@ Zotero.Commons = new function() {
return req;
}
+
+
+
+ function _getItemsFromBuckets() {
+ var items = [];
+ for (var name in _buckets) {
+ Zotero.debug('getting bucket ' + name);
+ var item = _buckets[name].item;
+ // Only return available items
+ if (item) {
+ Zotero.debug('found');
+ items.push(item);
+ }
+ }
+ return items;
+ }
+
+
+ /*
+ function _createUniqueBucket(name, callback) {
+ var uploadErrorMsg = "An error occurred uploading a file to the Internet Archive";
+
+ var bucket = new Zotero.Commons.Bucket(name);
+
+ bucket.create(function (success, error) {
+ if (success) {
+ callback(name);
+ return;
+ }
+
+ if (error == Zotero.Commons.ERROR_BUCKET_EXISTS) {
+ var maxTries = 5;
+
+ // Append suffixes until we find a unique name
+ var checkFunc = function (name, suffix, callback) {
+ var bucket = new Zotero.Commons.Bucket(name);
+ bucket.create(function (success, error) {
+ if (success) {
+ callback(name);
+ return;
+ }
+
+ if (error == Zotero.Commons.ERROR_BUCKET_EXISTS) {
+ maxTries--;
+ // If we've exceeded maxTries, just use a random suffix
+ if (maxTries < 1) {
+ suffix = Zotero.ID.getKey();
+ name = name.replace(/\-[0-9]+$/, "-" + suffix);
+ callback(name);
+ return;
+ }
+
+ suffix++;
+ name = name.replace(/\-[0-9]+$/, "-" + suffix);
+ checkFunc(name, suffix, callback);
+ return;
+ }
+
+ alert(uploadErrorMsg);
+ });
+ }
+
+ checkFunc(name + "-1", 1, callback);
+ return;
+ }
+
+ alert(uploadErrorMsg);
+ });
+ }
+ */
+
+
+ this.debug = function (message, level) {
+ Zotero.debug("Commons: " + message, level);
+ }
}
-// accessKey and secretKey are passed to allow easy implementation
-// of using multiple accounts
-Zotero.Commons.Bucket = function(name, accessKey, secretKey) {
+Zotero.Commons.Bucket = function (name) {
this.name = name;
- this.accessKey = accessKey;
- this.secretKey = secretKey;
+ this.accessKey = Zotero.Prefs.get("commons.accessKey");
+ this.secretKey = Zotero.Prefs.get("commons.secretKey");
this._items = null;
this._requestingItems = false;
this._needRefresh = false;
+
+ this._item = null;
+ this._metadataLoading = false;
+ this._itemDataLoaded = false;
+ this._itemDataLoading = false;
}
-Zotero.Commons.Bucket.prototype.RDF_TRANSLATOR = {
- 'label': 'Zotero RDF',
- 'target': 'rdf',
- 'translatorID': '14763d24-8ba0-45df-8f52-b8d1108e7ac9',
- 'displayOptions': {
- 'exportFileData': true,
- 'exportNotes': true
+Zotero.Commons.Bucket.prototype.__defineGetter__('item', function () {
+ Zotero.debug("REQUESTING ITEM FOR " + this.name);
+
+ if (this._item) {
+ Zotero.debug("RETURNING");
+ return this._item;
}
-};
+
+/* var item = new Zotero.Item('document');
+ item.setField('title', this.name);
+ return item;
+*/
+
+ Zotero.debug("LOADING");
+
+ this._loadMetadata(function () {
+ Zotero.debug("LOADED");
+ Zotero.Notifier.trigger('refresh', 'commons', []);
+ });
+
+ return false;
+});
Zotero.Commons.Bucket.prototype.__defineGetter__('uri', function () {
return 'http://www.archive.org/details/' + this.name;
});
+Zotero.Commons.Bucket.prototype.__defineGetter__('downloadURI', function () {
+ return 'http://www.archive.org/download/' + this.name;
+});
-Zotero.Commons.Bucket.prototype.getKeyUrl = function(name, key) {
- return 'http://' + name + '.s3.us.archive.org/' + key;
-
-}
-
+Zotero.Commons.Bucket.prototype.__defineGetter__('metadataURI', function () {
+ return this.downloadURI + '/' + this.name + '_meta.xml';
+});
-Zotero.Commons.Bucket.prototype.relationPredicate = "owl:sameAs";
+Zotero.Commons.Bucket.prototype.__defineGetter__('apiURI', function() {
+ return Zotero.Commons.apiUrl + '/' + this.name;
+});
+Zotero.Commons.Bucket.prototype.__defineGetter__('rdfURI', function() {
+ return Zotero.Commons.apiUrl + '/' + this.name + '/' + this.name + '.rdf';
+});
-// deletes selected items from IA.
-Zotero.Commons.Bucket.prototype.deleteItems = function(ids) {
- var method = "DELETE";
- var headers = {
- "x-archive-cascade-delete":"1"
- };
+Zotero.Commons.Bucket.prototype.relationPredicate = "owl:sameAs";
- Zotero.debug("Commons: called to delete: " + ids.toString());
+Zotero.Commons.Bucket.prototype.exists = function (callback, maxTries, tries) {
+ if (!tries) {
+ tries = 0;
+ }
+
var self = this;
+
+ Zotero.Utilities.HTTP.doHead(this.uri, function (xmlhttp) {
+ switch (xmlhttp.status) {
+ case 200:
+ callback(1);
+ return;
+
+ case 404:
+ case 503: // IA returns this for missing buckets
+ tries++;
+
+ if (tries >= maxTries) {
+ callback(0);
+ return;
+ }
+
+ var delay = Zotero.Commons.postCreateBucketDelay * tries;
+ var seconds = delay / 1000;
+ Zotero.debug("Bucket " + self.name + " doesn't yet exist -- retrying in " + seconds + " seconds");
+
+ Zotero.debug('---------');
+ Zotero.debug(setTimeout);
+
+ setTimeout(function () {
+ self.exists(callback, maxTries, tries);
+ }, delay);
+ return;
+
+ default:
+ Zotero.debug(xmlhttp.status);
+ Zotero.debug(xmlhttp.responseText);
+ callback(-1);
+ return;
+ }
+ });
+}
- // for each id passed in, issue delete request for <key>.ZIP file
- var items = Zotero.Items.get(ids);
-
- for(var i = 0, len = items.length; i < len; i++) {
- var item = items[i];
- var zipName = item.key + ".zip";
- // since cascade delete is enabled, delete the ZIP and derived files should follow.
- // this does not, however, delete the RDF file.
- var resource = '/' + self.name + '/' + zipName;
- Zotero.debug("Commons: Deleting: " + resource);
+/**
+ * Get OCRed PDFs from files in this bucket
+ *
+ * @param {Function} callback Function to run after adding each file --
+ * function is passed the new attachment item
+ * (which due to a Zotero.Attachments.importFromURL()
+ * limitation will still be downloading)
+ */
+Zotero.Commons.Bucket.prototype.syncFiles = function (callback) {
+ // Find local item if it exists
+ var rels = Zotero.Relations.getByURIs(null, this.relationPredicate, this.uri);
+ if (!rels.length) {
+ Zotero.debug("No local items linked to URI " + this.uri);
+ return;
+ }
+ if (rels.length > 1) {
+ throw ("Commons: More than one local item linked to remote bucket " + this.name);
+ }
+ var item = Zotero.URI.getURIItem(rels[0].subject);
+ if (!item) {
+ Zotero.debug("Linked local item not found for URI " + this.uri, 2);
+ return;
+ }
+
+ // Get array of possible attachment names
+ var pdfFileNames = [];
+ var pdfTitles = [];
+ var ids = item.getAttachments();
+ for each(var id in ids) {
+ var attachment = Zotero.Items.get(id);
+ var fileName = attachment.getFilename();
+ if (!fileName || !fileName.match(/.+\.pdf$/)) {
+ continue;
+ }
+ pdfFileNames.push(fileName);
+ pdfTitles.push(attachment.getField('title'));
+ }
+
+ if (this._requestingItems) {
+ throw ("Commons: Already requesting items for bucket");
+ }
+
+ this._requestingItems = true;
+
+ var self = this;
+
+ // Check for a full-text ("derived" in IA terms) OCRed version of the PDF,
+ // and if found add it as an attachment to the corresponding Zotero client item
+ Zotero.Utilities.HTTP.doGet(this.apiURI, function(xmlhttp) {
+ if (xmlhttp.status != 200) {
+ Zotero.debug(xmlhttp.status);
+ Zotero.debug(xmlhttp.responseText);
+ alert("Error loading data from the Internet Archive");
+ self._requestingItems = false;
+ return;
+ }
- // Delete IA items
- var callback = function (req) {
- if (req.status == 204) {
- Zotero.debug("Commons: " + resource + " was deleted successfully.");
- this._needRefresh = true;
- Zotero.Notifier.trigger('refresh', 'bucket', ids);
-
- //respecify metadata
- self.updateMetadata(item.key,"delete",null);
+ Zotero.debug(xmlhttp.responseText);
+
+ // TODO: replace original PDF?
+
+ var contents = xmlhttp.responseXML.getElementsByTagName("Contents");
+
+ // loop through files listed in bucket contents file
+ for(var i=0, len=contents.length; i<len; i++) {
+ var IAFileName = contents[i].getElementsByTagName('Key')[0].textContent;
+ // We care only about OCRed PDFs
+ if (!IAFileName.match(/\_text.pdf$/)) {
+ Zotero.debug("Skipping file " + IAFileName);
+ continue;
}
- else {
- Zotero.debug(req.status);
- Zotero.debug(req.responseText);
-
- if (req.status == 403) {
- alert("Failed to delete " + resource + " at IA: authentication failed.");
- }
- else if (req.status == 503) {
- alert("Failed to delete " + resource + " at IA: server unavailable.");
+
+ // Check if there's a relation for this PDF
+
+ var IAFileURI = self.downloadURI + "/" + IAFileName;
+ var rels = Zotero.Relations.getByURIs(null, self.relationPredicate, IAFileURI);
+ if (rels.length) {
+ Zotero.debug("Commons: " + IAFileName + " has already been downloaded -- skipping");
+ continue;
+ }
+
+ var title = null;
+ var baseName = null;
+ for (var i in pdfFileNames) {
+ var fn = pdfFileNames[i];
+ var n = IAFileName.replace("_text.pdf", ".pdf");
+ var pos = n.lastIndexOf(fn);
+ if (pos == -1) {
+ continue;
}
- else {
- alert("Failed to delete " + resource + " at IA.");
- Zotero.debug("Commons: delete failed with status code: " + req.status);
+ // Ignore if filename matches in the middle for some crazy reason
+ if (pos + fn.length != n.length) {
+ continue;
}
+ title = Zotero.localeJoin([pdfTitles[i], '(OCR)']);
+ baseName = fn.match(/(.+)\.pdf/)[1];
+ break;
}
- };
-
- Zotero.Commons.createAuthenticatedRequest(
- method, resource, headers, self.accessKey, self.secretKey, callback
- );
+
+ // If not, import PDF
+ var newAttachment = Zotero.Attachments.importFromURL(
+ IAFileURI, item.id, title, baseName, null, 'application/pdf'
+ );
+ if (!(newAttachment instanceof Zotero.Item)) {
+ throw (newAttachment + " is not a Zotero.Item in Zotero.Commons.Bucket.syncFiles()");
+ }
+
+ // Add a relation linking the new attachment to the IA file
+ var uri = Zotero.URI.getItemURI(newAttachment);
+ Zotero.Relations.add(null, uri, self.relationPredicate, IAFileURI);
+
+ callback(newAttachment);
+ }
- // Delete Zotero RDF file
- zipName = item.key + ".rdf";
- resource = '/' + self.name + '/' + zipName;
- Zotero.debug("Commons: Deleting: " + resource);
+ self._requestingItems = false;
+ });
+}
- Zotero.Commons.createAuthenticatedRequest(
- method, resource, headers, self.accessKey, self.secretKey
- );
- }
+
+// deletes selected items from IA.
+Zotero.Commons.Bucket.prototype.erase = function () {
+ var method = "DELETE";
+ var headers = {
+ "x-archive-cascade-delete":"1"
+ };
+
+ var resource = '/' + this.name;
+ var self = this;
+
+ // Delete IA bucket
+ var callback = function (req) {
+ if (req.status == 204) {
+ Zotero.debug("Commons: " + resource + " was deleted successfully.");
+ this._needRefresh = true;
+ Zotero.Notifier.trigger('refresh', 'bucket', ids);
+
+ //respecify metadata
+ self.updateMetadata(item.key,"delete",null);
+ }
+ else {
+ Zotero.debug(req.status);
+ Zotero.debug(req.responseText);
+
+ if (req.status == 403) {
+ alert("Failed to delete " + resource + " at IA: authentication failed.");
+ }
+ else if (req.status == 503) {
+ alert("Failed to delete " + resource + " at IA: server unavailable.");
+ }
+ else {
+ alert("Failed to delete " + resource + " at IA.");
+ Zotero.debug("Commons: delete failed with status code: " + req.status);
+ }
+ }
+ };
+
+ Zotero.Commons.createAuthenticatedRequest(
+ method, resource, headers, self.accessKey, self.secretKey, callback
+ );
}
-Zotero.Commons.Bucket.prototype.updateMetadata = function(key, action, data) {
- Zotero.debug("updating metadata...");
+// UNUSED
+Zotero.Commons.Bucket.prototype.updateMetadata = function(action, item, callback) {
+ Zotero.debug("Updating bucket metadata");
+
var method = "PUT";
- self = this;
- var headers2 = {
+ var headers = {
"x-archive-ignore-preexisting-bucket":"1",
"x-archive-meta01-collection":"scholarworkspaces",
"x-archive-meta02-collection":"zoterocommons",
@@ -399,63 +963,43 @@ Zotero.Commons.Bucket.prototype.updateMetadata = function(key, action, data) {
};
var meta = null;
- var resource3 = encodeURI('http://archive.org/download/' + self.name + '/' + self.name + '_meta.xml');
+ var resource = encodeURI('http://archive.org/download/' + this.name + '/' + this.name + '_meta.xml');
- // get previous metadata. multiple language support difficult via IA s3.
- Zotero.Utilities.HTTP.doGet(resource3, function(xmlHttp) {
-
- // recreate headers of languages already specified in metadata
- var languages = xmlHttp.responseXML.getElementsByTagName("metadata")[0].getElementsByTagName("language");
-
- if (data && data.items[0]) {
- var itemLanguage = data.items[0].getField('language');
- var langSet = false;
-
- for(var i = 0, len = languages.length; i < len; i++) {
- meta = "x-archive-meta0"+(i+1)+"-language";
- headers2[meta] = languages[i].textContent;
- if (languages[i].textContent == itemLanguage) langSet = true;
- }
+ var self = this;
- // add language for item if not already specified
- if (!langSet) {
- meta = "x-archive-meta0"+(i+1)+"-language";
- headers2[meta] = data.items[0].getField('language');
- }
+ // get previous metadata. multiple language support difficult via IA s3.
+ Zotero.Utilities.HTTP.doGet(resource, function (xmlhttp) {
+ if (xmlhttp.status == 404 || (xmlhttp.status == 200 && !xmlhttp.responseXML)) {
+ Zotero.Commons.error("Error updating bucket metadata");
+ return;
}
- // preserve metatdate for old zotero items
- var text = xmlHttp.responseText;
- var zitem = text.match(/<zoterokey(.*)ZIP/g);
- var zlen = 0;
-
- if (zitem) Zotero.debug(zitem.length);
- if (zitem) zlen = zitem.length;
-
- for(var i=0; i < zlen; i++) {
- var zitemp = zitem[0].split('>');
- meta = "x-archive-meta-" + zitemp[0].substr(1);
- Zotero.debug("Commons: found old zotero key: " + meta + " = " + zitemp[1]);
-
- // if action is delete, don't add
- if (action != "delete" && meta.substr(9).toUpperCase() != key)
- headers2[meta] = zitemp[1];
+ if (itemTitle) {
+ headers["x-archive-meta-title"] = itemTitle;
}
- // adding headers in this way allows for easy scraping from zotero commons pages.
- if (action == "add") {
- meta = "x-archive-meta-" + "zoterokey" + key;
- headers2[meta] = data.items[0].getField('title')+"|"+key+".ZIP";
+ // recreate headers of languages already specified in metadata
+ var languages = xmlhttp.responseXML.getElementsByTagName("metadata")[0].getElementsByTagName("language");
+ var itemLanguage = item.getField('language');
+
+ for (var i = 0, len = languages.length; i < len; i++) {
+ meta = "x-archive-meta0"+(i+1)+"-language";
+ headers[meta] = languages[i].textContent;
}
- Zotero.debug(headers2);
- resource2 = '/' + self.name;
+ Zotero.debug(headers);
+ resource = "/" + this.name;
- var callback = function (req) {
+ var updateCallback = function (req) {
+ Zotero.debug('========');
+ Zotero.debug("UPDATE");
+ Zotero.debug(req.status);
if(req.status < 202) {
- Zotero.debug("Commons: " + resource2 + " metadata updated successfully.");
- // if adding item, upload file
- data.bucket.putKeyCallback(data);
+ Zotero.debug("Commons: " + resource + " metadata updated successfully.");
+
+ if (callback) {
+ callback();
+ }
}
else {
Zotero.debug(req.status);
@@ -474,286 +1018,25 @@ Zotero.Commons.Bucket.prototype.updateMetadata = function(key, action, data) {
};
Zotero.Commons.createAuthenticatedRequest(
- method, resource2, headers2, self.accessKey, self.secretKey, callback
+ method, resource, headers, self.accessKey, self.secretKey, updateCallback
);
});
}
-// return an array of items currently stored in this bucket
-Zotero.Commons.Bucket.prototype.getItems = function() {
- var method = "GET";
- var resource = '/' + this.name;
-
- if(this._items && !this._needRefresh) {
- Zotero.debug("Commons: items already set. Returing existing items set");
- return this._items;
- }
- else {
- Zotero.debug("Commons: items need refresh. re-getting...");
- }
-
- // avoid multiple requests to IA
- if(this._requestingItems) {
- Zotero.debug("Commons: already requesting items");
- return [];
- }
-
- this._requestingItems = true;
- var self = this;
- self._items = [];
-
- // get a list of keys (files) associated with this bucket
- var req = Zotero.Utilities.HTTP.doGet(Zotero.Commons.apiUrl + resource, function(xmlhttp) {
- if (xmlhttp.status != 200) {
- Zotero.debug(xmlhttp.status);
- Zotero.debug(xmlhttp.responseText);
- alert("Error loading data from the Internet Archive");
- self._requestingItems = false;
- return;
- }
-
- Zotero.debug(xmlhttp.responseText);
-
- var itemIDs = [];
-
- // While looking for Zotero exported items in the bucket,
- // check for a full-text ("derived" in IA terms) OCR'd version of the PDF.
- // If so, get it and add it as an attachment to the corresponding Zotero client item.
-
- // TODO: replace original PDF?
-
- var contents = null;
- contents = xmlhttp.responseXML.getElementsByTagName("Contents");
-
- // loop through files listed in bucket contents file
- for(var i = 0, len = contents.length; i < len; i++) {
- var keyParts = contents[i].getElementsByTagName('Key')[0].textContent.split('.');
-
- // if key file is Zotero ZIP export item
- // TODO: check to see if really a zotero item, not just a IA zip
- if(keyParts.length == 2 && keyParts[1] == 'zip') {
- var key = keyParts[0];
- Zotero.debug("Commons: found key in IA response: " + key);
-
- // see if the ZIP item corresponds to a zotero item (ZIP name = item key)
- // This of course only works for the creator of the bucket.
- // Others will get Zotero items from the IA bucket via a translator.
- var item = Zotero.Items.getByLibraryAndKey(null, key);
-
- if(item) {
- Zotero.debug("Commons: found item:" + item.id);
- itemIDs.push(item.id);
- this._needRefresh = false;
-
- // loop through attachments of this item and look for missing OCR'd PDFs
- var attachmentIDs = item.getAttachments();
- for(var j = 0, len2 = attachmentIDs.length; j < len2; j++) {
- var attachedItem = Zotero.Items.get(attachmentIDs[j]);
- var fileName = attachedItem.getFilename();
-
- // Since we have to upload all files without spaces in the name (or they won't be OCR'd),
- // we need to look for the hyphenated version of actual attachment name.
- // A space next to a hyphen should be deleted, not repleaced with another hyphen
- if (fileName && fileName.substr(fileName.length-9) != "_text.pdf") {
- var haveOCRVersion = false;
- var IAfileName = fileName.substr(0,fileName.length-4).replace(/ /g,'-') + "_text.pdf";
- IAfileName = IAfileName.replace(/-+/g,'-');
- Zotero.debug("Commons: OCR'd file for this attachment would be: " + IAfileName);
-
- // check to see if we already have the OCR'd PDF attached to the zotero item
- for(var k = 0, len3 = attachmentIDs.length; k < len3; k++) {
- var attachedItem = Zotero.Items.get(attachmentIDs[k]);
- if (attachedItem.getFilename() == IAfileName)
- haveOCRVersion = true;
- }
-
- // if we need to get the OCR version...
- if (!haveOCRVersion) {
-
- // set up new attachment
- var attachmentUri = "http://s3.us.archive.org/"+self.name+"/" + IAfileName;
- var mimeType = "application/pdf";
-
- // scan bucket contents to see if the OCR'd PDF is available
- for(var con = 0, len = contents.length; con < len; con++) {
- var keys = contents[con].getElementsByTagName("Key");
-
- for(var l = 0, len4 = keys.length; l < len4; l++) {
- if (keys[l].textContent == IAfileName) {
- Zotero.debug("Commons: about to get OCR file from: " + attachmentUri);
- Zotero.Attachments.importFromURL(attachmentUri, item.id, null, null, null, mimeType, null);
- }
- else {
- //Zotero.debug("Commons: no OCR'd PDF of this attachment is available.");
- }
- } // for each key
- } // for each contents
- } // end if need to get PDF
- else {
- Zotero.debug("Commons: do not need OCR'd PDF for attachment " + fileName);
- }
- }
- }
-
- self._items.push(item);
- }
- }
- }
-
- Zotero.Notifier.trigger('refresh', 'bucket', itemIDs);
-
- self._requestingItems = false;
- });
-
- // Browser offline
- if (!req) {
- self._requestingItems = false;
- }
-
- // List isn't yet available
- return [];
-}
-
-
-// upload zipped Zotero RDF output of items to this bucket
-Zotero.Commons.Bucket.prototype.uploadItems = function(ids) {
- this._items = null;
- var items = Zotero.Items.get(ids);
-
- if (!items) {
- Zotero.debug("No items to upload");
- return;
- }
-
- var itemsToUpload = false;
- for (var i=0, len=items.length; i<len; i++) {
- if (items[i].isRegularItem()) {
- itemsToUpload = true;
- break;
- }
- }
-
- var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
- .getService(Components.interfaces.nsIPrompt);
-
- if (!itemsToUpload) {
- Zotero.debug("No regular items to upload");
- pr.alert("", "Only items with bibliographic metadata can be added to the Zotero Commons.");
- return;
- }
-
- var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
- + (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL);
- var index = pr.confirmEx(
- "Zotero Commons Upload",
- "By uploading items to Zotero Commons you agree to the terms of use at zotero.org and archive.org. "
- + "Please make sure metadata for your item(s) is set properly."
- + "\n\n "
- + "Continue to upload items to the Internet Archive?",
- buttonFlags,
- "Upload",
- null, null, null, {}
- );
-
- // if user chooses 'cancel', exit.
- if (index != 0) return;
-
- var tmpDir = Zotero.getTempDirectory();
-
- // export individual items through the Zotero RDF translation
- for(var i = 0, len = items.length; i < len; i++) {
- var item = items[i];
- if(item.isRegularItem()) {
- // generate file location for the export output
- var rdfExportPath = Components.classes["@mozilla.org/file/local;1"]
- .createInstance(Components.interfaces.nsILocalFile);
- rdfExportPath.initWithFile(tmpDir);
- rdfExportPath.append(item.key);
-
- // initialize and run the translator for this item
- var translation = new Zotero.Translate("export");
- translation.setItems([item]);
- translation.setTranslator(this.RDF_TRANSLATOR.translatorID);
- translation.setDisplayOptions(this.RDF_TRANSLATOR.displayOptions);
- translation.setHandler("done", this._translateCallback);
- translation.setLocation(rdfExportPath);
-
- // add some data to translator needed by _translateCallback
- translation._bucketData = {bucket: this, items: [item]};
-
- translation.translate(); // synchronous
- }
- }
-}
-
-
-// Zips the output of the translation and then calls putKey
-// Called after a translation is done.
-Zotero.Commons.Bucket.prototype._translateCallback = function(translation, success) {
- if(!success) {
- alert("Commons: translation failed for " + translation);
- return;
- }
-
- var data = translation._bucketData;
-
- try {
- var dir = Components.classes["@mozilla.org/file/local;1"]
- .createInstance(Components.interfaces.nsILocalFile);
- dir.initWithPath(translation.path);
-
-
- // capture RDF file because it needs to be sent along with all PDFs
- var rdfPath = translation.path + "/" + dir.leafName + ".rdf";
- var rdfFile = Components.classes["@mozilla.org/file/local;1"]
- .createInstance(Components.interfaces.nsILocalFile);
- rdfFile.initWithPath(rdfPath);
- Zotero.debug("Commons: RDF: " + rdfFile.path);
-
- // send one copy of RDF file with name of zotero item key.
- // this allows us to very easily roundtrip zotero items.
- data.uploadFile = rdfFile;
- data.mimetype = "application/rdf+xml";
- data.bucket.putKeyCallback(data);
-
- // create zip file
- var zipFile = Zotero.getTempDirectory();
- zipFile.append(dir.leafName + '.zip');
- Zotero.debug("Commons: created zipFile: " + dir.leafName);
-
- var zw = Components.classes["@mozilla.org/zipwriter;1"]
- .createInstance(Components.interfaces.nsIZipWriter);
- zw.open(zipFile, 0x04 | 0x08 | 0x20); // open rw, create, truncate
-
- data.bucket.zipDirectory(data.bucket, dir, dir, zw);
- data.uploadFile = zipFile;
- data.mimetype = "application/zip";
-
- // add observer so putKey is called on zip completion
- var observer = new Zotero.Commons.ZipWriterObserver(zw, data.bucket.putKey, data);
- zw.processQueue(observer, null);
- }
- catch (e) {
- alert("Commons: Upload failed: " + e);
- }
-}
-
-
-Zotero.Commons.Bucket.prototype.putKeyCallback = function(data) {
- var self = data.bucket;
- var keyHyphened = data.uploadFile.leafName.replace(/ /g,'-');
- var key = data.uploadFile.leafName;
+Zotero.Commons.Bucket.prototype.putFile = function (file, mimeType, callback) {
+ var fileName = file.leafName;
+ var fileNameHyphened = fileName.replace(/ /g,'-');
var method = "PUT";
- var resource = encodeURI('/' + self.name + '/' + keyHyphened);
- var content = self.readFileContents(data.uploadFile);
+ var resource = encodeURI('/' + this.name + '/' + fileNameHyphened);
+ var content = Zotero.File.getBinaryContents(file);
var headers = {};
+ var self = this;
- Zotero.debug("Uploading: " + resource);
-
- var callback = function (req) {
+ var putCallback = function (req) {
+ // Success
if (req.status == 201) {
- for (var i = 0, len = data.items.length; i < len; i++) {
+ /*for (var i = 0, len = data.items.length; i < len; i++) {
var url1 = Zotero.URI.getItemURI(data.items[i]);
var predicate = self.relationPredicate;
var url2 = self.getKeyUrl(self.name, keyHyphened);
@@ -764,58 +1047,43 @@ Zotero.Commons.Bucket.prototype.putKeyCallback = function(data) {
continue;
}
Zotero.Relations.add(null, url1, predicate, url2);
+ }*/
+ Zotero.debug("Commons: " + fileName + " was uploaded successfully.");
+ //this._needRefresh = true;
+ //Zotero.Notifier.trigger('refresh', 'bucket', null);
+
+ if (callback) {
+ callback(req.channel.URI.spec);
}
- Zotero.debug("Commons: " + key + " was uploaded successfully.");
- this._needRefresh = true;
- //Zotero.Notifier.trigger('refresh', 'bucket', null);
+ return;
+ }
+
+ // Error
+ Zotero.debug(req.status);
+ Zotero.debug(req.responseText);
+
+ if (req.status == 404) {
+ alert("Failed to upload " + fileName + " to IA: bucket not found");
+ }
+ else if (req.status == 403) {
+ alert("Failed to upload " + fileName + " to IA: authentication failed.");
+ }
+ else if (req.status == 503) {
+ alert("Failed to upload " + fileName + " to IA: server unavailable.");
}
else {
- Zotero.debug(req.status);
- Zotero.debug(req.responseText);
-
- if (req.status == 403) {
- alert("Failed to upload " + key + " to IA: authentication failed.");
- }
- else if (req.status == 503) {
- alert("Failed to upload " + key + " to IA: server unavailable.");
- }
- else {
- alert("Failed to upload " + key + " to IA. status is " + req.status);
- }
+ alert("Failed to upload " + fileName + " to IA. status is " + req.status);
}
};
Zotero.Commons.createAuthenticatedRequest(
- method, resource, headers, self.accessKey, self.secretKey, callback, content, true
+ method, resource, headers, this.accessKey, this.secretKey, putCallback, content, true
);
}
-// Does the put call to IA, puting data.uploadFile into the bucket
-// Changed to be a generic function to put something to IA
-Zotero.Commons.Bucket.prototype.putKey = function(data, skipMeta) {
- var self = data.bucket;
- var key = data.uploadFile.leafName.substr(0,data.uploadFile.leafName.length-4);
- var action = "add";
-
- // updateMetadata calls putKeyCallback after metadata request is successful.
- if (!skipMeta) self.updateMetadata(key, action, data);
-}
-
-
-// return the content of an input nsiFile
-Zotero.Commons.Bucket.prototype.readFileContents = function(bfile) {
- var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
- .createInstance(Components.interfaces.nsIFileInputStream);
- istream.init(bfile, -1, -1, false);
- var bstream = Components.classes["@mozilla.org/binaryinputstream;1"]
- .createInstance(Components.interfaces.nsIBinaryInputStream);
- bstream.setInputStream(istream);
- return bstream.readBytes(bstream.available());
-}
-
// Recursively add files and directories to zipWriter
-Zotero.Commons.Bucket.prototype.zipDirectory = function(self, rootDir, dir, zipWriter) {
+Zotero.Commons.Bucket.prototype.zipDirectory = function(rootDir, dir, zipWriter) {
dir = dir.directoryEntries;
while(dir.hasMoreElements()) {
var file = dir.getNext();
@@ -836,19 +1104,98 @@ Zotero.Commons.Bucket.prototype.zipDirectory = function(self, rootDir, dir, zipW
);
if(file.isDirectory()) {
- self.zipDirectory(self, rootDir, file, zipWriter);
+ this.zipDirectory(rootDir, file, zipWriter);
continue;
}
}
}
+Zotero.Commons.Bucket.prototype._loadMetadata = function (callback) {
+ if (this._metadataLoading) {
+ return;
+ }
+
+ this._metadataLoading = true;
+ var self = this;
+
+ Zotero.Utilities.HTTP.doGet(this.rdfURI, function (xmlhttp) {
+ // If RDF not available, use the bucket metadata
+ if (xmlhttp.status != 200) {
+ Zotero.debug("RDF for bucket " + self.name + " not available");
+
+ /*Zotero.Utilities.HTTP.doGet(self.metadataURI, function (xmlhttp) {
+ if (xmlhttp.status != 200) {
+ Zotero.debug(xmlhttp.status);
+ Zotero.debug(xmlhttp.responseText);
+ return;
+ }
+
+ Zotero.debug(xmlhttp.responseText);
+
+ // Strip XML declaration and convert to E4X
+ var xml = new XML(xmlhttp.responseText.replace(/<\?xml.*\?>/, ''));
+ var title = xml.title;
+ if (!self._item) {
+ self._item = new Zotero.Item("document");
+ self._item.id = Zotero.ID.getBigInt();
+ }
+ self._item.setField('title', title);
+
+ self._metadataLoading = false;
+
+ if (callback) {
+ callback();
+ }
+ });*/
+ return;
+ }
+
+ Zotero.debug(xmlhttp.responseText);
+
+ var translate = new Zotero.Translate("import");
+ translate.setString(xmlhttp.responseText);
+ translate.getTranslators()
+ translate.setTranslator(Zotero.Commons.RDF_IMPORT_TRANSLATOR.translatorID);
+ translate.setHandler("itemDone", function (translation, item) {
+ var typeID = Zotero.ItemTypes.getID(item.itemType);
+ var newItem = new Zotero.Item(typeID);
+ newItem.id = Zotero.ID.getBigInt();
+
+ for (var field in item) {
+ // Skip empty fields
+ if (!item[field]) {
+ continue;
+ }
+ var fieldID = Zotero.ItemFields.getID(field);
+ if (!fieldID) {
+ continue;
+ }
+ Zotero.debug('setting field ' + fieldID + ' to ' + item[field]);
+ try {
+ newItem.setField(fieldID, item[field]);
+ }
+ catch(e) { Zotero.debug(e); }
+ }
+
+ self._item = newItem;
+ self._metadataLoading = false;
+
+ if (callback) {
+ callback();
+ }
+ return;
+ });
+ translate.translate(false, false);
+ });
+}
+
+
// Implements nsIRequestObserver
-Zotero.Commons.ZipWriterObserver = function (zipWriter, callback, callbackData) {
+Zotero.Commons.ZipWriterObserver = function (zipWriter, callback) {
this._zipWriter = zipWriter;
this._callback = callback;
- this._callbackData = callbackData;
}
Zotero.Commons.ZipWriterObserver.prototype = {
@@ -856,7 +1203,7 @@ Zotero.Commons.ZipWriterObserver.prototype = {
onStopRequest: function(req, context, status) {
this._zipWriter.close();
- this._callback(this._callbackData);
+ this._callback();
}
}
diff --git a/chrome/content/zotero/xpcom/data/group.js b/chrome/content/zotero/xpcom/data/group.js
@@ -338,7 +338,7 @@ Zotero.Group.prototype.erase = function() {
Zotero.DB.query(sql, this.libraryID);
var prefix = "groups/" + this.id;
- Zotero.Relations.eraseByPathPrefix(prefix);
+ Zotero.Relations.eraseByURIPrefix(Zotero.URI.defaultPrefix + prefix);
// Delete group
sql = "DELETE FROM groups WHERE groupID=?";
diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js
@@ -741,7 +741,7 @@ Zotero.Item.prototype.setField = function(field, value, loadIn) {
}
if (!Zotero.ItemFields.isValidForType(fieldID, this.itemTypeID)) {
- var msg = '"' + field + "' is not a valid field for type " + this.itemTypeID;
+ var msg = "'" + field + "' is not a valid field for type " + this.itemTypeID;
if (loadIn) {
Zotero.debug(msg + " -- ignoring value '" + value + "'", 2);
@@ -1240,7 +1240,7 @@ Zotero.Item.prototype.save = function() {
if (Zotero.ItemFields.getID('accessDate') == fieldID
&& this.getField(fieldID) == 'CURRENT_TIMESTAMP') {
- value = Zotero.DB.transactionDateTime;
+ value = Zotero.DB.transactionDateTime;
}
var dataType = ZU.getSQLDataType(value);
@@ -3944,7 +3944,10 @@ Zotero.Item.prototype.erase = function() {
//Zotero.Fulltext.clearItemContent(this.id);
}
-
+ // Remove relations
+ var relation = Zotero.URI.getItemURI(this);
+ Zotero.Relations.eraseByURIPrefix(relation);
+
Zotero.DB.query('DELETE FROM annotations WHERE itemID=?', this.id);
Zotero.DB.query('DELETE FROM highlights WHERE itemID=?', this.id);
Zotero.DB.query('DELETE FROM deletedItems WHERE itemID=?', this.id);
diff --git a/chrome/content/zotero/xpcom/data/relations.js b/chrome/content/zotero/xpcom/data/relations.js
@@ -31,8 +31,6 @@ Zotero.Relations = new function () {
owl: 'http://www.w3.org/2002/07/owl#'
};
- var _prefix = "http://zotero.org/";
-
this.get = function (id) {
if (typeof id != 'number') {
throw ("id '" + id + "' must be an integer in Zotero.Relations.get()");
@@ -165,13 +163,40 @@ Zotero.Relations = new function () {
}
- this.eraseByPathPrefix = function (prefix) {
- prefix = _prefix + prefix + '%';
+ this.eraseByURIPrefix = function (prefix) {
+ prefix = prefix + '%';
sql = "DELETE FROM relations WHERE subject LIKE ? OR object LIKE ?";
Zotero.DB.query(sql, [prefix, prefix]);
}
+ this.eraseByURI = function (uri) {
+ sql = "DELETE FROM relations WHERE subject=? OR object=?";
+ Zotero.DB.query(sql, [uri, uri]);
+ }
+
+
+ this.purge = function () {
+ var sql = "SELECT subject FROM relations UNION SELECT object FROM relations";
+ var uris = Zotero.DB.columnQuery(sql);
+ if (uris) {
+ var prefix = Zotero.URI.defaultPrefix;
+ Zotero.DB.beginTransaction();
+ for each(var uri in uris) {
+ // Skip URIs that don't begin with the default prefix,
+ // since they don't correspond to local items
+ if (uri.indexOf(prefix) == -1) {
+ continue;
+ }
+ if (!Zotero.URI.getURIItem(uri)) {
+ this.eraseByURI(uri);
+ }
+ }
+ Zotero.DB.commitTransaction();
+ }
+ }
+
+
this.xmlToRelation = function (xml) {
var relation = new Zotero.Relation;
var libraryID = xml.@libraryID.toString();
@@ -196,7 +221,7 @@ Zotero.Relations = new function () {
var [prefix, value] = uri.split(':');
if (prefix && value) {
if (!_namespaces[prefix]) {
- throw ("Invalid prefix '" + prefix + "' in Zotero.Relations.add()");
+ throw ("Invalid prefix '" + prefix + "' in Zotero.Relations._getPrefixAndValue()");
}
return [prefix, value];
}
diff --git a/chrome/content/zotero/xpcom/file.js b/chrome/content/zotero/xpcom/file.js
@@ -137,6 +137,21 @@ Zotero.File = new function(){
}
+
+ /**
+ * Return the contents of a file as a byte array
+ */
+ this.getBinaryContents = function (bfile) {
+ var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Components.interfaces.nsIFileInputStream);
+ istream.init(bfile, -1, -1, false);
+ var bstream = Components.classes["@mozilla.org/binaryinputstream;1"]
+ .createInstance(Components.interfaces.nsIBinaryInputStream);
+ bstream.setInputStream(istream);
+ return bstream.readBytes(bstream.available());
+ }
+
+
/*
* Return the contents of a URL as a string
*
diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js
@@ -52,7 +52,7 @@ Zotero.ItemTreeView = function(itemGroup, sourcesOnly)
this._dataItems = [];
this.rowCount = 0;
- this._unregisterID = Zotero.Notifier.registerObserver(this, ['item', 'collection-item', 'share-items', 'bucket']);
+ this._unregisterID = Zotero.Notifier.registerObserver(this, ['item', 'collection-item', 'share-items', 'commons']);
}
@@ -260,6 +260,7 @@ Zotero.ItemTreeView.prototype.refresh = function()
*/
Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
{
+ Zotero.debug('=============');
if (!this._treebox || !this._treebox.treeBody) {
Components.utils.reportError("Treebox didn't exist in itemTreeView.notify()");
return;
@@ -269,7 +270,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
Zotero.debug("Item row map didn't exist in itemTreeView.notify()");
return;
}
-
+ Zotero.debug(1);
var itemGroup = this._itemGroup;
var madeChanges = false;
@@ -284,9 +285,10 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
this.refresh();
}
}
- else if (type == 'bucket') {
- if (itemGroup.isBucket()) {
+ else if (type == 'commons') {
+ if (itemGroup.isCommons()) {
this.refresh();
+ this.sort();
}
}
else if (savedSelection.length == 1 && savedSelection[0] == ids[0]) {
@@ -455,6 +457,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
}
else if(action == 'add')
{
+ Zotero.debug(2);
// If saved search or trash, just re-run search
if (itemGroup.isSearch() || itemGroup.isTrash()) {
this.refresh();
@@ -499,6 +502,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
if(madeChanges)
{
+ Zotero.debug(3);
// If adding and this is the active window, select the item
if(action == 'add' && ids.length===1 && activeWindow)
{
@@ -511,7 +515,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
// Reset to Info tab
this._ownerDocument.getElementById('zotero-view-tabbox').selectedIndex = 0;
-
+ Zotero.debug(4);
this.selectItem(ids[0]);
}
// If single item is selected and was modified
@@ -540,6 +544,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
}
else
{
+ Zotero.debug(4);
var previousRow = this._itemRowMap[ids[0]];
if (sort) {
@@ -1112,6 +1117,8 @@ Zotero.ItemTreeView.prototype.sort = function(itemID)
*/
Zotero.ItemTreeView.prototype.selectItem = function(id, expand, noRecurse)
{
+ Zotero.debug('=============');
+ Zotero.debug(Zotero.suppressUIUpdates);
// Don't change selection if UI updates are disabled (e.g., during sync)
if (Zotero.suppressUIUpdates) {
return;
@@ -1267,8 +1274,8 @@ Zotero.ItemTreeView.prototype.deleteSelection = function (force)
else if (itemGroup.isCollection()) {
itemGroup.ref.removeItems(ids);
}
- else if (itemGroup.isBucket()) {
- itemGroup.ref.deleteItems(ids);
+ else if (itemGroup.isCommons()) {
+ Zotero.Commons.deleteItems(ids);
}
this._treebox.endUpdateBatch();
}
diff --git a/chrome/content/zotero/xpcom/uri.js b/chrome/content/zotero/xpcom/uri.js
@@ -25,6 +25,8 @@
Zotero.URI = new function () {
+ this.__defineGetter__('defaultPrefix', function () 'http://zotero.org/');
+
var _baseURI = ZOTERO_CONFIG.BASE_URI;
var _apiURI = ZOTERO_CONFIG.API_URI;
@@ -166,12 +168,12 @@ Zotero.URI = new function () {
if (itemURI.indexOf(localUserURI) == 0) {
itemURI = itemURI.substr(localUserURI.length);
var libraryType = 'user';
- var libraryTypeID = null;
+ var libraryID = null;
}
}
*/
var libraryType = 'user';
- var libraryTypeID = null;
+ var libraryID = null;
}
// If not found, try global URI
@@ -186,7 +188,7 @@ Zotero.URI = new function () {
throw ("Invalid library URI '" + itemURI + "' in Zotero.URI.getURIItem()");
}
var libraryType = matches[1].substr(0, matches[1].length-1);
- var libraryTypeID = matches[2];
+ var libraryID = matches[2];
itemURI = itemURI.replace(typeRE, '');
}
@@ -202,7 +204,10 @@ Zotero.URI = new function () {
}
if (libraryType == 'group') {
- var libraryID = Zotero.Groups.getLibraryIDFromGroupID(libraryTypeID);
+ if (!Zotero.Libraries.exists(libraryID)) {
+ return false;
+ }
+ var libraryID = Zotero.Groups.getLibraryIDFromGroupID(libraryID);
return Zotero.Items.getByLibraryAndKey(libraryID, itemKey);
}
}
diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js
@@ -1033,6 +1033,8 @@ var Zotero = new function(){
* Returns true if an object (or associative array) has at least one value
*/
function hasValues(obj) {
+ Zotero.debug("WARNING: Zotero.isEmpty() is deprecated! Use Zotero.Utilities.isEmpty(obj)", 2);
+
for (var i in obj) {
return true;
}
@@ -1239,6 +1241,8 @@ var Zotero = new function(){
Zotero.Tags.purge();
Zotero.Fulltext.purgeUnusedWords();
Zotero.Items.purge();
+ // DEBUG: this might not need to be permanent
+ Zotero.Relations.purge();
if (!skipStoragePurge && Zotero.Utilities.prototype.probability(10)) {
Zotero.Sync.Storage.purgeDeletedStorageFiles('zfs');
diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js
@@ -110,7 +110,6 @@ pref("extensions.zotero.zeroconf.server.enabled", false);
// Zotero Commons
pref("extensions.zotero.commons.enabled", false);
-pref("extensions.zotero.commons.buckets", '');
pref("extensions.zotero.commons.accessKey", '');
pref("extensions.zotero.commons.secretKey", '');