Merge branch 'async-translators'
This commit is contained in:
commit
0490886f28
17 changed files with 937 additions and 918 deletions
|
@ -41,55 +41,56 @@ var Zotero_File_Exporter = function() {
|
|||
* Performs the actual export operation
|
||||
**/
|
||||
Zotero_File_Exporter.prototype.save = function() {
|
||||
var translation = new Zotero.Translate.Export();
|
||||
var translators = translation.getTranslators();
|
||||
|
||||
// present options dialog
|
||||
var io = {translators:translators}
|
||||
window.openDialog("chrome://zotero/content/exportOptions.xul",
|
||||
"_blank", "chrome,modal,centerscreen,resizable=no", io);
|
||||
if(!io.selectedTranslator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("fileInterface.export"), nsIFilePicker.modeSave);
|
||||
|
||||
// set file name and extension
|
||||
if(io.displayOptions.exportFileData) {
|
||||
// if the result will be a folder, don't append any extension or use
|
||||
// filters
|
||||
fp.defaultString = this.name;
|
||||
fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
|
||||
} else {
|
||||
// if the result will be a file, append an extension and use filters
|
||||
fp.defaultString = this.name+(io.selectedTranslator.target ? "."+io.selectedTranslator.target : "");
|
||||
fp.defaultExtension = io.selectedTranslator.target;
|
||||
fp.appendFilter(io.selectedTranslator.label, "*."+(io.selectedTranslator.target ? io.selectedTranslator.target : "*"));
|
||||
}
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
if(this.collection) {
|
||||
translation.setCollection(this.collection);
|
||||
} else if(this.items) {
|
||||
translation.setItems(this.items);
|
||||
var translation = new Zotero.Translate.Export(),
|
||||
me = this;
|
||||
translation.getTranslators().then(function(translators) {
|
||||
// present options dialog
|
||||
var io = {translators:translators}
|
||||
window.openDialog("chrome://zotero/content/exportOptions.xul",
|
||||
"_blank", "chrome,modal,centerscreen,resizable=no", io);
|
||||
if(!io.selectedTranslator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
translation.setLocation(fp.file);
|
||||
translation.setTranslator(io.selectedTranslator);
|
||||
translation.setDisplayOptions(io.displayOptions);
|
||||
translation.setHandler("itemDone", Zotero_File_Interface.updateProgress);
|
||||
translation.setHandler("done", this._exportDone);
|
||||
Zotero.UnresponsiveScriptIndicator.disable();
|
||||
Zotero_File_Interface.Progress.show(
|
||||
Zotero.getString("fileInterface.itemsExported")
|
||||
);
|
||||
translation.translate()
|
||||
}
|
||||
return false;
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("fileInterface.export"), nsIFilePicker.modeSave);
|
||||
|
||||
// set file name and extension
|
||||
if(io.displayOptions.exportFileData) {
|
||||
// if the result will be a folder, don't append any extension or use
|
||||
// filters
|
||||
fp.defaultString = me.name;
|
||||
fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
|
||||
} else {
|
||||
// if the result will be a file, append an extension and use filters
|
||||
fp.defaultString = me.name+(io.selectedTranslator.target ? "."+io.selectedTranslator.target : "");
|
||||
fp.defaultExtension = io.selectedTranslator.target;
|
||||
fp.appendFilter(io.selectedTranslator.label, "*."+(io.selectedTranslator.target ? io.selectedTranslator.target : "*"));
|
||||
}
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
if(me.collection) {
|
||||
translation.setCollection(me.collection);
|
||||
} else if(me.items) {
|
||||
translation.setItems(me.items);
|
||||
}
|
||||
|
||||
translation.setLocation(fp.file);
|
||||
translation.setTranslator(io.selectedTranslator);
|
||||
translation.setDisplayOptions(io.displayOptions);
|
||||
translation.setHandler("itemDone", Zotero_File_Interface.updateProgress);
|
||||
translation.setHandler("done", me._exportDone);
|
||||
Zotero.UnresponsiveScriptIndicator.disable();
|
||||
Zotero_File_Interface.Progress.show(
|
||||
Zotero.getString("fileInterface.itemsExported")
|
||||
);
|
||||
translation.translate()
|
||||
}
|
||||
return false;
|
||||
}).done();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -207,9 +208,7 @@ var Zotero_File_Interface = new function() {
|
|||
}
|
||||
|
||||
var translation = new Zotero.Translate.Import();
|
||||
if(!file) {
|
||||
var translators = translation.getTranslators();
|
||||
|
||||
(file ? Q(file) : translation.getTranslators().then(function(translators) {
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
|
@ -225,15 +224,17 @@ var Zotero_File_Interface = new function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
file = fp.file;
|
||||
}
|
||||
|
||||
translation.setLocation(file);
|
||||
// get translators again, bc now we can check against the file
|
||||
translation.setHandler("translators", function(obj, item) {
|
||||
_importTranslatorsAvailable(obj, item, createNewCollection);
|
||||
});
|
||||
translators = translation.getTranslators();
|
||||
return fp.file;
|
||||
})).then(function(file) {
|
||||
if(!file) return; // no file if user cancelled
|
||||
|
||||
translation.setLocation(file);
|
||||
// get translators again, bc now we can check against the file
|
||||
translation.setHandler("translators", function(obj, item) {
|
||||
_importTranslatorsAvailable(obj, item, createNewCollection);
|
||||
});
|
||||
translators = translation.getTranslators();
|
||||
}).done();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -115,31 +115,32 @@ const Zotero_Lookup = new function () {
|
|||
translate.setSearch(item);
|
||||
|
||||
// be lenient about translators
|
||||
var translators = translate.getTranslators();
|
||||
translate.setTranslator(translators);
|
||||
translate.getTranslators().then(function(translators) {
|
||||
translate.setTranslator(translators);
|
||||
|
||||
translate.setHandler("done", function(translate, success) {
|
||||
notDone--;
|
||||
successful += success;
|
||||
translate.setHandler("done", function(translate, success) {
|
||||
notDone--;
|
||||
successful += success;
|
||||
|
||||
if(!notDone) { //i.e. done
|
||||
Zotero_Lookup.toggleProgress(false);
|
||||
if(successful) {
|
||||
document.getElementById("zotero-lookup-panel").hidePopup();
|
||||
} else {
|
||||
var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
prompts.alert(window, Zotero.getString("lookup.failure.title"),
|
||||
Zotero.getString("lookup.failure.description"));
|
||||
if(!notDone) { //i.e. done
|
||||
Zotero_Lookup.toggleProgress(false);
|
||||
if(successful) {
|
||||
document.getElementById("zotero-lookup-panel").hidePopup();
|
||||
} else {
|
||||
var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
prompts.alert(window, Zotero.getString("lookup.failure.title"),
|
||||
Zotero.getString("lookup.failure.description"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
translate.setHandler("itemDone", function(obj, item) {
|
||||
if(collection) collection.addItem(item.id);
|
||||
translate.setHandler("itemDone", function(obj, item) {
|
||||
if(collection) collection.addItem(item.id);
|
||||
});
|
||||
|
||||
translate.translate(libraryID);
|
||||
});
|
||||
|
||||
translate.translate(libraryID);
|
||||
})(item);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ Zotero_Preferences.Export = {
|
|||
// Initialize default format drop-down
|
||||
var format = Zotero.Prefs.get("export.quickCopy.setting");
|
||||
var menulist = document.getElementById("zotero-quickCopy-menu");
|
||||
this.buildQuickCopyFormatDropDown(menulist, Zotero.QuickCopy.getContentType(format), format);
|
||||
menulist.setAttribute('preference', "pref-quickCopy-setting");
|
||||
this.buildQuickCopyFormatDropDown(menulist, Zotero.QuickCopy.getContentType(format), format);
|
||||
this.updateQuickCopyHTMLCheckbox();
|
||||
|
||||
if (!Zotero.isStandalone) {
|
||||
|
@ -106,30 +106,30 @@ Zotero_Preferences.Export = {
|
|||
|
||||
// add export formats to list
|
||||
var translation = new Zotero.Translate("export");
|
||||
var translators = translation.getTranslators();
|
||||
|
||||
for (var i=0; i<translators.length; i++) {
|
||||
// Skip RDF formats
|
||||
switch (translators[i].translatorID) {
|
||||
case '6e372642-ed9d-4934-b5d1-c11ac758ebb7':
|
||||
case '14763d24-8ba0-45df-8f52-b8d1108e7ac9':
|
||||
continue;
|
||||
translation.getTranslators()
|
||||
.then(function (translators) {
|
||||
for (var i=0; i<translators.length; i++) {
|
||||
// Skip RDF formats
|
||||
switch (translators[i].translatorID) {
|
||||
case '6e372642-ed9d-4934-b5d1-c11ac758ebb7':
|
||||
case '14763d24-8ba0-45df-8f52-b8d1108e7ac9':
|
||||
continue;
|
||||
}
|
||||
var val = 'export=' + translators[i].translatorID;
|
||||
var itemNode = document.createElement("menuitem");
|
||||
itemNode.setAttribute("value", val);
|
||||
itemNode.setAttribute("label", translators[i].label);
|
||||
itemNode.setAttribute("oncommand", 'Zotero_Preferences.Export.updateQuickCopyHTMLCheckbox()');
|
||||
popup.appendChild(itemNode);
|
||||
|
||||
if (val == currentFormat) {
|
||||
menulist.selectedItem = itemNode;
|
||||
}
|
||||
}
|
||||
var val = 'export=' + translators[i].translatorID;
|
||||
var itemNode = document.createElement("menuitem");
|
||||
itemNode.setAttribute("value", val);
|
||||
itemNode.setAttribute("label", translators[i].label);
|
||||
itemNode.setAttribute("oncommand", 'Zotero_Preferences.Export.updateQuickCopyHTMLCheckbox()');
|
||||
popup.appendChild(itemNode);
|
||||
|
||||
if (val == currentFormat) {
|
||||
menulist.selectedItem = itemNode;
|
||||
}
|
||||
}
|
||||
|
||||
menulist.click();
|
||||
|
||||
return popup;
|
||||
menulist.click();
|
||||
})
|
||||
.done();
|
||||
},
|
||||
|
||||
|
||||
|
@ -156,25 +156,28 @@ Zotero_Preferences.Export = {
|
|||
var asHTML = treerow.childNodes[2].getAttribute('label') != '';
|
||||
}
|
||||
|
||||
var format = Zotero.QuickCopy.getSettingFromFormattedName(format);
|
||||
if (asHTML) {
|
||||
format = format.replace('bibliography=', 'bibliography/html=');
|
||||
}
|
||||
|
||||
var io = {domain: domain, format: format, ok: false};
|
||||
window.openDialog('chrome://zotero/content/preferences/quickCopySiteEditor.xul', "zotero-preferences-quickCopySiteEditor", "chrome, modal", io);
|
||||
|
||||
if (!io.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (domain && domain != io.domain) {
|
||||
Zotero.DB.query("DELETE FROM settings WHERE setting='quickCopySite' AND key=?", [domain]);
|
||||
}
|
||||
|
||||
Zotero.DB.query("REPLACE INTO settings VALUES ('quickCopySite', ?, ?)", [io.domain, io.format]);
|
||||
|
||||
this.refreshQuickCopySiteList();
|
||||
Zotero.QuickCopy.getSettingFromFormattedName(format)
|
||||
.then(function (format) {
|
||||
if (asHTML) {
|
||||
format = format.replace('bibliography=', 'bibliography/html=');
|
||||
}
|
||||
|
||||
var io = {domain: domain, format: format, ok: false};
|
||||
window.openDialog('chrome://zotero/content/preferences/quickCopySiteEditor.xul', "zotero-preferences-quickCopySiteEditor", "chrome, modal", io);
|
||||
|
||||
if (!io.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (domain && domain != io.domain) {
|
||||
Zotero.DB.query("DELETE FROM settings WHERE setting='quickCopySite' AND key=?", [domain]);
|
||||
}
|
||||
|
||||
Zotero.DB.query("REPLACE INTO settings VALUES ('quickCopySite', ?, ?)", [io.domain, io.format]);
|
||||
|
||||
this.refreshQuickCopySiteList();
|
||||
}.bind(this))
|
||||
.done();
|
||||
},
|
||||
|
||||
|
||||
|
@ -192,26 +195,30 @@ Zotero_Preferences.Export = {
|
|||
return;
|
||||
}
|
||||
|
||||
for (var i=0; i<siteData.length; i++) {
|
||||
var treeitem = document.createElement('treeitem');
|
||||
var treerow = document.createElement('treerow');
|
||||
var domainCell = document.createElement('treecell');
|
||||
var formatCell = document.createElement('treecell');
|
||||
var HTMLCell = document.createElement('treecell');
|
||||
|
||||
domainCell.setAttribute('label', siteData[i].domainPath);
|
||||
|
||||
var formatted = Zotero.QuickCopy.getFormattedNameFromSetting(siteData[i].format);
|
||||
formatCell.setAttribute('label', formatted);
|
||||
var copyAsHTML = Zotero.QuickCopy.getContentType(siteData[i].format) == 'html';
|
||||
HTMLCell.setAttribute('label', copyAsHTML ? ' ✓ ' : '');
|
||||
|
||||
treerow.appendChild(domainCell);
|
||||
treerow.appendChild(formatCell);
|
||||
treerow.appendChild(HTMLCell);
|
||||
treeitem.appendChild(treerow);
|
||||
treechildren.appendChild(treeitem);
|
||||
}
|
||||
Q.async(function () {
|
||||
for (var i=0; i<siteData.length; i++) {
|
||||
let treeitem = document.createElement('treeitem');
|
||||
let treerow = document.createElement('treerow');
|
||||
let domainCell = document.createElement('treecell');
|
||||
let formatCell = document.createElement('treecell');
|
||||
let HTMLCell = document.createElement('treecell');
|
||||
|
||||
domainCell.setAttribute('label', siteData[i].domainPath);
|
||||
|
||||
yield Zotero.QuickCopy.getFormattedNameFromSetting(siteData[i].format)
|
||||
.then(function (formatted) {
|
||||
formatCell.setAttribute('label', formatted);
|
||||
var copyAsHTML = Zotero.QuickCopy.getContentType(siteData[i].format) == 'html';
|
||||
HTMLCell.setAttribute('label', copyAsHTML ? ' ✓ ' : '');
|
||||
|
||||
treerow.appendChild(domainCell);
|
||||
treerow.appendChild(formatCell);
|
||||
treerow.appendChild(HTMLCell);
|
||||
treeitem.appendChild(treerow);
|
||||
treechildren.appendChild(treeitem);
|
||||
});
|
||||
}
|
||||
})().done();
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -466,12 +466,13 @@ function init() {
|
|||
|
||||
// get translators, with code for unsupported translators
|
||||
if(!viewerMode) {
|
||||
Zotero.Translators.getAllForType(translatorType, new function() {
|
||||
Zotero.Translators.getAllForType(translatorType, true).
|
||||
then(new function() {
|
||||
var type = translatorType;
|
||||
return function(translators) {
|
||||
haveTranslators(translators, type);
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ Zotero_TranslatorTesters = new function() {
|
|||
var testers = [];
|
||||
var waitingForTranslators = TEST_TYPES.length;
|
||||
for(var i=0; i<TEST_TYPES.length; i++) {
|
||||
Zotero.Translators.getAllForType(TEST_TYPES[i], new function() {
|
||||
Zotero.Translators.getAllForType(TEST_TYPES[i], true).
|
||||
then(new function() {
|
||||
var type = TEST_TYPES[i];
|
||||
return function(translators) {
|
||||
try {
|
||||
|
@ -66,7 +67,7 @@ Zotero_TranslatorTesters = new function() {
|
|||
Zotero.logError(e);
|
||||
}
|
||||
};
|
||||
}, true);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -2980,7 +2980,6 @@ Zotero.Item.prototype.fileExistsAsync = function () {
|
|||
}
|
||||
|
||||
var nsIFile = self.getFile(null, true);
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
return Q(OS.File.exists(nsIFile.path))
|
||||
.then(function(exists) {
|
||||
self._updateAttachmentStates(exists);
|
||||
|
|
|
@ -145,15 +145,16 @@ Zotero.MIMETypeHandler = new function () {
|
|||
translation.setString(string);
|
||||
|
||||
// attempt to retrieve translators
|
||||
var translators = translation.getTranslators();
|
||||
if(!translators.length) {
|
||||
// we lied. we can't really translate this file.
|
||||
throw "No translator found for handled RIS, Refer or ISI file"
|
||||
}
|
||||
|
||||
// translate using first available
|
||||
translation.setTranslator(translators[0]);
|
||||
frontWindow.Zotero_Browser.performTranslation(translation);
|
||||
return translation.getTranslators().then(function(translators) {
|
||||
if(!translators.length) {
|
||||
// we lied. we can't really translate this file.
|
||||
throw "No translator found for handled RIS, Refer or ISI file"
|
||||
}
|
||||
|
||||
// translate using first available
|
||||
translation.setTranslator(translators[0]);
|
||||
frontWindow.Zotero_Browser.performTranslation(translation);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,7 +269,7 @@ Zotero.MIMETypeHandler = new function () {
|
|||
if (!this._storageStream) {
|
||||
this._storageStream = Components.classes["@mozilla.org/storagestream;1"].
|
||||
createInstance(Components.interfaces.nsIStorageStream);
|
||||
this._storageStream.init(4096, 4294967295, null); // PR_UINT32_MAX
|
||||
this._storageStream.init(16384, 4294967295, null); // PR_UINT32_MAX
|
||||
this._outputStream = this._storageStream.getOutputStream(0);
|
||||
|
||||
this._binaryInputStream = Components.classes["@mozilla.org/binaryinputstream;1"].
|
||||
|
@ -291,38 +292,36 @@ Zotero.MIMETypeHandler = new function () {
|
|||
const replacementChar = Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
|
||||
var convStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
convStream.init(inputStream, charset, 1024, replacementChar);
|
||||
convStream.init(inputStream, charset, 16384, replacementChar);
|
||||
var readString = "";
|
||||
var str = {};
|
||||
while (convStream.readString(4096, str) != 0) {
|
||||
while (convStream.readString(16384, str) != 0) {
|
||||
readString += str.value;
|
||||
}
|
||||
convStream.close();
|
||||
inputStream.close();
|
||||
|
||||
try {
|
||||
_typeHandlers[this._contentType](readString, (this._request.name ? this._request.name : null),
|
||||
this._contentType, channel);
|
||||
} catch(e) {
|
||||
// if there was an error, handle using nsIExternalHelperAppService
|
||||
var externalHelperAppService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"].
|
||||
getService(Components.interfaces.nsIExternalHelperAppService);
|
||||
var frontWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Components.interfaces.nsIWindowWatcher).activeWindow;
|
||||
|
||||
var inputStream = this._storageStream.newInputStream(0);
|
||||
var streamListener = externalHelperAppService.doContent(this._contentType, this._request, frontWindow, null);
|
||||
if (streamListener) {
|
||||
streamListener.onStartRequest(channel, context);
|
||||
streamListener.onDataAvailable(this._request, context, inputStream, 0, this._storageStream.length);
|
||||
streamListener.onStopRequest(channel, context, status);
|
||||
}
|
||||
this._storageStream.close();
|
||||
|
||||
// then throw our error
|
||||
throw e;
|
||||
}
|
||||
|
||||
this._storageStream.close();
|
||||
var me = this;
|
||||
Q(_typeHandlers[this._contentType](readString, (this._request.name ? this._request.name : null),
|
||||
this._contentType, channel)).fail(function(e) {
|
||||
// if there was an error, handle using nsIExternalHelperAppService
|
||||
var externalHelperAppService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"].
|
||||
getService(Components.interfaces.nsIExternalHelperAppService);
|
||||
var frontWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Components.interfaces.nsIWindowWatcher).activeWindow;
|
||||
|
||||
var inputStream = me._storageStream.newInputStream(0);
|
||||
var streamListener = externalHelperAppService.doContent(me._contentType, me._request, frontWindow, null);
|
||||
if (streamListener) {
|
||||
streamListener.onStartRequest(channel, context);
|
||||
streamListener.onDataAvailable(me._request, context, inputStream, 0, me._storageStream.length);
|
||||
streamListener.onStopRequest(channel, context, status);
|
||||
}
|
||||
|
||||
// then throw our error
|
||||
throw e;
|
||||
}).fin(function() {
|
||||
me._storageStream.close();
|
||||
}).done();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,38 +25,57 @@
|
|||
|
||||
|
||||
Zotero.QuickCopy = new function() {
|
||||
this.getFormattedNameFromSetting = getFormattedNameFromSetting;
|
||||
this.getSettingFromFormattedName = getSettingFromFormattedName;
|
||||
this.getContentType = getContentType;
|
||||
this.stripContentType = stripContentType;
|
||||
this.getFormatFromURL = getFormatFromURL;
|
||||
this.getContentFromItems = getContentFromItems;
|
||||
|
||||
var _initialized = false;
|
||||
var _formattedNames = {};
|
||||
|
||||
|
||||
function getFormattedNameFromSetting(setting) {
|
||||
if (!_initialized) {
|
||||
_init();
|
||||
}
|
||||
var _init = Zotero.lazy(function () {
|
||||
Zotero.debug("Initializing Quick Copy");
|
||||
|
||||
var name = _formattedNames[this.stripContentType(setting)];
|
||||
return name ? name : '';
|
||||
var translation = new Zotero.Translate.Export;
|
||||
return translation.getTranslators()
|
||||
.then(function (translators) {
|
||||
// add styles to list
|
||||
var styles = Zotero.Styles.getVisible();
|
||||
for each(var style in styles) {
|
||||
_formattedNames['bibliography=' + style.styleID] = style.title;
|
||||
}
|
||||
|
||||
for (var i=0; i<translators.length; i++) {
|
||||
// Skip RDF formats
|
||||
switch (translators[i].translatorID) {
|
||||
case '6e372642-ed9d-4934-b5d1-c11ac758ebb7':
|
||||
case '14763d24-8ba0-45df-8f52-b8d1108e7ac9':
|
||||
continue;
|
||||
}
|
||||
_formattedNames['export=' + translators[i].translatorID] = translators[i].label;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
this.getFormattedNameFromSetting = function (setting) {
|
||||
return _init()
|
||||
.then(function () {
|
||||
var name = _formattedNames[this.stripContentType(setting)];
|
||||
return name ? name : '';
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
function getSettingFromFormattedName(name) {
|
||||
if (!_initialized) {
|
||||
_init();
|
||||
}
|
||||
|
||||
for (var setting in _formattedNames) {
|
||||
if (_formattedNames[setting] == name) {
|
||||
return setting;
|
||||
this.getSettingFromFormattedName = function (name) {
|
||||
return _init()
|
||||
.then(function () {
|
||||
for (var setting in _formattedNames) {
|
||||
if (_formattedNames[setting] == name) {
|
||||
return setting;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -346,26 +365,4 @@ Zotero.QuickCopy = new function() {
|
|||
|
||||
throw ("Invalid mode '" + mode + "' in Zotero.QuickCopy.getContentFromItems()");
|
||||
}
|
||||
|
||||
|
||||
function _init() {
|
||||
var translation = new Zotero.Translate.Export;
|
||||
var translators = translation.getTranslators();
|
||||
|
||||
// add styles to list
|
||||
var styles = Zotero.Styles.getVisible();
|
||||
for each(var style in styles) {
|
||||
_formattedNames['bibliography=' + style.styleID] = style.title;
|
||||
}
|
||||
|
||||
for (var i=0; i<translators.length; i++) {
|
||||
// Skip RDF formats
|
||||
switch (translators[i].translatorID) {
|
||||
case '6e372642-ed9d-4934-b5d1-c11ac758ebb7':
|
||||
case '14763d24-8ba0-45df-8f52-b8d1108e7ac9':
|
||||
continue;
|
||||
}
|
||||
_formattedNames['export=' + translators[i].translatorID] = translators[i].label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1033,7 +1033,7 @@ Zotero.Schema = new function(){
|
|||
var translatorsDir = Zotero.getTranslatorsDirectory();
|
||||
translatorsDir.remove(true);
|
||||
Zotero.getTranslatorsDirectory(); // recreate directory
|
||||
return Zotero.Translators.init()
|
||||
return Zotero.Translators.reinit()
|
||||
.then(function () self.updateBundledFiles('translators', null, false))
|
||||
.then(function () {
|
||||
var stylesDir = Zotero.getStylesDirectory();
|
||||
|
@ -1058,7 +1058,7 @@ Zotero.Schema = new function(){
|
|||
var translatorsDir = Zotero.getTranslatorsDirectory();
|
||||
translatorsDir.remove(true);
|
||||
Zotero.getTranslatorsDirectory(); // recreate directory
|
||||
return Zotero.Translators.init()
|
||||
return Zotero.Translators.reinit()
|
||||
.then(function () self.updateBundledFiles('translators', null, true))
|
||||
.then(callback);
|
||||
}
|
||||
|
@ -1535,7 +1535,7 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
|
||||
// Rebuild caches
|
||||
yield Zotero.Translators.init();
|
||||
yield Zotero.Translators.reinit();
|
||||
Zotero.Styles.init();
|
||||
}
|
||||
catch (e) {
|
||||
|
|
|
@ -87,15 +87,20 @@ Zotero.Server.Connector.GetTranslators.prototype = {
|
|||
*/
|
||||
"init":function(data, sendResponseCallback) {
|
||||
// Translator data
|
||||
var me = this;
|
||||
if(data.url) {
|
||||
var me = this;
|
||||
Zotero.Translators.getWebTranslatorsForLocation(data.url, function(data) {
|
||||
Zotero.Translators.getWebTranslatorsForLocation(data.url).then(function(data) {
|
||||
sendResponseCallback(200, "application/json",
|
||||
JSON.stringify(me._serializeTranslators(data[0])));
|
||||
});
|
||||
} else {
|
||||
var responseData = this._serializeTranslators(Zotero.Translators.getAll());
|
||||
sendResponseCallback(200, "application/json", JSON.stringify(responseData));
|
||||
Zotero.Translators.getAll().then(function(translators) {
|
||||
var responseData = me._serializeTranslators(translators);
|
||||
sendResponseCallback(200, "application/json", JSON.stringify(responseData));
|
||||
}).fail(function(e) {
|
||||
sendResponseCallback(500);
|
||||
throw e;
|
||||
}).done();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -934,8 +934,6 @@ Zotero.Sync.Storage = new function () {
|
|||
throw new Task.Result(changed);
|
||||
}
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
let checkItems = function () {
|
||||
if (!items.length) return Q();
|
||||
|
||||
|
|
|
@ -295,13 +295,8 @@ Zotero.Translate.Sandbox = {
|
|||
var translatorsHandlerSet = false;
|
||||
safeTranslator.getTranslators = function() {
|
||||
if(!translation._handlers["translators"] || !translation._handlers["translators"].length) {
|
||||
if(Zotero.isConnector) {
|
||||
throw new Error('Translator must register a "translators" handler to '+
|
||||
'call getTranslators() in this translation environment.');
|
||||
} else {
|
||||
translate._debug('COMPAT WARNING: Translator must register a "translators" handler to '+
|
||||
'call getTranslators() in connector');
|
||||
}
|
||||
throw new Error('Translator must register a "translators" handler to '+
|
||||
'call getTranslators() in this translation environment.');
|
||||
}
|
||||
if(!translatorsHandlerSet) {
|
||||
translation.setHandler("translators", function() {
|
||||
|
@ -331,81 +326,57 @@ Zotero.Translate.Sandbox = {
|
|||
if(callback) {
|
||||
translate.incrementAsyncProcesses("safeTranslator#getTranslatorObject()");
|
||||
} else {
|
||||
translate._debug("COMPAT WARNING: Translator must pass a callback to getTranslatorObject() to operate in connector");
|
||||
throw new Error("Translator must pass a callback to getTranslatorObject() to "+
|
||||
"operate in this translation environment.");
|
||||
}
|
||||
|
||||
var sandbox;
|
||||
var haveTranslatorFunction = function(translator) {
|
||||
translation.translator[0] = translator;
|
||||
translation._loadTranslator(translator, function() {
|
||||
if(Zotero.isFx && !Zotero.isBookmarklet) {
|
||||
// do same origin check
|
||||
var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager);
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var outerSandboxURI = ioService.newURI(typeof translate._sandboxLocation === "object" ?
|
||||
translate._sandboxLocation.location : translate._sandboxLocation, null, null);
|
||||
var innerSandboxURI = ioService.newURI(typeof translation._sandboxLocation === "object" ?
|
||||
translation._sandboxLocation.location : translation._sandboxLocation, null, null);
|
||||
|
||||
try {
|
||||
secMan.checkSameOriginURI(outerSandboxURI, innerSandboxURI, false);
|
||||
} catch(e) {
|
||||
throw new Error("getTranslatorObject() may not be called from web or search "+
|
||||
"translators to web or search translators from different origins.");
|
||||
}
|
||||
}
|
||||
var translator = translation.translator[0];
|
||||
(typeof translator === "object" ? Q(translator) : Zotero.Translators.get(translator)).
|
||||
then(function(translator) {
|
||||
return translation._loadTranslator(translator);
|
||||
}).then(function() {
|
||||
if(Zotero.isFx && !Zotero.isBookmarklet) {
|
||||
// do same origin check
|
||||
var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager);
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
||||
translation._prepareTranslation();
|
||||
setDefaultHandlers(translate, translation);
|
||||
sandbox = translation._sandboxManager.sandbox;
|
||||
if(!Zotero.Utilities.isEmpty(sandbox.exports)) {
|
||||
sandbox.exports.Zotero = sandbox.Zotero;
|
||||
sandbox = sandbox.exports;
|
||||
} else {
|
||||
translate._debug("COMPAT WARNING: "+translation.translator[0].label+" does "+
|
||||
"not export any properties. Only detect"+translation._entryFunctionSuffix+
|
||||
" and do"+translation._entryFunctionSuffix+" will be available in "+
|
||||
"connectors.");
|
||||
}
|
||||
var outerSandboxURI = ioService.newURI(typeof translate._sandboxLocation === "object" ?
|
||||
translate._sandboxLocation.location : translate._sandboxLocation, null, null);
|
||||
var innerSandboxURI = ioService.newURI(typeof translation._sandboxLocation === "object" ?
|
||||
translation._sandboxLocation.location : translation._sandboxLocation, null, null);
|
||||
|
||||
if(callback) {
|
||||
try {
|
||||
callback(sandbox);
|
||||
} catch(e) {
|
||||
translate.complete(false, e);
|
||||
return;
|
||||
}
|
||||
translate.decrementAsyncProcesses("safeTranslator#getTranslatorObject()");
|
||||
try {
|
||||
secMan.checkSameOriginURI(outerSandboxURI, innerSandboxURI, false);
|
||||
} catch(e) {
|
||||
throw new Error("getTranslatorObject() may not be called from web or search "+
|
||||
"translators to web or search translators from different origins.");
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if(typeof translation.translator[0] === "object") {
|
||||
haveTranslatorFunction(translation.translator[0]);
|
||||
return translation._sandboxManager.sandbox;
|
||||
} else {
|
||||
if(Zotero.isConnector && (!Zotero.isFx || Zotero.isBookmarklet) && !callback) {
|
||||
throw new Error("Translator must pass a callback to getTranslatorObject() to "+
|
||||
"operate in this translation environment.");
|
||||
}
|
||||
|
||||
Zotero.Translators.get(translation.translator[0], haveTranslatorFunction);
|
||||
if(Zotero.isConnector && Zotero.isFx && !callback) {
|
||||
while(!sandbox && translate._currentState) {
|
||||
// This processNextEvent call is used to handle a deprecated case
|
||||
Zotero.mainThread.processNextEvent(true);
|
||||
}
|
||||
translation._prepareTranslation();
|
||||
setDefaultHandlers(translate, translation);
|
||||
sandbox = translation._sandboxManager.sandbox;
|
||||
if(!Zotero.Utilities.isEmpty(sandbox.exports)) {
|
||||
sandbox.exports.Zotero = sandbox.Zotero;
|
||||
sandbox = sandbox.exports;
|
||||
} else {
|
||||
translate._debug("COMPAT WARNING: "+translation.translator[0].label+" does "+
|
||||
"not export any properties. Only detect"+translation._entryFunctionSuffix+
|
||||
" and do"+translation._entryFunctionSuffix+" will be available in "+
|
||||
"connectors.");
|
||||
}
|
||||
if(sandbox) return sandbox;
|
||||
}
|
||||
|
||||
callback(sandbox);
|
||||
translate.decrementAsyncProcesses("safeTranslator#getTranslatorObject()");
|
||||
}).fail(function(e) {
|
||||
translate.complete(false, e);
|
||||
return;
|
||||
});
|
||||
};
|
||||
|
||||
// TODO security is not super-tight here, as someone could pass something into arg
|
||||
// that gets evaluated in the wrong scope in Fx < 4. We should wrap this.
|
||||
|
||||
return safeTranslator;
|
||||
},
|
||||
|
||||
|
@ -1010,9 +981,11 @@ Zotero.Translate.Base.prototype = {
|
|||
* @param {Boolean} [checkSetTranslator] If true, the appropriate detect function is run on the
|
||||
* set document/text/etc. using the translator set by setTranslator.
|
||||
* getAllTranslators parameter is meaningless in this context.
|
||||
* @return {Zotero.Translator[]} An array of {@link Zotero.Translator} objects
|
||||
* @return {Promise} Promise for an array of {@link Zotero.Translator} objects
|
||||
*/
|
||||
"getTranslators":function(getAllTranslators, checkSetTranslator) {
|
||||
var potentialTranslators;
|
||||
|
||||
// do not allow simultaneous instances of getTranslators
|
||||
if(this._currentState === "detect") throw new Error("getTranslators: detection is already running");
|
||||
this._currentState = "detect";
|
||||
|
@ -1021,10 +994,10 @@ Zotero.Translate.Base.prototype = {
|
|||
if(checkSetTranslator) {
|
||||
// setTranslator must be called beforehand if checkSetTranslator is set
|
||||
if( !this.translator || !this.translator[0] ) {
|
||||
throw new Error("getTranslators: translator must be set via setTranslator before calling" +
|
||||
" getTranslators with the checkSetTranslator flag");
|
||||
return Q.reject(new Error("getTranslators: translator must be set via setTranslator before calling" +
|
||||
" getTranslators with the checkSetTranslator flag"));
|
||||
}
|
||||
var translators = new Array();
|
||||
var promises = new Array();
|
||||
var t;
|
||||
for(var i=0, n=this.translator.length; i<n; i++) {
|
||||
if(typeof(this.translator[i]) == 'string') {
|
||||
|
@ -1034,80 +1007,83 @@ Zotero.Translate.Base.prototype = {
|
|||
t = this.translator[i];
|
||||
}
|
||||
/**TODO: check that the translator is of appropriate type?*/
|
||||
if(t) translators.push(t);
|
||||
if(t) promises.push(t);
|
||||
}
|
||||
if(!translators.length) throw new Error("getTranslators: no valid translators were set.");
|
||||
this._getTranslatorsTranslatorsReceived(translators);
|
||||
if(!promises.length) return Q.reject(new Error("getTranslators: no valid translators were set"));
|
||||
potentialTranslators = Q.all(promises);
|
||||
} else {
|
||||
this._getTranslatorsGetPotentialTranslators();
|
||||
potentialTranslators = this._getTranslatorsGetPotentialTranslators();
|
||||
}
|
||||
|
||||
// if detection returns immediately, return found translators
|
||||
if(!this._currentState) return this._foundTranslators;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all potential translators
|
||||
* @return {Zotero.Translator[]}
|
||||
*/
|
||||
"_getTranslatorsGetPotentialTranslators":function() {
|
||||
var me = this;
|
||||
Zotero.Translators.getAllForType(this.type,
|
||||
function(translators) { me._getTranslatorsTranslatorsReceived(translators) });
|
||||
},
|
||||
|
||||
/**
|
||||
* Called on completion of {@link #_getTranslatorsGetPotentialTranslators} call
|
||||
*/
|
||||
"_getTranslatorsTranslatorsReceived":function(allPotentialTranslators, properToProxyFunctions) {
|
||||
this._potentialTranslators = [];
|
||||
this._foundTranslators = [];
|
||||
|
||||
// this gets passed out by Zotero.Translators.getWebTranslatorsForLocation() because it is
|
||||
// specific for each translator, but we want to avoid making a copy of a translator whenever
|
||||
// possible.
|
||||
this._properToProxyFunctions = properToProxyFunctions ? properToProxyFunctions : null;
|
||||
this._waitingForRPC = false;
|
||||
|
||||
for(var i=0, n=allPotentialTranslators.length; i<n; i++) {
|
||||
var translator = allPotentialTranslators[i];
|
||||
if(translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER) {
|
||||
this._potentialTranslators.push(translator);
|
||||
} else if(this instanceof Zotero.Translate.Web && Zotero.Connector) {
|
||||
this._waitingForRPC = true;
|
||||
return potentialTranslators.spread(function(allPotentialTranslators, properToProxyFunctions) {
|
||||
me._potentialTranslators = [];
|
||||
me._foundTranslators = [];
|
||||
|
||||
// this gets passed out by Zotero.Translators.getWebTranslatorsForLocation() because it is
|
||||
// specific for each translator, but we want to avoid making a copy of a translator whenever
|
||||
// possible.
|
||||
me._properToProxyFunctions = properToProxyFunctions ? properToProxyFunctions : null;
|
||||
me._waitingForRPC = false;
|
||||
|
||||
for(var i=0, n=allPotentialTranslators.length; i<n; i++) {
|
||||
var translator = allPotentialTranslators[i];
|
||||
if(translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER) {
|
||||
me._potentialTranslators.push(translator);
|
||||
} else if(me instanceof Zotero.Translate.Web && Zotero.Connector) {
|
||||
me._waitingForRPC = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(this._waitingForRPC) {
|
||||
var me = this;
|
||||
Zotero.Connector.callMethod("detect", {"uri":this.location.toString(),
|
||||
"cookie":this.document.cookie,
|
||||
"html":this.document.documentElement.innerHTML},
|
||||
function(returnValue) { me._getTranslatorsRPCComplete(returnValue) });
|
||||
}
|
||||
|
||||
this._detect();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called on completion of detect RPC for
|
||||
* {@link Zotero.Translate.Base#_getTranslatorsTranslatorsReceived}
|
||||
*/
|
||||
"_getTranslatorsRPCComplete":function(rpcTranslators) {
|
||||
this._waitingForRPC = false;
|
||||
|
||||
// if there are translators, add them to the list of found translators
|
||||
if(rpcTranslators) {
|
||||
for(var i=0, n=rpcTranslators.length; i<n; i++) {
|
||||
rpcTranslators[i].runMode = Zotero.Translator.RUN_MODE_ZOTERO_STANDALONE;
|
||||
|
||||
// Attach handler for translators, so that we can return a
|
||||
// promise that provides them.
|
||||
// TODO make me._detect() return a promise
|
||||
var deferred = Q.defer(),
|
||||
translatorsHandler = function(obj, translators) {
|
||||
me.removeHandler("translators", translatorsHandler);
|
||||
deferred.resolve(translators);
|
||||
}
|
||||
me.setHandler("translators", translatorsHandler);
|
||||
me._detect();
|
||||
|
||||
if(me._waitingForRPC) {
|
||||
// Try detect in Zotero Standalone. If this fails, it fails; we shouldn't
|
||||
// get hung up about it.
|
||||
Zotero.Connector.callMethod("detect", {"uri":me.location.toString(),
|
||||
"cookie":me.document.cookie,
|
||||
"html":me.document.documentElement.innerHTML}).then(function(rpcTranslators) {
|
||||
me._waitingForRPC = false;
|
||||
|
||||
// if there are translators, add them to the list of found translators
|
||||
if(rpcTranslators) {
|
||||
for(var i=0, n=rpcTranslators.length; i<n; i++) {
|
||||
rpcTranslators[i].runMode = Zotero.Translator.RUN_MODE_ZOTERO_STANDALONE;
|
||||
}
|
||||
me._foundTranslators = me._foundTranslators.concat(rpcTranslators);
|
||||
}
|
||||
|
||||
// call _detectTranslatorsCollected to return detected translators
|
||||
if(me._currentState === null) {
|
||||
me._detectTranslatorsCollected();
|
||||
}
|
||||
});
|
||||
}
|
||||
this._foundTranslators = this._foundTranslators.concat(rpcTranslators);
|
||||
}
|
||||
|
||||
// call _detectTranslatorsCollected to return detected translators
|
||||
if(this._currentState === null) {
|
||||
this._detectTranslatorsCollected();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}).fail(function(e) {
|
||||
Zotero.logError(e);
|
||||
me.complete(false, e);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all potential translators (without running detect)
|
||||
* @return {Promise} Promise for an array of {@link Zotero.Translator} objects
|
||||
*/
|
||||
"_getTranslatorsGetPotentialTranslators":function() {
|
||||
return Zotero.Translators.getAllForType(this.type).
|
||||
then(function(translators) { return [translators] });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1136,14 +1112,14 @@ Zotero.Translate.Base.prototype = {
|
|||
var me = this;
|
||||
if(typeof this.translator[0] === "object") {
|
||||
// already have a translator object, so use it
|
||||
this._loadTranslator(this.translator[0], function() { me._translateTranslatorLoaded() });
|
||||
this._loadTranslator(this.translator[0]).then(function() { me._translateTranslatorLoaded() });
|
||||
} else {
|
||||
// need to get translator first
|
||||
Zotero.Translators.get(this.translator[0],
|
||||
function(translator) {
|
||||
me.translator[0] = translator;
|
||||
me._loadTranslator(translator, function() { me._translateTranslatorLoaded() });
|
||||
});
|
||||
Zotero.Translators.get(this.translator[0]).
|
||||
then(function(translator) {
|
||||
me.translator[0] = translator;
|
||||
me._loadTranslator(translator).then(function() { me._translateTranslatorLoaded() });
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1151,12 +1127,6 @@ Zotero.Translate.Base.prototype = {
|
|||
* Called when translator has been retrieved and loaded
|
||||
*/
|
||||
"_translateTranslatorLoaded":function() {
|
||||
if(!this.translator[0].code) {
|
||||
this.complete(false,
|
||||
new Error("Translator "+this.translator[0].label+" is unsupported within this environment"));
|
||||
return;
|
||||
}
|
||||
|
||||
// set display options to default if they don't exist
|
||||
if(!this._displayOptions) this._displayOptions = this._translatorInfo.displayOptions || {};
|
||||
|
||||
|
@ -1429,8 +1399,8 @@ Zotero.Translate.Base.prototype = {
|
|||
}
|
||||
|
||||
var me = this;
|
||||
this._loadTranslator(this._potentialTranslators[0],
|
||||
function() { me._detectTranslatorLoaded() });
|
||||
this._loadTranslator(this._potentialTranslators[0]).
|
||||
then(function() { me._detectTranslatorLoaded() });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1466,7 +1436,7 @@ Zotero.Translate.Base.prototype = {
|
|||
* @param {Zotero.Translator} translator
|
||||
* @return {Boolean} Whether the translator could be successfully loaded
|
||||
*/
|
||||
"_loadTranslator":function(translator, callback) {
|
||||
"_loadTranslator":function(translator) {
|
||||
var sandboxLocation = this._getSandboxLocation();
|
||||
if(!this._sandboxLocation || sandboxLocation !== this._sandboxLocation) {
|
||||
this._sandboxLocation = sandboxLocation;
|
||||
|
@ -1479,20 +1449,17 @@ Zotero.Translate.Base.prototype = {
|
|||
this._aborted = false;
|
||||
this.saveQueue = [];
|
||||
|
||||
Zotero.debug("Translate: Parsing code for "+translator.label, 4);
|
||||
|
||||
try {
|
||||
this._sandboxManager.eval("var exports = {}, ZOTERO_TRANSLATOR_INFO = "+translator.code,
|
||||
["detect"+this._entryFunctionSuffix, "do"+this._entryFunctionSuffix, "exports",
|
||||
var me = this;
|
||||
return translator.getCode().then(function(code) {
|
||||
Zotero.debug("Translate: Parsing code for "+translator.label, 4);
|
||||
me._sandboxManager.eval("var exports = {}, ZOTERO_TRANSLATOR_INFO = "+code,
|
||||
["detect"+me._entryFunctionSuffix, "do"+me._entryFunctionSuffix, "exports",
|
||||
"ZOTERO_TRANSLATOR_INFO"],
|
||||
(translator.file ? translator.file.path : translator.label));
|
||||
} catch(e) {
|
||||
this.complete(false, e);
|
||||
return;
|
||||
}
|
||||
this._translatorInfo = this._sandboxManager.sandbox.ZOTERO_TRANSLATOR_INFO;
|
||||
|
||||
if(callback) callback();
|
||||
me._translatorInfo = me._sandboxManager.sandbox.ZOTERO_TRANSLATOR_INFO;
|
||||
}).fail(function(e) {
|
||||
me.complete(false, e);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1682,13 +1649,7 @@ Zotero.Translate.Web.prototype.setLocation = function(location) {
|
|||
* Get potential web translators
|
||||
*/
|
||||
Zotero.Translate.Web.prototype._getTranslatorsGetPotentialTranslators = function() {
|
||||
var me = this;
|
||||
Zotero.Translators.getWebTranslatorsForLocation(this.location,
|
||||
function(data) {
|
||||
// data[0] = list of translators
|
||||
// data[1] = list of functions to convert proper URIs to proxied URIs
|
||||
me._getTranslatorsTranslatorsReceived(data[0], data[1]);
|
||||
});
|
||||
return Zotero.Translators.getWebTranslatorsForLocation(this.location);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1920,13 +1881,10 @@ Zotero.Translate.Import.prototype.complete = function(returnValue, error) {
|
|||
* Get all potential import translators, ordering translators with the right file extension first
|
||||
*/
|
||||
Zotero.Translate.Import.prototype._getTranslatorsGetPotentialTranslators = function() {
|
||||
if(this.location) {
|
||||
var me = this;
|
||||
Zotero.Translators.getImportTranslatorsForLocation(this.location,
|
||||
function(translators) { me._getTranslatorsTranslatorsReceived(translators) });
|
||||
} else {
|
||||
Zotero.Translate.Base.prototype._getTranslatorsGetPotentialTranslators.call(this);
|
||||
}
|
||||
return (this.location ?
|
||||
Zotero.Translators.getImportTranslatorsForLocation(this.location) :
|
||||
Zotero.Translators.getAllForType(this.type)).
|
||||
then(function(translators) { return [translators] });;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1938,12 +1896,13 @@ Zotero.Translate.Import.prototype.getTranslators = function() {
|
|||
if(this._currentState === "detect") throw new Error("getTranslators: detection is already running");
|
||||
this._currentState = "detect";
|
||||
var me = this;
|
||||
Zotero.Translators.getAllForType(this.type, function(translators) {
|
||||
return Zotero.Translators.getAllForType(this.type).
|
||||
then(function(translators) {
|
||||
me._potentialTranslators = [];
|
||||
me._foundTranslators = translators;
|
||||
me.complete(true);
|
||||
return me._foundTranslators;
|
||||
});
|
||||
if(this._currentState === null) return this._foundTranslators;
|
||||
} else {
|
||||
return Zotero.Translate.Base.prototype.getTranslators.call(this);
|
||||
}
|
||||
|
@ -1955,7 +1914,8 @@ Zotero.Translate.Import.prototype.getTranslators = function() {
|
|||
Zotero.Translate.Import.prototype._loadTranslator = function(translator, callback) {
|
||||
// call super
|
||||
var me = this;
|
||||
Zotero.Translate.Base.prototype._loadTranslator.call(this, translator, function() {
|
||||
return Zotero.Translate.Base.prototype._loadTranslator.call(this, translator).
|
||||
then(function() {
|
||||
me._loadTranslatorPrepareIO(translator, callback);
|
||||
});
|
||||
}
|
||||
|
@ -2113,12 +2073,17 @@ Zotero.Translate.Export.prototype.complete = function(returnValue, error) {
|
|||
* Overload {@link Zotero.Translate.Base#getTranslators} to return all translators immediately
|
||||
*/
|
||||
Zotero.Translate.Export.prototype.getTranslators = function() {
|
||||
if(this._currentState === "detect") throw new Error("getTranslators: detection is already running");
|
||||
this._currentState = "detect";
|
||||
this._foundTranslators = Zotero.Translators.getAllForType(this.type);
|
||||
this._potentialTranslators = [];
|
||||
this.complete(true);
|
||||
return this._foundTranslators;
|
||||
if(this._currentState === "detect") {
|
||||
return Q.reject(new Error("getTranslators: detection is already running"));
|
||||
}
|
||||
var me = this;
|
||||
return Zotero.Translators.getAllForType(this.type).then(function(translators) {
|
||||
me._currentState = "detect";
|
||||
me._foundTranslators = translators;
|
||||
me._potentialTranslators = [];
|
||||
me.complete(true);
|
||||
return me._foundTranslators;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2009 Center for History and New Media
|
||||
Copyright © 2013 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
|
@ -23,398 +23,22 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
// Enumeration of types of translators
|
||||
const TRANSLATOR_TYPES = {"import":1, "export":2, "web":4, "search":8};
|
||||
|
||||
/**
|
||||
* Singleton to handle loading and caching of translators
|
||||
* @namespace
|
||||
*/
|
||||
Zotero.Translators = new function() {
|
||||
var _cache, _translators;
|
||||
var _initialized = false;
|
||||
|
||||
/**
|
||||
* Initializes translator cache, loading all relevant translators into memory
|
||||
*/
|
||||
this.init = Q.async(function() {
|
||||
_initialized = true;
|
||||
|
||||
var start = (new Date()).getTime();
|
||||
var transactionStarted = false;
|
||||
|
||||
_cache = {"import":[], "export":[], "web":[], "search":[]};
|
||||
_translators = {};
|
||||
|
||||
var dbCacheResults = yield Zotero.DB.queryAsync("SELECT leafName, translatorJSON, "+
|
||||
"code, lastModifiedTime FROM translatorCache");
|
||||
var dbCache = {};
|
||||
for each(var cacheEntry in dbCacheResults) {
|
||||
dbCache[cacheEntry.leafName] = cacheEntry;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var filesInCache = {};
|
||||
var contents = Zotero.getTranslatorsDirectory().directoryEntries;
|
||||
while(contents.hasMoreElements()) {
|
||||
var file = contents.getNext().QueryInterface(Components.interfaces.nsIFile);
|
||||
var leafName = file.leafName;
|
||||
if(!(/^[^.].*\.js$/.test(leafName))) continue;
|
||||
var lastModifiedTime = file.lastModifiedTime;
|
||||
|
||||
var dbCacheEntry = false;
|
||||
if(dbCache[leafName]) {
|
||||
filesInCache[leafName] = true;
|
||||
if(dbCache[leafName].lastModifiedTime == lastModifiedTime) {
|
||||
dbCacheEntry = dbCache[file.leafName];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use async load method instead of constructor
|
||||
if(dbCacheEntry) {
|
||||
// get JSON from cache if possible
|
||||
var translator = new Zotero.Translator(file, dbCacheEntry.translatorJSON, dbCacheEntry.code);
|
||||
filesInCache[leafName] = true;
|
||||
} else {
|
||||
// otherwise, load from file
|
||||
var translator = new Zotero.Translator(file);
|
||||
}
|
||||
|
||||
if(translator.translatorID) {
|
||||
if(_translators[translator.translatorID]) {
|
||||
// same translator is already cached
|
||||
translator.logError('Translator with ID '+
|
||||
translator.translatorID+' already loaded from "'+
|
||||
_translators[translator.translatorID].file.leafName+'"');
|
||||
} else {
|
||||
// add to cache
|
||||
_translators[translator.translatorID] = translator;
|
||||
for(var type in TRANSLATOR_TYPES) {
|
||||
if(translator.translatorType & TRANSLATOR_TYPES[type]) {
|
||||
_cache[type].push(translator);
|
||||
}
|
||||
}
|
||||
|
||||
if(!dbCacheEntry) {
|
||||
yield Zotero.Translators.cacheInDB(
|
||||
leafName,
|
||||
translator.metadataString,
|
||||
translator.cacheCode ? translator.code : null,
|
||||
lastModifiedTime
|
||||
);
|
||||
delete translator.metadataString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// Remove translators from DB as necessary
|
||||
for(var leafName in dbCache) {
|
||||
if(!filesInCache[leafName]) {
|
||||
yield Zotero.DB.queryAsync(
|
||||
"DELETE FROM translatorCache WHERE leafName = ?", [leafName]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by priority
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
var cmp = function (a, b) {
|
||||
if (a.priority > b.priority) {
|
||||
return 1;
|
||||
}
|
||||
else if (a.priority < b.priority) {
|
||||
return -1;
|
||||
}
|
||||
return collation.compareString(1, a.label, b.label);
|
||||
}
|
||||
for(var type in _cache) {
|
||||
_cache[type].sort(cmp);
|
||||
}
|
||||
|
||||
Zotero.debug("Cached "+i+" translators in "+((new Date()).getTime() - start)+" ms");
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the translator that corresponds to a given ID
|
||||
* @param {String} id The ID of the translator
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned.
|
||||
*/
|
||||
this.get = function(id, callback) {
|
||||
if(!_initialized) this.init();
|
||||
var translator = _translators[id] ? _translators[id] : false;
|
||||
|
||||
if(callback) {
|
||||
callback(translator);
|
||||
return true;
|
||||
}
|
||||
return translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all translators for a specific type of translation
|
||||
* @param {String} type The type of translators to get (import, export, web, or search)
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned.
|
||||
*/
|
||||
this.getAllForType = function(type, callback) {
|
||||
if(!_initialized) this.init()
|
||||
|
||||
var translators = _cache[type].slice(0);
|
||||
if(callback) {
|
||||
callback(translators);
|
||||
return true;
|
||||
}
|
||||
return translators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all translators for a specific type of translation
|
||||
*/
|
||||
this.getAll = function() {
|
||||
if(!_initialized) this.init();
|
||||
return [translator for each(translator in _translators)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets web translators for a specific location
|
||||
* @param {String} uri The URI for which to look for translators
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned. The callback is passed a set of functions for
|
||||
* converting URLs from proper to proxied forms as the second
|
||||
* argument.
|
||||
*/
|
||||
this.getWebTranslatorsForLocation = function(uri, callback) {
|
||||
var allTranslators = this.getAllForType("web");
|
||||
var potentialTranslators = [];
|
||||
|
||||
var properHosts = [];
|
||||
var proxyHosts = [];
|
||||
|
||||
var properURI = Zotero.Proxies.proxyToProper(uri);
|
||||
var knownProxy = properURI !== uri;
|
||||
if(knownProxy) {
|
||||
// if we know this proxy, just use the proper URI for detection
|
||||
var searchURIs = [properURI];
|
||||
} else {
|
||||
var searchURIs = [uri];
|
||||
|
||||
// if there is a subdomain that is also a TLD, also test against URI with the domain
|
||||
// dropped after the TLD
|
||||
// (i.e., www.nature.com.mutex.gmu.edu => www.nature.com)
|
||||
var m = /^(https?:\/\/)([^\/]+)/i.exec(uri);
|
||||
if(m) {
|
||||
// First, drop the 0- if it exists (this is an III invention)
|
||||
var host = m[2];
|
||||
if(host.substr(0, 2) === "0-") host = host.substr(2);
|
||||
var hostnames = host.split(".");
|
||||
for(var i=1; i<hostnames.length-2; i++) {
|
||||
if(TLDS[hostnames[i].toLowerCase()]) {
|
||||
var properHost = hostnames.slice(0, i+1).join(".");
|
||||
searchURIs.push(m[1]+properHost+uri.substr(m[0].length));
|
||||
properHosts.push(properHost);
|
||||
proxyHosts.push(hostnames.slice(i+1).join("."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.debug("Translators: Looking for translators for "+searchURIs.join(", "));
|
||||
|
||||
var converterFunctions = [];
|
||||
for(var i=0; i<allTranslators.length; i++) {
|
||||
for(var j=0; j<searchURIs.length; j++) {
|
||||
if((!allTranslators[i].webRegexp
|
||||
&& allTranslators[i].runMode === Zotero.Translator.RUN_MODE_IN_BROWSER)
|
||||
|| (uri.length < 8192 && allTranslators[i].webRegexp.test(searchURIs[j]))) {
|
||||
// add translator to list
|
||||
potentialTranslators.push(allTranslators[i]);
|
||||
|
||||
if(j === 0) {
|
||||
if(knownProxy) {
|
||||
converterFunctions.push(Zotero.Proxies.properToProxy);
|
||||
} else {
|
||||
converterFunctions.push(null);
|
||||
}
|
||||
} else {
|
||||
converterFunctions.push(new function() {
|
||||
var re = new RegExp('^https?://(?:[^/]\\.)?'+Zotero.Utilities.quotemeta(properHosts[j-1]), "gi");
|
||||
var proxyHost = proxyHosts[j-1].replace(/\$/g, "$$$$");
|
||||
return function(uri) { return uri.replace(re, "$&."+proxyHost) };
|
||||
});
|
||||
}
|
||||
|
||||
// don't add translator more than once
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(callback) {
|
||||
callback([potentialTranslators, converterFunctions]);
|
||||
return true;
|
||||
}
|
||||
return potentialTranslators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets import translators for a specific location
|
||||
* @param {String} location The location for which to look for translators
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned.
|
||||
*/
|
||||
this.getImportTranslatorsForLocation = function(location, callback) {
|
||||
var allTranslators = Zotero.Translators.getAllForType("import");
|
||||
var tier1Translators = [];
|
||||
var tier2Translators = [];
|
||||
|
||||
for(var i=0; i<allTranslators.length; i++) {
|
||||
if(allTranslators[i].importRegexp && allTranslators[i].importRegexp.test(location)) {
|
||||
tier1Translators.push(allTranslators[i]);
|
||||
} else {
|
||||
tier2Translators.push(allTranslators[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var translators = tier1Translators.concat(tier2Translators);
|
||||
if(callback) {
|
||||
callback(translators);
|
||||
return true;
|
||||
}
|
||||
return translators;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} label
|
||||
* @return {String}
|
||||
*/
|
||||
this.getFileNameFromLabel = function(label, alternative) {
|
||||
var fileName = Zotero.Utilities.removeDiacritics(
|
||||
Zotero.File.getValidFileName(label)) + ".js";
|
||||
// Use translatorID if name still isn't ASCII (e.g., Cyrillic)
|
||||
if (alternative && !fileName.match(/^[\x00-\x7f]+$/)) {
|
||||
fileName = alternative + ".js";
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} metadata
|
||||
* @param {String} metadata.translatorID Translator GUID
|
||||
* @param {Integer} metadata.translatorType See TRANSLATOR_TYPES in translate.js
|
||||
* @param {String} metadata.label Translator title
|
||||
* @param {String} metadata.creator Translator author
|
||||
* @param {String|Null} metadata.target Target regexp
|
||||
* @param {String|Null} metadata.minVersion
|
||||
* @param {String} metadata.maxVersion
|
||||
* @param {String|undefined} metadata.configOptions
|
||||
* @param {String|undefined} metadata.displayOptions
|
||||
* @param {Integer} metadata.priority
|
||||
* @param {String} metadata.browserSupport
|
||||
* @param {Boolean} metadata.inRepository
|
||||
* @param {String} metadata.lastUpdated SQL date
|
||||
* @param {String} code
|
||||
* @return {Promise<nsIFile>}
|
||||
*/
|
||||
this.save = function(metadata, code) {
|
||||
if (!metadata.translatorID) {
|
||||
throw ("metadata.translatorID not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.translatorType) {
|
||||
var found = false;
|
||||
for each(var type in TRANSLATOR_TYPES) {
|
||||
if (metadata.translatorType & type) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw ("Invalid translatorType '" + metadata.translatorType + "' in Zotero.Translators.save()");
|
||||
}
|
||||
}
|
||||
|
||||
if (!metadata.label) {
|
||||
throw ("metadata.label not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.priority) {
|
||||
throw ("metadata.priority not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.lastUpdated) {
|
||||
throw ("metadata.lastUpdated not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
throw ("code not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
var fileName = Zotero.Translators.getFileNameFromLabel(
|
||||
metadata.label, metadata.translatorID
|
||||
);
|
||||
var destFile = Zotero.getTranslatorsDirectory();
|
||||
destFile.append(fileName);
|
||||
|
||||
// JSON.stringify has the benefit of indenting JSON
|
||||
var metadataJSON = JSON.stringify(metadata, null, "\t");
|
||||
|
||||
var str = metadataJSON + "\n\n" + code;
|
||||
|
||||
var translator = Zotero.Translators.get(metadata.translatorID);
|
||||
if (translator && destFile.equals(translator.file)) {
|
||||
var sameFile = true;
|
||||
}
|
||||
|
||||
return Q.fcall(function () {
|
||||
if (sameFile) return;
|
||||
|
||||
return Q(OS.File.exists(destFile.path))
|
||||
.then(function (exists) {
|
||||
if (exists) {
|
||||
var msg = "Overwriting translator with same filename '"
|
||||
+ fileName + "'";
|
||||
Zotero.debug(msg, 1);
|
||||
Zotero.debug(metadata, 1);
|
||||
Components.utils.reportError(msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
if (!translator) return;
|
||||
|
||||
return Q(OS.File.exists(translator.file.path))
|
||||
.then(function (exists) {
|
||||
translator.file.remove(false);
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
Zotero.debug("Saving translator '" + metadata.label + "'");
|
||||
Zotero.debug(str);
|
||||
return Zotero.File.putContentsAsync(destFile, str)
|
||||
.thenResolve(destFile);
|
||||
});
|
||||
}
|
||||
|
||||
this.cacheInDB = function(fileName, metadataJSON, code, lastModifiedTime) {
|
||||
return Zotero.DB.queryAsync(
|
||||
"REPLACE INTO translatorCache VALUES (?, ?, ?, ?)",
|
||||
[fileName, metadataJSON, code, lastModifiedTime]
|
||||
);
|
||||
}
|
||||
}
|
||||
// Properties required for every translator
|
||||
var TRANSLATOR_REQUIRED_PROPERTIES = ["translatorID", "translatorType", "label", "creator",
|
||||
"target", "priority", "lastUpdated"];
|
||||
// Properties that are preserved if present
|
||||
var TRANSLATOR_OPTIONAL_PROPERTIES = ["browserSupport", "minVersion", "maxVersion",
|
||||
"inRepository", "configOptions", "displayOptions",
|
||||
"hiddenPrefs"];
|
||||
// Properties that are passed from background to inject page in connector
|
||||
var TRANSLATOR_PASSING_PROPERTIES = TRANSLATOR_REQUIRED_PROPERTIES.
|
||||
concat(["browserSupport", "code", "runMode"]);
|
||||
// Properties that are saved in connector if set but not required
|
||||
var TRANSLATOR_SAVE_PROPERTIES = TRANSLATOR_REQUIRED_PROPERTIES.concat(["browserSupport"]);
|
||||
|
||||
/**
|
||||
* @class Represents an individual translator
|
||||
* @constructor
|
||||
* @param {nsIFile} file File from which to generate a translator object
|
||||
* @property {String} translatorID Unique GUID of the translator
|
||||
* @property {Integer} translatorType Type of the translator (use bitwise & with TRANSLATOR_TYPES to read)
|
||||
* @property {String} label Human-readable name of the translator
|
||||
|
@ -436,124 +60,118 @@ Zotero.Translators = new function() {
|
|||
* @property {Boolean} inRepository Whether the translator may be found in the repository
|
||||
* @property {String} lastUpdated SQL-style date and time of translator's last update
|
||||
* @property {String} code The executable JavaScript for the translator
|
||||
* @property {Boolean} cacheCode Whether to cache code for this session (non-connector only)
|
||||
* @property {nsIFile} [file] File corresponding to this translator (non-connector only)
|
||||
*/
|
||||
Zotero.Translator = function(file, json, code) {
|
||||
const codeGetterFunction = function() { return Zotero.File.getContents(this.file); }
|
||||
// Maximum length for the info JSON in a translator
|
||||
const MAX_INFO_LENGTH = 4096;
|
||||
const infoRe = /^\s*{[\S\s]*?}\s*?[\r\n]/;
|
||||
|
||||
this.file = file;
|
||||
|
||||
var fStream, cStream;
|
||||
if(json) {
|
||||
var info = JSON.parse(json);
|
||||
} else {
|
||||
fStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
cStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
fStream.init(file, -1, -1, 0);
|
||||
cStream.init(fStream, "UTF-8", 8192,
|
||||
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
|
||||
var str = {};
|
||||
cStream.readString(MAX_INFO_LENGTH, str);
|
||||
|
||||
var m = infoRe.exec(str.value);
|
||||
if (!m) {
|
||||
this.logError("Invalid or missing translator metadata JSON object in " + file.leafName);
|
||||
fStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.metadataString = m[0];
|
||||
|
||||
try {
|
||||
var info = JSON.parse(this.metadataString);
|
||||
} catch(e) {
|
||||
this.logError("Invalid or missing translator metadata JSON object in " + file.leafName);
|
||||
fStream.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var haveMetadata = true;
|
||||
Zotero.Translator = function(info) {
|
||||
this.init(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a translator from a set of info, clearing code if it is set
|
||||
*/
|
||||
Zotero.Translator.prototype.init = function(info) {
|
||||
// make sure we have all the properties
|
||||
for each(var property in ["translatorID", "translatorType", "label", "creator", "target", "minVersion", "maxVersion", "priority", "lastUpdated", "inRepository"]) {
|
||||
for(var i=0; i<TRANSLATOR_REQUIRED_PROPERTIES.length; i++) {
|
||||
var property = TRANSLATOR_REQUIRED_PROPERTIES[i];
|
||||
if(info[property] === undefined) {
|
||||
this.logError('Missing property "'+property+'" in translator metadata JSON object in ' + file.leafName);
|
||||
this.logError(new Error('Missing property "'+property+'" in translator metadata JSON object in ' + info.label));
|
||||
haveMetadata = false;
|
||||
break;
|
||||
} else {
|
||||
this[property] = info[property];
|
||||
}
|
||||
}
|
||||
if(!haveMetadata) {
|
||||
if(fStream) fStream.close();
|
||||
return;
|
||||
for(var i=0; i<TRANSLATOR_OPTIONAL_PROPERTIES.length; i++) {
|
||||
var property = TRANSLATOR_OPTIONAL_PROPERTIES[i];
|
||||
if(info[property] !== undefined) {
|
||||
this[property] = info[property];
|
||||
}
|
||||
}
|
||||
|
||||
this._configOptions = info["configOptions"] ? info["configOptions"] : {};
|
||||
this._displayOptions = info["displayOptions"] ? info["displayOptions"] : {};
|
||||
this._hiddenPrefs = info["hiddenPrefs"] ? info["hiddenPrefs"] : {};
|
||||
|
||||
this.browserSupport = info["browserSupport"] ? info["browserSupport"] : "g";
|
||||
this.runMode = Zotero.Translator.RUN_MODE_IN_BROWSER;
|
||||
|
||||
var supported = (
|
||||
Zotero.isBookmarklet ?
|
||||
(this.browserSupport.indexOf(Zotero.browser) !== -1 && this.browserSupport.indexOf("b") !== -1) ||
|
||||
/(?:^|; ?)bookmarklet-debug-mode=1(?:$|; ?)/.test(document.cookie) :
|
||||
this.browserSupport.indexOf(Zotero.browser) !== -1);
|
||||
|
||||
if(supported) {
|
||||
this.runMode = Zotero.Translator.RUN_MODE_IN_BROWSER;
|
||||
} else {
|
||||
this.runMode = Zotero.Translator.RUN_MODE_ZOTERO_STANDALONE;
|
||||
}
|
||||
|
||||
if(this.translatorType & TRANSLATOR_TYPES["import"]) {
|
||||
// compile import regexp to match only file extension
|
||||
try {
|
||||
this.importRegexp = this.target ? new RegExp("\\."+this.target+"$", "i") : null;
|
||||
} catch(e) {
|
||||
this.logError("Invalid target in " + file.leafName);
|
||||
this.importRegexp = null;
|
||||
if(fStream) fStream.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.cacheCode = false;
|
||||
if(this.translatorType & TRANSLATOR_TYPES["web"]) {
|
||||
// compile web regexp
|
||||
try {
|
||||
this.webRegexp = this.target ? new RegExp(this.target, "i") : null;
|
||||
} catch(e) {
|
||||
this.logError("Invalid target in " + file.leafName);
|
||||
this.webRegexp = null;
|
||||
if(fStream) fStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.target) {
|
||||
this.cacheCode = true;
|
||||
|
||||
if(json) {
|
||||
// if have JSON, also have code
|
||||
this.code = code;
|
||||
} else {
|
||||
// for translators used on every page, cache code in memory
|
||||
var strs = [str.value];
|
||||
var amountRead;
|
||||
while(amountRead = cStream.readString(8192, str)) strs.push(str.value);
|
||||
this.code = strs.join("");
|
||||
}
|
||||
}
|
||||
this.importRegexp = this.target ? new RegExp("\\."+this.target+"$", "i") : null;
|
||||
} else if(this.hasOwnProperty("importRegexp")) {
|
||||
delete this.importRegexp;
|
||||
}
|
||||
|
||||
if(!this.cacheCode) this.__defineGetter__("code", codeGetterFunction);
|
||||
if(!json) cStream.close();
|
||||
this.cacheCode = Zotero.isConnector;
|
||||
if(this.translatorType & TRANSLATOR_TYPES["web"]) {
|
||||
// compile web regexp
|
||||
this.cacheCode |= !this.target;
|
||||
this.webRegexp = this.target ? new RegExp(this.target, "i") : null;
|
||||
} else if(this.hasOwnProperty("webRegexp")) {
|
||||
delete this.webRegexp;
|
||||
}
|
||||
|
||||
if(info.file) this.file = info.file;
|
||||
if(info.code && this.cacheCode) {
|
||||
this.code = info.code;
|
||||
} else if(this.hasOwnProperty("code")) {
|
||||
delete this.code;
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Translator.prototype.__defineGetter__("displayOptions", function() {
|
||||
return Zotero.Utilities.deepCopy(this._displayOptions);
|
||||
});
|
||||
Zotero.Translator.prototype.__defineGetter__("configOptions", function() {
|
||||
return Zotero.Utilities.deepCopy(this._configOptions);
|
||||
});
|
||||
Zotero.Translator.prototype.__defineGetter__("hiddenPrefs", function() {
|
||||
return Zotero.Utilities.deepCopy(this._hiddenPrefs);
|
||||
});
|
||||
/**
|
||||
* Load code for a translator
|
||||
*/
|
||||
Zotero.Translator.prototype.getCode = function() {
|
||||
if(this.code) return Q(this.code);
|
||||
|
||||
var me = this;
|
||||
if(Zotero.isConnector) {
|
||||
// TODO make this a promise
|
||||
return Zotero.Repo.getTranslatorCode(this.translatorID).
|
||||
spread(function(code, source) {
|
||||
if(!code) {
|
||||
throw "Code for "+me.label+" could not be retrieved";
|
||||
}
|
||||
// Cache any translators for session, since retrieving via
|
||||
// HTTP may be expensive
|
||||
me.code = code;
|
||||
me.codeSource = source;
|
||||
return code;
|
||||
});
|
||||
} else {
|
||||
var promise = Zotero.File.getContentsAsync(this.file);
|
||||
if(this.cacheCode) {
|
||||
// Cache target-less web translators for session, since we
|
||||
// will use them a lot
|
||||
promise.then(function(code) {
|
||||
me.code = code;
|
||||
return code;
|
||||
});
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata block for a translator
|
||||
*/
|
||||
Zotero.Translator.prototype.serialize = function(properties) {
|
||||
var info = {};
|
||||
for(var i in properties) {
|
||||
var property = properties[i];
|
||||
info[property] = translator[property];
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a translator-related error
|
||||
|
@ -564,9 +182,13 @@ Zotero.Translator.prototype.__defineGetter__("hiddenPrefs", function() {
|
|||
* @param {Integer} colNumber
|
||||
*/
|
||||
Zotero.Translator.prototype.logError = function(message, type, line, lineNumber, colNumber) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
Zotero.log(message, type ? type : "error", ios.newFileURI(this.file).spec);
|
||||
if(Zotero.isFx && this.file) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
Zotero.log(message, type ? type : "error", ios.newFileURI(this.file).spec);
|
||||
} else {
|
||||
Zotero.logError(message);
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Translator.RUN_MODE_IN_BROWSER = 1;
|
||||
|
|
422
chrome/content/zotero/xpcom/translation/translators.js
Normal file
422
chrome/content/zotero/xpcom/translation/translators.js
Normal file
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2009 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
// Enumeration of types of translators
|
||||
const TRANSLATOR_TYPES = {"import":1, "export":2, "web":4, "search":8};
|
||||
|
||||
/**
|
||||
* Singleton to handle loading and caching of translators
|
||||
* @namespace
|
||||
*/
|
||||
Zotero.Translators = new function() {
|
||||
var _cache, _translators;
|
||||
var _initialized = false;
|
||||
|
||||
/**
|
||||
* Initializes translator cache, loading all relevant translators into memory
|
||||
*/
|
||||
this.reinit = Q.async(function() {
|
||||
var start = (new Date()).getTime();
|
||||
var transactionStarted = false;
|
||||
|
||||
_cache = {"import":[], "export":[], "web":[], "search":[]};
|
||||
_translators = {};
|
||||
|
||||
var dbCacheResults = yield Zotero.DB.queryAsync("SELECT leafName, translatorJSON, "+
|
||||
"code, lastModifiedTime FROM translatorCache");
|
||||
var dbCache = {};
|
||||
for each(var cacheEntry in dbCacheResults) {
|
||||
dbCache[cacheEntry.leafName] = cacheEntry;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var filesInCache = {};
|
||||
var contents = Zotero.getTranslatorsDirectory().directoryEntries;
|
||||
while(contents.hasMoreElements()) {
|
||||
var file = contents.getNext().QueryInterface(Components.interfaces.nsIFile);
|
||||
var leafName = file.leafName;
|
||||
if(!(/^[^.].*\.js$/.test(leafName))) continue;
|
||||
var lastModifiedTime = file.lastModifiedTime;
|
||||
|
||||
var dbCacheEntry = false;
|
||||
if(dbCache[leafName]) {
|
||||
filesInCache[leafName] = true;
|
||||
if(dbCache[leafName].lastModifiedTime == lastModifiedTime) {
|
||||
dbCacheEntry = dbCache[file.leafName];
|
||||
}
|
||||
}
|
||||
|
||||
if(dbCacheEntry) {
|
||||
// get JSON from cache if possible
|
||||
var translator = Zotero.Translators.load(file, dbCacheEntry.translatorJSON, dbCacheEntry.code);
|
||||
filesInCache[leafName] = true;
|
||||
} else {
|
||||
// otherwise, load from file
|
||||
var translator = yield Zotero.Translators.loadFromFile(file);
|
||||
}
|
||||
|
||||
if(translator.translatorID) {
|
||||
if(_translators[translator.translatorID]) {
|
||||
// same translator is already cached
|
||||
translator.logError('Translator with ID '+
|
||||
translator.translatorID+' already loaded from "'+
|
||||
_translators[translator.translatorID].file.leafName+'"');
|
||||
} else {
|
||||
// add to cache
|
||||
_translators[translator.translatorID] = translator;
|
||||
for(var type in TRANSLATOR_TYPES) {
|
||||
if(translator.translatorType & TRANSLATOR_TYPES[type]) {
|
||||
_cache[type].push(translator);
|
||||
}
|
||||
}
|
||||
|
||||
if(!dbCacheEntry) {
|
||||
var code = yield translator.getCode();
|
||||
yield Zotero.Translators.cacheInDB(
|
||||
leafName,
|
||||
translator.serialize(TRANSLATOR_REQUIRED_PROPERTIES.
|
||||
concat(TRANSLATOR_OPTIONAL_PROPERTIES)),
|
||||
translator.cacheCode ? translator.code : null,
|
||||
lastModifiedTime
|
||||
);
|
||||
delete translator.metadataString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// Remove translators from DB as necessary
|
||||
for(var leafName in dbCache) {
|
||||
if(!filesInCache[leafName]) {
|
||||
yield Zotero.DB.queryAsync(
|
||||
"DELETE FROM translatorCache WHERE leafName = ?", [leafName]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by priority
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
var cmp = function (a, b) {
|
||||
if (a.priority > b.priority) {
|
||||
return 1;
|
||||
}
|
||||
else if (a.priority < b.priority) {
|
||||
return -1;
|
||||
}
|
||||
return collation.compareString(1, a.label, b.label);
|
||||
}
|
||||
for(var type in _cache) {
|
||||
_cache[type].sort(cmp);
|
||||
}
|
||||
|
||||
Zotero.debug("Cached "+i+" translators in "+((new Date()).getTime() - start)+" ms");
|
||||
});
|
||||
this.init = Zotero.lazy(this.reinit);
|
||||
|
||||
/**
|
||||
* Loads a translator from JSON, with optional code
|
||||
*/
|
||||
this.load = function(file, json, code) {
|
||||
var info = JSON.parse(json);
|
||||
info.file = file;
|
||||
info.code = code;
|
||||
return new Zotero.Translator(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a translator from the disk
|
||||
*/
|
||||
this.loadFromDisk = function(file) {
|
||||
const infoRe = /^\s*{[\S\s]*?}\s*?[\r\n]/;
|
||||
Zotero.File.getContentsAsync(this.file).then(function(source) {
|
||||
return Zotero.Translators.load(file, infoRe.exec(source)[0], source);
|
||||
}).fail(function() {
|
||||
throw "Invalid or missing translator metadata JSON object in " + file.leafName;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translator that corresponds to a given ID
|
||||
* @param {String} id The ID of the translator
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned.
|
||||
*/
|
||||
this.get = function(id) {
|
||||
return this.init().then(function() {
|
||||
return _translators[id] ? _translators[id] : false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all translators for a specific type of translation
|
||||
* @param {String} type The type of translators to get (import, export, web, or search)
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned.
|
||||
*/
|
||||
this.getAllForType = function(type) {
|
||||
return this.init().then(function() {
|
||||
return _cache[type].slice();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all translators for a specific type of translation
|
||||
*/
|
||||
this.getAll = function() {
|
||||
return this.init().then(function() {
|
||||
return [translator for each(translator in _translators)];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets web translators for a specific location
|
||||
* @param {String} uri The URI for which to look for translators
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned. The callback is passed a set of functions for
|
||||
* converting URLs from proper to proxied forms as the second
|
||||
* argument.
|
||||
*/
|
||||
this.getWebTranslatorsForLocation = function(uri, callback) {
|
||||
return this.getAllForType("web").then(function(allTranslators) {
|
||||
var potentialTranslators = [];
|
||||
|
||||
var properHosts = [];
|
||||
var proxyHosts = [];
|
||||
|
||||
var properURI = Zotero.Proxies.proxyToProper(uri);
|
||||
var knownProxy = properURI !== uri;
|
||||
if(knownProxy) {
|
||||
// if we know this proxy, just use the proper URI for detection
|
||||
var searchURIs = [properURI];
|
||||
} else {
|
||||
var searchURIs = [uri];
|
||||
|
||||
// if there is a subdomain that is also a TLD, also test against URI with the domain
|
||||
// dropped after the TLD
|
||||
// (i.e., www.nature.com.mutex.gmu.edu => www.nature.com)
|
||||
var m = /^(https?:\/\/)([^\/]+)/i.exec(uri);
|
||||
if(m) {
|
||||
// First, drop the 0- if it exists (this is an III invention)
|
||||
var host = m[2];
|
||||
if(host.substr(0, 2) === "0-") host = host.substr(2);
|
||||
var hostnames = host.split(".");
|
||||
for(var i=1; i<hostnames.length-2; i++) {
|
||||
if(TLDS[hostnames[i].toLowerCase()]) {
|
||||
var properHost = hostnames.slice(0, i+1).join(".");
|
||||
searchURIs.push(m[1]+properHost+uri.substr(m[0].length));
|
||||
properHosts.push(properHost);
|
||||
proxyHosts.push(hostnames.slice(i+1).join("."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.debug("Translators: Looking for translators for "+searchURIs.join(", "));
|
||||
|
||||
var converterFunctions = [];
|
||||
for(var i=0; i<allTranslators.length; i++) {
|
||||
for(var j=0; j<searchURIs.length; j++) {
|
||||
if((!allTranslators[i].webRegexp
|
||||
&& allTranslators[i].runMode === Zotero.Translator.RUN_MODE_IN_BROWSER)
|
||||
|| (uri.length < 8192 && allTranslators[i].webRegexp.test(searchURIs[j]))) {
|
||||
// add translator to list
|
||||
potentialTranslators.push(allTranslators[i]);
|
||||
|
||||
if(j === 0) {
|
||||
if(knownProxy) {
|
||||
converterFunctions.push(Zotero.Proxies.properToProxy);
|
||||
} else {
|
||||
converterFunctions.push(null);
|
||||
}
|
||||
} else {
|
||||
converterFunctions.push(new function() {
|
||||
var re = new RegExp('^https?://(?:[^/]\\.)?'+Zotero.Utilities.quotemeta(properHosts[j-1]), "gi");
|
||||
var proxyHost = proxyHosts[j-1].replace(/\$/g, "$$$$");
|
||||
return function(uri) { return uri.replace(re, "$&."+proxyHost) };
|
||||
});
|
||||
}
|
||||
|
||||
// don't add translator more than once
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [potentialTranslators, converterFunctions];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets import translators for a specific location
|
||||
* @param {String} location The location for which to look for translators
|
||||
* @param {Function} [callback] An optional callback to be executed when translators have been
|
||||
* retrieved. If no callback is specified, translators are
|
||||
* returned.
|
||||
*/
|
||||
this.getImportTranslatorsForLocation = function(location, callback) {
|
||||
return Zotero.Translators.getAllForType("import").then(function(allTranslators) {
|
||||
var tier1Translators = [];
|
||||
var tier2Translators = [];
|
||||
|
||||
for(var i=0; i<allTranslators.length; i++) {
|
||||
if(allTranslators[i].importRegexp && allTranslators[i].importRegexp.test(location)) {
|
||||
tier1Translators.push(allTranslators[i]);
|
||||
} else {
|
||||
tier2Translators.push(allTranslators[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var translators = tier1Translators.concat(tier2Translators);
|
||||
if(callback) {
|
||||
callback(translators);
|
||||
return true;
|
||||
}
|
||||
return translators;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} label
|
||||
* @return {String}
|
||||
*/
|
||||
this.getFileNameFromLabel = function(label, alternative) {
|
||||
var fileName = Zotero.Utilities.removeDiacritics(
|
||||
Zotero.File.getValidFileName(label)) + ".js";
|
||||
// Use translatorID if name still isn't ASCII (e.g., Cyrillic)
|
||||
if (alternative && !fileName.match(/^[\x00-\x7f]+$/)) {
|
||||
fileName = alternative + ".js";
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} metadata
|
||||
* @param {String} metadata.translatorID Translator GUID
|
||||
* @param {Integer} metadata.translatorType See TRANSLATOR_TYPES in translate.js
|
||||
* @param {String} metadata.label Translator title
|
||||
* @param {String} metadata.creator Translator author
|
||||
* @param {String|Null} metadata.target Target regexp
|
||||
* @param {String|Null} metadata.minVersion
|
||||
* @param {String} metadata.maxVersion
|
||||
* @param {String|undefined} metadata.configOptions
|
||||
* @param {String|undefined} metadata.displayOptions
|
||||
* @param {Integer} metadata.priority
|
||||
* @param {String} metadata.browserSupport
|
||||
* @param {Boolean} metadata.inRepository
|
||||
* @param {String} metadata.lastUpdated SQL date
|
||||
* @param {String} code
|
||||
* @return {Promise<nsIFile>}
|
||||
*/
|
||||
this.save = function(metadata, code) {
|
||||
if (!metadata.translatorID) {
|
||||
throw ("metadata.translatorID not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.translatorType) {
|
||||
var found = false;
|
||||
for each(var type in TRANSLATOR_TYPES) {
|
||||
if (metadata.translatorType & type) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw ("Invalid translatorType '" + metadata.translatorType + "' in Zotero.Translators.save()");
|
||||
}
|
||||
}
|
||||
|
||||
if (!metadata.label) {
|
||||
throw ("metadata.label not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.priority) {
|
||||
throw ("metadata.priority not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.lastUpdated) {
|
||||
throw ("metadata.lastUpdated not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
throw ("code not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
var fileName = Zotero.Translators.getFileNameFromLabel(
|
||||
metadata.label, metadata.translatorID
|
||||
);
|
||||
var destFile = Zotero.getTranslatorsDirectory();
|
||||
destFile.append(fileName);
|
||||
|
||||
// JSON.stringify has the benefit of indenting JSON
|
||||
var metadataJSON = JSON.stringify(metadata, null, "\t");
|
||||
|
||||
var str = metadataJSON + "\n\n" + code,
|
||||
translator;
|
||||
|
||||
return Zotero.Translators.get(metadata.translatorID)
|
||||
.then(function(gTranslator) {
|
||||
translator = gTranslator;
|
||||
var sameFile = translator && destFile.equals(translator.file);
|
||||
if (sameFile) return;
|
||||
|
||||
return Q(OS.File.exists(destFile.path))
|
||||
.then(function (exists) {
|
||||
if (exists) {
|
||||
var msg = "Overwriting translator with same filename '"
|
||||
+ fileName + "'";
|
||||
Zotero.debug(msg, 1);
|
||||
Zotero.debug(metadata, 1);
|
||||
Components.utils.reportError(msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
if (!translator) return;
|
||||
|
||||
return Q(OS.File.exists(translator.file.path))
|
||||
.then(function (exists) {
|
||||
translator.file.remove(false);
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
Zotero.debug("Saving translator '" + metadata.label + "'");
|
||||
Zotero.debug(str);
|
||||
return Zotero.File.putContentsAsync(destFile, str)
|
||||
.thenResolve(destFile);
|
||||
});
|
||||
}
|
||||
|
||||
this.cacheInDB = function(fileName, metadataJSON, code, lastModifiedTime) {
|
||||
return Zotero.DB.queryAsync(
|
||||
"REPLACE INTO translatorCache VALUES (?, ?, ?, ?)",
|
||||
[fileName, metadataJSON, code, lastModifiedTime]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -96,7 +96,6 @@ Zotero.Utilities.Internal = {
|
|||
* rather than hex string
|
||||
*/
|
||||
"md5Async": function (file, base64) {
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
const CHUNK_SIZE = 16384;
|
||||
|
||||
var deferred = Q.defer();
|
||||
|
|
|
@ -44,6 +44,7 @@ const ZOTERO_CONFIG = {
|
|||
Components.utils.import("resource://zotero/q.js");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
/*
|
||||
* Core functions
|
||||
|
|
|
@ -44,6 +44,7 @@ const xpcomFilesAll = [
|
|||
'progressWindow',
|
||||
'translation/translate',
|
||||
'translation/translate_firefox',
|
||||
'translation/translator',
|
||||
'translation/tlds',
|
||||
'utilities',
|
||||
'utilities_internal',
|
||||
|
@ -104,7 +105,7 @@ const xpcomFilesLocal = [
|
|||
'timeline',
|
||||
'uri',
|
||||
'translation/translate_item',
|
||||
'translation/translator',
|
||||
'translation/translators',
|
||||
'server_connector'
|
||||
];
|
||||
|
||||
|
|
Loading…
Reference in a new issue