From 042e2d7fbc9f67527b95d7a9efd69b74a3194f6c Mon Sep 17 00:00:00 2001 From: aurimasv Date: Wed, 19 Dec 2012 21:15:08 -0600 Subject: [PATCH 01/15] Fix typo in cookie sandbox. i-- moved for clarity. --- chrome/content/zotero/xpcom/cookieSandbox.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/xpcom/cookieSandbox.js b/chrome/content/zotero/xpcom/cookieSandbox.js index 0d013ad91f..6d9d4ddb54 100755 --- a/chrome/content/zotero/xpcom/cookieSandbox.js +++ b/chrome/content/zotero/xpcom/cookieSandbox.js @@ -153,8 +153,9 @@ Zotero.CookieSandbox.Observer = new function() { var ir = this.trackedInterfaceRequestors[i].get(); if(!ir) { // The interface requestor is gone, so remove it from the list - this.trackedInterfaceRequestors.splice(i--, 1); - this.trackedInterfaceRequestorSandboxes.splice(i--, 1); + this.trackedInterfaceRequestors.splice(i, 1); + this.trackedInterfaceRequestorSandboxes.splice(i, 1); + i--; } else if(ir == notificationCallbacks) { // We are tracking this interface requestor trackedBy = this.trackedInterfaceRequestorSandboxes[i]; From a3f7f97e02ec733684df0ca51b0683c358d327db Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Thu, 20 Dec 2012 01:21:36 -0500 Subject: [PATCH 02/15] Fix broken Note/Citation option in "Create Bibiography" --- chrome/content/zotero/fileInterface.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/fileInterface.js b/chrome/content/zotero/fileInterface.js index 50ac1019b4..a4c63e513d 100644 --- a/chrome/content/zotero/fileInterface.js +++ b/chrome/content/zotero/fileInterface.js @@ -500,12 +500,12 @@ var Zotero_File_Interface = new function() { // generate bibliography try { if(io.method == 'copy-to-clipboard') { - copyItemsToClipboard(items, io.style, false, io.mode === "citation"); + copyItemsToClipboard(items, io.style, false, io.mode === "citations"); } else { var style = Zotero.Styles.get(io.style); var bibliography = Zotero.Cite.makeFormattedBibliographyOrCitationList(style, - items, format, io.mode === "citation"); + items, format, io.mode === "citations"); } } catch(e) { window.alert(Zotero.getString("fileInterface.bibliographyGenerationError")); From 11a83e5df3610db1b303329b2bdddbef0335ec21 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 21 Dec 2012 02:10:24 -0500 Subject: [PATCH 03/15] Don't count as duplicates if DOI/ISBN don't match or year is off by > 1 Fixes #214 --- chrome/content/zotero/xpcom/duplicates.js | 57 ++++++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/xpcom/duplicates.js b/chrome/content/zotero/xpcom/duplicates.js index 929e6e2de4..79953538ae 100644 --- a/chrome/content/zotero/xpcom/duplicates.js +++ b/chrome/content/zotero/xpcom/duplicates.js @@ -191,6 +191,12 @@ Zotero.Duplicates.prototype._findDuplicates = function () { Zotero.ItemFields.getID('ISBN') ] ); + var isbnCache = {}; + if (rows) { + for each(var row in rows) { + isbnCache[row.itemID] = row.value; + } + } processRows(); // DOI @@ -200,8 +206,34 @@ Zotero.Duplicates.prototype._findDuplicates = function () { + "AND itemID NOT IN (SELECT itemID FROM deletedItems) " + "ORDER BY value"; var rows = Zotero.DB.query(sql, [this._libraryID, Zotero.ItemFields.getID('DOI')]); + var doiCache = {}; + if (rows) { + for each(var row in rows) { + doiCache[row.itemID] = row.value; + } + } processRows(); + // Get years + var dateFields = [Zotero.ItemFields.getID('date')].concat( + Zotero.ItemFields.getTypeFieldsFromBase('date') + ); + var sql = "SELECT itemID, SUBSTR(value, 1, 4) AS year FROM items " + + "JOIN itemData USING (itemID) " + + "JOIN itemDataValues USING (valueID) " + + "WHERE libraryID=? AND fieldID IN (" + + dateFields.map(function () '?').join() + ") " + + "AND SUBSTR(value, 1, 4) != '0000' " + + "AND itemID NOT IN (SELECT itemID FROM deletedItems) " + + "ORDER BY value"; + var rows = Zotero.DB.query(sql, [this._libraryID].concat(dateFields)); + var yearCache = {}; + if (rows) { + for each(var row in rows) { + yearCache[row.itemID] = row.year; + } + } + var creatorRowsCache = {}; // Match on normalized title @@ -225,8 +257,29 @@ Zotero.Duplicates.prototype._findDuplicates = function () { return -1; } + // If both items have a DOI and they don't match, it's not a dupe + if (typeof doiCache[a.itemID] != 'undefined' + && typeof doiCache[b.itemID] != 'undefined' + && doiCache[a.itemID] != doiCache[b.itemID]) { + return -1; + } + + // If both items have an ISBN and they don't match, it's not a dupe + if (typeof isbnCache[a.itemID] != 'undefined' + && typeof isbnCache[b.itemID] != 'undefined' + && isbnCache[a.itemID] != isbnCache[b.itemID]) { + return -1; + } + + // If both items have a year and they're off by more than one, it's not a dupe + if (typeof yearCache[a.itemID] != 'undefined' + && typeof yearCache[b.itemID] != 'undefined' + && Math.abs(yearCache[a.itemID] - yearCache[b.itemID]) > 1) { + return -1; + } + // Check for at least one match on last name + first initial of first name - if (creatorRowsCache[a.itemID] != undefined) { + if (typeof creatorRowsCache[a.itemID] != 'undefined') { aCreatorRows = creatorRowsCache[a.itemID]; } else { @@ -239,7 +292,7 @@ Zotero.Duplicates.prototype._findDuplicates = function () { } // Check for at least one match on last name + first initial of first name - if (creatorRowsCache[b.itemID] != undefined) { + if (typeof creatorRowsCache[b.itemID] != 'undefined') { bCreatorRows = creatorRowsCache[b.itemID]; } else { From 74c9967b95aae512c17b8c4d1a8a8869138cf829 Mon Sep 17 00:00:00 2001 From: aurimasv Date: Fri, 21 Dec 2012 14:56:08 -0600 Subject: [PATCH 04/15] Tweak recognizePDF to avoid false positives: only count lines with more than 3 words (since we drop first and last later) as cleaned lines, increase number of pages read and number of lines away from median length as good lines (due to more stringent selection criteria), do not attempt to query google with a short query if we run out of lines, try to pick lines for a query that are not next to each other (to avoid finding articles that quote the article we're looking for) --- chrome/content/zotero/recognizePDF.js | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/chrome/content/zotero/recognizePDF.js b/chrome/content/zotero/recognizePDF.js index d36d90f769..95f6fbc460 100644 --- a/chrome/content/zotero/recognizePDF.js +++ b/chrome/content/zotero/recognizePDF.js @@ -243,7 +243,7 @@ Zotero_RecognizePDF.Recognizer = function () {} * (function will be passed image as URL and must return text of CAPTCHA) */ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, callback, captchaCallback) { - const MAX_PAGES = 3; + const MAX_PAGES = 5; this._libraryID = libraryID; this._callback = callback; @@ -315,9 +315,9 @@ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, c // Use only first column from multi-column lines const lineRe = /^\s*([^\s]+(?: [^\s]+)+)/; - for(var i=0; i 3) { cleanedLines.push(m[1]); cleanedLineLengths.push(m[1].length); } @@ -334,8 +334,8 @@ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, c // pick lines within 4 chars of the median (this is completely arbitrary) this._goodLines = []; - var uBound = medianLength + 4; - var lBound = medianLength - 4; + var uBound = medianLength + 6; + var lBound = medianLength - 6; for (var i=0; i lBound && cleanedLineLengths[i] < uBound) { // Strip quotation marks so they don't mess up search query quoting @@ -344,7 +344,7 @@ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, c } } - this._startLine = this._iteration = 0; + this._nextLine = this._iteration = 0; this._queryGoogle(); } } @@ -354,7 +354,7 @@ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, c * @private */ Zotero_RecognizePDF.Recognizer.prototype._queryGoogle = function() { - if(this._iteration > 3 || this._startLine >= this._goodLines.length) { + if(this._iteration > 3 || !this._goodLines.length) { try { if(this._hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(me._hiddenBrowser); } catch(e) {} @@ -385,8 +385,17 @@ Zotero_RecognizePDF.Recognizer.prototype._queryGoogle = function() { } else { // take the relevant parts of some lines (exclude hyphenated word) var queryStringWords = 0; - while(queryStringWords < 25 && this._startLine < this._goodLines.length) { - var words = this._goodLines[this._startLine].split(/\s+/); + while(queryStringWords < 25) { + /**a bit of a hack. We're relying on the same test being applied above. + * But this way we don't have to rewrite the same error reporting code + */ + if(!this._goodLines.length) this._queryGoogle(); + + var words = this._goodLines.splice(this._nextLine,1)[0].split(/\s+/); + //Try to avoid picking adjacent strings so the odds of them appearing in another + // document quoting our document is low. Every 7th line is a magic value + this._nextLine = (this._nextLine + 7) % this._goodLines.length; + // get rid of first and last words words.shift(); words.pop(); @@ -403,7 +412,6 @@ Zotero_RecognizePDF.Recognizer.prototype._queryGoogle = function() { queryStringWords += words.length; queryString += '"'+words.join(" ")+'" '; } - this._startLine++; } Zotero.debug("RecognizePDF: Query string "+queryString); From ea6a1098a6427d55eaa4e93b03bb9ee9ceb81edd Mon Sep 17 00:00:00 2001 From: aurimasv Date: Sat, 22 Dec 2012 10:47:57 -0600 Subject: [PATCH 05/15] [recognizePDF] Restructure file --- chrome/content/zotero/recognizePDF.js | 211 +++++++++++++++----------- 1 file changed, 120 insertions(+), 91 deletions(-) diff --git a/chrome/content/zotero/recognizePDF.js b/chrome/content/zotero/recognizePDF.js index 95f6fbc460..cd533521e2 100644 --- a/chrome/content/zotero/recognizePDF.js +++ b/chrome/content/zotero/recognizePDF.js @@ -293,10 +293,7 @@ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, c intlStream.QueryInterface(Components.interfaces.nsIUnicharLineInputStream); // get the lines in this sample - var lines = [], - cleanedLines = [], - cleanedLineLengths = [], - str = {}; + var lines = [], str = {}; while(intlStream.readLine(str)) { var line = str.value.trim(); if(line) lines.push(line); @@ -304,17 +301,57 @@ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, c inputStream.close(); cacheFile.remove(false); - + + var me = this; + // look for DOI var allText = lines.join("\n"); Zotero.debug(allText); var m = Zotero.Utilities.cleanDOI(allText); if(m) { - this._DOI = m; + this._queryDOI(m, function() { + me._cleanLines(lines, me._queryGoogle); + }); + } else { + this._cleanLines(lines, me._queryGoogle); } - +} + +/** + * Looks up item by DOI + * @private + * @param {String} doi DOI to search for + * @param {Function} onFail Callback function to call if a DOI is not found + */ +Zotero_RecognizePDF.Recognizer.prototype._queryDOI = function(doi, onFail) { + var me = this; + var translate = new Zotero.Translate.Search(); + translate.setTranslator("11645bd1-0420-45c1-badb-53fb41eeb753"); + var item = {"itemType":"journalArticle", "DOI":doi}; + translate.setSearch(item); + translate.setHandler("itemDone", function(translate, item) { + me._callback(item); + }); + translate.setHandler("select", function(translate, items, callback) { + return me._selectItems(translate, items, callback); + }); + translate.setHandler("done", function(translate, success) { + if(!success) onFail.call(me); + }); + translate.translate(this._libraryID, false); +} + +/** + * Prepares a list of lines that can be used for querying + * The lines are stored in this._goodLines + * @private + * @param {String[]} lines Array of lines + * @param {Function} callback A callback function to be called on completing + */ +Zotero_RecognizePDF.Recognizer.prototype._cleanLines = function(lines, callback) { // Use only first column from multi-column lines const lineRe = /^\s*([^\s]+(?: [^\s]+)+)/; + var cleanedLines = [], cleanedLineLengths = []; for(var i=0; i 3) { @@ -345,111 +382,103 @@ Zotero_RecognizePDF.Recognizer.prototype.recognize = function(file, libraryID, c } this._nextLine = this._iteration = 0; - this._queryGoogle(); + callback.call(this); } } +/** + * Deletes hidden browser and sends a failure message to this_callback + * @private + * @param {String} msg Message to be sent to this._callback + */ +Zotero_RecognizePDF.Recognizer.prototype._deleteBrowserAndFail = function(msg) { + var me = this; + try { + if(this._hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(me._hiddenBrowser); + } catch(e) {} + this._callback(false, msg); +} + /** * Queries Google Scholar for metadata for this PDF * @private */ Zotero_RecognizePDF.Recognizer.prototype._queryGoogle = function() { if(this._iteration > 3 || !this._goodLines.length) { - try { - if(this._hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(me._hiddenBrowser); - } catch(e) {} - this._callback(false, "recognizePDF.noMatches"); + this._deleteBrowserAndFail("recognizePDF.noMatches"); return; } this._iteration++; var queryString = ""; var me = this; - if(this._DOI) { - // use CrossRef to look for DOI - var translate = new Zotero.Translate.Search(); - translate.setTranslator("11645bd1-0420-45c1-badb-53fb41eeb753"); - var item = {"itemType":"journalArticle", "DOI":this._DOI}; - translate.setSearch(item); - translate.setHandler("itemDone", function(translate, item) { - me._callback(item); - }); - translate.setHandler("select", function(translate, items, callback) { - return me._selectItems(translate, items, callback); - }); - translate.setHandler("done", function(translate, success) { - if(!success) me._queryGoogle(); - }); - translate.translate(this._libraryID, false); - delete this._DOI; - } else { - // take the relevant parts of some lines (exclude hyphenated word) - var queryStringWords = 0; - while(queryStringWords < 25) { - /**a bit of a hack. We're relying on the same test being applied above. - * But this way we don't have to rewrite the same error reporting code - */ - if(!this._goodLines.length) this._queryGoogle(); - var words = this._goodLines.splice(this._nextLine,1)[0].split(/\s+/); - //Try to avoid picking adjacent strings so the odds of them appearing in another - // document quoting our document is low. Every 7th line is a magic value - this._nextLine = (this._nextLine + 7) % this._goodLines.length; + // take the relevant parts of some lines (exclude hyphenated word) + var queryStringWords = 0; + while(queryStringWords < 25) { + if(!this._goodLines.length) { + this._deleteBrowserAndFail("recognizePDF.noMatches"); + return; + } - // get rid of first and last words - words.shift(); - words.pop(); - // make sure there are no long words (probably OCR mistakes) - var skipLine = false; - for(var i=0; i 20) { - skipLine = true; - break; - } - } - // add words to query - if(!skipLine && words.length) { - queryStringWords += words.length; - queryString += '"'+words.join(" ")+'" '; + var words = this._goodLines.splice(this._nextLine,1)[0].split(/\s+/); + //Try to avoid picking adjacent strings so the odds of them appearing in another + // document quoting our document is low. Every 7th line is a magic value + this._nextLine = (this._nextLine + 7) % this._goodLines.length; + + // get rid of first and last words + words.shift(); + words.pop(); + // make sure there are no long words (probably OCR mistakes) + var skipLine = false; + for(var i=0; i 20) { + skipLine = true; + break; } } - - Zotero.debug("RecognizePDF: Query string "+queryString); - - // pass query string to Google Scholar and translate - var url = "http://scholar.google.com/scholar?q="+encodeURIComponent(queryString)+"&hl=en&lr=&btnG=Search"; - if(!this._hiddenBrowser) { - this._hiddenBrowser = Zotero.Browser.createHiddenBrowser(); - this._hiddenBrowser.docShell.allowImages = false; + // add words to query + if(!skipLine && words.length) { + queryStringWords += words.length; + queryString += '"'+words.join(" ")+'" '; } - - var translate = new Zotero.Translate.Web(); - var savedItem = false; - translate.setTranslator("57a00950-f0d1-4b41-b6ba-44ff0fc30289"); - translate.setHandler("itemDone", function(translate, item) { - Zotero.Browser.deleteHiddenBrowser(me._hiddenBrowser); - savedItem = true; - me._callback(item); - }); - translate.setHandler("select", function(translate, items, callback) { - me._selectItems(translate, items, callback); - }); - translate.setHandler("done", function(translate, success) { - if(!success || !savedItem) me._queryGoogle(); - }); - translate.setHandler("translators", function(translate, detected) { - if(detected.length) { - translate.translate(me._libraryID, false); - } else { - me._queryGoogle(); - } - }); - - this._hiddenBrowser.addEventListener("pageshow", function() { me._scrape(translate) }, true); - - this._hiddenBrowser.loadURIWithFlags(url, - Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, null, null); } + + Zotero.debug("RecognizePDF: Query string "+queryString); + + // pass query string to Google Scholar and translate + var url = "http://scholar.google.com/scholar?q="+encodeURIComponent(queryString)+"&hl=en&lr=&btnG=Search"; + if(!this._hiddenBrowser) { + this._hiddenBrowser = Zotero.Browser.createHiddenBrowser(); + this._hiddenBrowser.docShell.allowImages = false; + } + + var translate = new Zotero.Translate.Web(); + var savedItem = false; + translate.setTranslator("57a00950-f0d1-4b41-b6ba-44ff0fc30289"); + translate.setHandler("itemDone", function(translate, item) { + Zotero.Browser.deleteHiddenBrowser(me._hiddenBrowser); + savedItem = true; + me._callback(item); + }); + translate.setHandler("select", function(translate, items, callback) { + me._selectItems(translate, items, callback); + }); + translate.setHandler("done", function(translate, success) { + if(!success || !savedItem) me._queryGoogle(); + }); + translate.setHandler("translators", function(translate, detected) { + if(detected.length) { + translate.translate(me._libraryID, false); + } else { + me._queryGoogle(); + } + }); + + this._hiddenBrowser.addEventListener("pageshow", function() { me._scrape(translate) }, true); + + this._hiddenBrowser.loadURIWithFlags(url, + Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, null, null); } /** From 6c2b8e1688db1544054395b5c89667097802501d Mon Sep 17 00:00:00 2001 From: aurimasv Date: Tue, 1 Jan 2013 20:32:09 -0600 Subject: [PATCH 06/15] Minor documentation update --- .../content/zotero/xpcom/translation/translate_firefox.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/xpcom/translation/translate_firefox.js b/chrome/content/zotero/xpcom/translation/translate_firefox.js index ff4713e377..8e17c32d07 100644 --- a/chrome/content/zotero/xpcom/translation/translate_firefox.js +++ b/chrome/content/zotero/xpcom/translation/translate_firefox.js @@ -146,8 +146,10 @@ Zotero.Translate.SandboxManager.prototype = { * Imports an object into the sandbox * * @param {Object} object Object to be imported (under Zotero) - * @param {Boolean} passTranslateAsFirstArgument Whether the translate instance should be passed - * as the first argument to the function. + * @param {*} [passTranslateAsFirstArgument] An argument to pass + * as the first argument to the function. + * @param {Object} [attachTo] The object to attach `object` to. + * Defaults to this.sandbox.Zotero */ "importObject":function(object, passAsFirstArgument, attachTo) { if(!attachTo) attachTo = this.sandbox.Zotero; From beaaf8fc6b31b8471bcf13f169611b92212f7e8b Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 4 Jan 2013 13:00:26 -0500 Subject: [PATCH 07/15] Accept two missing letters in object keys (but don't use them yet) Also: - 'T' doesn't come after 'X' (but does probably appear disproportionally in existing object keys) This commit has been brought to you by the letters 'L' and 'Y'. --- chrome/content/zotero/xpcom/data/creator.js | 3 +-- chrome/content/zotero/xpcom/id.js | 9 ++++++++- chrome/content/zotero/xpcom/utilities.js | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/chrome/content/zotero/xpcom/data/creator.js b/chrome/content/zotero/xpcom/data/creator.js index 4aeace7d29..c9051d8b8a 100644 --- a/chrome/content/zotero/xpcom/data/creator.js +++ b/chrome/content/zotero/xpcom/data/creator.js @@ -536,8 +536,7 @@ Zotero.Creator.prototype._checkValue = function (field, value) { break; case 'key': - var re = /^[23456789ABCDEFGHIJKMNPQRSTUVWXTZ]{8}$/ - if (!re.test(value)) { + if (!Zotero.ID.isValidKey(value)) { this._invalidValueError(field, value); } break; diff --git a/chrome/content/zotero/xpcom/id.js b/chrome/content/zotero/xpcom/id.js index 9d56aa97da..17c85a8ac4 100644 --- a/chrome/content/zotero/xpcom/id.js +++ b/chrome/content/zotero/xpcom/id.js @@ -87,11 +87,18 @@ Zotero.ID_Tracker = function () { function getKey() { - var baseString = "23456789ABCDEFGHIJKMNPQRSTUVWXTZ"; + // TODO: add 'L' and 'Y' after 3.0.11 cut-off + var baseString = "23456789ABCDEFGHIJKMNPQRSTUVWXZ"; return Zotero.randomString(8, baseString); } + this.isValidKey = function () { + var re = /^[23456789ABCDEFGHIJKLMNPQRSTUVWXYZ]{8}$/ + return re.test(value); + } + + function getBigInt(max) { if (!max) { max = 9007199254740991; diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index e2f3cab5b6..3e90cb8073 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -1069,7 +1069,7 @@ Zotero.Utilities = { **/ "randomString":function(len, chars) { if (!chars) { - chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"; + chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz"; } if (!len) { len = 8; From d42b741756a263d89fcca31eabadcdaccdd9f429 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 4 Jan 2013 14:55:28 -0500 Subject: [PATCH 08/15] Add lowercase 'j' to randomString() (not used for keys) --- chrome/content/zotero/xpcom/utilities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index 3e90cb8073..129b7c718e 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -1069,7 +1069,7 @@ Zotero.Utilities = { **/ "randomString":function(len, chars) { if (!chars) { - chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz"; + chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; } if (!len) { len = 8; From 7a8e06cac2823c303bf8c8d15627c391283592f2 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 5 Jan 2013 16:35:33 -0500 Subject: [PATCH 09/15] Context-menu item delete from library root didn't show a prompt --- chrome/content/zotero/zoteroPane.js | 9 +++++---- chrome/content/zotero/zoteroPane.xul | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index 6579441db1..4e2177a57f 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -1484,10 +1484,11 @@ var ZoteroPane = new function() /* * Remove, trash, or delete item(s), depending on context * - * @param {Boolean} [force=false] Trash or delete even if in a collection or search, - * or trash without prompt in library + * @param {Boolean} [force=false] Trash or delete even if in a collection or search, + * or trash without prompt in library + * @param {Boolean} [fromMenu=false] If triggered from context menu, which always prompts for deletes */ - this.deleteSelectedItems = function (force) { + this.deleteSelectedItems = function (force, fromMenu) { if (!this.itemsView || !this.itemsView.selection.count) { return; } @@ -1513,7 +1514,7 @@ var ZoteroPane = new function() if (itemGroup.isLibrary(true)) { // In library, don't prompt if meta key was pressed - var prompt = force ? false : toTrash; + var prompt = (force && !fromMenu) ? false : toTrash; } else if (itemGroup.isCollection()) { // In collection, only prompt if trashing diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul index 45a0f29d33..f56c301c56 100644 --- a/chrome/content/zotero/zoteroPane.xul +++ b/chrome/content/zotero/zoteroPane.xul @@ -274,7 +274,7 @@ - + From f14b1f250e8eb59659d028af3651d73f11d03b2d Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Tue, 8 Jan 2013 19:27:57 -0500 Subject: [PATCH 10/15] Make clear that save to server code is non-Firefox only --- chrome/content/zotero/xpcom/connector/translate_item.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chrome/content/zotero/xpcom/connector/translate_item.js b/chrome/content/zotero/xpcom/connector/translate_item.js index b01710237a..e90d843219 100644 --- a/chrome/content/zotero/xpcom/connector/translate_item.js +++ b/chrome/content/zotero/xpcom/connector/translate_item.js @@ -91,6 +91,8 @@ Zotero.Translate.ItemSaver.prototype = { }); }, + // ALL CODE BELOW THIS POINT IS EXECUTED ONLY IN NON-FIREFOX ENVIRONMENTS + /** * Saves items to server * @param items Items in Zotero.Item.toArray() format From 9d8869cd3363ab35248910ae3f2b9a2a60f25776 Mon Sep 17 00:00:00 2001 From: aurimasv Date: Mon, 14 Jan 2013 00:31:00 -0600 Subject: [PATCH 11/15] [Utilities] Deep copy `null` as `null`. Display object type in varDump --- chrome/content/zotero/xpcom/utilities.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index 129b7c718e..2588028b8f 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -914,7 +914,7 @@ Zotero.Utilities = { for(var i in obj) { if(!obj.hasOwnProperty(i)) continue; - if(typeof obj[i] === "object") { + if(typeof obj[i] === "object" && obj[i] !== null) { obj2[i] = Zotero.Utilities.deepCopy(obj[i]); } else { obj2[i] = obj[i]; @@ -1139,7 +1139,7 @@ Zotero.Utilities = { closeBrace = ']'; } - dumped_text += level_padding + "'" + item + "' => " + openBrace; + dumped_text += level_padding + "'" + item + "' => " + type + ' ' + openBrace; //only recurse if there's anything in the object, purely cosmetical try { for(var i in value) { From 4ea05ce0912ee25cc7779eb57496113f3f9ec258 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Mon, 14 Jan 2013 16:00:25 -0500 Subject: [PATCH 12/15] Strip control characters when inserting notes and displaying reports --- chrome/content/zotero/xpcom/data/item.js | 5 ++++- chrome/content/zotero/xpcom/report.js | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 2d10b4ad3c..39673ad2a8 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -2441,7 +2441,10 @@ Zotero.Item.prototype.setNote = function(text) { throw ("text must be a string in Zotero.Item.setNote() (was " + typeof text + ")"); } - text = Zotero.Utilities.trim(text); + text = text + // Strip control characters + .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "") + .trim(); var oldText = this.getNote(); if (text == oldText) { diff --git a/chrome/content/zotero/xpcom/report.js b/chrome/content/zotero/xpcom/report.js index f8df3a4c12..d42735d50e 100644 --- a/chrome/content/zotero/xpcom/report.js +++ b/chrome/content/zotero/xpcom/report.js @@ -79,7 +79,14 @@ Zotero.Report = new function() { // If not valid XML, display notes with entities encoded var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"] .createInstance(Components.interfaces.nsIDOMParser); - var doc = parser.parseFromString('
' + arr.note.replace(/ /g, " ") + '
', "application/xml"); + var doc = parser.parseFromString('
' + + arr.note + //   isn't valid in HTML + .replace(/ /g, " ") + // Strip control characters (for notes that were + // added before item.setNote() started doing this) + .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "") + + '
', "application/xml"); if (doc.documentElement.tagName == 'parsererror') { Zotero.debug(doc.documentElement.textContent, 2); content += '

' + escapeXML(arr.note) + '

\n'; From 2562e64e82787f0d7557d1cb296f9a41dad1cc31 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Mon, 14 Jan 2013 20:27:25 -0500 Subject: [PATCH 13/15] Strip control characters when displaying child notes as well --- chrome/content/zotero/xpcom/report.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/chrome/content/zotero/xpcom/report.js b/chrome/content/zotero/xpcom/report.js index d42735d50e..d0435a7a24 100644 --- a/chrome/content/zotero/xpcom/report.js +++ b/chrome/content/zotero/xpcom/report.js @@ -113,7 +113,13 @@ Zotero.Report = new function() { // If not valid XML, display notes with entities encoded var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"] .createInstance(Components.interfaces.nsIDOMParser); - var doc = parser.parseFromString('
' + note.note.replace(/ /g, " ") + '
', "application/xml"); + var doc = parser.parseFromString('
' + + note.note + .replace(/ /g, " ") + // Strip control characters (for notes that were + // added before item.setNote() started doing this) + .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "") + + '
', "application/xml"); if (doc.documentElement.tagName == 'parsererror') { Zotero.debug(doc.documentElement.textContent, 2); content += '

' + escapeXML(note.note) + '

\n'; From f24091626d20de660344a327113a158b2cf33699 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Mon, 14 Jan 2013 20:30:46 -0500 Subject: [PATCH 14/15] Update version and maxVersion --- chrome/content/zotero/xpcom/zotero.js | 2 +- install.rdf | 4 ++-- update.rdf | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index 90d4878856..30cc02f2f3 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -35,7 +35,7 @@ const ZOTERO_CONFIG = { API_URL: 'https://api.zotero.org/', PREF_BRANCH: 'extensions.zotero.', BOOKMARKLET_URL: 'https://www.zotero.org/bookmarklet/', - VERSION: "3.0.11.SOURCE" + VERSION: "3.0.12.SOURCE" }; /* diff --git a/install.rdf b/install.rdf index 345fca70ee..a4450a0fab 100644 --- a/install.rdf +++ b/install.rdf @@ -6,7 +6,7 @@ zotero@chnm.gmu.edu Zotero - 3.0.11.SOURCE + 3.0.12.SOURCE Center for History and New Media
George Mason University
Dan Cohen Sean Takats @@ -26,7 +26,7 @@ {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 5.0 - 17.* + 18.* diff --git a/update.rdf b/update.rdf index 05bd2f47f6..adc906cdc6 100644 --- a/update.rdf +++ b/update.rdf @@ -7,12 +7,12 @@ - 3.0.11.SOURCE + 3.0.12.SOURCE {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 5.0 - 17.* + 18.* http://download.zotero.org/extension/zotero.xpi sha1: From a5dc9d9647ce6ea8b98f434bd89f3c784eda9bcc Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Fri, 18 Jan 2013 18:58:11 -0500 Subject: [PATCH 15/15] Fix III host code --- chrome/content/zotero/xpcom/translation/translator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chrome/content/zotero/xpcom/translation/translator.js b/chrome/content/zotero/xpcom/translation/translator.js index 5774358ac1..5a4b7b43b3 100644 --- a/chrome/content/zotero/xpcom/translation/translator.js +++ b/chrome/content/zotero/xpcom/translation/translator.js @@ -222,7 +222,7 @@ Zotero.Translators = new function() { if(m) { // First, drop the 0- if it exists (this is an III invention) var host = m[2]; - if(host.substr(0, 2) === "0-") host = substr(2); + if(host.substr(0, 2) === "0-") host = host.substr(2); var hostnames = host.split("."); for(var i=1; i