www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 017342a85e247d76b94b2e23b539385db6834d65
parent 8712f49426ed96a7f9876b7b2632f19e552bb720
Author: Dan Stillman <dstillman@zotero.org>
Date:   Thu, 28 May 2009 09:52:52 +0000

Fix Open/Save dialog and use of hidden browser when saving file types not handled natively using "Save Link as Zotero Snapshot" or drag-and-drop to create a standalone item

This need testing.


Diffstat:
Mchrome/content/zotero/overlay.js | 194++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mchrome/content/zotero/overlay.xul | 2+-
Mchrome/content/zotero/xpcom/attachments.js | 315+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mchrome/content/zotero/xpcom/mime.js | 32++++++++++++++++++++++++++++++++
4 files changed, 338 insertions(+), 205 deletions(-)

diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js @@ -628,16 +628,16 @@ var ZoteroPane = new function() return false; } - if (!this.canEdit(row)) { - this.displayCannotEditLibraryMessage(); - return; - } - // Currently selected row if (row === undefined) { row = this.collectionsView.selection.currentIndex; } + if (!this.canEdit(row)) { + this.displayCannotEditLibraryMessage(); + return; + } + if (row !== undefined) { var itemGroup = this.collectionsView._getItemAtRow(row); var libraryID = itemGroup.ref.libraryID; @@ -2255,30 +2255,6 @@ var ZoteroPane = new function() * regardless of automaticSnapshots pref */ this.addItemFromDocument = function (doc, itemType, saveSnapshot, row) { - if (!Zotero.stateCheck()) { - this.displayErrorMessage(true); - return false; - } - - // Currently selected row - if (row === undefined) { - row = this.collectionsView.selection.currentIndex; - } - - if (!this.canEdit(row)) { - this.displayCannotEditLibraryMessage(); - return; - } - - if (row !== undefined) { - var itemGroup = this.collectionsView._getItemAtRow(row); - var libraryID = itemGroup.ref.libraryID; - } - else { - var libraryID = null; - var itemGroup = null; - } - var progressWin = new Zotero.ProgressWindow(); progressWin.changeHeadline(Zotero.getString('ingester.scraping')); var icon = 'chrome://zotero/skin/treeitem-webpage.png'; @@ -2286,12 +2262,6 @@ var ZoteroPane = new function() progressWin.show(); progressWin.startCloseTimer(); - var data = { - title: doc.title, - url: doc.location.href, - accessDate: "CURRENT_TIMESTAMP" - } - // TODO: this, needless to say, is a temporary hack if (itemType == 'temporaryPDFHack') { itemType = null; @@ -2315,6 +2285,36 @@ var ZoteroPane = new function() } if (isPDF) { + // + // Duplicate newItem() checks here + // + if (!Zotero.stateCheck()) { + this.displayErrorMessage(true); + return false; + } + + // Currently selected row + if (row === undefined) { + row = this.collectionsView.selection.currentIndex; + } + + if (!this.canEdit(row)) { + this.displayCannotEditLibraryMessage(); + return; + } + + if (row !== undefined) { + var itemGroup = this.collectionsView._getItemAtRow(row); + var libraryID = itemGroup.ref.libraryID; + } + else { + var libraryID = null; + var itemGroup = null; + } + // + // + // + if (libraryID) { var pr = Components.classes["@mozilla.org/network/default-prompt;1"] .getService(Components.interfaces.nsIPrompt); @@ -2328,6 +2328,7 @@ var ZoteroPane = new function() else { var collectionID = false; } + Zotero.Attachments.importFromDocument(doc, false, false, collectionID); return; } @@ -2337,6 +2338,11 @@ var ZoteroPane = new function() if (!itemType) { itemType = 'webpage'; } + var data = { + title: doc.title, + url: doc.location.href, + accessDate: "CURRENT_TIMESTAMP" + } itemType = Zotero.ItemTypes.getID(itemType); var item = this.newItem(itemType, data, row); @@ -2369,17 +2375,113 @@ var ZoteroPane = new function() return this.addItemFromPage(itemType, saveSnapshot, row); } - var processor = function (doc) { - ZoteroPane.addItemFromDocument(doc, itemType, saveSnapshot, row); - }; - - var done = function () {} - - var exception = function (e) { - Zotero.debug(e); - } - - Zotero.Utilities.HTTP.processDocuments([url], processor, done, exception); + Zotero.MIME.getMIMETypeFromURL(url, function (mimeType, hasNativeHandler) { + // If native type, save using a hidden browser + if (hasNativeHandler) { + var processor = function (doc) { + ZoteroPane.addItemFromDocument(doc, itemType, saveSnapshot, row); + }; + + var done = function () {} + + var exception = function (e) { + Zotero.debug(e); + } + + Zotero.Utilities.HTTP.processDocuments([url], processor, done, exception); + } + // Otherwise create placeholder item, attach attachment, and update from that + else { + // TODO: this, needless to say, is a temporary hack + if (itemType == 'temporaryPDFHack') { + itemType = null; + + if (mimeType == 'application/pdf') { + // + // Duplicate newItem() checks here + // + if (!Zotero.stateCheck()) { + ZoteroPane.displayErrorMessage(true); + return false; + } + + // Currently selected row + if (row === undefined) { + row = ZoteroPane.collectionsView.selection.currentIndex; + } + + if (!ZoteroPane.canEdit(row)) { + ZoteroPane.displayCannotEditLibraryMessage(); + return; + } + + if (row !== undefined) { + var itemGroup = ZoteroPane.collectionsView._getItemAtRow(row); + var libraryID = itemGroup.ref.libraryID; + } + else { + var libraryID = null; + var itemGroup = null; + } + // + // + // + + if (libraryID) { + var pr = Components.classes["@mozilla.org/network/default-prompt;1"] + .getService(Components.interfaces.nsIPrompt); + pr.alert("", "Files cannot currently be added to group libraries."); + return; + } + + if (itemGroup && itemGroup.isCollection()) { + var collectionID = itemGroup.ref.id; + } + else { + var collectionID = false; + } + + Zotero.Attachments.importFromURL(url, false, false, collectionID); + return; + } + } + + if (!itemType) { + itemType = 'webpage'; + } + + var item = ZoteroPane.newItem(itemType, {}, row); + + if (item.libraryID) { + var group = Zotero.Groups.getByLibraryID(item.libraryID); + filesEditable = group.filesEditable; + } + else { + filesEditable = true; + } + + // Save snapshot if explicitly enabled or automatically pref is set and not explicitly disabled + if (saveSnapshot || (saveSnapshot !== false && Zotero.Prefs.get('automaticSnapshots'))) { + var link = false; + + if (link) { + //Zotero.Attachments.linkFromURL(doc, item.id); + } + else if (filesEditable) { + var attachmentItem = Zotero.Attachments.importFromURL(url, item.id, false, false, false, mimeType); + if (attachmentItem) { + item.setField('title', attachmentItem.getField('title')); + item.setField('url', attachmentItem.getField('url')); + item.setField('accessDate', attachmentItem.getField('accessDate')); + item.save(); + } + } + } + + return item.id; + + } + }); } diff --git a/chrome/content/zotero/overlay.xul b/chrome/content/zotero/overlay.xul @@ -63,7 +63,7 @@ <!-- TODO: localize and remove zotero.contextMenu.saveLinkAsItem/saveImageAsSnapshot --> <menuitem id="zotero-context-save-link-as-item" class="menu-iconic" label="Save Link as Zotero Item" hidden="true" - oncommand="ZoteroPane.addItemFromURL(window.gContextMenu.linkURL)"/> + oncommand="ZoteroPane.addItemFromURL(window.gContextMenu.linkURL, 'temporaryPDFHack')"/> <menuitem id="zotero-context-save-image-as-item" class="menu-iconic" label="Save Image as Zotero Item" hidden="true" oncommand="ZoteroPane.addItemFromURL(window.gContextMenu.onImage ? (window.gContextMenu.mediaURL ? window.gContextMenu.mediaURL : window.gContextMenu.imageURL) : window.gContextMenu.bgImageURL, 'artwork')"/> diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js @@ -187,7 +187,7 @@ Zotero.Attachments = new function(){ } - function importFromURL(url, sourceItemID, forceTitle, forceFileBaseName, parentCollectionIDs){ + function importFromURL(url, sourceItemID, forceTitle, forceFileBaseName, parentCollectionIDs, mimeType) { Zotero.debug('Importing attachment from URL'); if (sourceItemID && parentCollectionIDs) { @@ -206,180 +206,181 @@ Zotero.Attachments = new function(){ throw ("Invalid URL '" + url + "' in Zotero.Attachments.importFromURL()"); } - Zotero.Utilities.HTTP.doHead(url, function(obj){ - if (obj.status != 200 && obj.status != 204) { - Zotero.debug("Attachment HEAD request returned with status code " - + obj.status + " in Attachments.importFromURL()", 2); - var mimeType = ''; + // Save using a hidden browser + var nativeHandlerImport = function () { + var browser = Zotero.Browser.createHiddenBrowser(); + var imported = false; + var onpageshow = function() { + // ignore spurious about:blank loads + if(browser.contentDocument.location.href == "about:blank") return; + + // pageshow can be triggered multiple times on some pages, + // so make sure we only import once + // (https://www.zotero.org/trac/ticket/795) + if (imported) { + return; + } + var callback = function () { + browser.removeEventListener("pageshow", onpageshow, false); + Zotero.Browser.deleteHiddenBrowser(browser); + }; + Zotero.Attachments.importFromDocument(browser.contentDocument, + sourceItemID, forceTitle, parentCollectionIDs, callback); + imported = true; + }; + browser.addEventListener("pageshow", onpageshow, false); + browser.loadURI(url); + }; + + // Save using remote web browser persist + var externalHandlerImport = function (mimeType) { + if (forceFileBaseName) { + var ext = _getExtensionFromURL(url, mimeType); + var fileName = forceFileBaseName + (ext != '' ? '.' + ext : ''); } else { - var mimeType = obj.channel.contentType; + var fileName = _getFileNameFromURL(url, mimeType); } - var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"] - .createInstance(Components.interfaces.nsIURL); - nsIURL.spec = url; + var title = forceTitle ? forceTitle : fileName; - // Override MIME type to application/pdf if extension is .pdf -- - // workaround for sites that respond to the HEAD request with an - // invalid MIME type (https://www.zotero.org/trac/ticket/460) - // - // Downloaded file is inspected below and deleted if actually HTML - if (nsIURL.fileName.match(/pdf$/) || url.match(/pdf$/)) { - mimeType = 'application/pdf'; - } + const nsIWBP = Components.interfaces.nsIWebBrowserPersist; + var wbp = Components + .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(nsIWBP); + wbp.persistFlags = nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; + var encodingFlags = false; - // If we can load this natively, use a hidden browser (so we can - // get the charset and title and index the document) - if (Zotero.MIME.hasNativeHandler(mimeType, ext)){ - var browser = Zotero.Browser.createHiddenBrowser(); - var imported = false; - var onpageshow = function() { - // ignore spurious about:blank loads - if(browser.contentDocument.location.href == "about:blank") return; - - // pageshow can be triggered multiple times on some pages, - // so make sure we only import once - // (https://www.zotero.org/trac/ticket/795) - if (imported) { - return; - } - var callback = function () { - browser.removeEventListener("pageshow", onpageshow, false); - Zotero.Browser.deleteHiddenBrowser(browser); - }; - Zotero.Attachments.importFromDocument(browser.contentDocument, - sourceItemID, forceTitle, parentCollectionIDs, callback); - imported = true; - }; - browser.addEventListener("pageshow", onpageshow, false); - browser.loadURI(url); - } + Zotero.DB.beginTransaction(); - // Otherwise use a remote web page persist - else { - if (forceFileBaseName) { - var ext = _getExtensionFromURL(url, mimeType); - var fileName = forceFileBaseName + (ext != '' ? '.' + ext : ''); - } - else { - var fileName = _getFileNameFromURL(url, mimeType); + try { + // Create a new attachment + var attachmentItem = new Zotero.Item('attachment'); + if (sourceItemID) { + var parentItem = Zotero.Items.get(sourceItemID); + attachmentItem.libraryID = parentItem.libraryID; } + attachmentItem.setField('title', title); + attachmentItem.setField('url', url); + attachmentItem.setField('accessDate', "CURRENT_TIMESTAMP"); + attachmentItem.setSource(sourceItemID); + attachmentItem.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_URL; + attachmentItem.attachmentMIMEType = mimeType; + var itemID = attachmentItem.save(); + attachmentItem = Zotero.Items.get(itemID); - var title = forceTitle ? forceTitle : fileName; + // Add to collections + if (parentCollectionIDs){ + var ids = Zotero.flattenArguments(parentCollectionIDs); + for each(var id in ids){ + var col = Zotero.Collections.get(id); + col.addItem(itemID); + } + } - const nsIWBP = Components.interfaces.nsIWebBrowserPersist; - var wbp = Components - .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] - .createInstance(nsIWBP); - wbp.persistFlags = nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; - var encodingFlags = false; + // Create a new folder for this item in the storage directory + var destDir = Zotero.Attachments.createDirectoryForItem(itemID); - Zotero.DB.beginTransaction(); + var file = destDir.clone(); + file.append(fileName); - try { - // Create a new attachment - var attachmentItem = new Zotero.Item('attachment'); - if (sourceItemID) { - var parentItem = Zotero.Items.get(sourceItemID); - attachmentItem.libraryID = parentItem.libraryID; - } - attachmentItem.setField('title', title); - attachmentItem.setField('url', url); - attachmentItem.setField('accessDate', "CURRENT_TIMESTAMP"); - attachmentItem.setSource(sourceItemID); - attachmentItem.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_URL; - attachmentItem.attachmentMIMEType = mimeType; - var itemID = attachmentItem.save(); - attachmentItem = Zotero.Items.get(itemID); - - // Add to collections - if (parentCollectionIDs){ - var ids = Zotero.flattenArguments(parentCollectionIDs); - for each(var id in ids){ - var col = Zotero.Collections.get(id); - col.addItem(itemID); - } - } - - // Create a new folder for this item in the storage directory - var destDir = Zotero.Attachments.createDirectoryForItem(itemID); - - var file = destDir.clone(); - file.append(fileName); - - wbp.progressListener = new Zotero.WebProgressFinishListener(function(){ - try { - var str = Zotero.File.getSample(file); - - if (mimeType == 'application/pdf' && - Zotero.MIME.sniffForMIMEType(str) != 'application/pdf') { - Zotero.debug("Downloaded PDF did not have MIME type " - + "'application/pdf' in Attachments.importFromURL()", 2); - attachmentItem.erase(); - return; - } - - attachmentItem.attachmentPath = - Zotero.Attachments.getPath( - file, Zotero.Attachments.LINK_MODE_IMPORTED_URL - ); - attachmentItem.save(); - - Zotero.Notifier.trigger('add', 'item', itemID); - Zotero.Notifier.trigger('modify', 'item', sourceItemID); - - // We don't have any way of knowing that the file - // is flushed to disk, so we just wait a second - // and hope for the best -- we'll index it later - // if it fails - // - // TODO: index later - var timer = Components.classes["@mozilla.org/timer;1"]. - createInstance(Components.interfaces.nsITimer); - timer.initWithCallback({notify: function() { - Zotero.Fulltext.indexItems([itemID]); - }}, 1000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); - } - catch (e) { - // Clean up + wbp.progressListener = new Zotero.WebProgressFinishListener(function(){ + try { + var str = Zotero.File.getSample(file); + + if (mimeType == 'application/pdf' && + Zotero.MIME.sniffForMIMEType(str) != 'application/pdf') { + Zotero.debug("Downloaded PDF did not have MIME type " + + "'application/pdf' in Attachments.importFromURL()", 2); attachmentItem.erase(); - - throw (e); + return; } - }); - - // Disable the Notifier during the commit - var disabled = Zotero.Notifier.disable(); - - // The attachment is still incomplete here, but we can't risk - // leaving the transaction open if the callback never triggers - Zotero.DB.commitTransaction(); - - if (disabled) { - Zotero.Notifier.enable(); + + attachmentItem.attachmentPath = + Zotero.Attachments.getPath( + file, Zotero.Attachments.LINK_MODE_IMPORTED_URL + ); + attachmentItem.save(); + + Zotero.Notifier.trigger('add', 'item', itemID); + Zotero.Notifier.trigger('modify', 'item', sourceItemID); + + // We don't have any way of knowing that the file + // is flushed to disk, so we just wait a second + // and hope for the best -- we'll index it later + // if it fails + // + // TODO: index later + var timer = Components.classes["@mozilla.org/timer;1"]. + createInstance(Components.interfaces.nsITimer); + timer.initWithCallback({notify: function() { + Zotero.Fulltext.indexItems([itemID]); + }}, 1000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); } - - wbp.saveURI(nsIURL, null, null, null, null, file); - } - catch (e){ - Zotero.DB.rollbackTransaction(); - - try { + catch (e) { // Clean up - if (itemID) { - var itemDir = this.getStorageDirectory(itemID); - if (itemDir.exists()) { - itemDir.remove(true); - } + attachmentItem.erase(); + + throw (e); + } + }); + + // Disable the Notifier during the commit + var disabled = Zotero.Notifier.disable(); + + // The attachment is still incomplete here, but we can't risk + // leaving the transaction open if the callback never triggers + Zotero.DB.commitTransaction(); + + if (disabled) { + Zotero.Notifier.enable(); + } + + var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"] + .createInstance(Components.interfaces.nsIURL); + nsIURL.spec = url; + wbp.saveURI(nsIURL, null, null, null, null, file); + + return attachmentItem; + } + catch (e){ + Zotero.DB.rollbackTransaction(); + + try { + // Clean up + if (itemID) { + var itemDir = this.getStorageDirectory(itemID); + if (itemDir.exists()) { + itemDir.remove(true); } } - catch (e) {} - - throw (e); } + catch (e) {} + + throw (e); } - }); + } + + var process = function (mimeType, hasNativeHandler) { + // If we can load this natively, use a hidden browser + // (so we can get the charset and title and index the document) + if (hasNativeHandler) { + nativeHandlerImport(); + } + // Otherwise use a remote web page persist + else { + return externalHandlerImport(mimeType); + } + } + + if (mimeType) { + return process(mimeType); + } + else { + Zotero.MIME.getMIMETypeFromURL(url, function (mimeType, hasNativeHandler) { + process(mimeType, hasNativeHandler); + }); + } } @@ -425,9 +426,7 @@ Zotero.Attachments = new function(){ if (!mimeType) { // If we don't have the MIME type, do a HEAD request for it - Zotero.Utilities.HTTP.doHead(url, function(obj){ - var mimeType = obj.channel.contentType; - + Zotero.MIME.getMIMETypeFromURL(url, function (mimeType) { if (mimeType) { var disabled = Zotero.Notifier.disable(); diff --git a/chrome/content/zotero/xpcom/mime.js b/chrome/content/zotero/xpcom/mime.js @@ -275,6 +275,38 @@ Zotero.MIME = new function(){ } + this.getMIMETypeFromURL = function (url, callback) { + Zotero.Utilities.HTTP.doHead(url, function(xmlhttp) { + if (xmlhttp.status != 200 && xmlhttp.status != 204) { + Zotero.debug("Attachment HEAD request returned with status code " + + xmlhttp.status + " in Zotero.MIME.getMIMETypeFromURL()", 2); + var mimeType = ''; + } + else { + var mimeType = xmlhttp.channel.contentType; + } + + var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"] + .createInstance(Components.interfaces.nsIURL); + nsIURL.spec = url; + + // Override MIME type to application/pdf if extension is .pdf -- + // workaround for sites that respond to the HEAD request with an + // invalid MIME type (https://www.zotero.org/trac/ticket/460) + // + // Downloaded file is inspected in attachment code and deleted if actually HTML + if (nsIURL.fileName.match(/pdf$/) || url.match(/pdf$/)) { + mimeType = 'application/pdf'; + } + + var ext = nsIURL.fileExtension; + var hasNativeHandler = Zotero.MIME.hasNativeHandler(mimeType, ext) + + callback(mimeType, hasNativeHandler); + }); + } + + /* * Determine if a MIME type can be handled natively * or if it needs to be passed off to a plugin or external helper app