From 380668cc60c6c543d1a8cbb6dda2fe4d0b599c18 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Thu, 7 Aug 2014 18:35:12 -0400 Subject: [PATCH] Changes to item and file retrieval methods - Zotero.Item.prototype.getFilePath() is now synchronous, with a separate async getFilePathAsync() - getFile() no longer takes a skipExistsCheck parameter, since that shouldn't happen synchronously - Zotero.Items.getByLibraryAndKey() is now synchronous again, with a separate Zotero.Items.getByLibraryAndKeyAsync() - I haven't fully tested this, so I'm not sure if there will need to be any async calls. - Some of the full-text indexing functions now take file paths instead of nsIFile objects - Zotero.File.getContentsAsync() can now take a string path as well --- chrome/content/zotero/bindings/noteeditor.xml | 2 +- chrome/content/zotero/locateMenu.js | 2 +- chrome/content/zotero/xpcom/attachments.js | 4 +- .../content/zotero/xpcom/data/collection.js | 2 +- .../content/zotero/xpcom/data/dataObjects.js | 31 +-- chrome/content/zotero/xpcom/data/item.js | 204 +++++++++++++++--- chrome/content/zotero/xpcom/file.js | 7 +- chrome/content/zotero/xpcom/fulltext.js | 71 +++--- chrome/content/zotero/xpcom/itemTreeView.js | 2 +- chrome/content/zotero/xpcom/search.js | 4 +- .../zotero/xpcom/utilities_internal.js | 4 + chrome/content/zotero/zoteroPane.js | 4 +- 12 files changed, 248 insertions(+), 89 deletions(-) diff --git a/chrome/content/zotero/bindings/noteeditor.xml b/chrome/content/zotero/bindings/noteeditor.xml index 73f91126b..a663d56ed 100644 --- a/chrome/content/zotero/bindings/noteeditor.xml +++ b/chrome/content/zotero/bindings/noteeditor.xml @@ -120,7 +120,7 @@ var parentKey = this.item.parentKey; if (parentKey) { - this.parentItem = yield Zotero.Items.getByLibraryAndKey(this.item.libraryID, parentKey); + this.parentItem = Zotero.Items.getByLibraryAndKey(this.item.libraryID, parentKey); } this._id('links').item = this.item; diff --git a/chrome/content/zotero/locateMenu.js b/chrome/content/zotero/locateMenu.js index f19cedb3a..1eca96ec9 100644 --- a/chrome/content/zotero/locateMenu.js +++ b/chrome/content/zotero/locateMenu.js @@ -499,7 +499,7 @@ var Zotero_LocateMenu = new function() { var attachments = item.isAttachment() ? [item] : (yield item.getBestAttachments()); for each(var attachment in attachments) { if(attachment.attachmentLinkMode !== Zotero.Attachments.LINK_MODE_LINKED_URL) { - var path = yield attachment.getFilePath(); + var path = yield attachment.getFilePathAsync(); if (path) { var ext = Zotero.File.getExtension(Zotero.File.pathToFile(path)); if(!attachment.attachmentMIMEType || diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js index 0f6bec882..e6339b090 100644 --- a/chrome/content/zotero/xpcom/attachments.js +++ b/chrome/content/zotero/xpcom/attachments.js @@ -668,7 +668,7 @@ Zotero.Attachments = new function(){ // We'll index it later if it fails. (This may not be necessary.) setTimeout(function () { if (contentType == 'application/pdf') { - Zotero.Fulltext.indexPDF(file, attachmentItem.id); + Zotero.Fulltext.indexPDF(file.path, attachmentItem.id); } else if (Zotero.MIME.isTextType(contentType)) { Zotero.Fulltext.indexDocument(document, attachmentItem.id); @@ -788,7 +788,7 @@ Zotero.Attachments = new function(){ * If a directory exists with the same name, move it to orphaned-files * * @param {Number} itemID - Item id - * @return {Promise} + * @return {Promise} */ this.createDirectoryForItem = Zotero.Promise.coroutine(function* (item) { if (!(item instanceof Zotero.Item)) { diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js index c7ad7ca0c..ef2835fff 100644 --- a/chrome/content/zotero/xpcom/data/collection.js +++ b/chrome/content/zotero/xpcom/data/collection.js @@ -319,7 +319,7 @@ Zotero.Collection.prototype.save = Zotero.Promise.coroutine(function* () { // Verify parent if (this._parentKey) { - let newParent = yield Zotero.Collections.getByLibraryAndKey( + let newParent = Zotero.Collections.getByLibraryAndKey( this.libraryID, this._parentKey ); diff --git a/chrome/content/zotero/xpcom/data/dataObjects.js b/chrome/content/zotero/xpcom/data/dataObjects.js index 503a9659c..699231fa6 100644 --- a/chrome/content/zotero/xpcom/data/dataObjects.js +++ b/chrome/content/zotero/xpcom/data/dataObjects.js @@ -105,7 +105,7 @@ Zotero.DataObjects = function (object, objectPlural, id, table) { let id = ids[i]; // Check if already loaded if (!this._objectCache[id]) { - throw new Error(this._ZDO_Object + " " + id + " not yet loaded"); + throw new this.UnloadedDataException(this._ZDO_Object + " " + id + " not yet loaded"); } toReturn.push(this._objectCache[id]); } @@ -215,21 +215,28 @@ Zotero.DataObjects = function (object, objectPlural, id, table) { * @param {String} key * @return {Zotero.DataObject} Zotero data object, or FALSE if not found */ - this.getByLibraryAndKey = Zotero.Promise.coroutine(function* (libraryID, key, options) { - var sql = "SELECT ROWID FROM " + this._ZDO_table + " WHERE "; - if (this._ZDO_idOnly) { - sql += "ROWID=?"; - var params = [key] - } - else { - sql += "libraryID=? AND key=?"; - var params = [libraryID, key]; - } - var id = yield Zotero.DB.valueQueryAsync(sql, params); + this.getByLibraryAndKey = function (libraryID, key, options) { + var id = this.getIDFromLibraryAndKey(libraryID, key); if (!id) { return false; } return Zotero[this._ZDO_Objects].get(id, options); + }; + + + /** + * Asynchronously retrieves an object by its libraryID and key + * + * @param {Integer} - libraryID + * @param {String} - key + * @return {Promise} - Promise for a data object, or FALSE if not found + */ + this.getByLibraryAndKeyAsync = Zotero.Promise.coroutine(function* (libraryID, key, options) { + var id = this.getIDFromLibraryAndKey(libraryID, key); + if (!id) { + return false; + } + return Zotero[this._ZDO_Objects].getAsync(id, options); }); diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 8a704c4f2..28f9ccce9 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -1356,7 +1356,7 @@ Zotero.Item.prototype.save = Zotero.Promise.coroutine(function* (options) { // Parent item let parentItem = this.parentKey; - parentItem = parentItem ? yield Zotero.Items.getByLibraryAndKey(this.libraryID, parentItem) : null; + parentItem = parentItem ? Zotero.Items.getByLibraryAndKey(this.libraryID, parentItem) : null; if (this._changed.parentKey) { if (isNew) { if (!parentItem) { @@ -1394,7 +1394,7 @@ Zotero.Item.prototype.save = Zotero.Promise.coroutine(function* (options) { var oldParentKey = this._previousData.parentKey; if (oldParentKey) { - var oldParentItem = yield Zotero.Items.getByLibraryAndKey(this.libraryID, oldParentKey); + var oldParentItem = Zotero.Items.getByLibraryAndKey(this.libraryID, oldParentKey); if (oldParentItem) { let oldParentItemNotifierData = {}; //oldParentItemNotifierData[oldParentItem.id] = {}; @@ -2088,13 +2088,15 @@ Zotero.Item.prototype.numAttachments = function(includeTrashed) { /** - * Get an nsILocalFile for the attachment, or false if it doesn't exist + * Get an nsILocalFile for the attachment, or false for invalid paths + * + * This no longer checks whether a file exists * * @return {nsILocalFile|false} An nsIFile, or false for invalid paths */ -Zotero.Item.prototype.getFile = function (skipExistsCheck) { - if (arguments.length > 1) { - Zotero.debug("WARNING: Zotero.Item.prototype.getFile() no longer takes two parameters"); +Zotero.Item.prototype.getFile = function () { + if (arguments.length) { + Zotero.debug("WARNING: Zotero.Item.prototype.getFile() no longer takes any arguments"); } if (!this.isAttachment()) { @@ -2186,21 +2188,17 @@ Zotero.Item.prototype.getFile = function (skipExistsCheck) { } } - if (!skipExistsCheck && !file.exists()) { - return false; - } - return file; }; /** - * Get the absolute file path for the attachment, or false if the associated file doesn't exist + * Get the absolute file path for the attachment * * @return {Promise} - A promise for either the absolute file path of the attachment - * or false for invalid paths or if the file doesn't exist + * or false for invalid paths */ -Zotero.Item.prototype.getFilePath = Zotero.Promise.coroutine(function* (skipExistsCheck) { +Zotero.Item.prototype.getFilePath = function () { if (!this.isAttachment()) { throw new Error("getFilePath() can only be called on attachment items"); } @@ -2216,7 +2214,137 @@ Zotero.Item.prototype.getFilePath = Zotero.Promise.coroutine(function* (skipExis if (!path) { Zotero.debug("Attachment path is empty", 2); if (!skipExistsCheck) { - yield this._updateAttachmentStates(false); + this._updateAttachmentStates(false); + } + return false; + } + + // Imported file with relative path + if (linkMode == Zotero.Attachments.LINK_MODE_IMPORTED_URL || + linkMode == Zotero.Attachments.LINK_MODE_IMPORTED_FILE) { + try { + if (path.indexOf("storage:") == -1) { + Zotero.debug("Invalid attachment path '" + path + "'", 2); + throw ('Invalid path'); + } + // Strip "storage:" + var path = path.substr(8); + // setRelativeDescriptor() silently uses the parent directory on Windows + // if the filename contains certain characters, so strip them — + // but don't skip characters outside of XML range, since they may be + // correct in the opaque relative descriptor string + // + // This is a bad place for this, since the change doesn't make it + // back up to the sync server, but we do it to make sure we don't + // accidentally use the parent dir. Syncing to OS X, which doesn't + // exhibit this bug, will properly correct such filenames in + // storage.js and propagate the change + if (Zotero.isWin) { + path = Zotero.File.getValidFileName(path, true); + } + var file = Zotero.Attachments.getStorageDirectory(this); + file.QueryInterface(Components.interfaces.nsILocalFile); + file.setRelativeDescriptor(file, path); + } + catch (e) { + Zotero.debug(e); + + // See if this is a persistent path + // (deprecated for imported attachments) + Zotero.debug('Trying as persistent descriptor'); + + try { + var file = Components.classes["@mozilla.org/file/local;1"]. + createInstance(Components.interfaces.nsILocalFile); + file.persistentDescriptor = path; + + // If valid, convert this to a relative descriptor in the background + OS.File.exists(file.path) + .then(function (exists) { + if (exists) { + return Zotero.DB.queryAsync( + "UPDATE itemAttachments SET path=? WHERE itemID=?", + ["storage:" + file.leafName, this._id] + ); + } + }); + } + catch (e) { + Zotero.debug('Invalid persistent descriptor', 2); + this._updateAttachmentStates(false); + return false; + } + } + } + // Linked file with relative path + else if (linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE && + path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0) { + var file = Zotero.Attachments.resolveRelativePath(path); + if (!file) { + this._updateAttachmentStates(false); + return false; + } + } + else { + var file = Components.classes["@mozilla.org/file/local;1"]. + createInstance(Components.interfaces.nsILocalFile); + + try { + file.persistentDescriptor = path; + } + catch (e) { + // See if this is an old relative path (deprecated) + Zotero.debug('Invalid persistent descriptor -- trying relative'); + try { + var refDir = (linkMode == this.LINK_MODE_LINKED_FILE) + ? Zotero.getZoteroDirectory() : Zotero.getStorageDirectory(); + file.setRelativeDescriptor(refDir, path); + // If valid, convert this to a persistent descriptor in the background + OS.File.exists(file.path) + .then(function (exists) { + if (exists) { + return Zotero.DB.queryAsync( + "UPDATE itemAttachments SET path=? WHERE itemID=?", + [file.persistentDescriptor, this._id] + ); + } + }); + } + catch (e) { + Zotero.debug('Invalid relative descriptor', 2); + this._updateAttachmentStates(false); + return false; + } + } + } + + return file.path; +}; + + +/** + * Get the absolute path for the attachment, if it exists + * + * @return {Promise} - A promise for either the absolute path of the attachment + * or false for invalid paths or if the file doesn't exist + */ +Zotero.Item.prototype.getFilePathAsync = Zotero.Promise.coroutine(function* (skipExistsCheck) { + if (!this.isAttachment()) { + throw new Error("getFilePathAsync() can only be called on attachment items"); + } + + var linkMode = this.attachmentLinkMode; + var path = this.attachmentPath; + + // No associated files for linked URLs + if (linkMode == Zotero.Attachments.LINK_MODE_LINKED_URL) { + return false; + } + + if (!path) { + Zotero.debug("Attachment path is empty", 2); + if (!skipExistsCheck) { + this._updateAttachmentStates(false); } return false; } @@ -2269,7 +2397,7 @@ Zotero.Item.prototype.getFilePath = Zotero.Promise.coroutine(function* (skipExis catch (e) { Zotero.debug('Invalid persistent descriptor', 2); if (!skipExistsCheck) { - yield this._updateAttachmentStates(false); + this._updateAttachmentStates(false); } return false; } @@ -2280,7 +2408,7 @@ Zotero.Item.prototype.getFilePath = Zotero.Promise.coroutine(function* (skipExis path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0) { var file = Zotero.Attachments.resolveRelativePath(path); if (!skipExistsCheck && !file) { - yield this._updateAttachmentStates(false); + this._updateAttachmentStates(false); return false; } } @@ -2307,32 +2435,33 @@ Zotero.Item.prototype.getFilePath = Zotero.Promise.coroutine(function* (skipExis catch (e) { Zotero.debug('Invalid relative descriptor', 2); if (!skipExistsCheck) { - yield this._updateAttachmentStates(false); + this._updateAttachmentStates(false); } return false; } } } - path = file.path; + var path = file.path; if (!skipExistsCheck && !(yield OS.File.exists(path))) { Zotero.debug("Attachment file '" + path + "' not found", 2); - yield this._updateAttachmentStates(false); + this._updateAttachmentStates(false); return false; } if (!skipExistsCheck) { - yield this._updateAttachmentStates(true); + this._updateAttachmentStates(true); } - return path; + return file.path; }); + /** * Update file existence state of this item and best attachment state of parent item */ -Zotero.Item.prototype._updateAttachmentStates = Zotero.Promise.coroutine(function* (exists) { +Zotero.Item.prototype._updateAttachmentStates = function (exists) { this._fileExists = exists; if (this.isTopLevelItem()) { @@ -2351,9 +2480,18 @@ Zotero.Item.prototype._updateAttachmentStates = Zotero.Promise.coroutine(functio return; } - var item = yield Zotero.Items.getByLibraryAndKey(this.libraryID, parentKey); + try { + var item = Zotero.Items.getByLibraryAndKey(this.libraryID, parentKey); + } + catch (e) { + if (e instanceof Zotero.Items.UnloadedDataException) { + Zotero.debug("Attachment parent not yet loaded in Zotero.Item.updateAttachmentStates()", 2); + return; + } + throw e; + } item.clearBestAttachmentState(); -}); +}; Zotero.Item.prototype.getFilename = function () { @@ -2366,7 +2504,6 @@ Zotero.Item.prototype.getFilename = function () { } var file = this.getFile(); - // Invalid path if (!file) { return ''; } @@ -2377,7 +2514,7 @@ Zotero.Item.prototype.getFilename = function () { /** * Asynchronous cached check for file existence, used for items view * - * This is updated only initially and on subsequent getFilePath() calls. + * This is updated only initially and on subsequent getFilePathAsync() calls. */ Zotero.Item.prototype.fileExists = Zotero.Promise.coroutine(function* () { if (this._fileExists !== null) { @@ -2392,9 +2529,7 @@ Zotero.Item.prototype.fileExists = Zotero.Promise.coroutine(function* () { throw new Error("Zotero.Item.fileExists() cannot be called on link attachments"); } - var exists = !!(yield this.getFilePath()); - yield this._updateAttachmentStates(exists); - return exists; + return !!(yield this.getFilePathAsync()); }); @@ -2794,7 +2929,7 @@ Zotero.Item.prototype.__defineGetter__('attachmentModificationTime', Zotero.Prom return undefined; } - var path = yield this.getFilePath(); + var path = yield this.getFilePathAsync(); if (!path) { return undefined; } @@ -2832,7 +2967,7 @@ Zotero.Item.prototype.__defineGetter__('attachmentHash', function () { return undefined; } - return Zotero.Utilities.Internal.md5(file); + return Zotero.Utilities.Internal.md5(file) || undefined; }); @@ -2855,6 +2990,11 @@ Zotero.Item.prototype.__defineGetter__('attachmentText', Zotero.Promise.coroutin } var file = this.getFile(); + + if (!(yield OS.File.exists(file.path))) { + file = false; + } + var cacheFile = Zotero.Fulltext.getItemCacheFile(this); if (!file) { if (cacheFile.exists()) { @@ -3820,7 +3960,7 @@ Zotero.Item.prototype.erase = Zotero.Promise.coroutine(function* () { } var parentItem = this.parentKey; - parentItem = parentItem ? yield Zotero.Items.getByLibraryAndKey(this.libraryID, parentItem) : null; + parentItem = parentItem ? Zotero.Items.getByLibraryAndKey(this.libraryID, parentItem) : null; // // Delete associated attachment files if (this.isAttachment()) { diff --git a/chrome/content/zotero/xpcom/file.js b/chrome/content/zotero/xpcom/file.js index eaa907476..6da8901a6 100644 --- a/chrome/content/zotero/xpcom/file.js +++ b/chrome/content/zotero/xpcom/file.js @@ -186,7 +186,7 @@ Zotero.File = new function(){ /** * Get the contents of a text source asynchronously * - * @param {nsIURI|nsIFile|string spec|nsIChannel|nsIInputStream} source The source to read + * @param {nsIURI|nsIFile|string spec|string path|nsIChannel|nsIInputStream} source The source to read * @param {String} [charset] The character set; defaults to UTF-8 * @param {Integer} [maxLength] Maximum length to fetch, in bytes * @return {Promise} A Q promise that is resolved with the contents of the file @@ -194,6 +194,11 @@ Zotero.File = new function(){ this.getContentsAsync = function (source, charset, maxLength) { Zotero.debug("Getting contents of " + source); + // If path is given, convert to file:// URL + if (typeof source == 'string' && !source.match(/^file:/)) { + source = 'file://' + source; + } + var options = { charset: charset ? Zotero.CharacterSets.getName(charset) : "UTF-8", // This doesn't seem to work -- reading an image file still throws NS_ERROR_ILLEGAL_INPUT diff --git a/chrome/content/zotero/xpcom/fulltext.js b/chrome/content/zotero/xpcom/fulltext.js index 6af74d4a6..c8a88f3d4 100644 --- a/chrome/content/zotero/xpcom/fulltext.js +++ b/chrome/content/zotero/xpcom/fulltext.js @@ -325,26 +325,29 @@ Zotero.Fulltext = new function(){ /** + * @param {String} path * @param {Boolean} [complete=FALSE] Index the file in its entirety, ignoring maxLength */ - var indexFile = Zotero.Promise.coroutine(function* (file, mimeType, charset, itemID, complete, isCacheFile) { - if (!file.exists()){ + var indexFile = Zotero.Promise.coroutine(function* (path, contentType, charset, itemID, complete, isCacheFile) { + if (!(yield OS.File.exists(path))) { Zotero.debug('File not found in indexFile()', 2); return false; } - if (!itemID){ throw ('Item ID not provided to indexFile()'); } - - if (!mimeType) { - Zotero.debug("MIME type not provided in indexFile()", 1); + if (!contentType) { + Zotero.debug("Content type not provided in indexFile()", 1); return false; } - if (mimeType == 'application/pdf') { - return this.indexPDF(file, itemID, complete); + if (!itemID) { + throw new Error('Item ID not provided'); } - if (!Zotero.MIME.isTextType(mimeType)) { + if (contentType == 'application/pdf') { + return this.indexPDF(path, itemID, complete); + } + + if (!Zotero.MIME.isTextType(contentType)) { Zotero.debug('File is not text in indexFile()', 2); return false; } @@ -354,13 +357,13 @@ Zotero.Fulltext = new function(){ return false; } - Zotero.debug('Indexing file ' + file.path); + Zotero.debug('Indexing file ' + path); - var text = yield Zotero.File.getContentsAsync(file, charset); + var text = yield Zotero.File.getContentsAsync(path, charset); var totalChars = text.length; var maxLength = complete ? false : Zotero.Prefs.get('fulltext.textMaxLength'); - if (mimeType == 'text/html') { + if (contentType == 'text/html') { let obj = yield convertItemHTMLToText(itemID, text, maxLength); text = obj.text; totalChars = obj.totalChars; @@ -394,7 +397,7 @@ Zotero.Fulltext = new function(){ * @param {Boolean} [allPages] - If true, index all pages rather than pdfMaxPages * @return {Promise} */ - this.indexPDF = Zotero.Promise.coroutine(function* (file, itemID, allPages) { + this.indexPDF = Zotero.Promise.coroutine(function* (filePath, itemID, allPages) { if (!_pdfConverter) { Zotero.debug("PDF tools are not installed -- skipping indexing"); return false; @@ -410,23 +413,22 @@ Zotero.Fulltext = new function(){ // If file is stored outside of Zotero, create a directory for the item // in the storage directory and save the cache file there if (linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) { - var cacheFile = yield Zotero.Attachments.createDirectoryForItem(item); + var parentDirPath = (yield Zotero.Attachments.createDirectoryForItem(item)).path; } else { - var cacheFile = file.parent; + var parentDirPath = OS.Path.dirname(filePath); } - cacheFile.append(this.pdfConverterCacheFile); + var cacheFilePath = OS.Path.join(parentDirPath, this.pdfConverterCacheFile); if (_pdfInfo) { - var infoFile = cacheFile.parent; - infoFile.append(this.pdfInfoCacheFile); - Zotero.debug('Running pdfinfo "' + file.path + '" "' + infoFile.path + '"'); + var infoFilePath = OS.Path.join(parentDirPath, this.pdfInfoCacheFile); + Zotero.debug('Running pdfinfo "' + filePath + '" "' + infoFilePath + '"'); var proc = Components.classes["@mozilla.org/process/util;1"]. createInstance(Components.interfaces.nsIProcess); proc.init(_pdfInfo); - var args = [file.path, infoFile.path]; + var args = [filePath, infoFilePath]; try { proc.runw(true, args, args.length); var totalPages = yield getTotalPagesFromFile(itemID); @@ -440,8 +442,8 @@ Zotero.Fulltext = new function(){ } Zotero.debug('Running pdftotext -enc UTF-8 -nopgbrk ' - + (allPages ? '' : '-l ' + maxPages) + ' "' + file.path + '" "' - + cacheFile.path + '"'); + + (allPages ? '' : '-l ' + maxPages) + ' "' + filePath + '" "' + + cacheFilePath + '"'); var proc = Components.classes["@mozilla.org/process/util;1"]. createInstance(Components.interfaces.nsIProcess); @@ -457,7 +459,7 @@ Zotero.Fulltext = new function(){ args.push('-l', maxPages); var pagesIndexed = Math.min(maxPages, totalPages); } - args.push(file.path, cacheFile.path); + args.push(filePath, cacheFilePath); try { proc.runw(true, args, args.length); } @@ -466,10 +468,11 @@ Zotero.Fulltext = new function(){ return false; } - if (!cacheFile.exists()) { - var msg = file.leafName + " was not indexed"; - if (!file.leafName.match(/^[\u0000-\u007F]+$/)) { - msg += " -- PDFs with filenames containing extended characters cannot currently be indexed due to a Firefox limitation"; + if (!(yield OS.File.exists(cacheFilePath))) { + let fileName = OS.Path.basename(filePath); + let msg = fileName + " was not indexed"; + if (!fileName.match(/^[\u0000-\u007F]+$/)) { + msg += " -- PDFs with filenames containing extended characters cannot currently be indexed due to a Mozilla limitation"; } Zotero.debug(msg, 2); Components.utils.reportError(msg); @@ -477,7 +480,7 @@ Zotero.Fulltext = new function(){ } yield Zotero.DB.executeTransaction(function* () { - yield indexFile(cacheFile, 'text/plain', 'utf-8', itemID, true, true); + yield indexFile(cacheFilePath, 'text/plain', 'utf-8', itemID, true, true); yield setPages(itemID, { indexed: pagesIndexed, total: totalPages }); }); @@ -500,24 +503,24 @@ Zotero.Fulltext = new function(){ let itemID = item.id; - var file = yield item.getFile(); - if (!file){ + var path = yield item.getFilePathAsync(); + if (!path) { Zotero.debug("No file to index for item " + itemID + " in Fulltext.indexItems()"); continue; } if (ignoreErrors) { try { - yield indexFile(file, item.attachmentMIMEType, item.attachmentCharset, itemID, complete); + yield indexFile(path, item.attachmentContentType, item.attachmentCharset, itemID, complete); } catch (e) { Zotero.debug(e, 1); - Components.utils.reportError("Error indexing " + file.path); + Components.utils.reportError("Error indexing " + path); Components.utils.reportError(e); } } else { - yield indexFile(file, item.attachmentMIMEType, item.attachmentCharset, itemID, complete); + yield indexFile(path, item.attachmentContentType, item.attachmentCharset, itemID, complete); } } }); @@ -693,7 +696,7 @@ Zotero.Fulltext = new function(){ */ this.setItemContent = Zotero.Promise.coroutine(function* (libraryID, key, text, stats, version) { var libraryKey = libraryID + "/" + key; - var item = yield Zotero.Items.getByLibraryAndKey(libraryID, key); + var item = Zotero.Items.getByLibraryAndKey(libraryID, key); if (!item) { let msg = "Item " + libraryKey + " not found setting full-text content"; Zotero.debug(msg, 1); diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js index f823f5e61..d05081251 100644 --- a/chrome/content/zotero/xpcom/itemTreeView.js +++ b/chrome/content/zotero/xpcom/itemTreeView.js @@ -1363,7 +1363,7 @@ Zotero.ItemTreeView.prototype.sort = Zotero.Promise.coroutine(function* (itemID) case 'hasAttachment': if (item.isAttachment()) { - var state = item.fileExists() ? 1 : -1; + var state = item.fileExistsCached() ? 1 : -1; } else if (item.isRegularItem()) { var state = item.getBestAttachmentState(); diff --git a/chrome/content/zotero/xpcom/search.js b/chrome/content/zotero/xpcom/search.js index f838cda31..687428785 100644 --- a/chrome/content/zotero/xpcom/search.js +++ b/chrome/content/zotero/xpcom/search.js @@ -1184,7 +1184,7 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () { if (condition.value) { var lkh = Zotero.Collections.parseLibraryKeyHash(condition.value); if (lkh) { - col = yield Zotero.Collections.getByLibraryAndKey(lkh.libraryID, lkh.key); + col = Zotero.Collections.getByLibraryAndKey(lkh.libraryID, lkh.key); } } if (!col) { @@ -1225,7 +1225,7 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () { if (condition.value) { var lkh = Zotero.Searches.parseLibraryKeyHash(condition.value); if (lkh) { - search = yield Zotero.Searches.getByLibraryAndKey(lkh.libraryID, lkh.key); + search = Zotero.Searches.getByLibraryAndKey(lkh.libraryID, lkh.key); } } if (!search) { diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js index a874e0bcf..d7bbc85d9 100644 --- a/chrome/content/zotero/xpcom/utilities_internal.js +++ b/chrome/content/zotero/xpcom/utilities_internal.js @@ -75,6 +75,10 @@ Zotero.Utilities.Internal = { ch.update(data, data.length); } else if (strOrFile instanceof Components.interfaces.nsIFile) { + if (!strOrFile.exists()) { + return false; + } + // Otherwise throws (NS_ERROR_NOT_AVAILABLE) [nsICryptoHash.updateFromStream] if (!strOrFile.fileSize) { // MD5 for empty string diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index 0df3c76c0..3351ec140 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -1512,7 +1512,7 @@ var ZoteroPane = new function() for (var i=0; i