diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js index 2683403cd..a5c2783ee 100644 --- a/chrome/content/zotero/xpcom/attachments.js +++ b/chrome/content/zotero/xpcom/attachments.js @@ -586,9 +586,70 @@ Zotero.Attachments = new function(){ } } + var browser; + if (contentType === 'text/html' || contentType === 'application/xhtml+xml') { + // If page looks like an article, run it through Reader Mode + try { + Components.utils.import("resource://gre/modules/ReaderMode.jsm") + if (ReaderMode.isProbablyReaderable(document)) { + Zotero.debug("Document is probably readerable"); + browser = Zotero.Browser.createHiddenBrowser(); + let loadDeferred = Zotero.Promise.defer(); + browser.addEventListener('DOMContentLoaded', () => loadDeferred.resolve()); + // Use Firefox's Reader Mode template + browser.loadURI("chrome://global/content/reader/aboutReader.html"); + yield loadDeferred.promise; + let doc = browser.contentDocument; + + let article = yield ReaderMode.parseDocument(document); + + let scriptElement = doc.getElementsByTagName('script')[0]; + let toolbarElement = doc.getElementById('reader-toolbar'); + let headerElement = doc.getElementById('reader-header'); + let domainElement = doc.getElementById('reader-domain'); + let titleElement = doc.getElementById('reader-title'); + let bylineElement = doc.getElementById('reader-credits'); + let contentElement = doc.getElementById('moz-reader-content'); + let footerElement = doc.getElementById('reader-footer'); + + // Remove Reader Mode controls + [scriptElement, toolbarElement, domainElement, footerElement].forEach(elem => { + elem.parentNode.removeChild(elem); + }); + + // The following logic more or less follows AboutReader.jsm::_showContent() + doc.title = article.title; + titleElement.textContent = article.title; + + if (article.byline) { + bylineElement.textContent = article.byline; + } + + headerElement.style.display = 'block'; + + let parserUtils = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils); + let contentFragment = parserUtils.parseFragment( + article.content, + Ci.nsIParserUtils.SanitizerDropForms | Ci.nsIParserUtils.SanitizerAllowStyle, + false, + Services.io.newURI(url, null, null), + contentElement + ); + contentElement.innerHTML = ""; + contentElement.appendChild(contentFragment); + + contentElement.style.display = 'block'; + + document = doc; + } + } + catch (e) { + Zotero.logError(e); + } + // Load WebPageDump code - var wpd = {"Zotero":Zotero}; + var wpd = { Zotero }; Components.classes["@mozilla.org/moz/jssubscript-loader;1"] .getService(Components.interfaces.mozIJSSubScriptLoader) .loadSubScript("chrome://zotero/content/webpagedump/common.js", wpd); @@ -688,6 +749,10 @@ Zotero.Attachments = new function(){ yield Zotero.Fulltext.indexDocument(document, attachmentItem.id); } + if (browser) { + Zotero.Browser.deleteHiddenBrowser(browser); + } + return attachmentItem; }); diff --git a/chrome/content/zotero/xpcom/translation/translate_item.js b/chrome/content/zotero/xpcom/translation/translate_item.js index 0c3084d4e..f959bdab6 100644 --- a/chrome/content/zotero/xpcom/translation/translate_item.js +++ b/chrome/content/zotero/xpcom/translation/translate_item.js @@ -554,12 +554,27 @@ Zotero.Translate.ItemSaver.prototype = { Zotero.debug('Importing attachment from document'); attachment.linkMode = "imported_url"; - return Zotero.Attachments.importFromDocument({ - libraryID: this._libraryID, - document: attachment.document, - parentItemID: parentID, - title: title - }); + let url = attachment.document.location.href; + let html = attachment.document.documentElement.innerHTML; + + // Save via connector server to address bug saving document directly + Zotero.Server.Connector.Data[url] = "" + html + ""; + let deferred = Zotero.Promise.defer(); + Zotero.HTTP.processDocuments( + ["zotero://connector/" + encodeURIComponent(url)], + function (doc) { + delete Zotero.Server.Connector.Data[url]; + + return Zotero.Attachments.importFromDocument({ + document: doc, + parentItemID: parentID, + title: doc.title + }) + .then(attachment => deferred.resolve(attachment)) + .catch(e => deferred.reject(e)); + } + ); + return deferred.promise; } // Import from URL diff --git a/test/tests/server_connectorTest.js b/test/tests/server_connectorTest.js index 2591ccc3c..16331b956 100644 --- a/test/tests/server_connectorTest.js +++ b/test/tests/server_connectorTest.js @@ -104,7 +104,7 @@ describe("Connector Server", function () { }); describe("/connector/saveSnapshot", function () { - it("should save a webpage item and snapshot to the current selected collection", function* () { + it("should save a webpage item and non-readerable snapshot to the current selected collection", function* () { var collection = yield createDataObject('collection'); yield waitForItemsLoad(win); @@ -144,6 +144,68 @@ describe("Connector Server", function () { item = Zotero.Items.get(ids2[0]); assert.isTrue(item.isImportedAttachment()); assert.equal(item.getField('title'), 'Title'); + var path = yield item.getFilePathAsync(); + var fileContents = yield Zotero.File.getContentsAsync(path); + assert.notInclude(fileContents, 'moz-reader-content'); + }); + + it("should save a webpage item and readerable snapshot to the current selected collection", function* () { + var collection = yield createDataObject('collection'); + yield waitForItemsLoad(win); + + var pageTitle = "Page Title"; + var articleTitle = "Article Title"; + var byline = "First Last"; + var content = "
" + new Array(50).fill("").map(x => Zotero.Utilities.randomString()).join(" ") + "
" + + "" + new Array(50).fill("").map(x => Zotero.Utilities.randomString()).join(" ") + "
" + + "" + new Array(50).fill("").map(x => Zotero.Utilities.randomString()).join(" ") + "
" + + // saveSnapshot saves parent and child before returning + var ids1, ids2; + var promise = waitForItemEvent('add').then(function (ids) { + ids1 = ids; + return waitForItemEvent('add').then(function (ids) { + ids2 = ids; + }); + }); + yield Zotero.HTTP.request( + 'POST', + connectorServerPath + "/connector/saveSnapshot", + { + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + url: "http://example.com/articles/1", + html: `