Skip to content

Instantly share code, notes, and snippets.

Created April 26, 2012 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/2499686 to your computer and use it in GitHub Desktop.
Save anonymous/2499686 to your computer and use it in GitHub Desktop.
Slightly improved ZotFile.js (with file move error handling)
Zotero.ZotFile = {
prefs: null,
wm: null,
fileMap: {}, //maps collections to their file objects
folderSep:null,
projectNr: new Array("01","02","03","04","05","06","07","08","09","10","11","12","13","14","15"),
projectPath: new Array("","","","","","","","","","","","","","",""),
projectMax:15,
zotfileURL:"http://www.columbia.edu/~jpl2136/zotfile.html",
temp:"",
// ========================= //
// FUNCTIONS: INIT FUNCTIONS //
// ========================= //
firstRun: function() {
// transfer preferences and uninstall zotreader
if(!Zotero.isFx36) AddonManager.getAddonByID("zotreader@columbia.edu",function(aAddon) {
// transfer preferences
Zotero.ZotFile.prefs.setCharPref("tablet.dest_dir",Zotero.ZotReader.prefs.getCharPref("dest_dir"));
Zotero.ZotFile.prefs.setCharPref("tablet.subfolderFormat",Zotero.ZotReader.prefs.getCharPref("subfolderFormat"));
Zotero.ZotFile.prefs.setBoolPref("tablet.subfolder",Zotero.ZotReader.prefs.getBoolPref("subfolder"));
Zotero.ZotFile.prefs.setIntPref("tablet.mode",Zotero.ZotReader.prefs.getIntPref("mode"));
Zotero.ZotFile.prefs.setIntPref("tablet.projectFolders",Zotero.ZotReader.prefs.getIntPref("projectFolders"));
Zotero.ZotFile.prefs.setIntPref("tablet.mode",Zotero.ZotReader.prefs.getIntPref("mode"));
for (i=0;i<Zotero.ZotFile.projectMax;i++) {
Zotero.ZotFile.prefs.setBoolPref("tablet.projectFolders"+Zotero.ZotFile.projectNr[i],Zotero.ZotReader.prefs.getBoolPref("projectFolders"+Zotero.ZotFile.projectNr[i]));
Zotero.ZotFile.prefs.setCharPref("tablet.projectFolders"+Zotero.ZotFile.projectNr[i]+"_folder",Zotero.ZotReader.prefs.getCharPref("projectFolders"+Zotero.ZotFile.projectNr[i]+"_folder"));
Zotero.ZotFile.prefs.setCharPref("tablet.projectFolders"+Zotero.ZotFile.projectNr[i]+"_label",Zotero.ZotReader.prefs.getCharPref("projectFolders"+Zotero.ZotFile.projectNr[i]+"_label"));
}
Zotero.ZotFile.prefs.setBoolPref("tablet",true);
//uninstall zotreader
aAddon.uninstall();
// prompt for restart
if (confirm("ZotFile has transfered most of your preferences from ZotFile Reader to the new version of ZotFile and uninstalled the ZotFile Reader add-on.\n\nPlease restart Firefox now!")) {
var boot = Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(Components.interfaces.nsIAppStartup);
boot.quit(Components.interfaces.nsIAppStartup.eForceQuit|Components.interfaces.nsIAppStartup.eRestart);
}
});
},
versionChanges: function (currentVersion) {
// open webpage
if(this.prefs.getCharPref("version")==="" || currentVersion=="2.0") {
if(!Zotero.isStandalone) this.futureRun(function(){gBrowser.selectedTab = gBrowser.addTab(Zotero.ZotFile.zotfileURL); });
if( Zotero.isStandalone) this.futureRun(function(){ZoteroPane_Local.loadURI(Zotero.ZotFile.zotfileURL); });
}
// add saved search and change tag when upgrading to 2.1
if(currentVersion=="2.1" && this.prefs.getBoolPref("tablet")) {
// create saved search for modified tablet items
this.createSavedSearch("tablet_modified");
if(Zotero.Tags.getID("_READ",0)!==false) {
try {
// change tablet tag
Zotero.Tags.rename(Zotero.Tags.getID("_READ",0), "_tablet");
// show message
this.infoWindow("ZotFile Warning","In ZotFile 2.1, the tag for tablet attachments was changed from '_READ' to '_tablet'. Please do not use or change the '_tablet' tag manually!",8000);
} catch (ex) {
alert("Warning: ZotFile has changed the tag for attachments on the tablet from '_READ' to '_tablet' but was unable to automatically change the existing tag. Please make the changes manually or ask for help in the zotfile thread on the zotero forum.");
}
}
// change saved searches
var searches=Zotero.Searches.getAll();
for(var i=0; i<searches.length;i++ ) {
var conditions=searches[i].getSearchConditions();
for(var j=1; j<conditions.length;j++ ) {
if(conditions[j].condition=="tag" && conditions[j].value=="_READ") {
searches[i].updateCondition(conditions[j].id,'tag',conditions[j].operator,'_tablet');
searches[i].save();
}
}
}
}
// set current version
this.prefs.setCharPref("version",currentVersion);
// code for specific version upgrades
// if(currentVersion=="2.1" && oldVersion!="2.1")
},
init: function () {
// only do this stuff for the first run
if(this.prefs===null) {
//get preference objects
this.prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService);
this.prefs = this.prefs.getBranch("extensions.zotfile.");
this.ffPrefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).getBranch("browser.download.");
this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
// set source dir to custom folder if zotero standalone
if(Zotero.isStandalone && this.prefs.getBoolPref('source_dir_ff')) this.prefs.setBoolPref('source_dir_ff',false);
// version handeling
var oldVersion=this.prefs.getCharPref("version");
if(!Zotero.isFx36) Components.utils.import("resource://gre/modules/AddonManager.jsm");
// if first run, check for zotfile reader and transfer preferences
if (oldVersion=="") this.firstRun();
// update current version
if(!Zotero.isFx36) AddonManager.getAddonByID("zotfile@columbia.edu",function(aAddon) {
var currentVersion=aAddon.version;
// if different version then previously
if(currentVersion!=oldVersion) Zotero.ZotFile.versionChanges(currentVersion);
});
if(Zotero.isFx36) {
var em = Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager);
var addon = em.getItemForID("zotfile@columbia.edu");
if(addon.version!=oldVersion) this.versionChanges(addon.version);
}
// run in future to not burden start-up
this.futureRun(function(){
// determine folder seperator depending on OS
Zotero.ZotFile.folderSep="/";
if (Zotero.isWin) Zotero.ZotFile.folderSep="\\";
// check whether extraction of annotations is supported
if (Zotero.ZotFile.pdfAnnotations.popplerSupportedPlatforms.join().indexOf(Zotero.platform)!=-1) Zotero.ZotFile.pdfAnnotations.popplerExtractorSupported=true;
// set path and check whether installed
if (Zotero.ZotFile.pdfAnnotations.popplerExtractorSupported) {
// set Extractor Path
Zotero.ZotFile.pdfAnnotations.popplerExtractorSetPath();
// check whether tool is installed
Zotero.ZotFile.pdfAnnotations.popplerExtractorTool=Zotero.ZotFile.pdfAnnotations.popplerExtractorCheckInstalled();
// set to pdf.js if poppler is not installed
if(!Zotero.ZotFile.pdfAnnotations.popplerExtractorTool) Zotero.ZotFile.prefs.setBoolPref("pdfExtraction.UsePDFJS",true);
}
// set to pdf.js if poppler is not supported
if(!Zotero.ZotFile.pdfAnnotations.popplerExtractorSupported) Zotero.ZotFile.prefs.setBoolPref("pdfExtraction.UsePDFJS",true);
});
}
// add event listener for zotfile menu items
var win = this.wm.getMostRecentWindow("navigator:browser");
win.document.getElementById('zotero-itemmenu').addEventListener('popupshowing', this.showMenu, false);
// add event listener for selecting the 'modified tablet attachments' saved search
if(this.prefs.getBoolPref("tablet")) this.savedSearchEventListener(true);
// show items in right-click menu conditional on options using an event listener
// CODE NOT IMPLEMENTED (just to remember how it works if needed)
/*var cm = document.getElementById('zotero-itemmenu');
cm.addEventListener("popupshowing", this.showMenu, false);
// Register the callback in Zotero as an item observer
var notifierID = Zotero.Notifier.registerObserver(this.notifierCallback, ['item']);*/
},
savedSearchEventListener: function(activate) {
var win = this.wm.getMostRecentWindow("navigator:browser");
if(activate) win.document.getElementById('zotero-collections-tree').addEventListener('click', this.updateModifiedAttachmentsSearch, false);
if(!activate) win.document.getElementById('zotero-collections-tree').removeEventListener('click', this.updateModifiedAttachmentsSearch, false);
},
/*showMenu: function(event) {
Zotero.ZotFile.infoWindow("ZotFile Report","event fired!",8000);
},*/
// ============================ //
// FUNCTIONS: HELPER FUNCTIONS //
// ============================ //
// detect duplicates in array
removeDuplicates: function (x) {
x = x.sort();
var y = [];
y.push(x[0]);
for (var i=1; i < (x.length); i++) {
if (x[i-1] != x[i]) y.push(x[i]);
}
return(y);
},
// search and replace in array
arrayReplace: function (x,search, replace) {
for(var i=0; i<x.length;i++ ) {
if(x[i]==search) x.splice(i,1,replace);
}
return(x);
},
getSelectedAttachments: function () {
// get selected items
var win = this.wm.getMostRecentWindow("navigator:browser");
var items = win.ZoteroPane.getSelectedItems();
// create array of attachments to pull
var attIDs=[];
for (var i=0; i < items.length; i++) {
var item = items[i];
// regular item
if(item.isRegularItem()) {
// get all attachments
var attachments = item.getAttachments();
// go through all attachments and add those with a tag
for (var j=0; j < attachments.length; j++) attIDs.push(attachments[j]);
}
// attachment item
if(item.isAttachment()) attIDs.push(item.getID());
}
// remove duplicate elements
attIDs=this.removeDuplicates(attIDs);
return(attIDs);
},
futureRun: function(aFunc) {
var tm = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager);
tm.mainThread.dispatch({run: function(){aFunc();}},Components.interfaces.nsIThread.DISPATCH_NORMAL);
},
createSavedSearch: function(which) {
if(which=="tablet" || which=="both") {
var search = new Zotero.Search();
search.addCondition('tag', 'is', this.prefs.getCharPref("tablet.tag"));
search.addCondition('includeParentsAndChildren', 'true');
search.addCondition('noChildren', 'true');
search.setName("Tablet Files");
search.save();
}
if(which=="tablet_modified" || which=="both") {
var search_modified = new Zotero.Search();
search_modified.addCondition('tag', 'is', this.prefs.getCharPref("tablet.tagModified"));
search_modified.setName("Tablet Files (modified)");
search_modified.save();
}
},
// ================== //
// FUNCTIONS: WINDOWS //
// ================== //
openPreferenceWindow: function (paneID, action) {
var io = {
pane: paneID,
action: action
};
window.openDialog('chrome://zotfile/content/options.xul',
'zotfile-options',
'chrome,titlebar,toolbar,centerscreen'+ Zotero.Prefs.get('browser.preferences.instantApply', true) ? 'dialog=no' : 'modal',io
);
},
openSubfolderWindow: function (paneID, action) {
var io = {
pane: paneID,
action: action
};
var prefWindow=window.openDialog('chrome://zotfile/content/options-projects.xul',
'zotfile-tablet-subfolders',
'chrome,titlebar,toolbar,centerscreen'+ Zotero.Prefs.get('browser.preferences.instantApply', true) ? 'dialog=no' : 'modal',io
);
},
chooseDirectory: function () {
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow('navigator:browser');
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var nsIFilePicker = Components.interfaces.nsIFilePicker;
while (true) {
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
fp.init(win, Zotero.getString('dataDir.selectDir'), nsIFilePicker.modeGetFolder);
fp.appendFilters(nsIFilePicker.filterAll);
if (fp.show() == nsIFilePicker.returnOK) {
var file = fp.file;
// Set preference
//Zotero.ZotFile.prefs.setCharPref(pref,file.path);
return(file.path);
}
else {
return("");
}
}
},
infoWindow: function(main, message, time){
var pw = new (Zotero.ProgressWindow);
pw.changeHeadline(main);
if (main=="error") pw.changeHeadline(Zotero.getString("general.errorHasOccurred")); pw.addDescription(message);
pw.show();
pw.startCloseTimer(time);
},
promptUser: function(message,option1,option2,option3) {
var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var check = {value: false}; // default the checkbox to false
var flags = prompts.BUTTON_POS_0 * prompts.BUTTON_TITLE_IS_STRING +
prompts.BUTTON_POS_1 * prompts.BUTTON_TITLE_IS_STRING +
prompts.BUTTON_POS_2 * prompts.BUTTON_TITLE_IS_STRING;
var button = prompts.confirmEx(null, "ZotFile Dialog", message,
flags, option1,option2,option3, null, check);
// this.infoWindow("ZotReader Report","button " + button,8000);
return(button);
},
// ======================= //
// FUNCTIONS: ZOTFILE MENU //
// ======================= //
showMenu: function() {
var showMenu=false;
// get selected items
var win = Zotero.ZotFile.wm.getMostRecentWindow("navigator:browser");
var items = win.ZoteroPane.getSelectedItems();
//iterate through selected items
for (var i=0; i < items.length; i++) {
if(items[i].isAttachment() || items[i].isRegularItem()) {
showMenu=true;
break;
}
}
// show or hide zotfile menu items
win.document.getElementById("id-zotfile-separator").hidden = !showMenu;
win.document.getElementById("id-zotfile-attach-file").hidden = !showMenu;
win.document.getElementById("id-zotfile-manage-attachments").hidden = !showMenu;
},
buildZotFileMenu: function () {
var menuItemExtract=true;
// get selected items
var win = this.wm.getMostRecentWindow("navigator:browser");
var items = win.ZoteroPane.getSelectedItems();
var item;
// get menu and recreate structure of child items
var menu = win.ZoteroPane.document.getElementById('id-zotfile-menu');
var m = {
warning1:0,
rename: 1,
extractanno: 2,
sep1: 3,
warning2: 4,
push2reader: 5,
updatefile: 6,
pullreader: 7,
sep2: 8,
subfolders: 9,
warning3: 10,
push2readerFolder:new Array(11,12,13,14,15,16,17,18,19,20,21,22,23,24,25),
sep3: 26,
menuConfigure: 27,
length:28
};
// list of disabled and show menu-items
var disable = [m.subfolders,m.warning1,m.warning2,m.warning3], show = [];
// check selected items
var groupLib=1;
if (!items[0].libraryID) groupLib=0;
var oneItem=0;
var oneAtt=0;
var onePushed=0;
for (var i=0; i < items.length; i++) {
item=items[i];
if(item.isRegularItem()) {
oneItem=1;
// get all attachments
var attachments = item.getAttachments();
// go through all attachments
for (var j=0; j < attachments.length; j++) {
oneAtt=1;
// get current attachments
var att = Zotero.Items.get(attachments[j]);
if(att.hasTag(Zotero.Tags.getID(this.prefs.getCharPref("tablet.tag"),0))) onePushed=1;
}
}
// attachment item
if(item.isAttachment()) {
oneAtt=1;
oneItem=1;
if(item.hasTag(Zotero.Tags.getID(this.prefs.getCharPref("tablet.tag"),0))) onePushed=1;
}
if(onePushed==1) break;
}
// check whether destitination folder is defined (and valid)
var dest_dir_valid=this.fileExists(this.prefs.getCharPref("tablet.dest_dir"));
// if(this.prefs.getCharPref("tablet.dest_dir")!="") var dest_dir_valid=1;
// warnings
if(!oneItem) {
show.push(m.warning1);
menu.childNodes[m.warning1].setAttribute('label',"No item or attachment selected.");
}
// at least one item and one attachment
if(oneItem) {
// add 'new att' and 'rename'
show = [
m.rename
];
// warning
if(!oneAtt) {
disable.push(m.rename, m.extractanno);
show.push(m.sep1,m.warning2);
menu.childNodes[m.warning2].setAttribute('label',"Selected item(s) have no attachments.");
}
// add 'Extract annotations'
if(this.prefs.getBoolPref("pdfExtraction.MenuItem")) show.push(m.extractanno);
// tablet menu part
if(this.prefs.getBoolPref("tablet") && oneAtt) {
// add sep
show.push(m.sep1);
// warnings
if(!dest_dir_valid) {
show.push(m.warning2);
menu.childNodes[m.warning2].setAttribute('label',"Location for tablet files is not defined or invalid.");
}
if(groupLib) {
show.push(m.warning2);
menu.childNodes[m.warning2].setAttribute('label',"Selected item is in group library.");
}
if(dest_dir_valid && !groupLib) {
show.push(m.push2reader,m.pullreader);
// set tooltip for base folder
menu.childNodes[m.push2reader].setAttribute('tooltiptext',"Send Attachment File to \'" + this.prefs.getCharPref("tablet.dest_dir") + "\'");
if(!onePushed) disable.push(m.pullreader);
// add update menu item
if(this.checkSelectedSearch() || this.prefs.getBoolPref("tablet.updateAlwaysShow")) {
show.push(m.updatefile);
if(!onePushed) disable.push(m.updatefile);
}
// Collection based project folders
var projectsSet=0;
if(this.prefs.getIntPref("tablet.projectFolders")==1) {
show.push(m.sep2,m.subfolders);
// get first selected item
item=items[0];
if(item.isAttachment()) if(item.getSource()) item=Zotero.Items.get(item.getSource());
// create folders from collections
var folders = [];
var collections=item.getCollections();
for (i=0;i<collections.length;i++) {
var collection=Zotero.Collections.get(collections[i]);
var folder=this.folderSep + collection.getName();
var parent=collection.getParent();
while (parent) {
parent=Zotero.Collections.get(parent);
folder=this.folderSep + parent.getName() + folder;
parent=parent.getParent();
}
folders.push(folder);
}
// add folders to menu
if(folders.length) {
projectsSet=1;
folders=folders.sort();
for (i=0;i<folders.length;i++) {
show.push(m.push2readerFolder[i]);
menu.childNodes[m.push2readerFolder[i]].setAttribute('label',folders[i]);
menu.childNodes[m.push2readerFolder[i]].setAttribute('tooltiptext',"Send Attachment File to \'..." + folders[i] + "\'");
this.projectPath[i]=folders[i];
if(i>9) break;
}
}
}
// User defined project folders
if(this.prefs.getIntPref("tablet.projectFolders")==2) {
show.push(m.sep2,m.subfolders,m.sep3,m.menuConfigure);
for (i=0;i<this.projectMax;i++) {
if(this.prefs.getBoolPref("tablet.projectFolders" + this.projectNr[i])) {
show.push(m.push2readerFolder[i]);
menu.childNodes[m.push2readerFolder[i]].setAttribute('label', this.prefs.getCharPref("tablet.projectFolders" + this.projectNr[i] +"_label"));
menu.childNodes[m.push2readerFolder[i]].setAttribute('tooltiptext',"Send Attachment File to \'..." + this.prefs.getCharPref("tablet.projectFolders" + this.projectNr[i] +"_folder") + "\'");
projectsSet=1;
}
}
}
// message that no folders are defined
if(!projectsSet && this.prefs.getIntPref("tablet.projectFolders")!=0) {
var warning;
show.push(m.warning3);
if(this.prefs.getIntPref("tablet.projectFolders")==1) warning="Item is in no collection.";
if(this.prefs.getIntPref("tablet.projectFolders")==2) warning="No subfolders defined.";
menu.childNodes[m.warning3].setAttribute('label', warning);
}
}
}
}
// enable all items by default
for (i=0;i<m.length;i++) menu.childNodes[i].setAttribute('disabled', false);
// disable menu items
for (i in disable) menu.childNodes[disable[i]].setAttribute('disabled', true);
// Hide all items by default
for (i=0;i<m.length;i++) menu.childNodes[i].setAttribute('hidden', true);
// Show items
for (i in show) menu.childNodes[show[i]].setAttribute('hidden', false);
},
// =================================== //
// FUNCTIONS: GET FILE- & FOLDER NAME //
// =================================== //
addUserInput: function(filename, original_filename){
var default_str = this.prefs.getCharPref("userInput_Default");
if (default_str=="[original filename]") default_str=original_filename;
var filesuffix = prompt("Enter file suffix (press Cancel to add nothing)\n\nOriginal Filename\n"+original_filename+"\n\nNew Filename\n"+filename + " (YOUR INPUT)", default_str);
if (filesuffix != '' && filesuffix != null) {
// add file type to the file name
filename = filename + " (" + filesuffix + ")";
}
return(filename);
},
truncateTitle: function(title){
// truncnate title after : . and ?
if(this.prefs.getBoolPref("truncate_title")) {
var truncate = title.search(/:|\.|\?/);
if(truncate!=-1) title = title.substr(0,truncate);
}
// truncate if to long
var title_length = title.length;
if (title_length>this.prefs.getIntPref("max_titlelength")) {
var max_titlelength=this.prefs.getIntPref("max_titlelength");
var before_trunc_char = title.substr(max_titlelength,1);
// truncate title at max length
title = title.substr(0,max_titlelength);
// remove the last word until a space is found
if(this.prefs.getBoolPref("truncate_smart") && title.search(" ")!=-1 && before_trunc_char.search(/[a-zA-Z0-9]/!=-1)) {
while (title.substring(title.length-1, title.length) != ' ') title = title.substring(0, title.length-1);
title = title.substring(0, title.length-1);
}
} else {
// remove some non letter characters if they apear at the end of the title that was not truncated
var endchar = title.substring(title.length-1, title.length);
if (endchar == ':' || endchar == '?' || endchar == '.' || endchar == '/' || endchar == '\\' || endchar == '>' || endchar == '<' || endchar == '*' || endchar == '|') {
title = title.substring(0, title.length-1);
}
}
// replace forbidden characters with meaningful alternatives (they can only apear in the middle of the text at this point)
title = title.replace(/[\/\\]/g, '-');
title = title.replace(/[\*|"<>]/g, '');
title = title.replace(/[\?:]/g, ' -');
return(title);
},
// Function replaces wildcard both for filename and subfolder definition
replaceWildcard: function(zitem, rule){
// get item type
var item_type = zitem.getType();
var item_type_string = Zotero.ItemTypes.getLocalizedString(item_type);
// get title of selected item
var title = zitem.getField('title');
// truncnate title
title = this.truncateTitle(title);
// get journal
var journal = zitem.getField('publicationTitle');
// get journal abbreviation
var journal_abb = zitem.getField('journalAbbreviation');
// get publisher
var publisher = zitem.getField('publisher');
// get volume and issue
var volume = zitem.getField('volume');
var issue = zitem.getField('issue');
// get patent stuff
// var inventor
var assignee = zitem.getField('assignee');
var patentnr = zitem.getField('patentNumber');
var priority_date = patentnr.substr(2,4);
// get creator and create authors string
// creator types: author/editor(1,3) for book(2), inventor(14) for patent(19),programmer(24) for computer prog.(27),presenter(21) for presentation(32)
var creatorType=[1];
if (zitem.getType()==2) creatorType=[1,3];
if (zitem.getType()==19) creatorType=[14];
if (zitem.getType()==32) creatorType=[21];
if (zitem.getType()==27) creatorType=[24];
var add_etal=this.prefs.getBoolPref("add_etal");
var author = "";
var creators = zitem.getCreators();
var numauthors = creators.length;
for (var i=0; i < creators.length; i++) {
if(creatorType.indexOf(creators[i].creatorTypeID)==-1) numauthors=numauthors-1;
}
var max_authors=(this.prefs.getBoolPref("truncate_authors")) ? this.prefs.getIntPref("max_authors") : 500;
if (numauthors<=max_authors) add_etal=0;
if (numauthors>max_authors) numauthors = 1;
var j=0;
for (i=0; i < creators.length; i++) {
if (j<numauthors && creatorType.indexOf(creators[i].creatorTypeID)!=-1) {
if (author!="") author = author + "_" + creators[i].ref.lastName;
if (author=="") author = creators[i].ref.lastName;
j=j+1;
}
}
if (add_etal==1) author = author + this.prefs.getCharPref("etal");
// date
var year_issue="";
var year = zitem.getField('date', true).substr(0,4);
if(item_type==19) {
year_issue = zitem.getField('issueDate', true).substr(0,4);
year = year_issue;
}
// create output from rule
var field=0;
var output='';
for (i=0; i<rule.length; i++) {
var char=rule.charAt(i);
switch (char) {
case '%':
field=1;
break;
case 'a':
if (field==1) output = output + author;
field=0;
break;
case 'A':
if (field==1) output = output + author.substr(0,1).toUpperCase();
field=0;
break;
case 't':
if (field==1) output = output + title;
field=0;
break;
case 'y':
if (field==1) output = output + year;
field=0;
break;
case 'j':
if (field==1) output = output + journal;
field=0;
break;
case 'p':
if (field==1) output = output + publisher;
field=0;
break;
case 'n':
if (field==1) output = output + patentnr;
field=0;
break;
case 'i':
if (field==1) output = output + assignee;
field=0;
break;
case 'u':
if (field==1) output = output + year_issue;
field=0;
break;
case 'w':
if (field==1) {
output = output + journal;
if(journal=="") output = output + publisher;
}
field=0;
break;
case 's':
if (field==1) output = output + journal_abb;
field=0;
break;
case 'v':
if (field==1) output = output + volume;
field=0;
break;
case 'e':
if (field==1) output = output + issue;
field=0;
break;
case 'T':
if (field==1) output = output + item_type_string;
field=0;
break;
default: output = output + char;
}
}
return(output);
},
getFiletype: function(fname){
if(fname) {
var temp = [];
temp = fname.split('.');
return(temp[temp.length-1].toLowerCase());
}
else {
return("");
}
},
checkFileType: function (file) {
if(!this.prefs.getBoolPref("useFileTypes")) return(true);
// check
var filetype=this.getFiletype(file.leafName);
var type=filetype.search(new RegExp(this.prefs.getCharPref("filetypes").replace(/,/gi,"|")));
if (type>=0) {
return(true);
}
else {
return(false);
}
},
completePath: function(location,filename) {
return (location + this.folderSep + filename);
},
addSuffix: function(filename,k) {
var temp = [];
temp = filename.split('.');
return(temp[0] + k + "." + this.getFiletype(filename));
},
getFilename: function(item,filename_org){
var filename;
// create the new filename from the selected item
var item_type = item.getType();
var rename_rule=this.prefs.getCharPref("renameFormat");
if(item_type==19) rename_rule=this.prefs.getCharPref("renameFormat_patent");
if (!this.prefs.getBoolPref("useZoteroToRename")) {
filename=this.replaceWildcard(item, rename_rule);
//var filename = author + "_" + year + "_" + title;
// Strip potentially invalid characters
// (code line adopted from Zotero)
filename = filename.replace(/[\/\\\?\*:|"<>\.]/g, '');
// replace multiple blanks in filename with single blank & remove whitespace
//var filename = filename.replace(/ {2,}/g, ' ');
filename = Zotero.Utilities.trimInternal(filename);
// replace blanks with '_' if option selected
if (this.prefs.getBoolPref("replace_blanks")) filename = filename.replace(/ /g, '_');
// remove all the accents and other strange characters from filename
if (Zotero.version[0]>=3 && this.prefs.getBoolPref("removeDiacritics")) filename = Zotero.Utilities.removeDiacritics(filename);
}
if (this.prefs.getBoolPref("useZoteroToRename")) filename=Zotero.Attachments.getFileBaseNameFromItem(item.itemID);
if(this.prefs.getBoolPref("userInput")) filename=this.addUserInput(filename,filename_org);
// add filetype to filename
if(filename_org!="") filename = filename + "." + this.getFiletype(filename_org);
// return
filename = Zotero.File.getValidFileName(filename);
return(filename);
},
getLocation: function(zitem, dest_dir,subfolder, rule) {
var subfolderFormat="";
if(subfolder) {
subfolderFormat=this.replaceWildcard(zitem, rule);
if (!Zotero.isWin) subfolderFormat=subfolderFormat.replace('//','/undefined/');
if ( Zotero.isWin) subfolderFormat=subfolderFormat.replace('\\\\','\\undefined\\');
}
// var journal = zitem.getField('publicationTitle');
var folder = dest_dir + subfolderFormat;
return(folder);
//return(folder.replace(/[\?%\*:|"<>]/g, ''));
},
// ================ //
// FUNCTIONS: FILES //
// ================ //
createFile: function(path) {
try {
var file = Components.classes["@mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(path);
return(file);
}
catch (err) {
return(-1);
}
},
// function to check whether a file exists
// argument: path as string (with optional filename), zotero att, or file obj
fileExists: function (arg, filename) {
var file;
// when string is passed
if(typeof(arg)=='string') {
if(filename!=null) arg=this.completePath(arg,filename);
file=this.createFile(arg);
}
// when object (i.e. zotero attachment item) is passed
if(typeof(arg)=='object') {
if( arg.getFile) file=arg.getFile();
if(!arg.getFile) file=arg;
}
// check whether the file exsists
try {
return(file.exists());
}
catch (err) {
return(false);
}
},
moveFile: function(file, destination, filename, att_name){
/* moves 'file' to 'destination' path an renames it to 'filename'; 'att_name' is the attachment title used in error messages
* -> returns the path to the new (created) file, in case of an error: path="NULL"
*/
// file.path!= this.createFile(this.completePath(location, filename)).path
if(file.path!=this.completePath(destination,filename)) {
var filename_temp=filename;
var k=2;
while(this.fileExists(destination, filename_temp)) {
filename_temp = this.addSuffix(filename,k);
k++;
if(k>99)
//TODO There should be a prompt window which let the user choose a name
// If not, it would create an error like file exists or more severe: it will override the existing file
break;
}
filename=filename_temp;
try {
// create a nslFile Object of the destination folder
var dir = this.createFile(destination);
// move file to new location
file.moveTo(dir, filename);
}
catch(err) {
if(err.name == "NS_ERROR_FILE_IS_LOCKED")
this.infoWindow("ZotFile Report",
"ZotFile was unable to move the attachment with name '" + att_name + "' because it is locked. " +
"Probably it is opened in a program, so please close it.",
100000);
else
this.infoWindow("ZotFile Report",
"ZotFile gets an untreated error while moving the attachment with name '" + att_name + ". \n\n" +
"Error details: " + err,
100000);
file.path = "NULL";
}
}
return(file.path);
},
copyFile: function(file, destination, filename){
// create a nslFile Object of the destination folder
var dir = this.createFile(destination);
// check whether already exists and add name if it does
if(file.path!=this.completePath(destination,filename)) {
var filename_temp=filename;
var k=2;
while(this.fileExists(destination,filename_temp)) {
filename_temp = this.addSuffix(filename,k);
k++;
if(k>99) break;
}
filename=filename_temp;
// copy file
file.copyTo(dir, filename);
}
// return file
return(this.createFile(this.completePath(dir.path,filename)));
},
removeFile: function(file) {
if(file.exists()) {
try {
file.remove(false);
}
catch(err){
if(file.isDirectory()) this.infoWindow("ZotFile Report","ZotFile was unable delete the old folder probably because other files are in the folder.",8000);
}
}
},
showFolder: function(folderFile) {
// create folder if it does not exsist
Zotero.File.createDirectoryIfMissing(folderFile);
// open folder in file system
folderFile.QueryInterface(Components.interfaces.nsILocalFile);
try {
folderFile.reveal();
}
catch (e) {
// On platforms that don't support nsILocalFile.reveal() (e.g. Linux), we
// open a small window with a selected read-only textbox containing the
// file path, so the user can open it, Control-c, Control-w, Alt-Tab, and
// Control-v the path into another app
var io = {alertText: folderFile.path};
window.openDialog('chrome://zotero/content/selectableAlert.xul', "zotero-reveal-window", "chrome", io);
}
},
// ============================== //
// FUNCTIONS: ATTACHING NEW FILES //
// ============================== //
getAllFilesInFolder: function(dir_path){
var return_files=[];
// create a nslFile Object for the dir
try {
var dir = this.createFile(dir_path);
var success=0;
// go through all the files in the dir
var files = dir.directoryEntries;
while (files.hasMoreElements()) {
// get one after the other file
var file = files.getNext();
file.QueryInterface(Components.interfaces.nsIFile);
// only look at files which are neither folders nor hidden
if(!file.isDirectory() && !file.isHidden()) {
// is this a file we want to work with?
if (this.checkFileType(file)) {
return_files[success]=file;
success=success+1;
}
}
}
if (success>0) return(return_files);
else return(-1);
} catch (e) {
Components.utils.reportError(e);
return (-2);
}
},
getLastFileInFolder: function(dir_path){
var return_files=[];
// create a nslFile Object for the dir
try {
var dir = this.createFile(dir_path);
var lastfile_date=0;
var lastfile_path="";
var success=0;
// go through all the files in the dir
var i=0;
var files = dir.directoryEntries;
while (files.hasMoreElements()) {
// get one after the other file
var file = files.getNext();
file.QueryInterface(Components.interfaces.nsIFile);
// only look at files which are neither folders nor hidden
if(!file.isDirectory() && !file.isHidden()) {
// now we want to check which filetype we are looking at
// we only want to consider pdfs, docs, ...
if (this.checkFileType(file)) {
var modtime = file.lastModifiedTime;
i=i+1;
// finally, we set return_files to the file with the most recent modification
if (modtime>lastfile_date){
lastfile_date=modtime;
return_files[0]=file;
// lastfile=file;
success=1;
}
}
}
}
if (success==1) return(return_files);
else return(-1);
} catch (e) {
Components.utils.reportError(e);
return (-2);
}
},
getFFDownloadFolder: function () {
var path="";
try {
if(this.ffPrefs.getBoolPref('useDownloadDir')) {
var downloadManager = Components.classes["@mozilla.org/download-manager;1"]
.getService(Components.interfaces.nsIDownloadManager);
path=downloadManager.userDownloadsDirectory.path;
}
if(!this.ffPrefs.getBoolPref('useDownloadDir') && this.ffPrefs.prefHasUserValue('lastDir') ) {
path=this.ffPrefs.getCharPref('lastDir');
}
}
catch (err) {
path="";
}
return(path);
},
getSourceDir: function(message) {
var source_dir="";
if ( this.prefs.getBoolPref("source_dir_ff")) source_dir=this.getFFDownloadFolder();
if (!this.prefs.getBoolPref("source_dir_ff")) source_dir=this.prefs.getCharPref("source_dir");
// test whether valid source dir
if (source_dir!="" && this.fileExists(source_dir)) {
return (source_dir);
} else {
if(message) this.infoWindow("ZotFile Error","The source folder is not valid. Please change the the source folder under Zotero-Actions-Zotfile Preferences. You might have to use a custom folder.",8000);
return(-1);
}
},
// FUNCTION: Attach New File(s) from Download Folder
attachNewFile: function(){
var win = this.wm.getMostRecentWindow("navigator:browser");
var items = win.ZoteroPane.getSelectedItems();
// var items = ZoteroPane.getSelectedItems();
var item = items[0];
//check whether it really is an bibliographic item (no Attachment, note or collection)
if (item.isRegularItem()) {
// check whether valid FF default download folder
if(this.prefs.getBoolPref('source_dir_ff') && this.getSourceDir(false)==-1) {
this.prefs.setBoolPref('source_dir_ff',false);
this.prefs.setCharPref('source_dir',prompt("ZotFile Settings\n\nZotfile is not able to determine your default FF download folder. Please enter a custom source dir. The source dir is the directory where ZotFile looks for the most recently modified file when you use the ZotFile function 'Attach New File'."));
return;
}
// get source dir
var source_dir=this.getSourceDir(true);
// exit if getting source dir was not successful
if (source_dir==-1) return;
// get files from source dir
if (!this.prefs.getBoolPref("allFiles")) file=this.getLastFileInFolder(source_dir);
if ( this.prefs.getBoolPref("allFiles")) file=this.getAllFilesInFolder(source_dir);
// attach them
if(file!=-1 && file!=-2) {
for (var i=0; i < file.length; i++) {
// confirmation from user
var file_oldpath=file[i].leafName;
var confirmed=1;
if (this.prefs.getBoolPref("confirmation")) confirmed=confirm("Do you want to rename and attach/link the file \'" + file_oldpath + "\' to the currently selected Zotero item?");
if(confirmed){
var attID;
// create linked attachment if local library
if (!item.libraryID) attID=Zotero.Attachments.linkFromFile(file[i], item.itemID,item.libraryID);
// import attachment if cloud library
if (item.libraryID) {
attID=Zotero.Attachments.importFromFile(file[i], item.itemID,item.libraryID);
this.removeFile(file[i]);
}
// Rename and Move Attachment
var att = Zotero.Items.get(attID);
this.renameAttachment(item, att,this.prefs.getBoolPref("import"),this.prefs.getCharPref("dest_dir"),this.prefs.getBoolPref("subfolder"),this.prefs.getCharPref("subfolderFormat"),true);
}
}
}
else this.infoWindow("Zotfile Error","Unable to find file(s) in " + source_dir,8000);
}
else this.infoWindow("Zotfile Error","Selected item is either an Attachment, a note, or a collection.",8000);
// else this.infoWindow("Zotfile Error","Selected item is in a Group Library.",8000);
},
// ============================ //
// FUNCTIONS: TABLET FUNCTIONS //
// =========================== //
clearInfo: function (att) {
att.setNote("");
att.save();
},
getInfo: function (att,tagname) {
try {
var note = att.getNote();
var search=note.search(tagname);
var content=note.substring(search);
content=content.substring(content.search("{")+1,content.search("}"));
// for location tag: replace [BaseFolder] with destination folder
if(tagname=="location") content=content.replace("[BaseFolder]",this.prefs.getCharPref("tablet.dest_dir"));
return(content);
}
catch (err) {
return("");
}
},
addInfo: function(att,tagname,value) {
var note = att.getNote();
var tag_content=this.getInfo(att,tagname).replace(this.prefs.getCharPref("tablet.dest_dir"),"[BaseFolder]");
// for location tag: replace destination folder with [BaseFolder]
if(tagname=="location" && this.prefs.getBoolPref("tablet.dest_dir_relativePath")) value=value.replace(this.prefs.getCharPref("tablet.dest_dir"),"[BaseFolder]");
// check whether tag already exists
var search=note.search(tagname);
// tag already exists
if (search!=-1) {
att.setNote(note.replace(tagname +"{"+tag_content+"}",tagname +"{"+value+"}"));
}
// tag does not exists
else {
if(note=="") att.setNote(note + tagname +"{"+value+"}");
if(note!="") att.setNote(note + "; " + tagname +"{"+value+"}");
}
att.save();
},
getTabletStatus: function(att) {
var tagID=Zotero.Tags.getID(this.prefs.getCharPref("tablet.tag"),0);
return(att.hasTag(tagID));
},
getTabletStatusModified: function(item) {
var modified=false;
if (this.getTabletStatus(item)) {
var file=this.getTabletFile(item);
if(file!==false) if (file.exists()) {
// get last modified time from att note and add att to list if file was modified
var lastmod=this.getInfo(item,"lastmod");
if(file.lastModifiedTime + ""!=lastmod) if (lastmod!="") modified=true;
}
}
return modified;
},
getTabletFile: function(att) {
try {
if(this.getTabletStatus(att)) {
// get file depending on mode
var file=this.getInfo(att,"mode")==1 ? this.createFile(this.getInfo(att,"location")) : att.getFile();
return(file);
}
return(false);
}
catch (err) {
return(false);
}
},
getTabletLocationFile: function(subfolder) {
if(subfolder==null) subfolder="";
return(this.createFile(this.prefs.getCharPref("tablet.dest_dir")+subfolder));
},
getAttachmentsOnTablet: function(subfolder) {
// search for attachments with tag
var search = new Zotero.Search();
search.addCondition('tag', 'is', this.prefs.getCharPref("tablet.tag"));
var results = search.search();
var items = Zotero.Items.get(results);
var atts = [];
// iterate through attachment items
for (var i=0; i < items.length; i++) {
var item = items[i];
// show warning if regular item with tablet tag
if(item.isRegularItem()) this.infoWindow("ZotFile Warning","A regular Zotero item has the \'" + this.prefs.getCharPref("tablet.tag") + "\' tag. This tag should only be used by zotfile and not assigned manually.",8000);
// check whether non-top level attachment
if(!item.isTopLevelItem() && item.isAttachment()) {
// show warning if no information in note
if(this.getInfo(item,"mode")==="") this.infoWindow("ZotFile Warning","The information stored in attachment notes is missing for an attachment on the tablet. Make sure that you do not delete this information manually.",8000);
if(this.getInfo(item,"mode")!="") {
if(subfolder===undefined) atts.push(item);
if(subfolder!==undefined) if(this.getInfo(item,"projectFolder").toLowerCase()==subfolder.toLowerCase()) atts.push(item);
}
}
}
// return attachments
return(atts);
},
getModifiedAttachmentsOnTablet: function (subfolder) {
var items=this.getAttachmentsOnTablet(subfolder);
var atts=[];
// iterate through attachment items
for (var i=0; i < items.length; i++) {
// get attachment item, parent and file
var item = items[i];
if(this.getTabletStatusModified(item)) atts.push(item);
}
// return attachments
return(atts);
},
setTabletFolder:function (items,projectFolder) {
for (var i=0; i < items.length; i++) {
var item = items[i];
if(item.getSource()) {
// get parent item
var parent=Zotero.Items.get(item.getSource());
// first pull if background mode
var att_mode=this.getInfo(item,"mode");
if(att_mode==1 || att_mode!=this.prefs.getIntPref("tablet.mode")) {
var itemID=this.getAttachmentFromTablet(parent,item,true);
item = Zotero.Items.get(itemID);
}
// now push
if(parent.isRegularItem()) {
if(projectFolder!==null) this.sendAttachmentToTablet(parent,item,projectFolder,false);
if(projectFolder===null) this.sendAttachmentToTablet(parent,item,this.getInfo(item,"projectFolder"),false);
}
}
}
// report
var mess_loc=(projectFolder!=="" && projectFolder!==null) ? ("'..." + projectFolder + "'.") : "the base folder.";
Zotero.ZotFile.infoWindow("ZotFile Report","ZotFile has moved " + items.length + " attachments to " + mess_loc,8000);
},
checkSelectedSearch: function() {
// get selected saved search
var win = this.wm.getMostRecentWindow("navigator:browser");
var savedSearch = win.ZoteroPane.getSelectedSavedSearch();
// returns false if no saved search is selected (e.g. collection)
// check whether saved search 'tablet files (modified)' is selected based on search conditions
var searchModifiedTabletFiles=false;
if(savedSearch!==false) {
var savedSearchConditions=savedSearch.getSearchConditions();
for (var i=1; i < savedSearchConditions.length; i++) {
if(savedSearchConditions[i].condition=="tag" && savedSearchConditions[i].value==this.prefs.getCharPref("tablet.tagModified")) searchModifiedTabletFiles=true;
}
}
return searchModifiedTabletFiles;
},
updateModifiedAttachmentsSearch: function(event) {
// debug output
if(Zotero.ZotFile.prefs.getBoolPref("debug")) Zotero.debug("zotfile.updateModifiedAttachmentsSearch - event fired");
// update saved search only if 'tablet files (modified)' saved search is selected
if(Zotero.ZotFile.checkSelectedSearch()) {
var items = Zotero.ZotFile.getModifiedAttachmentsOnTablet();
if(Zotero.ZotFile.prefs.getBoolPref("debug")) Zotero.debug("zotfile.updateModifiedAttachmentsSearch - saved search selected with " + items.length + " modified atts.");
for (var j=0; j < items.length; j++) items[j].addTag(Zotero.ZotFile.prefs.getCharPref("tablet.tagModified"));
// expand all rows in when search is selected
//var win = this.wm.getMostRecentWindow("navigator:browser");
//win.ZoteroPane.itemsView.expandAllRows();
}
},
scanTabletFiles: function() {
// get items on tablet
var items = this.getModifiedAttachmentsOnTablet();
if(items.length===0) this.infoWindow("ZotFile Report","Scan Tablet did not find any updated items in the destination folder.",8000);
// iterate through attachment items
for (var i=0; i < items.length; i++) {
// get attachment item, parent and file
var item = items[i];
var parent=Zotero.Items.get(item.getSource());
var file=this.getTabletFile(item);
// ask user
var userInput=this.promptUser("Attachment \'" + file.leafName + "\' was modified. What do you want to do?","Get Attachment from Tablet","Update Zotero File","Cancel");
// Pull attachment
if(userInput===0) this.getAttachmentFromTablet(parent,item,false);
// change modification date of attachment and update file
if(userInput==1) {
if(this.getInfo(item,"mode")==2) this.addInfo(item,"lastmod",file.lastModifiedTime);
if(this.getInfo(item,"mode")==1) {
var projectFolder=this.getInfo(item,"projectFolder");
// first pull if already on reader
// this.getAttachmentFromTablet(parent,item,true);
var att_mode=this.getInfo(item,"mode");
if(att_mode==1 || att_mode!=this.prefs.getIntPref("tablet.mode")) {
var itemID=this.getAttachmentFromTablet(parent,item,true);
item = Zotero.Items.get(itemID);
}
// now push
var newAttID=this.sendAttachmentToTablet(parent,item,projectFolder);
}
}
}
},
sendAttachmentToTablet: function(item, att, projectFolder, verbose) {
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendAttachmentToTablet - sending attachment " + att.getID() + " (mode is " + this.prefs.getIntPref("tablet.mode") + ")");
var newFile;
verbose = (typeof verbose == 'undefined') ? true : verbose;
var newAttID=null;
var file = att.getFile();
if(this.fileExists(att) && this.checkFileType(att.getFile())) {
// background mode: Rename and Move Attachment
if(this.prefs.getIntPref("tablet.mode")==1) {
// change name of file
if (this.prefs.getBoolPref("tablet.rename")) {
var filename=this.getFilename(item,file.leafName);
if(filename!=file.leafName) {
att.renameAttachmentFile(filename);
att.setField('title', filename);
att.save();
file = att.getFile();
}
}
newAttID=att.getID();
// add tags and catch error if it does not work
try {
if(!this.getTabletStatus(att)) att.addTag(this.prefs.getCharPref("tablet.tag"));
if (this.prefs.getBoolPref("tablet.tagParentPush")) item.addTag(this.prefs.getCharPref("tablet.tagParentPush_tag"));
}
catch (err) {
this.infoWindow("ZotFile Error","Zotfile was unable to send the file \'" + file.leafName + "\' to the tablet (error: tag assignment). Please try again and report the problem if it happens again.",8000);
return(null);
}
// create copy of file on tablet and catch errors
try {
// create copy on tablet
var folder=this.getLocation(item,this.prefs.getCharPref("tablet.dest_dir")+projectFolder,this.prefs.getBoolPref("tablet.subfolder"),this.prefs.getCharPref("tablet.subfolderFormat"));
newFile=this.copyFile(file,folder,file.leafName);
}
catch (err) {
if(this.getTabletStatus(att)) att.removeTag(Zotero.Tags.getID(this.prefs.getCharPref("tablet.tag"),0));
this.infoWindow("ZotFile Error","Zotfile was unable to send the file \'" + file.leafName + "\' to the tablet (error: moving the file). Please try again and report the problem if it happens again.",8000);
return(null);
}
}
// foreground mode: Rename and Move Attachment
if(this.prefs.getIntPref("tablet.mode")==2) {
newAttID=this.renameAttachment(item, att,false,this.prefs.getCharPref("tablet.dest_dir")+projectFolder,this.prefs.getBoolPref("tablet.subfolder"),this.prefs.getCharPref("tablet.subfolderFormat"),false);
// get new attachment and file
att = Zotero.Items.get(newAttID);
newFile = att.getFile();
// add tag to attachment
if(!this.getTabletStatus(att)) att.addTag(this.prefs.getCharPref("tablet.tag"));
if (this.prefs.getBoolPref("tablet.tagParentPush")) item.addTag(this.prefs.getCharPref("tablet.tagParentPush_tag"));
}
// add info to note (date of modification to attachment, location, and mode)
this.addInfo(att,"lastmod",newFile.lastModifiedTime);
this.addInfo(att,"mode",this.prefs.getIntPref("tablet.mode"));
this.addInfo(att,"location",newFile.path);
this.addInfo(att,"projectFolder",projectFolder);
// notification
if(verbose) this.infoWindow("ZotFile Report","The attachment \'" + newFile.leafName + "\' was sent to the tablet.",8000); // at \'" + projectFolder + "\'.
}
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendAttachmentToTablet - attachment send with new ID " + newAttID);
return(newAttID);
},
sendSelectedAttachmentsToTablet: function(project) {
// save current selection
var win = this.wm.getMostRecentWindow("navigator:browser");
var selection=win.ZoteroPane.itemsView.saveSelection();
// get selected attachments
var attIDs=this.getSelectedAttachments();
var attID;
// debug
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - sending " + attIDs.length + " attachments to tablet");
// get projectFolder
var projectFolder="";
if (project!='') {
if(this.prefs.getIntPref("tablet.projectFolders")==1) projectFolder=this.projectPath[parseInt(project,10)-1];
if(this.prefs.getIntPref("tablet.projectFolders")==2) projectFolder=this.prefs.getCharPref("tablet.projectFolders" + project + "_folder");
}
// debug
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - projectFolder set to '" + projectFolder +"'");
// Check which attachments are already on the reader
var attOnReader=[];
var attOnReaderCount=0;
for (var i=0; i < attIDs.length; i++) {
var hasTag=this.getTabletStatus(Zotero.Items.get(attIDs[i]));
attOnReader.push(hasTag);
if (hasTag) attOnReaderCount++;
}
// debug
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - attachments on tablet: " + attOnReaderCount);
var repush=!this.prefs.getBoolPref("tablet.confirmRepush");
// Push attachments
var confirmed=1;
if (this.prefs.getBoolPref("confirmation_batch_ask") && attIDs.length>=this.prefs.getIntPref("confirmation_batch")) confirmed=confirm("Do you want to send " + attIDs.length + " attachments to the tablet?");
if(confirmed) {
if (!repush && attOnReaderCount>0) repush=confirm(attOnReaderCount + " of the selected attachments are already on the tablet. Do you want to replace these files on the tablet?");
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - iterating through " + attIDs.length + " attachments...");
for (i=0; i < attIDs.length; i++) {
var att = Zotero.Items.get(attIDs[i]);
var item= Zotero.Items.get(att.getSource());
if(!attOnReader[i] || (attOnReader[i] && repush)) {
// first pull if already on reader
if (attOnReader[i]) {
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - get attachment " + i + " from tablet before sending it");
var att_mode=this.getInfo(att,"mode");
if(att_mode==1 || att_mode!=this.prefs.getIntPref("tablet.mode")) {
attID=this.getAttachmentFromTablet(item,att,true);
att = Zotero.Items.get(attID);
}
}
// now push
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - send attachment " + i);
attID=this.sendAttachmentToTablet(item,att,projectFolder);
if(attID!==null && attIDs[i]!=attID) selection=this.arrayReplace(selection,attIDs[i],attID);
}
}
// restore selection
if(Zotero.version>="3") win.ZoteroPane.itemsView.selectItems(selection);
// debug
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - attachments sent to tablet");
}
if(confirmed===0 && this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.sendSelectedAttachmentsToTablet - sending attachments canceled by user");
},
updateSelectedTabletAttachments: function () {
// get selected attachments
var itemIDs=this.getSelectedAttachments();
var attID, newAttID;
// iterate through selected attachments
for (i=0; i < itemIDs.length; i++) {
var item = Zotero.Items.get(itemIDs[i]);
if(this.getTabletStatusModified(item)) {
// get parent and file
var parent=Zotero.Items.get(item.getSource());
var file=this.getTabletFile(item);
var filename=file.leafName;
var att_mode=this.getInfo(item,"mode");
if(att_mode==2) {
this.addInfo(item,"lastmod",file.lastModifiedTime);
var tagIDModified=Zotero.Tags.getID(this.prefs.getCharPref("tablet.tagModified"),0);
if(item.hasTag(tagIDModified)) item.removeTag(tagIDModified);
newAttID=item.getID();
}
if(att_mode==1) {
var projectFolder=this.getInfo(item,"projectFolder");
// first get from tablet
var itemID=this.getAttachmentFromTablet(parent,item,true);
item = Zotero.Items.get(itemID);
// now send back to reader
newAttID=this.sendAttachmentToTablet(parent,item,projectFolder,false);
}
// extract annotations
if (this.prefs.getBoolPref("tablet.updateExtractAnnotations")) this.pdfAnnotations.getAnnotations([newAttID]);
// show message
this.infoWindow("ZotFile Report","The attachment \'" + filename + "\' was synced between Zotero and the tablet folder.",8000);
}
}
},
getAttachmentFromTablet: function (item, att,fakeRemove) {
var attID=att.getID();
var option=2;
var itemPulled=false;
var att_mode=this.getInfo(att,"mode");
//debug
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.getAttachmentFromTablet - begin with mode " + att_mode);
// get files
var file_zotero=att.getFile();
var file_reader=this.getTabletFile(att);
// get modification times for files
var time_reader = file_reader.exists() ? parseInt(file_reader.lastModifiedTime+"",10) : 0;
var time_saved = parseInt(this.getInfo(att,"lastmod"),10);
var time_zotero = (file_zotero!=false) ? parseInt(file_zotero.lastModifiedTime+"",10) : 0;
//debug
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.getAttachmentFromTablet - modification times: tablet=" + time_reader + "; saved=" + time_saved + "; zotero=" + time_zotero);
// background mode
if(att_mode==1) {
if (time_reader!=0 || time_zotero!=0) {
// set options
if (time_reader>time_saved && time_zotero<=time_saved) option=0;
if (time_reader<=time_saved && time_zotero<=time_saved) option=1;
if (time_reader<=time_saved && time_zotero>time_saved) option=1;
if (time_reader>time_saved && time_zotero>time_saved) option=2;
// if attachment gets replaced
if (!this.prefs.getBoolPref("tablet.storeCopyOfFile")) {
// prompt if both file have been modified
if (option==2) option=this.promptUser("Both copies of the attachment file \'" + file_zotero.leafName + "\' have been modified. What do you want to do?\n\nRemoving the tablet file discards all changes made to the file on the tablet.","Replace Zotero File","Remove Tablet File","Cancel");
// Replace Zotero file
if(option==0) {
file_reader.moveTo(file_zotero.parent,file_zotero.leafName);
itemPulled=true;
}
}
// if saving a copy of the file as a new attachment with suffix
if (this.prefs.getBoolPref("tablet.storeCopyOfFile")) {
// only if reader file was modified
if(option!=1) {
var filename=this.addSuffix(file_zotero.leafName,this.prefs.getCharPref("tablet.storeCopyOfFile_suffix"));
//add linked attachment
if (!item.libraryID && !this.prefs.getBoolPref("import")) {
file_reader.moveTo(file_zotero.parent,filename);
attID=Zotero.Attachments.linkFromFile(file_reader, item.itemID,item.libraryID);
itemPulled=true;
}
//imports attachment
if (item.libraryID || this.prefs.getBoolPref("import")) {
// import file on reader
attID=Zotero.Attachments.importFromFile(file_reader, item.itemID,item.libraryID);
var attAnnotated = Zotero.Items.get(attID);
// rename file associated with attachment
attAnnotated.renameAttachmentFile(filename);
// change title of attachment item
attAnnotated.setField('title', filename);
attAnnotated.save();
// remove file on reader
this.removeFile(file_reader);
itemPulled=true;
}
}
}
// Pull without replacement (i.e. remove file on tablet)
if(option==1) {
this.removeFile(file_reader);
itemPulled=true;
}
}
}
// foreground mode
if(att_mode==2) {
attID=this.renameAttachment(item, att,this.prefs.getBoolPref("import"),this.prefs.getCharPref("dest_dir"),this.prefs.getBoolPref("subfolder"),this.prefs.getCharPref("subfolderFormat"),false);
att = Zotero.Items.get(attID);
itemPulled=true;
option = time_zotero>time_saved ? 0 : 1;
}
// post-processing if attachment has been removed & it's not a fake-pull
if (itemPulled && !fakeRemove) {
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.getAttachmentFromTablet - post-processing after attachment was removed");
// remove info (tag and att note)
var tagID=Zotero.Tags.getID(this.prefs.getCharPref("tablet.tag"),0);
att.removeTag(tagID);
this.clearInfo(att);
// extract annotations from attachment and add note
if (this.prefs.getBoolPref("pdfExtraction.Pull") && option!=1) this.pdfAnnotations.getAnnotations([attID]);
// remove tag from parent item
tagID=Zotero.Tags.getID(this.prefs.getCharPref("tablet.tagParentPush_tag"),0);
if(item.hasTag(tagID)) item.removeTag(tagID);
// add tag to parent item
if (this.prefs.getBoolPref("tablet.tagParentPull")) item.addTag(this.prefs.getCharPref("tablet.tagParentPull_tag"));
// notification
this.infoWindow("ZotFile Report","The attachment \'" + att.getFile().leafName + "\' was removed from the tablet.",8000);
}
// remove modified tag from attachment
if (itemPulled) {
var tagIDModified=Zotero.Tags.getID(this.prefs.getCharPref("tablet.tagModified"),0);
if(att.hasTag(tagIDModified)) att.removeTag(tagIDModified);
}
//debug
if(this.prefs.getBoolPref("debug")) Zotero.debug("zotfile.getAttachmentFromTablet - end");
// return new id
return(attID);
},
getSelectedAttachmentsFromTablet: function() {
// save current selection
var win = this.wm.getMostRecentWindow("navigator:browser");
var selection=win.ZoteroPane.itemsView.saveSelection();
// get selected attachments
var attIDs=this.getSelectedAttachments();
// Pull attachments
var tagID=Zotero.Tags.getID(this.prefs.getCharPref("tablet.tag"),0);
var confirmed=1;
if (this.prefs.getBoolPref("confirmation_batch_ask") && attIDs.length>=this.prefs.getIntPref("confirmation_batch")) confirmed=confirm("Do you want to get the " + attIDs.length + " selected attachments from your tablet?");
if(confirmed) for (var i=0; i < attIDs.length; i++) {
var att = Zotero.Items.get(attIDs[i]);
var item= Zotero.Items.get(att.getSource());
if(att.hasTag(tagID)) {
var attID=this.getAttachmentFromTablet(item,att,false);
if(attID!==null && attIDs[i]!=attID) selection=this.arrayReplace(selection,attIDs[i],attID);
}
}
// restore selection
if(Zotero.version>="3") win.ZoteroPane.itemsView.selectItems(selection);
},
// ============================= //
// FUNCTIONS: RENAME ATTACHMENTS //
// ============================ //
// Rename & Move Existing Attachments
renameAttachment: function(item, att,import_att,dest_dir,subfolder,subfolderFormat,notification) {
var file;
var newAttID=null;
// get link mode and item ID
var linkmode = att.attachmentLinkMode;
var itemID = item.id;
// only proceed if linked or imported attachment
if(att.isImportedAttachment() || linkmode==Zotero.Attachments.LINK_MODE_LINKED_FILE) {
// get object of attached file
file = att.getFile();
// create file name using ZotFile rules
var filename = this.getFilename(item, file.leafName);
var location = this.getLocation(item,dest_dir,subfolder,subfolderFormat);
if (import_att || item.libraryID) {
// rename file associated with attachment
att.renameAttachmentFile(filename);
// change title of attachment item
att.setField('title', filename);
att.save();
// get object of attached file
file = att.getFile();
// output
if (linkmode!=Zotero.Attachments.LINK_MODE_LINKED_FILE && notification) this.infoWindow("Zotfile Report","Imported Attachment renamed to \'" + filename + "\'.",8000);
}
// (a) LINKED ATTACHMENT TO IMPORTED ATTACHMENT
if (linkmode==Zotero.Attachments.LINK_MODE_LINKED_FILE && import_att) {
// Attach file to selected Zotero item
newAttID=Zotero.Attachments.importFromFile(file, itemID,item.libraryID);
// remove file from hard-drive
file.remove(false);
// erase old attachment
att.erase();
// output
if(notification) this.infoWindow("Zotfile Report","Imported Attachment \'" + filename + "\'.",8000);
// return id of attachment
return newAttID;
}
// (b) TO LINKED ATTACHMENT (only if library is local and not cloud)
// if (linkmode==Zotero.Attachments.LINK_MODE_IMPORTED_FILE && !import_att) {
if (!import_att && !item.libraryID) {
// move pdf file
var newfile_path=this.moveFile(file,location, filename, att.getDisplayTitle());
if (newfile_path!="NULL") {
// recreate the outfile nslFile Object
file = this.createFile(newfile_path);
// create linked attachment
newAttID=Zotero.Attachments.linkFromFile(file, itemID,item.libraryID);
// erase old attachment
att.erase();
if(notification) this.infoWindow("Zotfile Report","Linked Attachment \'" + file.leafName + "\'.",8000);
// return id of attachment
return newAttID;
}
}
}
// return id of attachment
return newAttID;
},
// FUNCTION: Rename & Move Existing Attachments
renameSelectedAttachments: function(){
// save current selection
var win = this.wm.getMostRecentWindow("navigator:browser");
var selection=win.ZoteroPane.itemsView.saveSelection();
// get selected attachments
var attIDs=this.getSelectedAttachments();
// Pull attachments
var confirmed=1;
if (this.prefs.getBoolPref("confirmation_batch_ask") && attIDs.length>=this.prefs.getIntPref("confirmation_batch")) confirmed=confirm("Do you want to move and rename " + attIDs.length + " attachments?");
if(confirmed) {
for (var i=0; i < attIDs.length; i++) {
// get attachment and item
var att = Zotero.Items.get(attIDs[i]);
var item= Zotero.Items.get(att.getSource());
// preserve attachment note and tags
var att_note=att.getNote();
var att_tags=att.getTags();
if(att_tags.length>0) for (var j=0; j < att_tags.length; j++) att_tags[j]= att_tags[j]._get('name');
// Rename and Move Attachment
var file = att.getFile();
if(this.fileExists(att) && this.checkFileType(file) && !this.getTabletStatus(att)) {
// move & rename
var attID=this.renameAttachment(item, att,this.prefs.getBoolPref("import"),this.prefs.getCharPref("dest_dir"),this.prefs.getBoolPref("subfolder"),this.prefs.getCharPref("subfolderFormat"),true);
//update list of selected item
if(attID!==null && attIDs[i]!=attID) selection=this.arrayReplace(selection,attIDs[i],attID);
// restore attachments note and tags
if(att_note!="" || att_tags.length>0) {
att = Zotero.Items.get(attID);
if(att_note!="") att.setNote(att_note);
if(att_tags) for each(var tag in att_tags) att.addTag(tag);
att.save();
}
}
if(this.getTabletStatus(att)) this.infoWindow("Zotfile Error","Attachment could not be renamed because it is on the tablet.",8000);
}
// restore selection
if(Zotero.version>="3") win.ZoteroPane.itemsView.selectItems(selection);
}
},
// =========================================== //
// FUNCTIONS: PDF ANNOTATION EXTRACTION CLASS //
// ========================================== //
// class to extract pdf annotations
pdfAnnotations : {
popplerExtractorFileName: 'ExtractPDFAnnotations',
popplerExtractorPath:null,
popplerExtractorVersion:1.0,
popplerSupportedPlatforms:['MacIntel'],
pdfExtraction:false,
popplerExtractorTool:false,
popplerExtractorSupported:false,
popplerExtractorBaseURL:'http://www.columbia.edu/~jpl2136/PDFTools/',
/** The list of PDFs we should extract annotations from. Each
element is an object with the following fields:
attachment: the Zotero object representing the attachment
path: an absolute path to the attachment file
item: the Zotero item containing the attachment
*/
pdfAttachmentsForExtraction: [],
numTotalPdfAttachments: 0,
errorExtractingAnnotations: false,
/** The hidden browser where PDFs get rendered by pdf.js. */
pdfHiddenBrowser: null,
PDF_EXTRACT_URL: 'chrome://zotfile/content/pdfextract/extract.html',
popplerExtractorSetPath: function() {
// extractor filename
this.popplerExtractorFileName += '-' + Zotero.platform;
if (Zotero.isWin) this.popplerExtractorFileName+='.exe';
//“pdftotext-{platform}”, where {platform} is “Win32”, “MacIntel”, “MacPPC”, “Linux-i686”, etc. (To determine your current platform, type javascript:alert(navigator.platform) in the Firefox URL bar and hit Enter.)
// extractor path
this.popplerExtractorPath = Zotero.getZoteroDirectory().path + "/ExtractPDFAnnotations/" + this.popplerExtractorFileName;
if (Zotero.isWin) this.popplerExtractorPath.replace(/\\\//g,"\\").replace(/\//g,"\\");
},
popplerExtractorCheckInstalled: function () {
// str = toolIsRegistered ? "Installed..." : "Download Tool to Extract PDF Annotations";
try {
var fileobj = Zotero.ZotFile.createFile(this.popplerExtractorPath);
if (fileobj.exists()) return(1);
if (!fileobj.exists()) return(0);
}
catch (err) {
return(0);
}
},
openFileStream: function (file) {
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, 0x01, 0444, 0);
istream.QueryInterface(Components.interfaces.nsILineInputStream);
/* Need to find out what the character encoding is. Using UTF-8 for this example: */
var charset = "UTF-8";
var is = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
.createInstance(Components.interfaces.nsIConverterInputStream);
// This assumes that fis is the template.Interface("nsIInputStream") you want to read from
is.init(istream, charset, 1024, 0xFFFD);
is.QueryInterface(Components.interfaces.nsIUnicharLineInputStream);
return(is);
},
popplerExtractorCall: function (pdfFilePath,outputFile) {
// set up process
var extractorFile=Zotero.ZotFile.createFile(this.popplerExtractorPath);
var proc = Components.classes["@mozilla.org/process/util;1"].
createInstance(Components.interfaces.nsIProcess);
proc.init(extractorFile);
// define arguments
var args = [pdfFilePath,outputFile];
// run process
if (!Zotero.isFx36) {
proc.runw(true, args, args.length);
}
else {
proc.run(true, args, args.length);
}
},
getAnnotations: function(attIDs) {
// Zotero.debug("ZotFile - pdfAnnotations - getAnnotations() - called");
// get selected attachments if no att ids are passed
if(attIDs==null) attIDs=Zotero.ZotFile.getSelectedAttachments();
// Zotero.debug("ZotFile - pdfAnnotations - getAnnotations() - " + attIDs.length + " attachments");
// iterate through attachment items
var file;
if(attIDs!=null) for (var i=0; i < attIDs.length; i++) {
// get attachment item, parent and file
var att = Zotero.Items.get(attIDs[i]);
var item = Zotero.Items.get(att.getSource());
// if file is on tablet in background mode, take the one which was modified
if(Zotero.ZotFile.getTabletStatus(att) && Zotero.ZotFile.getInfo(att,"mode")==1) {
var file_zotero=att.getFile();
var file_reader=Zotero.ZotFile.getTabletFile(att);
// get times
var time_reader = file_reader.exists() ? parseInt(file_reader.lastModifiedTime+"",10) : 0;
var time_saved = parseInt(Zotero.ZotFile.getInfo(att,"lastmod"),10);
var time_zotero = (file_zotero!=false) ? parseInt(file_zotero.lastModifiedTime+"",10) : 0;
if (time_reader!=0 || time_zotero!=0) {
// set options
var option;
if (time_reader>time_saved && time_zotero<=time_saved) option=0;
if (time_reader<=time_saved && time_zotero<=time_saved) option=1;
if (time_reader<=time_saved && time_zotero>time_saved) option=1;
if (time_reader>time_saved && time_zotero>time_saved) option=2;
// prompt if both file have been modified
if(option==2) option =Zotero.ZotFile.promptUser("Both copies of the attachment file \'" + file_zotero.leafName + "\' have been modified. From which copy do you want to extract annotations?","Use Copy on Tablet","Use Copy in Zotero","Cancel");
if(option==0) file =file_reader;
if(option==1) file =file_zotero;
if(option==2) return(false);
}
}
else {
file = att.getFile();
}
// extract annotations from pdf and create note with annotations
if(Zotero.ZotFile.getFiletype(file.leafName)=="pdf") {
if (Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.UsePDFJS") || Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.UsePDFJSandPoppler")) {
var a = {};
a.attachment = att;
a.path = file.path;
a.item = item;
this.pdfAttachmentsForExtraction.push(a);
}
if (this.popplerExtractorTool && (
!Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.UsePDFJS") ||
Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.UsePDFJSandPoppler"))) {
var outputFile=file.path.replace(".pdf",".txt");
this.popplerExtractorCall(file.path,outputFile);
var annotations = this.popplerExtractorGetAnnotationsFromFile(outputFile);
if(annotations.length!=0) this.createNote(annotations, item, "poppler");
// delete output text file
if(Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.popplerDeleteTxtFile")) Zotero.ZotFile.removeFile(Zotero.ZotFile.createFile(outputFile));
}
}
}
if (this.pdfAttachmentsForExtraction.length > 0 &&
(Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.UsePDFJS") || Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.UsePDFJSandPoppler"))) {
if (!Zotero.isFx36) {
// setup extraction process
this.errorExtractingAnnotations = false;
this.numTotalPdfAttachments = this.pdfAttachmentsForExtraction.length;
Zotero.showZoteroPaneProgressMeter("Extract PDF annotations (press ESC to cancel)",true);
var win = Zotero.ZotFile.wm.getMostRecentWindow("navigator:browser");
win.ZoteroPane.document.addEventListener('keypress', this.cancellationListener,false);
this.pdfHiddenBrowser = Zotero.Browser.createHiddenBrowser();
this.pdfHiddenBrowser.loadURI(this.PDF_EXTRACT_URL);
}
else Zotero.ZotFile.infoWindow("ZotFile Error","The extraction of pdf annotations with pdf.js is not supported on Firefox 3.6. Install the most recent Firefox version to use this feature. Mac users can also switch to poppler for the extraction of pdf annotations (in 'ZotFile Preferences' under 'Advanced Settings').",8000);
}
// Zotero.debug("ZotFile - pdfAnnotations - getAnnotations() - end - done");
},
popplerExtractorGetAnnotationsFromFile: function(outputFile) {
var annotations = [];
var file=Zotero.ZotFile.createFile(outputFile);
if(file.exists()) {
// open an input stream from file
var istream=this.openFileStream(file);
// read lines into array
var line = {};
do {
// get line
cont = istream.readLine(line);
var line_split = line.value.split(' ; ');
var strMarkUp = (line_split[5]) ? this.trim(line_split[5].replace(/\\n/g,"<br>")) : "";
var strText = (line_split[4]) ? this.trim(line_split[4].replace(/\\n/g,"<br>")) : "";
// if(strText!="") var strText=this.removeHyphens(strText);
// create annotation object
/* structure: filename ; page ; ID ; type ; text ; textMarkUp */
if(strMarkUp!="" || strText!="") {
a = {
filename:line_split[0],
page:parseInt(line_split[1],10),
ID:parseInt(line_split[2],10),
type:line_split[3],
// date:line_split[7],
// creator:line_split[11],
content:strText,
markup:strMarkUp
};
annotations.push(a);
}
} while (cont);
istream.close();
}
else Zotero.ZotFile.infoWindow("ZotFile Error","Annotation extraction failed.",8000);
return annotations;
},
createNote: function(annotations, item, method) {
var note_content=this.getNoteContent(annotations, item, method);
var note = new Zotero.Item("note");
note.libraryID = item._libraryID;
// note.setNote(Zotero.Utilities.text2html(note_content));
note.setNote(note_content);
note.setSource(item.getID());
var noteID = note.save();
// Zotero.ZotFile.infoWindow("ZotFile Report","TAB:" + prefWindow.document.getElementById('zotfile-tabbox').selectedTab,8000);
},
getNoteContent: function(annotations, item, method) {
// get current date
var date_str=new Date().toUTCString();
// set note title
var note="<b>Extracted Annotations (" + date_str;
if (Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.UsePDFJSandPoppler")) note += ", " + method;
note += ")</b><br><br>";
// get html tags for notes and highlights
var htmlTagNoteStart=Zotero.ZotFile.prefs.getCharPref("pdfExtraction.NoteHtmlTagStart");
var htmlTagNoteEnd=Zotero.ZotFile.prefs.getCharPref("pdfExtraction.NoteHtmlTagEnd");
var htmlTagHighlightStart=Zotero.ZotFile.prefs.getCharPref("pdfExtraction.HighlightHtmlTagStart");
var htmlTagHighlightEnd=Zotero.ZotFile.prefs.getCharPref("pdfExtraction.HighlightHtmlTagEnd");
var htmlTagUnderlineStart=Zotero.ZotFile.prefs.getCharPref("pdfExtraction.UnderlineHtmlTagStart");
var htmlTagUnderlineEnd=Zotero.ZotFile.prefs.getCharPref("pdfExtraction.UnderlineHtmlTagEnd");
// iterature through annotations
for (var i=0; i < annotations.length; i++) {
var anno=annotations[i];
// get page
var page=anno.page;
if(Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.NoteTruePage")) {
try {
var itemPages=item.getField('pages');
if(itemPages) page=parseInt(itemPages.split('-')[0],10)+page-1;
}
catch(err) {}
}
// get citation
var cite="p. ";
if(Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.NoteFullCite")) cite=Zotero.ZotFile.replaceWildcard(item, "%a %y:").replace(/_(?!.*_)/," and ").replace(/_/g,", ");
// add to note text pdfExtractionNoteRemoveHtmlNote
if(anno.content && anno.content != "" &&
(!anno.markup || this.strDistance(anno.content,anno.markup)>0.15 )) {
var content = anno.content.replace(/(\r\n|\n|\r)/gm,"<br/>");
note += "<p>"+htmlTagNoteStart+content+" (note on p." + page + ")"+htmlTagNoteEnd+"</p><br>";
}
if(anno.markup && anno.markup != "") {
var markup = this.trim(anno.markup);
if(Zotero.ZotFile.prefs.getBoolPref("pdfExtraction.NoteRemoveHyphens")) markup = this.removeHyphens(markup);
var tagStart = htmlTagHighlightStart;
var tagEnd = htmlTagHighlightEnd;
if (anno.type == "Highlight") {
tagStart = htmlTagHighlightStart;
tagEnd = htmlTagHighlightEnd;
} else if (anno.type == "Underline") {
tagStart = htmlTagUnderlineStart;
tagEnd = htmlTagUnderlineEnd;
}
note += "<p>"+tagStart+"\""+markup+"\" (" + cite + page + ")" +tagEnd+"</p>";
}
}
return note;
},
trim: function(str) {
//return str.replace (/^\s+/, '').replace (/\s+$/, '');
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
},
strDistance: function (s1,s2) {
s1=Zotero.Utilities.trimInternal(s1).replace(/ /g,"");
s2=Zotero.Utilities.trimInternal(s2).replace(/ /g,"");
var l = (s1.length > s2.length) ? s1.length : s2.length;
return Zotero.Utilities.levenshtein(s1,s2)/l;
},
removeHyphens: function(str) {
while (true) {
var pos = str.search(/[a-zA-Z]- [a-zA-Z]/g);
if (pos == -1) break;
str = str.substring(0,pos+1) + str.substring(pos+3,str.length);
}
return str;
},
/* Runs the annotation extraction code in extract.html/extract.js,
* to extract annotations from a single PDF. */
extractAnnotationsFromFiles: function() {
var attachment = this.pdfAttachmentsForExtraction.shift();
var args = {};
args.url = 'file://'+attachment.path;
args.item = attachment.item;
args.callbackObj = this;
args.callback = this.extractionComplete;
Zotero.ZotFile.PdfExtractor.extractAnnotations(args);
},
/** Called from extract.js whenever a page is processed. */
pageExtractionComplete: function(pagesProcessed, totalPages) {
// update progress bar
var fractionDone = (this.numTotalPdfAttachments - this.pdfAttachmentsForExtraction.length - 1) /
this.numTotalPdfAttachments;
fractionDone += ((pagesProcessed / totalPages) * (1.0 / this.numTotalPdfAttachments));
Zotero.updateZoteroPaneProgressMeter(fractionDone * 100.0);
},
/** Keypress listener that cancels the extraction if the user presses escape. */
cancellationListener: function(keyEvent) {
if (keyEvent.keyCode == KeyboardEvent.DOM_VK_ESCAPE) {
var zzpa = Zotero.ZotFile.pdfAnnotations;
zzpa.pdfAttachmentsForExtraction = [];
zzpa.extractionComplete([], null);
keyEvent.currentTarget.removeEventListener('keypress', zzpa.cancellationListener);
}
},
/* Called from extract.js when all annotations for a single PDF have
* been extracted.
* @param annotations An array of annotation objects. Each element
* contains the following fields: url (a url pointing to the file
* this annotation came from), page (the page number within the
* document where this annotation appears), type (the type of
* annotation, e.g. "Highlight", or "Text"), content (the text of
* any pop-up note in this annotation), and markup (the words from
* the document, if any, that were highlighted/underlined).
* @param item The Zotero item these annotations came from */
extractionComplete: function(annotations, item) {
// put annotations into a Zotero note
if (annotations.length > 0) this.createNote(annotations, item, "pdf.js");
// move on to the next pdf, if there is one
if (this.pdfAttachmentsForExtraction.length > 0) {
this.extractAnnotationsFromFiles();
} else { // we're done
if (this.errorExtractingAnnotations) {
Zotero.ZotFile.infoWindow("ZotFile Report","ZotFile was unable to extract all annotations because pdf.js does not support certain PDF standards yet. Please see the JavaScript error console for more details.",8000);
}
this.errorExtractingAnnotations = false;
Zotero.Browser.deleteHiddenBrowser(this.pdfHiddenBrowser);
this.pdfHiddenBrowser = null;
this.numTotalPdfAttachments = 0;
Zotero.hideZoteroPaneOverlay(); // hide progress bar
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment