diff --git a/chrome/content/zotero/xpcom/pdfExport.js b/chrome/content/zotero/xpcom/pdfExport.js
deleted file mode 100644
index ad916b6f4c..0000000000
--- a/chrome/content/zotero/xpcom/pdfExport.js
+++ /dev/null
@@ -1,168 +0,0 @@
-class PDFExport {
- constructor() {
- this._queue = [];
- this._queueProcessing = false;
- this._processingItemID = null;
- this._progressQueue = Zotero.ProgressQueues.create({
- id: 'pdf-export',
- title: 'pdfExport.title',
- columns: [
- 'recognizePDF.pdfName.label',
- 'pdfImport.annotations.label'
- ]
- });
-
- this._progressQueue.addListener('cancel', () => {
- this._queue = [];
- });
- }
-
- hasAnnotations(item) {
- item._loaded.childItems = true;
- return item.isAttachment() && item.getAnnotations().length;
- }
-
- canExport(item) {
- if (this.hasAnnotations(item)) {
- return true;
- }
- else if (item.isRegularItem()) {
- let ids = item.getAttachments();
- for (let id of ids) {
- let attachment = Zotero.Items.get(id);
- if (this.hasAnnotations(attachment)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Triggers queue processing and returns when all items in the queue are processed
- * @return {Promise}
- */
- async _processQueue() {
- // await Zotero.Schema.schemaUpdatePromise;
-
- if (this._queueProcessing) return;
- this._queueProcessing = true;
-
- while (1) {
- let data = this._queue.pop();
- if (!data) break;
-
- let { itemID, path } = data;
-
- this._processingItemID = itemID;
-
- this._progressQueue.updateRow(itemID, Zotero.ProgressQueue.ROW_PROCESSING, Zotero.getString('general.processing'));
-
- try {
- let item = await Zotero.Items.getAsync(itemID);
-
- if (!item) {
- throw new Error();
- }
-
- let num = await this._exportItemAnnotations(item, path);
- this._progressQueue.updateRow(itemID, Zotero.ProgressQueue.ROW_SUCCEEDED, num);
- }
- catch (e) {
- Zotero.logError(e);
-
- this._progressQueue.updateRow(
- itemID,
- Zotero.ProgressQueue.ROW_FAILED,
- e instanceof Zotero.Exception.Alert
- ? e.message
- : Zotero.getString('general.error')
- );
- }
- }
-
- this._queueProcessing = false;
- this._processingItemID = null;
- }
-
- /**
- * Adds items to the queue and triggers processing
- * @param {Zotero.Item[]} items
- */
- async export(items) {
- let pdfItems = [];
-
- if (!Array.isArray(items)) {
- items = [items];
- }
-
- for (let item of items) {
- if (this.hasAnnotations(item)) {
- pdfItems.push(item);
- }
- else if (item.isRegularItem()) {
- let ids = item.getAttachments();
- for (let id of ids) {
- let attachment = Zotero.Items.get(id);
- if (this.hasAnnotations(attachment)) {
- pdfItems.push(attachment);
- }
- }
- }
- }
-
- for (let item of pdfItems) {
- if (
- this._processingItemID === item.id ||
- this._queue.find(x => x.itemID === item.id)
- ) {
- continue;
- }
- this._queue.unshift({ itemID: item.id });
- this._progressQueue.addRow(item);
- }
- await this._processQueue();
- }
-
- async exportToPath(item, path, isPriority) {
- if (isPriority) {
- this._queue.push({ itemID: item.id, path });
- }
- else {
- this._queue.unshift({ itemID: item.id, path });
- }
- this._progressQueue.addRow(item);
- await this._processQueue();
- }
-
- async _exportItemAnnotations(item, path) {
- let ids = item.getAnnotations();
-
- let annotations = [];
- for (let id of ids) {
- try {
- annotations.push(Zotero.Annotations.toJSON(Zotero.Items.get(id)));
- } catch (e) {
- Zotero.logError(e);
- }
- }
-
- annotations.id = annotations.key;
- // annotations.image = annotations.imageURL;
-
- for (let annotation of annotations) {
- delete annotation.key;
- for (let key in annotation) {
- annotation[key] = annotation[key] || '';
- }
-
- annotation.authorName = '';
- }
-
- await Zotero.PDFWorker.writeAnnotations(item.id, annotations, path);
- return annotations.length;
- }
-}
-
-Zotero.PDFExport = new PDFExport();
diff --git a/chrome/content/zotero/xpcom/pdfImport.js b/chrome/content/zotero/xpcom/pdfImport.js
deleted file mode 100644
index 7623a09ab2..0000000000
--- a/chrome/content/zotero/xpcom/pdfImport.js
+++ /dev/null
@@ -1,167 +0,0 @@
-// TODO: Import ToC
-
-class PdfImport {
- constructor() {
- this._queue = [];
- this._queueProcessing = false;
- this._processingItemID = null;
- this._progressQueue = Zotero.ProgressQueues.create({
- id: 'pdf-import',
- title: 'pdfImport.title',
- columns: [
- 'recognizePDF.pdfName.label',
- 'pdfImport.annotations.label'
- ]
- });
-
- this._progressQueue.addListener('cancel', () => {
- this._queue = [];
- });
- }
-
- isPDFAttachment(item) {
- return item.isAttachment() && item.attachmentContentType === 'application/pdf';
- }
-
- canImport(item) {
- if (this.isPDFAttachment(item)) {
- return true;
- }
- else if (item.isRegularItem()) {
- let ids = item.getAttachments();
- for (let id of ids) {
- let attachment = Zotero.Items.get(id);
- if (this.isPDFAttachment(attachment)) {
- return true;
- }
- }
- }
- };
-
- /**
- * Triggers queue processing and returns when all items in the queue are processed
- * @return {Promise}
- */
- async _processQueue() {
- // await Zotero.Schema.schemaUpdatePromise;
-
- if (this._queueProcessing) return;
- this._queueProcessing = true;
-
- while (1) {
- let itemID = this._queue.pop();
- if (!itemID) break;
-
- this._processingItemID = itemID;
-
- this._progressQueue.updateRow(itemID, Zotero.ProgressQueue.ROW_PROCESSING, Zotero.getString('general.processing'));
-
- try {
- let item = await Zotero.Items.getAsync(itemID);
-
- if (!item) {
- throw new Error();
- }
-
- let num = await this._importItemAnnotations(item);
- this._progressQueue.updateRow(itemID, Zotero.ProgressQueue.ROW_SUCCEEDED, num);
- }
- catch (e) {
- Zotero.logError(e);
-
- this._progressQueue.updateRow(
- itemID,
- Zotero.ProgressQueue.ROW_FAILED,
- e instanceof Zotero.Exception.Alert
- ? e.message
- : Zotero.getString('general.error')
- );
- }
- }
-
- this._queueProcessing = false;
- this._processingItemID = null;
- }
-
- /**
- * Adds items to the queue and triggers processing
- * @param {Zotero.Item[]} items
- */
- async import(items, isPriority) {
- let pdfItems = [];
-
- if (!Array.isArray(items)) {
- items = [items];
- }
-
- for (let item of items) {
- if (this.isPDFAttachment(item)) {
- pdfItems.push(item);
- }
- else if (item.isRegularItem()) {
- let ids = item.getAttachments();
- for (let id of ids) {
- let attachment = Zotero.Items.get(id);
- if (this.isPDFAttachment(attachment)) {
- pdfItems.push(attachment);
- }
- }
- }
- }
-
- for (let item of pdfItems) {
- if (
- this._processingItemID === item.id ||
- this._queue.includes(item.id)
- ) {
- continue;
- }
- this._queue.unshift(item.id);
- this._progressQueue.addRow(item);
- }
- await this._processQueue();
- }
-
- similarAnnotions(annotation1, annotation2) {
- return (annotation1.position.pageIndex === annotation2.position.pageIndex &&
- JSON.stringify(annotation1.position.rects) === JSON.stringify(annotation2.position.rects));
- }
-
- async _importItemAnnotations(item) {
- if (!item.isAttachment() || item.attachmentContentType !== 'application/pdf') {
- throw new Error('Not a valid PDF attachment');
- }
-
- // TODO: Remove when fixed
- item._loaded.childItems = true;
- let ids = item.getAnnotations();
- let existingAnnotations = [];
- for (let id of ids) {
- try {
- existingAnnotations.push(Zotero.Annotations.toJSON(Zotero.Items.get(id)));
- } catch (e) {
- Zotero.logError(e);
- }
- }
-
- let annotations = await Zotero.PDFWorker.readAnnotations(item.id);
- annotations = annotations.filter(x => ['highlight', 'note'].includes(x.type));
-
- let num = 0;
- for (let annotation of annotations) {
- annotation.comment = annotation.comment || '';
- if (existingAnnotations.some(existingAnnotation => this.similarAnnotions(existingAnnotation, annotation))) {
- continue;
- }
-
- // TODO: Utilize the saved Zotero item key for deduplication
- annotation.key = Zotero.DataObjectUtilities.generateKey();
- let annotationItem = await Zotero.Annotations.saveFromJSON(item, annotation);
- num++;
- }
-
- return num;
- }
-}
-
-Zotero.PDFImport = new PdfImport();
diff --git a/chrome/content/zotero/xpcom/pdfWorker/manager.js b/chrome/content/zotero/xpcom/pdfWorker/manager.js
new file mode 100644
index 0000000000..fa7b6c1d33
--- /dev/null
+++ b/chrome/content/zotero/xpcom/pdfWorker/manager.js
@@ -0,0 +1,283 @@
+/*
+ ***** BEGIN LICENSE BLOCK *****
+
+ Copyright © 2020 Corporation for Digital Scholarship
+ Vienna, Virginia, USA
+ http://digitalscholar.org/
+
+ This file is part of Zotero.
+
+ Zotero is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Zotero is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Zotero. If not, see .
+
+ ***** END LICENSE BLOCK *****
+*/
+
+const WORKER_URL = 'chrome://zotero/content/xpcom/pdfWorker/worker.js';
+const CMAPS_URL = 'resource://zotero/pdf-reader/cmaps/';
+
+class PDFWorker {
+ constructor() {
+ this._worker = null;
+ this._lastPromiseID = 0;
+ this._waitingPromises = {};
+ this._queue = [];
+ this._processingQueue = false;
+ }
+
+ async _processQueue() {
+ this._init();
+ if (this._processingQueue) {
+ return;
+ }
+ this._processingQueue = true;
+ let item;
+ while ((item = this._queue.shift())) {
+ if (item) {
+ let [fn, resolve, reject] = item;
+ try {
+ resolve(await fn());
+ }
+ catch (e) {
+ reject(e);
+ }
+ }
+ }
+ this._processingQueue = false;
+ }
+
+ async _enqueue(fn, isPriority) {
+ return new Promise((resolve, reject) => {
+ if (isPriority) {
+ this._queue.unshift([fn, resolve, reject]);
+ }
+ else {
+ this._queue.push([fn, resolve, reject]);
+ }
+ this._processQueue();
+ });
+ }
+
+ async _query(action, data, transfer) {
+ return new Promise((resolve, reject) => {
+ this._lastPromiseID++;
+ this._waitingPromises[this._lastPromiseID] = { resolve, reject };
+ this._worker.postMessage({ id: this._lastPromiseID, action, data }, transfer);
+ });
+ }
+
+ _init() {
+ if (this._worker) return;
+ this._worker = new Worker(WORKER_URL);
+ this._worker.addEventListener('message', async (event) => {
+ let message = event.data;
+ // console.log(event.data)
+ if (message.responseId) {
+ let { resolve, reject } = this._waitingPromises[message.responseId];
+ delete this._waitingPromises[message.responseId];
+ if (message.data) {
+ resolve(message.data);
+ }
+ else {
+ let err = new Error(message.error.message);
+ Object.assign(err, message.error);
+ reject(err);
+ }
+ return;
+ }
+ if (message.id) {
+ let respData = null;
+ try {
+ if (message.action === 'FetchBuiltInCMap') {
+ let response = await Zotero.HTTP.request(
+ 'GET',
+ CMAPS_URL + event.data.data.name + '.bcmap',
+ { responseType: 'arraybuffer' }
+ );
+ respData = {
+ compressionType: 1,
+ cMapData: new Uint8Array(response.response)
+ };
+ }
+ }
+ catch (e) {
+ Zotero.debug('Failed to fetch CMap data:');
+ Zotero.debug(e);
+ }
+ this._worker.postMessage({ responseId: event.data.id, data: respData });
+ }
+ });
+ this._worker.addEventListener('error', (event) => {
+ Zotero.debug('PDF Web Worker error:');
+ Zotero.debug(event);
+ });
+ }
+
+ isPDFAttachment(item) {
+ return item.isAttachment() && item.attachmentContentType === 'application/pdf';
+ }
+
+ canImport(item) {
+ if (this.isPDFAttachment(item)) {
+ return true;
+ }
+ else if (item.isRegularItem()) {
+ let ids = item.getAttachments();
+ for (let id of ids) {
+ let attachment = Zotero.Items.get(id);
+ if (this.isPDFAttachment(attachment)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Export attachment with annotations to specified path
+ *
+ * @param {Integer} itemID
+ * @param {String} path
+ * @param {Boolean} isPriority
+ * @param {String} password
+ * @returns {Promise} Number of written annotations
+ */
+ async export(itemID, path, isPriority, password) {
+ return this._enqueue(async () => {
+ let attachment = await Zotero.Items.getAsync(itemID);
+ if (!this.isPDFAttachment(attachment)) {
+ throw new Error('not a valid attachment');
+ }
+ let ids = attachment.getAnnotations();
+ let annotations = [];
+ for (let id of ids) {
+ let item = await Zotero.Items.getAsync(id);
+ annotations.push({
+ id: item.key,
+ type: item.annotationType,
+ authorName: Zotero.Users.getName(item.createdByUserID) || '',
+ comment: item.annotationComment || '',
+ color: item.annotationColor,
+ position: JSON.parse(item.annotationPosition),
+ dateModified: item.dateModified
+ });
+ }
+ let attachmentPath = await attachment.getFilePath();
+ let buf = await OS.File.read(attachmentPath, {});
+ buf = new Uint8Array(buf).buffer;
+ let res = await this._query('export', { buf, annotations, password }, [buf]);
+ await OS.File.writeAtomic(path, new Uint8Array(res.buf));
+ return annotations.length;
+ });
+ }
+
+ /**
+ * Export children PDF attachments with annotations
+ *
+ * @param {Zotero.Item} item
+ * @param {String} directory
+ */
+ async exportParent(item, directory) {
+ if (!item.isRegularItem()) {
+ throw new Error('regular item not provided');
+ }
+ if (!directory) {
+ throw new Error('\'directory\' not provided');
+ }
+ let promises = [];
+ let ids = item.getAttachments();
+ for (let id of ids) {
+ let attachment = Zotero.Items.get(id);
+ if (this.isPDFAttachment(attachment)) {
+ let path = OS.Path.join(directory, attachment.attachmentFilename);
+ promises.push(this.export(id, path));
+ }
+ }
+ await Promise.all(promises);
+ }
+
+ /**
+ * Import annotations from PDF attachment
+ *
+ * @param {Integer} itemID
+ * @param {Boolean} save Save imported annotations, or otherwise just return the number of importable annotations
+ * @param {Boolean} isPriority
+ * @param {String} password
+ * @returns {Promise} Number of annotations
+ */
+ async import(itemID, save, isPriority, password) {
+ return this._enqueue(async () => {
+ let attachment = await Zotero.Items.getAsync(itemID);
+ if (!this.isPDFAttachment(attachment)) {
+ throw new Error('not a valid PDF attachment');
+ }
+ // TODO: Remove when fixed
+ attachment._loaded.childItems = true;
+ let ids = attachment.getAnnotations();
+ let existingAnnotations = [];
+ for (let id of ids) {
+ let item = await Zotero.Items.getAsync(id);
+ existingAnnotations.push({
+ id: item.key,
+ type: item.annotationType,
+ comment: item.annotationComment || '',
+ position: JSON.parse(item.annotationPosition)
+ });
+ }
+ let path = await attachment.getFilePath();
+ let buf = await OS.File.read(path, {});
+ buf = new Uint8Array(buf).buffer;
+ let res = await this._query('import', { buf, existingAnnotations, password }, [buf]);
+ let annotations = res.annotations;
+ if (save) {
+ for (let annotation of annotations) {
+ // TODO: Utilize the saved Zotero item key for deduplication. Newer annotation modificaiton date wins
+ annotation.key = Zotero.DataObjectUtilities.generateKey();
+ await Zotero.Annotations.saveFromJSON(attachment, annotation);
+ }
+ Zotero.PDF.hasUnmachedAnnotations[itemID] = false;
+ }
+ else {
+ Zotero.PDF.hasUnmachedAnnotations[itemID] = !!annotations.length;
+ }
+ for (let readerWindow of Zotero.Reader._readerWindows) {
+ if (readerWindow._itemID === itemID) {
+ readerWindow.toggleImportPrompt(!!Zotero.PDF.hasUnmachedAnnotations[itemID]);
+ }
+ }
+ Zotero.PDF.dateChecked[itemID] = Zotero.Date.dateToISO(new Date());
+ return annotations.length;
+ });
+ }
+
+ /**
+ * Import children PDF attachment annotations
+ *
+ * @param {Zotero.Item} item
+ */
+ async importParent(item) {
+ if (!item.isRegularItem()) {
+ throw new Error('regular item not provided');
+ }
+ let promises = [];
+ let ids = item.getAttachments();
+ for (let id of ids) {
+ let attachment = Zotero.Items.get(id);
+ if (this.isPDFAttachment(attachment)) {
+ promises.push(this.import(id, true));
+ }
+ }
+ await Promise.all(promises);
+ }
+}
+
+Zotero.PDFWorker = new PDFWorker();
diff --git a/chrome/content/zotero/xpcom/pdfWorker/transport.js b/chrome/content/zotero/xpcom/pdfWorker/transport.js
deleted file mode 100644
index 3ae1ec8bf5..0000000000
--- a/chrome/content/zotero/xpcom/pdfWorker/transport.js
+++ /dev/null
@@ -1,106 +0,0 @@
-
-const CMAPS_URL = 'resource://zotero/pdf-reader/cmaps/';
-
-class PDFWorker {
- constructor() {
- this.worker = null;
- this.promiseId = 0;
- this.waitingPromises = {};
- }
-
- async query(op, data, transfer) {
- return new Promise((resolve, reject) => {
- this.promiseId++;
- this.waitingPromises[this.promiseId] = {resolve, reject};
- this.worker.postMessage({id: this.promiseId, op, data}, transfer);
- });
- }
-
- init() {
- if (this.worker) return;
- this.worker = new Worker('chrome://zotero/content/xpcom/pdfWorker/worker.js');
-
- this.worker.addEventListener('message', async e => {
- let message = e.data;
- // console.log(e.data)
- if (message.responseId) {
- let { resolve, reject } = this.waitingPromises[message.responseId];
- if (message.data) {
- resolve(message.data);
- }
- else {
- reject(message.error);
- }
- return;
- }
-
- if (message.id) {
- let respData = null;
-
- try {
- if (message.op === 'FetchBuiltInCMap') {
- let response = await Zotero.HTTP.request(
- "GET",
- CMAPS_URL + e.data.data.name + '.bcmap',
- {responseType: 'arraybuffer'}
- );
- respData = {
- compressionType: 1,
- cMapData: new Uint8Array(response.response)
- };
- }
- }
- catch (e) {
- Zotero.debug('Failed to fetch CMap data:');
- Zotero.debug(e);
- }
- this.worker.postMessage({responseId: e.data.id, data: respData});
- }
- });
-
- this.worker.addEventListener('error', e => {
- Zotero.debug('PDF Web Worker error:');
- Zotero.debug(e);
- });
- }
-
- async writeAnnotations(itemID, annotations, path) {
- Zotero.debug("Writing annotations");
- this.init();
-
-
- let password = '';
-
- let item = await Zotero.Items.getAsync(itemID);
- let itemFilePath = await item.getFilePath();
-
- let buf = await OS.File.read(itemFilePath, {});
- buf = new Uint8Array(buf).buffer;
-
- let res = await this.query('write', {buf, annotations, password}, [buf]);
-
- if (!path) {
- path = itemFilePath;
- }
-
- await OS.File.writeAtomic(path, new Uint8Array(res.buf));
- }
-
- async readAnnotations(itemID) {
- this.init();
-
- let password = '';
-
- let item = await Zotero.Items.getAsync(itemID);
- let path = await item.getFilePath();
-
- let buf = await OS.File.read(path, {});
- buf = new Uint8Array(buf).buffer;
-
- let res = await this.query('read', {buf, password}, [buf]);
-
- return res.annotations;
- }
-}
-
-Zotero.PDFWorker = new PDFWorker();
diff --git a/chrome/content/zotero/xpcom/reader.js b/chrome/content/zotero/xpcom/reader.js
index aacbc2a072..c1addaab5a 100644
--- a/chrome/content/zotero/xpcom/reader.js
+++ b/chrome/content/zotero/xpcom/reader.js
@@ -1,8 +1,12 @@
-let PDFStates = {};
+// Temporary stuff
+Zotero.PDF = {
+ dateChecked: {},
+ hasUnmachedAnnotations: {}
+};
class ReaderWindow {
constructor() {
- this.annotationItemIds = [];
+ this.annotationItemIDs = [];
this._instanceID = Zotero.Utilities.randomString();
this._window = null;
this._iframeWindow = null;
@@ -115,7 +119,8 @@ class ReaderWindow {
state,
location,
enablePrev: !!this._prevHistory.length,
- enableNext: !!this._nextHistory.length
+ enableNext: !!this._nextHistory.length,
+ promptImport: !!Zotero.PDF.hasUnmachedAnnotations[this._itemID]
}, [buf]);
return true;
}
@@ -156,6 +161,10 @@ class ReaderWindow {
this._postMessage({ action: 'navigate', location });
}
+ toggleImportPrompt(enable) {
+ this._postMessage({ action: 'toggleImportPrompt', enable });
+ }
+
close() {
this._window.close();
}
@@ -337,7 +346,7 @@ class ReaderWindow {
let annotation = Zotero.Items.getByLibraryAndKey(libraryID, key);
// A small check, as we are receiving a list of item keys from a less secure code
if (annotation && annotation.isAnnotation() && annotation.parentID === this._itemID) {
- this.annotationItemIds = this.annotationItemIds.filter(id => id !== annotation.id);
+ this.annotationItemIDs = this.annotationItemIDs.filter(id => id !== annotation.id);
await annotation.eraseTx();
}
}
@@ -380,8 +389,7 @@ class ReaderWindow {
}
case 'import': {
Zotero.debug('Importing PDF annotations');
- let item = Zotero.Items.get(this._itemID);
- Zotero.PDFImport.import(item);
+ Zotero.PDFWorker.import(this._itemID, true, true);
return;
}
case 'importDismiss': {
@@ -534,7 +542,7 @@ class Reader {
// Listen for the parent item, PDF attachment and its annotation items updates
for (let readerWindow of this._readerWindows) {
if (event === 'delete') {
- let disappearedIds = readerWindow.annotationItemIds.filter(x => ids.includes(x));
+ let disappearedIds = readerWindow.annotationItemIDs.filter(x => ids.includes(x));
if (disappearedIds.length) {
let keys = disappearedIds.map(id => extraData[id].key);
readerWindow.unsetAnnotations(keys);
@@ -547,9 +555,9 @@ class Reader {
let item = Zotero.Items.get(readerWindow._itemID);
// TODO: Remove when fixed
item._loaded.childItems = true;
- let annotationItemIds = item.getAnnotations();
- readerWindow.annotationItemIds = annotationItemIds;
- let affectedAnnotationIds = annotationItemIds.filter(annotationID => {
+ let annotationItemIDs = item.getAnnotations();
+ readerWindow.annotationItemIDs = annotationItemIDs;
+ let affectedAnnotationIds = annotationItemIDs.filter(annotationID => {
let annotation = Zotero.Items.get(annotationID);
let imageAttachmentID = null;
annotation._loaded.childItems = true;
@@ -586,6 +594,7 @@ class Reader {
}
async open(itemID, location) {
+ this.triggerAnnotationsImportCheck(itemID);
let reader = this._getReaderWindow(itemID);
if (reader) {
if (location) {
@@ -605,6 +614,15 @@ class Reader {
}
reader._window.focus();
}
+
+ async triggerAnnotationsImportCheck(itemID) {
+ let item = await Zotero.Items.getAsync(itemID);
+ let mtime = await item.attachmentModificationTime;
+ let dateModified = Zotero.Date.dateToISO(new Date(mtime));
+ if (!Zotero.PDF.dateChecked[itemID] || Zotero.PDF.dateChecked[itemID] < dateModified) {
+ await Zotero.PDFWorker.import(itemID, false);
+ }
+ }
}
Zotero.Reader = new Reader();
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
index 6ec39af8d2..ee9d1481c0 100644
--- a/chrome/content/zotero/zoteroPane.js
+++ b/chrome/content/zotero/zoteroPane.js
@@ -2746,8 +2746,7 @@ var ZoteroPane = new function()
'createParent',
'renameAttachments',
'reindexItem',
- 'importAnnotations',
- 'exportAnnotations'
+ 'importAnnotations'
];
var m = {};
@@ -2795,8 +2794,7 @@ var ZoteroPane = new function()
canRecognize = true,
canUnrecognize = true,
canRename = true,
- canImportAnnotations = true,
- canExportAnnotations = true;
+ canImportAnnotations = true;
var canMarkRead = collectionTreeRow.isFeed();
var markUnread = true;
@@ -2818,14 +2816,10 @@ var ZoteroPane = new function()
canUnrecognize = false;
}
- if (canImportAnnotations && !Zotero.PDFImport.canImport(item)) {
+ if (canImportAnnotations && !Zotero.PDFWorker.canImport(item)) {
canImportAnnotations = false;
}
- if (canExportAnnotations && !Zotero.PDFExport.canExport(item)) {
- canExportAnnotations = false;
- }
-
// Show rename option only if all items are child attachments
if (canRename && (!item.isAttachment() || item.isTopLevelItem() || item.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_URL)) {
canRename = false;
@@ -2908,10 +2902,6 @@ var ZoteroPane = new function()
if (canImportAnnotations) {
show.push(m.importAnnotations);
}
-
- if (canExportAnnotations) {
- show.push(m.exportAnnotations);
- }
}
// Single item selected
@@ -2981,13 +2971,9 @@ var ZoteroPane = new function()
show.push(m.duplicateItem);
}
- if (Zotero.PDFImport.canImport(item)) {
+ if (Zotero.PDFWorker.canImport(item)) {
show.push(m.importAnnotations);
}
-
- if (Zotero.PDFExport.canExport(item)) {
- show.push(m.exportAnnotations);
- }
}
// Update attachment submenu
@@ -4578,16 +4564,16 @@ var ZoteroPane = new function()
}
};
- this.exportAnnotationsForSelected = async function () {
- var items = ZoteroPane.getSelectedItems();
- Zotero.PDFExport.export(items);
- Zotero.ProgressQueues.get('pdf-export').getDialog().open();
- };
-
this.importAnnotationsForSelected = async function () {
- var items = ZoteroPane.getSelectedItems();
- Zotero.PDFImport.import(items);
- Zotero.ProgressQueues.get('pdf-import').getDialog().open();
+ let items = ZoteroPane.getSelectedItems();
+ for (let item of items) {
+ if (item.isRegularItem()) {
+ Zotero.PDFWorker.importParent(item);
+ }
+ else if (item.isAttachment()) {
+ Zotero.PDFWorker.import(item.id, true);
+ }
+ }
};
this.reportMetadataForSelected = async function () {
@@ -4709,7 +4695,7 @@ var ZoteroPane = new function()
var rv = await fp.show();
if (rv === fp.returnOK || rv === fp.returnReplace) {
let outputFile = fp.file;
- Zotero.PDFExport.exportToPath(item, outputFile, true);
+ await Zotero.PDFWorker.export(item.id, outputFile, true);
}
};
diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul
index 323ec585e2..d84fbd6e44 100644
--- a/chrome/content/zotero/zoteroPane.xul
+++ b/chrome/content/zotero/zoteroPane.xul
@@ -292,10 +292,7 @@
-
-
-
-
+
diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd
index e4647b4d16..6fd497f201 100644
--- a/chrome/locale/en-US/zotero/zotero.dtd
+++ b/chrome/locale/en-US/zotero/zotero.dtd
@@ -100,7 +100,6 @@
-
diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties
index 68a89f87df..527702cdbb 100644
--- a/chrome/locale/en-US/zotero/zotero.properties
+++ b/chrome/locale/en-US/zotero/zotero.properties
@@ -1131,11 +1131,6 @@ recognizePDF.reportMetadata = Report Incorrect Metadata
recognizePDF.pdfName.label = PDF Name
recognizePDF.itemName.label = Item Name
-pdfExport.title = PDF Annotations Export
-
-pdfImport.title = PDF Annotations Import
-pdfImport.annotations.label = Annotations
-
rtfScan.openTitle = Select a file to scan
rtfScan.scanning.label = Scanning RTF Document…
rtfScan.saving.label = Formatting RTF Document…
diff --git a/chrome/skin/default/zotero/overlay.css b/chrome/skin/default/zotero/overlay.css
index b619c3a3de..0a5835f484 100644
--- a/chrome/skin/default/zotero/overlay.css
+++ b/chrome/skin/default/zotero/overlay.css
@@ -620,24 +620,6 @@
margin-top: 1px;
}
-#zotero-tb-pq-pdf-export {
- list-style-image: url(chrome://zotero/skin/pdf-search.png);
-}
-
-#zotero-tb-pq-pdf-export .toolbarbutton-icon {
- width: 18px;
- margin-top: 1px;
-}
-
-#zotero-tb-pq-pdf-import {
- list-style-image: url(chrome://zotero/skin/pdf-search.png);
-}
-
-#zotero-tb-pq-pdf-import .toolbarbutton-icon {
- width: 18px;
- margin-top: 1px;
-}
-
/* Sync error icon */
#zotero-tb-sync-error {
list-style-image: url(chrome://zotero/skin/error.png);
diff --git a/components/zotero-service.js b/components/zotero-service.js
index 63ded69215..5147925321 100644
--- a/components/zotero-service.js
+++ b/components/zotero-service.js
@@ -47,7 +47,7 @@ const xpcomFilesAll = [
'http',
'mimeTypeHandler',
'openurl',
- 'pdfWorker/transport',
+ 'pdfWorker/manager',
'ipc',
'profile',
'progressWindow',
@@ -113,8 +113,6 @@ const xpcomFilesLocal = [
'progressQueueDialog',
'quickCopy',
'recognizePDF',
- 'pdfExport',
- 'pdfImport',
'report',
'retractions',
'router',
diff --git a/pdf-worker b/pdf-worker
index 20b9f8f7a1..9067fc6a92 160000
--- a/pdf-worker
+++ b/pdf-worker
@@ -1 +1 @@
-Subproject commit 20b9f8f7a197b809c310db0c94bc7a5d22ed9bd0
+Subproject commit 9067fc6a9245019b0a4670f8a2b5d81f9f36ad0f