diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js index e71482ac3..01e4e7f5e 100644 --- a/chrome/content/zotero/overlay.js +++ b/chrome/content/zotero/overlay.js @@ -1983,8 +1983,17 @@ 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); + event.stopPropagation(); + } } else if (tree.id == 'zotero-items-tree') { var viewOnDoubleClick = Zotero.Prefs.get('viewOnDoubleClick'); diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js index 2a0a8d1f2..326500689 100644 --- a/chrome/content/zotero/xpcom/collectionTreeView.js +++ b/chrome/content/zotero/xpcom/collectionTreeView.js @@ -224,6 +224,26 @@ Zotero.CollectionTreeView.prototype.refresh = function() this._showItem(new Zotero.ItemGroup('share', share)); } } + + var buckets = Zotero.Commons.buckets; + if(buckets.length) { + 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); + } this._refreshHashMap(); @@ -473,6 +493,9 @@ 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': @@ -485,7 +508,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(); + return itemGroup.isLibrary(true) || itemGroup.isCollection() || itemGroup.isHeader() || itemGroup.isBucket(); } Zotero.CollectionTreeView.prototype.isContainerOpen = function(row) @@ -505,6 +528,9 @@ Zotero.CollectionTreeView.prototype.isContainerEmpty = function(row) if (itemGroup.isHeader()) { return false; } + if (itemGroup.isBucket()) { + return true; + } if (itemGroup.isGroup()) { return !itemGroup.ref.hasCollections(); } @@ -562,6 +588,8 @@ 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(); @@ -999,6 +1027,11 @@ Zotero.CollectionTreeView.prototype.canDrop = function(row, orient, dragData) } if (dataType == 'zotero/item') { + + if(itemGroup.isBucket()) { + return true; + } + var ids = data; var items = Zotero.Items.get(ids); var skip = true; @@ -1139,6 +1172,11 @@ Zotero.CollectionTreeView.prototype.drop = function(row, orient) else { var targetLibraryID = null; } + + if(itemGroup.isBucket()) { + itemGroup.ref.uploadItems(ids); + return; + } Zotero.DB.beginTransaction(); @@ -1472,6 +1510,11 @@ Zotero.ItemGroup.prototype.isShare = function() return this.type == 'share'; } +Zotero.ItemGroup.prototype.isBucket = function() +{ + return this.type == 'bucket'; +} + Zotero.ItemGroup.prototype.isTrash = function() { return this.type == 'trash'; @@ -1535,6 +1578,9 @@ 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'); @@ -1556,6 +1602,9 @@ Zotero.ItemGroup.prototype.getChildItems = function() // Fake results if this is a shared library case 'share': return this.ref.getAll(); + + case 'bucket': + return this.ref.getItems(); case 'header': return []; @@ -1661,6 +1710,9 @@ Zotero.ItemGroup.prototype.getChildTags = function() { // TODO: implement? case 'share': return false; + + case 'bucket': + return false; case 'header': return false; @@ -1703,4 +1755,4 @@ Zotero.ItemGroup.prototype.isSearchMode = function() { return true; } } -} \ No newline at end of file +} diff --git a/chrome/content/zotero/xpcom/commons.js b/chrome/content/zotero/xpcom/commons.js new file mode 100644 index 000000000..c6eae09fd --- /dev/null +++ b/chrome/content/zotero/xpcom/commons.js @@ -0,0 +1,557 @@ +/* + ***** BEGIN LICENSE BLOCK ***** + + Copyright (c) 2006 Center for History and New Media + George Mason University, Fairfax, Virginia, USA + http://chnm.gmu.edu + + Licensed under the Educational Community License, Version 1.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.opensource.org/licenses/ecl1.php + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ***** END LICENSE BLOCK ***** +*/ + +Zotero.Commons = new function() { + + this.uri = 'http://www.archive.org/'; + + this.__defineGetter__('buckets', function () { + if(!Zotero.Prefs.get("commons.enabled")) { + return []; + } + + 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; + }); +} + + +// accessKey and secretKey are passed to allow easy implementation +// of using multiple accounts +Zotero.Commons.Bucket = function(name, accessKey, secretKey) { + this.name = name; + this._accessKey = accessKey; + this._secretKey = secretKey; + this._items = null; + this._requestingItems = false; +} + + +Zotero.Commons.Bucket.prototype.apiUrl = 'http://s3.us.archive.org'; + +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__('uri', function () { + return 'http://www.archive.org/details/' + this.name; +}); + +Zotero.Commons.Bucket.prototype.getKeyUrl = function(name, key) { + return 'http://' + name + '.s3.us.archive.org/' + key; + +} + +Zotero.Commons.Bucket.prototype.relationPredicate = "owl:sameAs"; + +// return an array of items currently stored in this bucket +Zotero.Commons.Bucket.prototype.getItems = function() { + /*if(this._items) { + return this._items; + } + + // avoid multiple requests to IA + if(this._requestingItems) { + return []; + } + + this._requestingItems = true; + + // get a list of keys associated with this bucket + var method = "GET"; + var resource = '/' + this.name + '/'; + var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Components.interfaces.nsIXMLHttpRequest); + req.open(method, this.apiUrl + resource, true); + //req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; + + var self = this; + req.onreadystatechange = function() { + if (req.readyState == 4) { + if(req.status < 400) { + // TODO this is completely wrong and needs to change + // Need to figure out IA/Zotero interaction first + self._items = []; + var contents = req.responseXML.getElementsByTagName("Contents"); + for(var i = 0, len = contents.length; i < len; i++) { + var keyParts = contents[i].getElementsByTagName('Key')[0].textContent.split('.'); + if(keyParts.length == 2 && keyParts[1] == 'zip') { + var key = keyParts[0]; + var item = Zotero.Items.getByLibraryAndKey(null, key); + if(item) { + self._items.push(item); + } + } + } + Zotero.Notifier.trigger('refresh', 'bucket', 'all'); + } + else { + alert("Request to get the keys of bucket " + self.name + " failed."); + } + self._requestingItems = false; + } + }; + + req.send(null); + */ + return []; +} + + +// upload zipped Zotero RDF output of items to this bucket +Zotero.Commons.Bucket.prototype.uploadItems = function(ids) { + var items = Zotero.Items.get(ids); + if (!items) { + 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, successful) { + if(!successful) { + alert("Commons.TranslatorManager: tranlation failed for " + translation); + } + + var data = translation._bucketData; + + try { + var dir = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + dir.initWithPath(translation.path); + + // create zip file + var zipFile = Zotero.getTempDirectory(); + zipFile.append(dir.leafName + '.zip'); + + 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; + // 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); + } +} + +// Does the put call to IA, puting data.uploadFile into the bucket +Zotero.Commons.Bucket.prototype._putKey = function(data) { + var self = data.bucket; + var method = "PUT"; + var mimeType = 'application/zip'; + var key = data.uploadFile.leafName; + var resource = '/' + self.name + '/' + key; + var content = self._readFileContents(data.uploadFile); + + var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Components.interfaces.nsIXMLHttpRequest); + req.open(method, self.apiUrl + resource, true); + + var d = new Date(); + var headers = {}; + headers["Content-Type"] = mimeType; + headers["Content-Length"] = content.length; + headers["Date"] = d.toUTCString(); + headers["x-amz-meta-creator"] = "Zotero Commons"; + + for(var header in headers) { + req.setRequestHeader(header, headers[header]); + } + + var signature = self._generateSignature(method, resource, headers, self._secretKey); + req.setRequestHeader("Authorization", "AWS " + self._accessKey + ":" + signature); + //req.setRequestHeader("Authorization", "LOW " + self._accessKey + ":" + self._secretKey); + + req.onreadystatechange = function() { + if (req.readyState == 4) { + if(req.status < 400) { + 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, key); + + if (Zotero.Relations.getByURIs(url1, predicate, url2).length + || Zotero.Relations.getByURIs(url2, predicate, url1).length) { + Zotero.debug(url1 + " and " + url2 + " are already linked"); + continue; + } + Zotero.Relations.add(null, url1, predicate, url2); + } + Zotero.debug("Commons: " + key + " was uploaded successfully."); + } + else 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."); + } + } + }; + + req.sendAsBinary(content); +} + +// 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) { + dir = dir.directoryEntries; + while(dir.hasMoreElements()) { + var file = dir.getNext(); + file.QueryInterface(Components.interfaces.nsILocalFile); + + var fileName = file.getRelativeDescriptor(rootDir); + if(fileName.indexOf('.') == 0) { + Zotero.debug('Skipping file ' + fileName); + continue; + } + + // addEntryFile works for both files and directories + zipWriter.addEntryFile( + fileName, + Components.interfaces.nsIZipWriter.COMPRESSION_DEFAULT, + file, + true + ); + + if(file.isDirectory()) { + self._zipDirectory(self, rootDir, file, zipWriter); + continue; + } + } +} + +Zotero.Commons.Bucket.prototype._generateSignature = function(method, resource, headers, secretKey) { + var data = method + '\n' + + ((headers['Content-MD5']) ? headers['Content-MD5'] : '') + '\n' + + ((headers['Content-Type']) ? headers['Content-Type'] : '') + '\n' + + ((headers['Date']) ? headers['Date'] : '') + '\n'; + + // add x-amz- headers in alphabetic order + var amz = []; + for(header in headers) { + if(header.indexOf("x-amz-") == 0) { + amz.push(header + ":" + headers[header] + '\n'); + } + } + data += amz.sort().join(''); + + data += resource; + + return Zotero.Commons.SHA1.b64_hmac_sha1(secretKey, data) + '='; +} + + + +// Implements nsIRequestObserver +Zotero.Commons.ZipWriterObserver = function (zipWriter, callback, callbackData) { + this._zipWriter = zipWriter; + this._callback = callback; + this._callbackData = callbackData; +} + +Zotero.Commons.ZipWriterObserver.prototype = { + onStartRequest: function () {}, + + onStopRequest: function(req, context, status) { + this._zipWriter.close(); + this._callback(this._callbackData); + } +} + + + +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ +Zotero.Commons.SHA1 = new function() { + + // added by Ben Parr to expose function for Zotero + this.hex_sha1 = hex_sha1; + this.b64_sha1 = b64_sha1; + this.str_sha1 = str_sha1; + this.hex_hmac_sha1 = hex_hmac_sha1; + this.b64_hmac_sha1 = b64_hmac_sha1; + this.str_hmac_sha1 = str_hmac_sha1; + + + /* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ + var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ + var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ + var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + + /* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ + function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} + function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} + function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} + function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} + function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} + function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} + + /* + * Perform a simple self-test to see if the VM is working + */ + function sha1_vm_test() + { + return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; + } + + /* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ + function core_sha1(x, len) + { + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + for(var j = 0; j < 80; j++) + { + if(j < 16) w[j] = x[i + j]; + else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + + } + + /* + * Perform the appropriate triplet combination function for the current + * iteration + */ + function sha1_ft(t, b, c, d) + { + if(t < 20) return (b & c) | ((~b) & d); + if(t < 40) return b ^ c ^ d; + if(t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; + } + + /* + * Determine the appropriate additive constant for the current iteration + */ + function sha1_kt(t) + { + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; + } + + /* + * Calculate the HMAC-SHA1 of a key and some data + */ + function core_hmac_sha1(key, data) + { + var bkey = str2binb(key); + if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); + return core_sha1(opad.concat(hash), 512 + 160); + } + + /* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + function safe_add(x, y) + { + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } + + /* + * Bitwise rotate a 32-bit number to the left. + */ + function rol(num, cnt) + { + return (num << cnt) | (num >>> (32 - cnt)); + } + + /* + * Convert an 8-bit or 16-bit string to an array of big-endian words + * In 8-bit function, characters >255 have their hi-byte silently ignored. + */ + function str2binb(str) + { + var bin = Array(); + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); + return bin; + } + + /* + * Convert an array of big-endian words to a string + */ + function binb2str(bin) + { + var str = ""; + var mask = (1 << chrsz) - 1; + for(var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); + return str; + } + + /* + * Convert an array of big-endian words to a hex string. + */ + function binb2hex(binarray) + { + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8)) & 0xF); + } + return str; + } + + /* + * Convert an array of big-endian words to a base-64 string + */ + function binb2b64(binarray) + { + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + } + return str; + } +} + diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js index dd7c48025..440be5995 100644 --- a/chrome/content/zotero/xpcom/itemTreeView.js +++ b/chrome/content/zotero/xpcom/itemTreeView.js @@ -49,7 +49,7 @@ Zotero.ItemTreeView = function(itemGroup, sourcesOnly) this._dataItems = []; this.rowCount = 0; - this._unregisterID = Zotero.Notifier.registerObserver(this, ['item', 'collection-item', 'share-items']); + this._unregisterID = Zotero.Notifier.registerObserver(this, ['item', 'collection-item', 'share-items', 'bucket']); } @@ -281,6 +281,11 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData) this.refresh(); } } + else if (type == 'bucket') { + if (itemGroup.isBucket()) { + this.refresh(); + } + } else if (savedSelection.length == 1 && savedSelection[0] == ids[0]) { this.selection.clearSelection(); this.rememberSelection(savedSelection); @@ -2389,4 +2394,4 @@ Zotero.ItemTreeView.TreeRow.prototype.numAttachments = function(includeTrashed) return this.ref.numAttachments(includeTrashed); else return 0; -} \ No newline at end of file +} diff --git a/chrome/content/zotero/xpcom/notifier.js b/chrome/content/zotero/xpcom/notifier.js index 0564f630b..b1dd6bcd0 100644 --- a/chrome/content/zotero/xpcom/notifier.js +++ b/chrome/content/zotero/xpcom/notifier.js @@ -25,7 +25,7 @@ Zotero.Notifier = new function(){ var _disabled = false; var _types = [ 'collection', 'creator', 'search', 'share', 'share-items', 'item', - 'collection-item', 'item-tag', 'tag', 'group' + 'collection-item', 'item-tag', 'tag', 'group', 'bucket' ]; var _inTransaction; var _locked = false; diff --git a/chrome/skin/default/zotero/treesource-bucket.png b/chrome/skin/default/zotero/treesource-bucket.png new file mode 100644 index 000000000..3d09261a2 Binary files /dev/null and b/chrome/skin/default/zotero/treesource-bucket.png differ diff --git a/chrome/skin/default/zotero/treesource-commons.png b/chrome/skin/default/zotero/treesource-commons.png new file mode 100644 index 000000000..68f21d301 Binary files /dev/null and b/chrome/skin/default/zotero/treesource-commons.png differ diff --git a/components/zotero-service.js b/components/zotero-service.js index 5cb2b8d68..4e9d1677a 100644 --- a/components/zotero-service.js +++ b/components/zotero-service.js @@ -19,6 +19,7 @@ var xpcomFiles = [ 'annotate', 'attachments', 'collectionTreeView', + 'commons', 'csl', 'dataServer', 'data_access', diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index bb3a0bc4c..42b472442 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -100,6 +100,12 @@ pref("extensions.zotero.integration.realWindow", false); // Zeroconf 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", ''); + // Annotation settings pref("extensions.zotero.annotations.warnOnClose", true); @@ -123,4 +129,4 @@ pref("extensions.zotero.proxies.transparent", true); pref("extensions.zotero.purge.creators", false); pref("extensions.zotero.purge.fulltext", false); pref("extensions.zotero.purge.items", false); -pref("extensions.zotero.purge.tags", false); \ No newline at end of file +pref("extensions.zotero.purge.tags", false);