Document export-import UI and integration code (#1501)

This commit is contained in:
Adomas Ven 2019-05-15 04:06:18 +03:00 committed by Dan Stillman
parent dd8ceb93aa
commit 48778f2847
10 changed files with 259 additions and 68 deletions

View file

@ -0,0 +1,3 @@
.chevron {
font-size: 1.5em;
}

View file

@ -32,6 +32,7 @@
// Class to provide options for bibliography // Class to provide options for bibliography
// Used by rtfScan.xul, integrationDocPrefs.xul, and bibliography.xul // Used by rtfScan.xul, integrationDocPrefs.xul, and bibliography.xul
Components.utils.import("resource://gre/modules/Services.jsm");
var Zotero_File_Interface_Bibliography = new function() { var Zotero_File_Interface_Bibliography = new function() {
var _io; var _io;
@ -174,6 +175,10 @@ var Zotero_File_Interface_Bibliography = new function() {
document.getElementById("automaticCitationUpdates-checkbox").checked = !_io.delayCitationUpdates; document.getElementById("automaticCitationUpdates-checkbox").checked = !_io.delayCitationUpdates;
} }
if (_io.showImportExport) {
document.querySelector('#exportImport').hidden = false;
}
} }
// set style to false, in case this is cancelled // set style to false, in case this is cancelled
@ -237,7 +242,38 @@ var Zotero_File_Interface_Bibliography = new function() {
window.sizeToContent(); window.sizeToContent();
}; };
this.toggleAdvanced = function() {
var advancedSettings = document.querySelector("#advanced-settings");
advancedSettings.hidden = !advancedSettings.hidden;
var chevron = document.querySelector('.chevron');
chevron.classList.toggle('chevron-down');
chevron.classList.toggle('chevron-up');
window.sizeToContent();
};
this.exportDocument = function() {
const importExportWikiURL = "https://www.zotero.org/support/kb/export_import_document";
var ps = Services.prompt;
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_OK)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL)
+ (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING);
var result = ps.confirmEx(null,
Zotero.getString('integration.exportDocument'),
Zotero.getString('integration.exportDocument.description'),
buttonFlags,
null,
null,
Zotero.getString('general.moreInformation'), null, {});
if (result == 0) {
_io.exportDocument = true;
document.documentElement.acceptDialog();
} else if (result == 2) {
Zotero.launchURL(importExportWikiURL);
}
}
/* /*
* Update locale menulist when style is changed * Update locale menulist when style is changed
*/ */

View file

@ -26,6 +26,7 @@
<?xml-stylesheet href="chrome://global/skin/global.css"?> <?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
<?xml-stylesheet href="chrome://zotero/skin/bibliography.css"?> <?xml-stylesheet href="chrome://zotero/skin/bibliography.css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/bibliography.css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd"> <!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
<dialog <dialog
@ -81,14 +82,27 @@
</radiogroup> </radiogroup>
</groupbox> </groupbox>
<vbox id="automaticJournalAbbreviations-vbox"> <vbox class="pref-vbox" id="automaticJournalAbbreviations-vbox">
<checkbox id="automaticJournalAbbreviations-checkbox" label="&zotero.integration.prefs.automaticJournalAbbeviations.label;"/> <checkbox id="automaticJournalAbbreviations-checkbox" label="&zotero.integration.prefs.automaticJournalAbbeviations.label;"/>
<description class="radioDescription">&zotero.integration.prefs.automaticJournalAbbeviations.caption;</description> <description class="radioDescription">&zotero.integration.prefs.automaticJournalAbbeviations.caption;</description>
</vbox> </vbox>
<vbox id="automaticCitationUpdates-vbox"> <!--<vbox id="advanced-separator" align="center">-->
<checkbox id="automaticCitationUpdates-checkbox" label="&zotero.integration.prefs.automaticCitationUpdates.label;" tooltiptext="&zotero.integration.prefs.automaticCitationUpdates.tooltip;"/> <!--<hbox align="center" onclick="Zotero_File_Interface_Bibliography.toggleAdvanced()">-->
<description class="radioDescription">&zotero.integration.prefs.automaticCitationUpdates.description;</description> <!--<label>&zotero.general.advancedOptions.label;</label>-->
<!--<label class="chevron chevron-down">➤</label>-->
<!--</hbox>-->
<!--</vbox> -->
<vbox id="advanced-settings" hidden="false">
<vbox id="automaticCitationUpdates-vbox">
<checkbox id="automaticCitationUpdates-checkbox" label="&zotero.integration.prefs.automaticCitationUpdates.label;" tooltiptext="&zotero.integration.prefs.automaticCitationUpdates.tooltip;"/>
<description class="radioDescription">&zotero.integration.prefs.automaticCitationUpdates.description;</description>
</vbox>
<hbox id="exportImport" hidden="true">
<button label="&zotero.integration.prefs.exportDocument;" oncommand="Zotero_File_Interface_Bibliography.exportDocument()"/>
</hbox>
</vbox> </vbox>
</vbox> </vbox>
</dialog> </dialog>

View file

@ -59,12 +59,16 @@ Zotero.HTTPIntegrationClient.Application = function() {
this.secondaryFieldType = "Http"; this.secondaryFieldType = "Http";
this.outputFormat = 'html'; this.outputFormat = 'html';
this.supportedNotes = ['footnotes']; this.supportedNotes = ['footnotes'];
this.supportsImportExport = false;
this.processorName = "HTTP Integration";
}; };
Zotero.HTTPIntegrationClient.Application.prototype = { Zotero.HTTPIntegrationClient.Application.prototype = {
getActiveDocument: async function() { getActiveDocument: async function() {
let result = await Zotero.HTTPIntegrationClient.sendCommand('Application.getActiveDocument'); let result = await Zotero.HTTPIntegrationClient.sendCommand('Application.getActiveDocument');
this.outputFormat = result.outputFormat || this.outputFormat; this.outputFormat = result.outputFormat || this.outputFormat;
this.supportedNotes = result.supportedNotes || this.supportedNotes; this.supportedNotes = result.supportedNotes || this.supportedNotes;
this.supportsImportExport = result.supportsImportExport || this.supportsImportExport;
this.processorName = result.processorName || this.processorName;
return new Zotero.HTTPIntegrationClient.Document(result.documentID); return new Zotero.HTTPIntegrationClient.Document(result.documentID);
} }
}; };
@ -76,7 +80,7 @@ Zotero.HTTPIntegrationClient.Document = function(documentID) {
this._documentID = documentID; this._documentID = documentID;
}; };
for (let method of ["activate", "canInsertField", "displayAlert", "getDocumentData", for (let method of ["activate", "canInsertField", "displayAlert", "getDocumentData",
"setDocumentData", "setBibliographyStyle"]) { "setDocumentData", "setBibliographyStyle", "importDocument", "exportDocument"]) {
Zotero.HTTPIntegrationClient.Document.prototype[method] = async function() { Zotero.HTTPIntegrationClient.Document.prototype[method] = async function() {
return Zotero.HTTPIntegrationClient.sendCommand("Document."+method, return Zotero.HTTPIntegrationClient.sendCommand("Document."+method,
[this._documentID].concat(Array.prototype.slice.call(arguments))); [this._documentID].concat(Array.prototype.slice.call(arguments)));

View file

@ -74,7 +74,7 @@ Zotero.Server.Endpoints['/connector/document/respond'].prototype = {
// For managing macOS integration and progress window focus // For managing macOS integration and progress window focus
Zotero.Server.Endpoints['/connector/sendToBack'] = function() {}; Zotero.Server.Endpoints['/connector/sendToBack'] = function() {};
Zotero.Server.Endpoints['/connector/sendToBack'].prototype = { Zotero.Server.Endpoints['/connector/sendToBack'].prototype = {
supportedMethods: ["POST"], supportedMethods: ["POST", "GET"],
supportedDataTypes: ["application/json"], supportedDataTypes: ["application/json"],
permitBookmarklet: true, permitBookmarklet: true,
init: function() { init: function() {

View file

@ -59,6 +59,8 @@ const DELAYED_CITATION_RTF_STYLING_CLEAR = "\\ulclear";
const DELAYED_CITATION_HTML_STYLING = "<div class='delayed-zotero-citation-updates'>" const DELAYED_CITATION_HTML_STYLING = "<div class='delayed-zotero-citation-updates'>"
const DELAYED_CITATION_HTML_STYLING_END = "</div>" const DELAYED_CITATION_HTML_STYLING_END = "</div>"
const EXPORTED_DOCUMENT_MARKER = "ZOTERO_EXPORTED_DOCUMENT";
Zotero.Integration = new function() { Zotero.Integration = new function() {
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
@ -210,7 +212,7 @@ Zotero.Integration = new function() {
* Executes an integration command, first checking to make sure that versions are compatible * Executes an integration command, first checking to make sure that versions are compatible
*/ */
this.execCommand = async function(agent, command, docId) { this.execCommand = async function(agent, command, docId) {
var document, session; var document, session, documentImported;
if (Zotero.Integration.currentDoc) { if (Zotero.Integration.currentDoc) {
Zotero.Utilities.Internal.activate(); Zotero.Utilities.Internal.activate();
@ -243,12 +245,13 @@ Zotero.Integration = new function() {
} }
Zotero.Integration.currentDoc = document = await documentPromise; Zotero.Integration.currentDoc = document = await documentPromise;
Zotero.Integration.currentSession = session = await Zotero.Integration.getSession(application, document, agent); [session, documentImported] = await Zotero.Integration.getSession(application, document, agent);
// TODO: this is a pretty awful circular dependence Zotero.Integration.currentSession = session;
session.fields = new Zotero.Integration.Fields(session, document);
// TODO: figure this out // TODO: figure this out
// Zotero.Notifier.trigger('delete', 'collection', 'document'); // Zotero.Notifier.trigger('delete', 'collection', 'document');
await (new Zotero.Integration.Interface(application, document, session))[command](); if (!documentImported) {
await (new Zotero.Integration.Interface(application, document, session))[command]();
}
await document.setDocumentData(session.data.serialize()); await document.setDocumentData(session.data.serialize());
} }
catch (e) { catch (e) {
@ -257,7 +260,9 @@ Zotero.Integration = new function() {
} }
else { else {
// If user cancels we should still write the currently assigned session ID // If user cancels we should still write the currently assigned session ID
await document.setDocumentData(session.data.serialize()); if (session) {
await document.setDocumentData(session.data.serialize());
}
} }
} }
finally { finally {
@ -415,6 +420,7 @@ Zotero.Integration = new function() {
* @return {Zotero.Integration.Session} Promise * @return {Zotero.Integration.Session} Promise
*/ */
this.getSession = async function (app, doc, agent) { this.getSession = async function (app, doc, agent) {
let documentImported = false;
try { try {
var progressBar = new Zotero.Integration.Progress(4, Zotero.isMac && agent != 'http'); var progressBar = new Zotero.Integration.Progress(4, Zotero.isMac && agent != 'http');
progressBar.show(); progressBar.show();
@ -428,7 +434,7 @@ Zotero.Integration = new function() {
data = new Zotero.Integration.DocumentData(); data = new Zotero.Integration.DocumentData();
} }
if (data.prefs.fieldType) { if (dataString != EXPORTED_DOCUMENT_MARKER && data.prefs.fieldType) {
if (data.dataVersion < DATA_VERSION) { if (data.dataVersion < DATA_VERSION) {
if (data.dataVersion == 1 if (data.dataVersion == 1
&& data.prefs.fieldType == "Field" && data.prefs.fieldType == "Field"
@ -462,36 +468,54 @@ Zotero.Integration = new function() {
session = new Zotero.Integration.Session(doc, app); session = new Zotero.Integration.Session(doc, app);
session.reload = true; session.reload = true;
} }
try { session.agent = agent;
await session.setData(data); session._doc = doc;
} catch(e) { session.progressBar = progressBar;
// make sure style is defined // TODO: this is a pretty awful circular dependence
if (e instanceof Zotero.Exception.Alert && e.name === "integration.error.invalidStyle") { session.fields = new Zotero.Integration.Fields(session, doc);
if (data.style.styleID) {
let trustedSource = /^https?:\/\/(www\.)?(zotero\.org|citationstyles\.org)/.test(data.style.styleID); if (dataString == EXPORTED_DOCUMENT_MARKER) {
let errorString = Zotero.getString("integration.error.styleMissing", data.style.styleID); Zotero.Integration.currentSession = session;
if (trustedSource || data = await session.importDocument();
await doc.displayAlert(errorString, DIALOG_ICON_WARNING, DIALOG_BUTTONS_YES_NO)) { documentImported = true;
// We're slightly abusing the system here, but importing a document should cancel
// any other operation the user was trying to perform since the document will change
// significantly
} else {
try {
await session.setData(data);
} catch(e) {
// make sure style is defined
if (e instanceof Zotero.Exception.Alert && e.name === "integration.error.invalidStyle") {
if (data.style.styleID) {
let trustedSource =
/^https?:\/\/(www\.)?(zotero\.org|citationstyles\.org)/.test(data.style.styleID);
let errorString = Zotero.getString("integration.error.styleMissing", data.style.styleID);
if (trustedSource ||
await doc.displayAlert(errorString, DIALOG_ICON_WARNING, DIALOG_BUTTONS_YES_NO)) {
let installed = false; let installed = false;
try { try {
let { styleTitle, styleID } = await Zotero.Styles.install( let { styleTitle, styleID } = await Zotero.Styles.install(
{url: data.style.styleID}, data.style.styleID, true {url: data.style.styleID}, data.style.styleID, true
); );
data.style.styleID = styleID; data.style.styleID = styleID;
installed = true; installed = true;
} }
catch (e) { catch (e) {
await doc.displayAlert( await doc.displayAlert(
Zotero.getString( Zotero.getString(
'integration.error.styleNotFound', data.style.styleID 'integration.error.styleNotFound', data.style.styleID
), ),
DIALOG_ICON_WARNING, DIALOG_ICON_WARNING,
DIALOG_BUTTONS_OK DIALOG_BUTTONS_OK
); );
} }
if (installed) { if (installed) {
await session.setData(data, true); await session.setData(data, true);
} else {
await session.setDocPrefs();
}
} else { } else {
await session.setDocPrefs(); await session.setDocPrefs();
} }
@ -499,24 +523,19 @@ Zotero.Integration = new function() {
await session.setDocPrefs(); await session.setDocPrefs();
} }
} else { } else {
await session.setDocPrefs(); throw e;
} }
} else {
throw e;
} }
} }
} catch (e) { } catch (e) {
progressBar.hide(true); progressBar.hide(true);
throw e; throw e;
} }
session.agent = agent;
session._doc = doc;
if (session.progressBar) { if (session.progressBar) {
progressBar.reset(); progressBar.reset();
progressBar.segments = session.progressBar.segments; progressBar.segments = session.progressBar.segments;
} }
session.progressBar = progressBar; return [session, documentImported];
return session;
}; };
} }
@ -731,12 +750,12 @@ Zotero.Integration.Interface.prototype.setDocPrefs = Zotero.Promise.coroutine(fu
if(!haveSession) { if(!haveSession) {
// This is a brand new document; don't try to get fields // This is a brand new document; don't try to get fields
oldData = yield this._session.setDocPrefs(); oldData = yield this._session.setDocPrefs(true);
} else { } else {
// Can get fields while dialog is open // Can get fields while dialog is open
oldData = yield Zotero.Promise.all([ oldData = yield Zotero.Promise.all([
this._session.fields.get(), this._session.fields.get(),
this._session.setDocPrefs() this._session.setDocPrefs(true)
]).spread(function (fields, setDocPrefs) { ]).spread(function (fields, setDocPrefs) {
// Only return value from setDocPrefs // Only return value from setDocPrefs
return setDocPrefs; return setDocPrefs;
@ -861,9 +880,9 @@ Zotero.Integration.Fields.prototype.addField = async function(note) {
*/ */
Zotero.Integration.Fields.prototype.get = new function() { Zotero.Integration.Fields.prototype.get = new function() {
var deferred; var deferred;
return async function() { return async function(force=false) {
// If we already have fields, just return them // If we already have fields, just return them
if(this._fields != undefined) { if(!force && this._fields != undefined) {
return this._fields; return this._fields;
} }
@ -1519,10 +1538,11 @@ Zotero.Integration.Session.prototype.setData = async function (data, resetStyle)
* if there wasn't, or rejected with Zotero.Exception.UserCancelled if the dialog was * if there wasn't, or rejected with Zotero.Exception.UserCancelled if the dialog was
* cancelled. * cancelled.
*/ */
Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(function* (highlightDelayCitations=false) { Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(function* (showImportExport=false) {
var io = new function() { this.wrappedJSObject = this; }; var io = new function() { this.wrappedJSObject = this; };
io.primaryFieldType = this.primaryFieldType; io.primaryFieldType = this.primaryFieldType;
io.secondaryFieldType = this.secondaryFieldType; io.secondaryFieldType = this.secondaryFieldType;
io.showImportExport = false;
if (this.data) { if (this.data) {
io.style = this.data.style.styleID; io.style = this.data.style.styleID;
@ -1532,14 +1552,18 @@ Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(func
io.fieldType = this.data.prefs.fieldType; io.fieldType = this.data.prefs.fieldType;
io.delayCitationUpdates = this.data.prefs.delayCitationUpdates; io.delayCitationUpdates = this.data.prefs.delayCitationUpdates;
io.dontAskDelayCitationUpdates = this.data.prefs.dontAskDelayCitationUpdates; io.dontAskDelayCitationUpdates = this.data.prefs.dontAskDelayCitationUpdates;
io.highlightDelayCitations = highlightDelayCitations;
io.automaticJournalAbbreviations = this.data.prefs.automaticJournalAbbreviations; io.automaticJournalAbbreviations = this.data.prefs.automaticJournalAbbreviations;
io.requireStoreReferences = !Zotero.Utilities.isEmpty(this.embeddedItems); io.requireStoreReferences = !Zotero.Utilities.isEmpty(this.embeddedItems);
io.showImportExport = showImportExport && this.data.prefs.fieldType && this._app.supportsImportExport;
} }
// Make sure styles are initialized for new docs // Make sure styles are initialized for new docs
yield Zotero.Styles.init(); yield Zotero.Styles.init();
yield Zotero.Integration.displayDialog('chrome://zotero/content/integration/integrationDocPrefs.xul', '', io); yield Zotero.Integration.displayDialog('chrome://zotero/content/integration/integrationDocPrefs.xul', '', io);
if (io.exportDocument) {
return this.exportDocument();
}
if (!io.style || !io.fieldType) { if (!io.style || !io.fieldType) {
throw new Zotero.Exception.UserCancelled("document preferences window"); throw new Zotero.Exception.UserCancelled("document preferences window");
@ -1581,14 +1605,61 @@ Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(func
return oldData || null; return oldData || null;
}) })
/** Zotero.Integration.Session.prototype.exportDocument = async function() {
* Adds a citation based on a serialized Word field Zotero.debug("Integration: Exporting the document");
*/ var timer = new Zotero.Integration.Timer();
Zotero.Integration._oldCitationLocatorMap = { timer.start();
p:"page", try {
g:"paragraph", this.data.style.bibliographyStyleHasBeenSet = false;
l:"line" await this._doc.setDocumentData(this.data.serialize());
}; await this._doc.exportDocument(this.data.prefs.fieldType,
Zotero.getString('integration.importInstructions'));
} finally {
Zotero.debug(`Integration: Export finished in ${timer.stop()}`);
}
}
Zotero.Integration.Session.prototype.importDocument = async function() {
const importExportWikiURL = "https://www.zotero.org/support/kb/export_import_document";
var ps = Services.prompt;
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_OK)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL)
+ (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING);
var result = ps.confirmEx(null,
Zotero.getString('integration.importDocument'),
Zotero.getString('integration.importDocument.description'),
buttonFlags,
null,
null,
Zotero.getString('general.moreInformation'), null, {});
if (result == 1) {
throw new Zotero.Exception.UserCancelled("the document import");
} else if (result == 2) {
Zotero.launchURL(importExportWikiURL);
return;
}
Zotero.debug("Integration: Importing the document");
var timer = new Zotero.Integration.Timer();
timer.start();
try {
var importSuccessful = await this._doc.importDocument(this._app.primaryFieldType);
if (!importSuccessful) {
Zotero.debug("Integration: No importable data found in the document");
return this.displayAlert("No importable data found", DIALOG_ICON_WARNING, DIALOG_BUTTONS_OK);
}
var data = new Zotero.Integration.DocumentData(await this._doc.getDocumentData());
data.prefs.fieldType = this._app.primaryFieldType;
await this.setData(data, true);
await this.fields.get(true);
await this.fields.updateSession(FORCE_CITATIONS_RESET_TEXT);
await this.fields.updateDocument(FORCE_CITATIONS_RESET_TEXT, true, true);
} finally {
Zotero.debug(`Integration: Import finished in ${timer.stop()}`);
}
return data;
}
/** /**
* Adds a citation to the arrays representing the document * Adds a citation to the arrays representing the document
@ -2228,6 +2299,16 @@ Zotero.Integration.Field.loadExisting = async function(docField) {
return field; return field;
}; };
/**
* Adds a citation based on a serialized Word field
*/
Zotero.Integration._oldCitationLocatorMap = {
p:"page",
g:"paragraph",
l:"line"
};
Zotero.Integration.CitationField = class extends Zotero.Integration.Field { Zotero.Integration.CitationField = class extends Zotero.Integration.Field {
constructor(field, rawCode) { constructor(field, rawCode) {
super(field, rawCode); super(field, rawCode);
@ -2908,7 +2989,8 @@ Zotero.Integration.LegacyPluginWrapper = function(application) {
primaryFieldType: application.primaryFieldType, primaryFieldType: application.primaryFieldType,
secondaryFieldType: application.secondaryFieldType, secondaryFieldType: application.secondaryFieldType,
outputFormat: 'rtf', outputFormat: 'rtf',
supportedNotes: ['footnotes', 'endnotes'] supportedNotes: ['footnotes', 'endnotes'],
processorName: ''
} }
} }
Zotero.Integration.LegacyPluginWrapper.wrapField = function (field) { Zotero.Integration.LegacyPluginWrapper.wrapField = function (field) {

View file

@ -243,10 +243,12 @@
<!ENTITY zotero.integration.prefs.automaticCitationUpdates.tooltip "Citations with pending updates will be highlighted in the document"> <!ENTITY zotero.integration.prefs.automaticCitationUpdates.tooltip "Citations with pending updates will be highlighted in the document">
<!ENTITY zotero.integration.prefs.automaticCitationUpdates.description "Disabling updates can speed up citation insertion in large documents. Click Refresh to update citations manually."> <!ENTITY zotero.integration.prefs.automaticCitationUpdates.description "Disabling updates can speed up citation insertion in large documents. Click Refresh to update citations manually.">
<!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.label "Use MEDLINE journal abbreviations"> <!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.label "Use MEDLINE journal abbreviations">
<!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.caption "The “Journal Abbr” field will be ignored."> <!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.caption "The “Journal Abbr” field will be ignored.">
<!ENTITY zotero.integration.prefs.exportDocument "Export document…">
<!ENTITY zotero.integration.prefs.importDocument "Import document…">
<!ENTITY zotero.integration.showEditor.label "Show Editor"> <!ENTITY zotero.integration.showEditor.label "Show Editor">
<!ENTITY zotero.integration.classicView.label "Classic View"> <!ENTITY zotero.integration.classicView.label "Classic View">

View file

@ -897,6 +897,11 @@ integration.delayCitationUpdates.alert.text2.tab = You will need to click Refres
integration.delayCitationUpdates.alert.text3 = You can change this setting later in the document preferences. integration.delayCitationUpdates.alert.text3 = You can change this setting later in the document preferences.
integration.delayCitationUpdates.bibliography.toolbar = Automatic citation updates are disabled. To see the bibliography, click Refresh in the Zotero toolbar. integration.delayCitationUpdates.bibliography.toolbar = Automatic citation updates are disabled. To see the bibliography, click Refresh in the Zotero toolbar.
integration.delayCitationUpdates.bibliography.tab = Automatic citation updates are disabled. To see the bibliography, click Refresh in the Zotero tab. integration.delayCitationUpdates.bibliography.tab = Automatic citation updates are disabled. To see the bibliography, click Refresh in the Zotero tab.
integration.importDocument = Import Document?
integration.importDocument.description = Would you like to import this document for use with Zotero?
integration.exportDocument = Export Document?
integration.exportDocument.description = Exporting the document will allow you to import it in a different Zotero supported word processor and retain citation links. You should make a backup of your document before exporting. Do you want to proceed?
integration.importInstructions = This document contains exported Zotero citations. Open it with a Zotero supported document editor and press "Refresh" in the Zotero plugin to import it. NOTE: Do not copy and paste the contents of the document from one processor to the other.
styles.install.title = Install Style styles.install.title = Install Style
styles.install.unexpectedError = An unexpected error occurred while installing "%1$S" styles.install.unexpectedError = An unexpected error occurred while installing "%1$S"

View file

@ -25,6 +25,25 @@ radio:not(:first-child)
} }
#automaticJournalAbbreviations-vbox, #automaticCitationUpdates-vbox { #automaticJournalAbbreviations-vbox, #advanced-settings {
padding: 0 14px; padding: 0 14px;
} }
#advanced-separator * {
cursor: pointer;
}
.chevron {
color: #444;
}
.chevron.chevron-down {
transform: rotate(90deg);
}
.chevron.chevron-up {
transform: rotate(-90deg);
}
#advanced-settings > * {
margin-bottom: 10px;
}

View file

@ -21,6 +21,7 @@ describe("Zotero.Integration", function () {
this.primaryFieldType = "Field"; this.primaryFieldType = "Field";
this.secondaryFieldType = "Bookmark"; this.secondaryFieldType = "Bookmark";
this.supportedNotes = ['footnotes', 'endnotes']; this.supportedNotes = ['footnotes', 'endnotes'];
this.supportsImportExport = true;
this.fields = []; this.fields = [];
}; };
DocumentPluginDummy.Application.prototype = { DocumentPluginDummy.Application.prototype = {
@ -119,6 +120,31 @@ describe("Zotero.Integration", function () {
* Informs the document processor that the operation is complete * Informs the document processor that the operation is complete
*/ */
complete: () => 0, complete: () => 0,
/**
* Converts field text in document to their underlying codes and appends
* document preferences and bibliography style as paragraphs at the end
* of the document. Prefixes:
* - Bibliography style: "BIBLIOGRAPHY_STYLE "
* - Document preferences: "DOCUMENT_PREFERENCES "
*
* All Zotero exported text must be converted to a hyperlink
* (with any url, e.g. http://www.zotero.org)
*/
exportDocument: (fieldType) => 0,
/**
* Converts a document from an exported form described in #exportDocument()
* to a Zotero editable form. Bibliography Style and Document Preferences
* text is removed and stored internally within the doc. The citation codes are
* also stored within the doc in appropriate representation.
*
* Note that no citation text updates are needed. Zotero will issue field updates
* manually.
*
* @returns {Boolean} whether the document contained importable data
*/
importDocument: (fieldType) => 0,
}; };
/** /**