Adds RTF scan feature. this could probably use some more testing. Acceptable citations are in the form
(Smith, 2006) The database is scanned for each citation, and positioning is adjusted automatically for footnotes. Currently, this won't work with names with accents, but I'll get to that.
This commit is contained in:
parent
e619cab8f3
commit
ac53f35056
10 changed files with 724 additions and 12 deletions
|
@ -43,11 +43,13 @@ var Zotero_File_Interface_Bibliography = new function() {
|
|||
// Set font size from pref
|
||||
// Affects bibliography.xul and integrationDocPrefs.xul
|
||||
var sbc = document.getElementById('zotero-bibliography-container');
|
||||
Zotero.setFontSize(sbc);
|
||||
if(sbc) Zotero.setFontSize(sbc);
|
||||
|
||||
_io = window.arguments[0];
|
||||
if(_io.wrappedJSObject){
|
||||
_io = _io.wrappedJSObject;
|
||||
if(window.arguments && window.arguments.length) {
|
||||
_io = window.arguments[0];
|
||||
if(_io.wrappedJSObject) _io = _io.wrappedJSObject;
|
||||
} else {
|
||||
_io = {};
|
||||
}
|
||||
|
||||
var listbox = document.getElementById("style-listbox");
|
||||
|
@ -103,7 +105,8 @@ var Zotero_File_Interface_Bibliography = new function() {
|
|||
if(document.getElementById("displayAs")) {
|
||||
if(_io.useEndnotes && _io.useEndnotes == 1) document.getElementById("displayAs").selectedIndex = 1;
|
||||
styleChanged(selectIndex);
|
||||
|
||||
}
|
||||
if(document.getElementById("formatUsing")) {
|
||||
if(_io.useBookmarks && _io.useBookmarks == 1) document.getElementById("formatUsing").selectedIndex = 1;
|
||||
if(_io.openOffice) {
|
||||
var formatOption = "referenceMarks";
|
||||
|
@ -139,13 +142,17 @@ var Zotero_File_Interface_Bibliography = new function() {
|
|||
var selectedStyle = selectedItem.getAttribute('value');
|
||||
|
||||
// update status of displayAs box based on style class
|
||||
var isNote = Zotero.Styles.get(selectedStyle).class == "note";
|
||||
document.getElementById("displayAs").disabled = !isNote;
|
||||
if(document.getElementById("displayAs")) {
|
||||
var isNote = Zotero.Styles.get(selectedStyle).class == "note";
|
||||
document.getElementById("displayAs").disabled = !isNote;
|
||||
}
|
||||
|
||||
// update status of formatUsing box based on style class
|
||||
if(isNote) document.getElementById("formatUsing").selectedIndex = 0;
|
||||
document.getElementById("bookmarks").disabled = isNote;
|
||||
document.getElementById("bookmarks-caption").disabled = isNote;
|
||||
if(document.getElementById("formatUsing")) {
|
||||
if(isNote) document.getElementById("formatUsing").selectedIndex = 0;
|
||||
document.getElementById("bookmarks").disabled = isNote;
|
||||
document.getElementById("bookmarks-caption").disabled = isNote;
|
||||
}
|
||||
}
|
||||
|
||||
function acceptSelection() {
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
<menupopup id="zotero-tb-actions-popup" onpopupshowing="document.getElementById('cmd_zotero_reportErrors').setAttribute('disabled', Zotero.getErrors().length == 0)">
|
||||
<menuitem id="zotero-tb-actions-import" label="&zotero.toolbar.import.label;" oncommand="Zotero_File_Interface.importFile();"/>
|
||||
<menuitem id="zotero-tb-actions-export" label="&zotero.toolbar.export.label;" oncommand="Zotero_File_Interface.exportFile();"/>
|
||||
<menuitem id="zotero-tb-actions-rtfScan" label="&zotero.toolbar.rtfScan.label;" oncommand="window.openDialog('chrome://zotero/content/rtfScan.xul', 'rtfScan', 'chrome,centerscreen')"/>
|
||||
<menuitem hidden="true" id="zotero-tb-actions-zeroconf-update"
|
||||
label="Search for Shared Libraries" oncommand="Zotero.Zeroconf.findInstances()"/>
|
||||
<menuseparator id="zotero-tb-actions-plugins-separator"/>
|
||||
|
|
583
chrome/content/zotero/rtfScan.js
Normal file
583
chrome/content/zotero/rtfScan.js
Normal file
|
@ -0,0 +1,583 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (c) 2006 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://chnm.gmu.edu
|
||||
|
||||
Licensed under the Educational Community License, Version 1.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.opensource.org/licenses/ecl1.php
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Tools for automatically retrieving a citation for the given PDF
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Front end for recognizing PDFs
|
||||
* @namespace
|
||||
*/
|
||||
var Zotero_RTFScan = new function() {
|
||||
const ACCEPT_ICON = "chrome://zotero/skin/rtfscan-accept.png";
|
||||
const LINK_ICON = "chrome://zotero/skin/rtfscan-link.png";
|
||||
const BIBLIOGRAPHY_PLACEHOLDER = "\\{Bibliography\\}";
|
||||
|
||||
var inputFile = null, outputFile = null;
|
||||
var unmappedCitationsItem, ambiguousCitationsItem, mappedCitationsItem;
|
||||
var unmappedCitationsChildren, ambiguousCitationsChildren, mappedCitationsChildren;
|
||||
var citations, citationItemIDs, allCitedItemIDs, contents;
|
||||
|
||||
/** INTRO PAGE UI **/
|
||||
|
||||
/**
|
||||
* Called when the first page is shown; loads target file from preference, if one is set
|
||||
*/
|
||||
this.introPageShowing = function() {
|
||||
var path = Zotero.Prefs.get("rtfScan.lastInputFile");
|
||||
if(path) {
|
||||
inputFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
|
||||
inputFile.initWithPath(path);
|
||||
}
|
||||
var path = Zotero.Prefs.get("rtfScan.lastOutputFile");
|
||||
if(path) {
|
||||
outputFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
|
||||
outputFile.initWithPath(path);
|
||||
}
|
||||
_updatePath();
|
||||
document.getElementById("choose-input-file").focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the first page is hidden
|
||||
*/
|
||||
this.introPageAdvanced = function() {
|
||||
Zotero.Prefs.set("rtfScan.lastInputFile", inputFile.path);
|
||||
Zotero.Prefs.set("rtfScan.lastOutputFile", outputFile.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to select the file to be processed
|
||||
*/
|
||||
this.chooseInputFile = function() {
|
||||
// display file picker
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("rtfScan.openTitle"), nsIFilePicker.modeOpen);
|
||||
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
fp.appendFilter(Zotero.getString("rtfScan.rtf"), "*.rtf");
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
inputFile = fp.file;
|
||||
_updatePath();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to select the output file
|
||||
*/
|
||||
this.chooseOutputFile = function() {
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("rtfScan.saveTitle"), nsIFilePicker.modeSave);
|
||||
fp.appendFilter(Zotero.getString("rtfScan.rtf"), "*.rtf");
|
||||
fp.defaultString = "Untitled.rtf";
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
outputFile = fp.file;
|
||||
_updatePath();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the path label in the dialog box
|
||||
* @private
|
||||
*/
|
||||
function _updatePath() {
|
||||
document.documentElement.canAdvance = inputFile && outputFile;
|
||||
if(inputFile) document.getElementById("input-path").value = inputFile.path;
|
||||
if(outputFile) document.getElementById("output-path").value = outputFile.path;
|
||||
}
|
||||
|
||||
/** SCAN PAGE UI **/
|
||||
|
||||
/**
|
||||
* Called when second page is shown.
|
||||
*/
|
||||
this.scanPageShowing = function() {
|
||||
// can't advance
|
||||
document.documentElement.canAdvance = false;
|
||||
|
||||
// wait a ms so that UI thread gets updated
|
||||
window.setTimeout(function() { _scanRTF() }, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans file for citations, then proceeds to next wizard page.
|
||||
*/
|
||||
function _scanRTF() {
|
||||
// set up globals
|
||||
citations = [];
|
||||
citationItemIDs = {};
|
||||
|
||||
unmappedCitationsItem = document.getElementById("unmapped-citations-item");
|
||||
ambiguousCitationsItem = document.getElementById("ambiguous-citations-item");
|
||||
mappedCitationsItem = document.getElementById("mapped-citations-item");
|
||||
unmappedCitationsChildren = document.getElementById("unmapped-citations-children");
|
||||
ambiguousCitationsChildren = document.getElementById("ambiguous-citations-children");
|
||||
mappedCitationsChildren = document.getElementById("mapped-citations-children");
|
||||
|
||||
// set up regular expressions
|
||||
// this assumes that names are >=2 chars or only capital initials and that there are no
|
||||
// more than 4 names
|
||||
const nameRe = "(?:[^ .,;]{2,} |[A-Z].? ?){0,3}[A-Z][^ .,;]+";
|
||||
const creatorRe = '((?:(?:'+nameRe+', )*'+nameRe+'(?:,? and|,? \\&|,) )?'+nameRe+')(,? et al\\.?)?';
|
||||
// TODO: localize "and" term
|
||||
const creatorSplitRe = /(?:,| *(?:and|\&)) +/g;
|
||||
var citationRe = new RegExp('(\\(|; )('+creatorRe+', (?:"([^"]+)(?:,"|",) )?([0-9]{4})[a-z]?)(?:, ([0-9]+))?(?=[);])|(([A-Z][^ .,;]+)(,? et al\\.?)? (\\(([0-9]{4})[a-z]?\\)))', "gm");
|
||||
|
||||
// read through RTF file and display items as they're found
|
||||
// we could read the file in chunks, but unless people start having memory issues, it's
|
||||
// probably faster and definitely simpler if we don't
|
||||
contents = Zotero.File.getContents(inputFile).replace(/([^\\\r])\r?\n/, "$1 ").replace("\\'92", "'", "g").replace("\\rquote ", "’");
|
||||
var m;
|
||||
var lastCitation = false;
|
||||
while((m = citationRe.exec(contents))) {
|
||||
// determine whether suppressed or standard regular expression was used
|
||||
if(m[2]) { // standard parenthetical
|
||||
var citationString = m[2];
|
||||
var creators = m[3];
|
||||
var etAl = !!m[4];
|
||||
var title = m[5];
|
||||
var date = m[6];
|
||||
var pages = m[7];
|
||||
var start = citationRe.lastIndex-m[0].length;
|
||||
var end = citationRe.lastIndex+1;
|
||||
} else { // suppressed
|
||||
var citationString = m[8];
|
||||
var creators = m[9];
|
||||
var etAl = !!m[10];
|
||||
var title = false;
|
||||
var date = m[12];
|
||||
var pages = false;
|
||||
var start = citationRe.lastIndex-m[11].length;
|
||||
var end = citationRe.lastIndex;
|
||||
}
|
||||
var suppressAuthor = !m[2];
|
||||
|
||||
if(lastCitation && lastCitation.end >= start) {
|
||||
// if this citation is just an extension of the last, add items to it
|
||||
lastCitation.citationStrings.push(citationString);
|
||||
lastCitation.pages.push(pages);
|
||||
lastCitation.end = end;
|
||||
} else {
|
||||
// otherwise, add another citation
|
||||
var lastCitation = {"citationStrings":[citationString], "pages":[pages], "start":start,
|
||||
"end":end, "suppressAuthor":suppressAuthor};
|
||||
citations.push(lastCitation);
|
||||
}
|
||||
|
||||
// only add each citation once
|
||||
if(citationItemIDs[citationString]) continue;
|
||||
Zotero.debug("Found citation "+citationString);
|
||||
|
||||
// for each individual match, look for an item in the database
|
||||
var s = new Zotero.Search;
|
||||
creators = creators.replace(".", "");
|
||||
// TODO: localize "et al." term
|
||||
creators = creators.split(creatorSplitRe);
|
||||
|
||||
for(var i=0; i<creators.length; i++) {
|
||||
if(!creators[i]) {
|
||||
if(i == creators.length-1) {
|
||||
break;
|
||||
} else {
|
||||
creators.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
var spaceIndex = creators[i].lastIndexOf(" ");
|
||||
var lastName = spaceIndex == -1 ? creators[i] : creators[i].substr(spaceIndex+1);
|
||||
s.addCondition("lastName", "contains", lastName);
|
||||
}
|
||||
if(title) s.addCondition("title", "contains", title);
|
||||
s.addCondition("date", "is", date);
|
||||
var ids = s.search();
|
||||
Zotero.debug("Mapped to "+ids);
|
||||
citationItemIDs[citationString] = ids;
|
||||
|
||||
if(!ids) { // no mapping found
|
||||
unmappedCitationsChildren.appendChild(_generateItem(citationString, ""));
|
||||
unmappedCitationsItem.hidden = undefined;
|
||||
} else { // some mapping found
|
||||
var items = Zotero.Items.get(ids);
|
||||
if(items.length > 1) {
|
||||
// check to see how well the author list matches the citation
|
||||
var matchedItems = [];
|
||||
for(var i=0; i<items.length; i++) {
|
||||
if(_matchesItemCreators(creators, items[i])) matchedItems.push(items[i]);
|
||||
}
|
||||
|
||||
if(matchedItems.length != 0) items = matchedItems;
|
||||
}
|
||||
|
||||
if(items.length == 1) { // only one mapping
|
||||
mappedCitationsChildren.appendChild(_generateItem(citationString, items[0].getField("title")));
|
||||
citationItemIDs[citationString] = [items[0].id];
|
||||
mappedCitationsItem.hidden = undefined;
|
||||
} else { // ambiguous mapping
|
||||
var treeitem = _generateItem(citationString, "");
|
||||
|
||||
// generate child items
|
||||
var treeitemChildren = document.createElement('treechildren');
|
||||
treeitem.appendChild(treeitemChildren);
|
||||
for(var i=0; i<items.length; i++) {
|
||||
treeitemChildren.appendChild(_generateItem("", items[i].getField("title"), true));
|
||||
}
|
||||
|
||||
treeitem.setAttribute("container", "true");
|
||||
treeitem.setAttribute("open", "true");
|
||||
ambiguousCitationsChildren.appendChild(treeitem);
|
||||
ambiguousCitationsItem.hidden = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when scanning is complete, go to citations page
|
||||
document.documentElement.canAdvance = true;
|
||||
document.documentElement.advance();
|
||||
}
|
||||
|
||||
function _generateItem(citationString, itemName, accept) {
|
||||
var treeitem = document.createElement('treeitem');
|
||||
var treerow = document.createElement('treerow');
|
||||
|
||||
var treecell = document.createElement('treecell');
|
||||
treecell.setAttribute("label", citationString);
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
var treecell = document.createElement('treecell');
|
||||
treecell.setAttribute("label", itemName);
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
var treecell = document.createElement('treecell');
|
||||
treecell.setAttribute("src", accept ? ACCEPT_ICON : LINK_ICON);
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
treeitem.appendChild(treerow);
|
||||
return treeitem;
|
||||
}
|
||||
|
||||
function _matchesItemCreators(creators, item, etAl) {
|
||||
var itemCreators = item.getCreators();
|
||||
var primaryCreators = [];
|
||||
var primaryCreatorTypeID = Zotero.CreatorTypes.getPrimaryIDForType(item.itemTypeID);
|
||||
|
||||
// use only primary creators if primary creators exist
|
||||
for(var i=0; i<itemCreators.length; i++) {
|
||||
if(itemCreators[i].creatorTypeID == primaryCreatorTypeID) {
|
||||
primaryCreators.push(itemCreators[i]);
|
||||
}
|
||||
}
|
||||
// if primaryCreators matches the creator list length, or if et al is being used, use only
|
||||
// primary creators
|
||||
if(primaryCreators.length == creators.length || etAl) itemCreators = primaryCreators;
|
||||
|
||||
// for us to have an exact match, either the citation creator list length has to match the
|
||||
// item creator list length, or et al has to be used
|
||||
if(itemCreators.length == creators.length || (etAl && itemCreators.length > creators.length)) {
|
||||
var matched = true;
|
||||
for(var i=0; i<creators.length; i++) {
|
||||
// check each item creator to see if it matches
|
||||
matched = matched && _matchesItemCreator(creators[i], itemCreators[i]);
|
||||
if(!matched) break;
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function _matchesItemCreator(creator, itemCreator) {
|
||||
// make sure last name matches
|
||||
var lowerLast = itemCreator.ref.lastName.toLowerCase();
|
||||
if(lowerLast != creator.substr(-lowerLast.length).toLowerCase()) return false;
|
||||
|
||||
// make sure first name matches, if it exists
|
||||
if(creator.length > lowerLast.length) {
|
||||
var firstName = Zotero.Utilities.prototype.trim(creator.substr(0, creator.length-lowerLast.length));
|
||||
if(firstName.length) {
|
||||
// check to see whether the first name is all initials
|
||||
const initialRe = /^(?:[A-Z]\.? ?)+$/;
|
||||
var m = initialRe.exec(firstName);
|
||||
if(m) {
|
||||
var initials = firstName.replace(/[^A-Z]/g, "");
|
||||
var itemInitials = [name[0].toUpperCase() for each (name in itemCreator.ref.firstName.split(/ +/g))].join("");
|
||||
if(initials != itemInitials) return false;
|
||||
} else {
|
||||
// not all initials; verify that the first name matches
|
||||
var firstWord = firstName.substr(0, itemCreator.ref.firstName).toLowerCase();
|
||||
var itemFirstWord = itemCreator.ref.firstName.substr(0, itemCreator.ref.firstName.indexOf(" ")).toLowerCase();
|
||||
if(firstWord != itemFirstWord) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** CITATIONS PAGE UI **/
|
||||
|
||||
/**
|
||||
* Called when citations page is shown to determine whether user can immediately advance.
|
||||
*/
|
||||
this.citationsPageShowing = function() {
|
||||
_refreshCanAdvance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the citations page is rewound. Removes all citations from the list, clears
|
||||
* globals, and returns to intro page.
|
||||
*/
|
||||
this.citationsPageRewound = function() {
|
||||
// skip back to intro page
|
||||
document.documentElement.currentPage = document.getElementById('intro-page');
|
||||
|
||||
// remove children from tree
|
||||
while(unmappedCitationsChildren.hasChildNodes()) {
|
||||
unmappedCitationsChildren.removeChild(unmappedCitationsChildren.firstChild);
|
||||
}
|
||||
while(ambiguousCitationsChildren.hasChildNodes()) {
|
||||
ambiguousCitationsChildren.removeChild(ambiguousCitationsChildren.firstChild);
|
||||
}
|
||||
while(mappedCitationsChildren.hasChildNodes()) {
|
||||
mappedCitationsChildren.removeChild(mappedCitationsChildren.firstChild);
|
||||
}
|
||||
// hide headings
|
||||
unmappedCitationsItem.hidden = ambiguousCitationsItem.hidden = mappedCitationsItem.hidden = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a tree item is clicked to remap a citation, or accept a suggestion for an
|
||||
* ambiguous citation
|
||||
*/
|
||||
this.treeClick = function(event) {
|
||||
var tree = document.getElementById("tree");
|
||||
|
||||
// get clicked cell
|
||||
var row = { }, col = { }, child = { };
|
||||
tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, child);
|
||||
|
||||
// figure out which item this corresponds to
|
||||
row = row.value;
|
||||
var level = tree.view.getLevel(row);
|
||||
if(col.value.index == 2 && level > 0) {
|
||||
var iconColumn = col.value;
|
||||
var itemNameColumn = iconColumn.getPrevious();
|
||||
var citationColumn = itemNameColumn.getPrevious();
|
||||
|
||||
if(level == 2) { // ambiguous citation item
|
||||
// get relevant information
|
||||
var parentIndex = tree.view.getParentIndex(row);
|
||||
var citation = tree.view.getCellText(parentIndex, citationColumn);
|
||||
var itemName = tree.view.getCellText(row, itemNameColumn);
|
||||
|
||||
// update item name on parent and delete children
|
||||
tree.view.setCellText(parentIndex, itemNameColumn, itemName);
|
||||
var treeitem = tree.view.getItemAtIndex(row);
|
||||
treeitem.parentNode.parentNode.removeChild(treeitem.parentNode);
|
||||
|
||||
// update array
|
||||
citationItemIDs[citation] = [citationItemIDs[citation][row-parentIndex-1]];
|
||||
} else { // mapped or unmapped citation, or ambiguous citation parent
|
||||
var citation = tree.view.getCellText(row, citationColumn);
|
||||
var io = {singleSelection:true};
|
||||
if(citationItemIDs[citation] && citationItemIDs[citation].length == 1) { // mapped citation
|
||||
// specify that item should be selected in window
|
||||
io.select = citationItemIDs[citation];
|
||||
}
|
||||
|
||||
window.openDialog('chrome://zotero/content/selectItemsDialog.xul', '', 'chrome,modal', io);
|
||||
|
||||
if(io.dataOut && io.dataOut.length) {
|
||||
var selectedItemID = io.dataOut[0];
|
||||
var selectedItem = Zotero.Items.get(selectedItemID);
|
||||
|
||||
var treeitem = tree.view.getItemAtIndex(row);
|
||||
|
||||
// remove any children (if ambiguous)
|
||||
var children = treeitem.getElementsByTagName("treechildren");
|
||||
if(children.length) treeitem.removeChild(children[0]);
|
||||
|
||||
// update item name
|
||||
tree.view.setCellText(row, itemNameColumn, selectedItem.getField("title"));
|
||||
|
||||
// update array
|
||||
citationItemIDs[citation] = [selectedItemID];
|
||||
}
|
||||
}
|
||||
}
|
||||
_refreshCanAdvance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the button to advance the wizard should be enabled or not based on whether
|
||||
* unmapped citations exist, and sets the status appropriately
|
||||
*/
|
||||
function _refreshCanAdvance() {
|
||||
var canAdvance = true;
|
||||
for each(var itemList in citationItemIDs) {
|
||||
if(itemList.length != 1) {
|
||||
canAdvance = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
document.documentElement.canAdvance = canAdvance;
|
||||
}
|
||||
|
||||
/** STYLE PAGE UI **/
|
||||
|
||||
/**
|
||||
* Called when style page is shown to add styles to listbox.
|
||||
*/
|
||||
this.stylePageShowing = function() {
|
||||
Zotero_File_Interface_Bibliography.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when style page is hidden to save preferences.
|
||||
*/
|
||||
this.stylePageAdvanced = function() {
|
||||
Zotero.Prefs.set("export.lastStyle", document.getElementById("style-listbox").selectedItem.value);
|
||||
}
|
||||
|
||||
/** FORMAT PAGE UI **/
|
||||
|
||||
this.formatPageShowing = function() {
|
||||
// can't advance
|
||||
document.documentElement.canAdvance = false;
|
||||
|
||||
// wait a ms so that UI thread gets updated
|
||||
window.setTimeout(function() { _formatRTF() }, 1);
|
||||
}
|
||||
|
||||
function _formatRTF() {
|
||||
// load style and create ItemSet with all items
|
||||
var style = Zotero.Styles.get(document.getElementById("style-listbox").selectedItem.value).csl;
|
||||
var isNote = style.class == "note";
|
||||
var itemSet = style.createItemSet();
|
||||
|
||||
// create citations
|
||||
var k = 0;
|
||||
var cslCitations = [];
|
||||
var shouldBeSubsequent = {};
|
||||
for(var i=0; i<citations.length; i++) {
|
||||
var citation = citations[i];
|
||||
var cslCitation = style.createCitation();
|
||||
cslCitations.push(cslCitation);
|
||||
|
||||
// create citation items
|
||||
for(var j=0; j<citation.citationStrings.length; j++) {
|
||||
var itemID = citationItemIDs[citation.citationStrings[j]];
|
||||
var cslItem = itemSet.getItemsByIds(itemID)[0];
|
||||
|
||||
// determine position
|
||||
var position = Zotero.CSL.POSITION_SUBSEQUENT;
|
||||
if(!cslItem) { // if item is not yet in item set, add it and mark as first citation
|
||||
var position = Zotero.CSL.POSITION_FIRST;
|
||||
var cslItem = itemSet.add(itemID)[0];
|
||||
} else if(// this citation and previous citation only cite one item
|
||||
citation.citationStrings.length == citations[i-1].citationStrings.length == 1
|
||||
// this citation and previous citation cite the same item
|
||||
&& citation.citationStrings[0] == citations[i-1].citationStrings[0]
|
||||
// either previous item had no locator, or this item has a locator
|
||||
&& (!citations[i-1].pages[0] || citation.pages[0])) {
|
||||
if(citation.pages[0] == citations[i-1].pages[0]) {
|
||||
var position = Zotero.CSL.POSITION_IBID;
|
||||
} else {
|
||||
var position = Zotero.CSL.POSITION_IBID_WITH_LOCATOR;
|
||||
}
|
||||
}
|
||||
|
||||
var cslCitationItem = new Zotero.CSL.CitationItem(cslItem);
|
||||
cslCitation.add([cslCitationItem]);
|
||||
cslCitationItem.position = position;
|
||||
cslCitationItem.locator = citation.pages[j];
|
||||
cslCitationItem.suppressAuthor = citation.suppressAuthor && !isNote;
|
||||
}
|
||||
}
|
||||
|
||||
// sort item set, now that we have the indices
|
||||
itemSet.resort();
|
||||
|
||||
// format citations
|
||||
var contentArray = [];
|
||||
var lastEnd = 0;
|
||||
for(var i=0; i<citations.length; i++) {
|
||||
var citation = style.formatCitation(cslCitations[i], "RTF");
|
||||
Zotero.debug("Formatted "+citation);
|
||||
|
||||
// if using notes, we might have to move the note after the punctuation
|
||||
if(isNote && citations[i].start != 0 && contents[citations[i].start-1] == " ") {
|
||||
contentArray.push(contents.substring(lastEnd, citations[i].start-1));
|
||||
} else {
|
||||
contentArray.push(contents.substring(lastEnd, citations[i].start));
|
||||
}
|
||||
|
||||
lastEnd = citations[i].end;
|
||||
if(isNote && citations[i].end < contents.length && ".,!?".indexOf(contents[citations[i].end]) !== -1) {
|
||||
contentArray.push(contents[citations[i].end]);
|
||||
lastEnd++;
|
||||
}
|
||||
|
||||
if(isNote) {
|
||||
if(document.getElementById("displayAs").selectedIndex) { // endnotes
|
||||
contentArray.push("{\\super\\chftn}\\ftnbj {\\footnote\\ftnalt {\\super\\chftn } "+citation+"}");
|
||||
} else { // footnotes
|
||||
contentArray.push("{\\super\\chftn}\\ftnbj {\\footnote {\\super\\chftn } "+citation+"}");
|
||||
}
|
||||
} else {
|
||||
contentArray.push(citation);
|
||||
}
|
||||
}
|
||||
contentArray.push(contents.substring(lastEnd));
|
||||
contents = contentArray.join("");
|
||||
|
||||
// add bibliography
|
||||
if(style.hasBibliography) {
|
||||
var bibliography = false;
|
||||
contents = contents.replace(BIBLIOGRAPHY_PLACEHOLDER, function() {
|
||||
if(bibliography !== false) {
|
||||
return bibliography;
|
||||
} else {
|
||||
bibliography = style.formatBibliography(itemSet, "RTF");
|
||||
return bibliography;
|
||||
}
|
||||
}, "g");
|
||||
}
|
||||
|
||||
Zotero.File.putContents(outputFile, contents);
|
||||
|
||||
document.documentElement.canAdvance = true;
|
||||
document.documentElement.advance();
|
||||
}
|
||||
}
|
101
chrome/content/zotero/rtfScan.xul
Normal file
101
chrome/content/zotero/rtfScan.xul
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" ?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/upgrade.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/bibliography.css"?>
|
||||
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
|
||||
|
||||
<wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&zotero.rtfScan.title;" width="700" height="550"
|
||||
id="zotero-rtfScan">
|
||||
|
||||
<script src="include.js"/>
|
||||
<script src="bibliography.js"/>
|
||||
<script src="rtfScan.js"/>
|
||||
|
||||
<wizardpage id="intro-page" label="&zotero.rtfScan.introPage.label;"
|
||||
onpageshow="Zotero_RTFScan.introPageShowing()"
|
||||
onpageadvanced="Zotero_RTFScan.introPageAdvanced()">
|
||||
<description width="700">&zotero.rtfScan.introPage.description;</description>
|
||||
<groupbox>
|
||||
<caption label="&zotero.rtfScan.inputFile.label;"/>
|
||||
<hbox align="center">
|
||||
<textbox value="&zotero.file.noneSelected.label;" id="input-path" flex="1" readonly="true"/>
|
||||
<button id="choose-input-file" label="&zotero.file.choose.label;" onclick="Zotero_RTFScan.chooseInputFile()"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
<groupbox>
|
||||
<caption label="&zotero.rtfScan.outputFile.label;"/>
|
||||
<hbox align="center">
|
||||
<textbox value="&zotero.file.noneSelected.label;" id="output-path" flex="1" readonly="true"/>
|
||||
<button id="choose-output-file" label="&zotero.file.choose.label;" onclick="Zotero_RTFScan.chooseOutputFile()"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="scan-page" label="&zotero.rtfScan.scanPage.label;"
|
||||
onpageshow="Zotero_RTFScan.scanPageShowing()">
|
||||
<description width="700">&zotero.rtfScan.scanPage.description;</description>
|
||||
<progressmeter id="progress-indicator" mode="undetermined" flex="1"/>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="citations-page" label="&zotero.rtfScan.citationsPage.label;"
|
||||
onpageshow="Zotero_RTFScan.citationsPageShowing()"
|
||||
onpagerewound="return Zotero_RTFScan.citationsPageRewound();">
|
||||
<description width="700">&zotero.rtfScan.citationsPage.description;</description>
|
||||
<tree flex="1" id="tree" hidecolumnpicker="true" onclick="Zotero_RTFScan.treeClick(event)">
|
||||
<treecols>
|
||||
<treecol label="&zotero.rtfScan.citation.label;" id="pdf-col" flex="1" primary="true"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&zotero.rtfScan.itemName.label;" id="item-col" flex="2"/>
|
||||
<treecol id="action-col" style="width:40px"/>
|
||||
</treecols>
|
||||
<treechildren id="treechildren">
|
||||
<treeitem id="unmapped-citations-item" container="true" open="true" hidden="true">
|
||||
<treerow>
|
||||
<treecell label="&zotero.rtfScan.unmappedCitations.label;"/>
|
||||
</treerow>
|
||||
<treechildren id="unmapped-citations-children"/>
|
||||
</treeitem>
|
||||
<treeitem id="ambiguous-citations-item" container="true" open="true" hidden="true">
|
||||
<treerow>
|
||||
<treecell label="&zotero.rtfScan.ambiguousCitations.label;"/>
|
||||
</treerow>
|
||||
<treechildren id="ambiguous-citations-children"/>
|
||||
</treeitem>
|
||||
<treeitem id="mapped-citations-item" container="true" open="true" hidden="true">
|
||||
<treerow>
|
||||
<treecell label="&zotero.rtfScan.mappedCitations.label;"/>
|
||||
</treerow>
|
||||
<treechildren id="mapped-citations-children"/>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="style-page" label="&zotero.rtfScan.stylePage.label;"
|
||||
onpageadvanced="Zotero_RTFScan.stylePageAdvanced()"
|
||||
onpageshow="Zotero_RTFScan.stylePageShowing()">
|
||||
<groupbox flex="1">
|
||||
<caption label="&zotero.bibliography.style.label;"/>
|
||||
<listbox id="style-listbox" onselect="Zotero_File_Interface_Bibliography.styleChanged()" flex="1"/>
|
||||
</groupbox>
|
||||
|
||||
<groupbox>
|
||||
<caption label="&zotero.integration.prefs.displayAs.label;"/>
|
||||
<radiogroup id="displayAs" orient="horizontal">
|
||||
<radio id="footnotes" label="&zotero.integration.prefs.footnotes.label;" selected="true"/>
|
||||
<radio id="endnotes" label="&zotero.integration.prefs.endnotes.label;"/>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="format-page" label="&zotero.rtfScan.formatPage.label;"
|
||||
onpageshow="Zotero_RTFScan.formatPageShowing()">
|
||||
<description width="700">&zotero.rtfScan.formatPage.description;</description>
|
||||
<progressmeter id="progress-indicator" mode="undetermined" flex="1"/>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="complete-page" label="&zotero.rtfScan.completePage.label;">
|
||||
<description width="700">&zotero.rtfScan.completePage.description;</description>
|
||||
</wizardpage>
|
||||
</wizard>
|
|
@ -42,6 +42,7 @@ function doLoad()
|
|||
|
||||
collectionsView = new Zotero.CollectionTreeView();
|
||||
document.getElementById('zotero-collections-tree').view = collectionsView;
|
||||
if(io.select) itemsView.selectItem(io.select);
|
||||
}
|
||||
|
||||
function doUnload()
|
||||
|
|
|
@ -184,4 +184,20 @@
|
|||
<!ENTITY zotero.rtfScan.itemName.label "Item Name">
|
||||
<!ENTITY zotero.rtfScan.unmappedCitations.label "Unmapped Citations">
|
||||
<!ENTITY zotero.rtfScan.ambiguousCitations.label "Ambiguous Citations">
|
||||
<!ENTITY zotero.rtfScan.mappedCitations.label "Mapped Citations">
|
||||
<!ENTITY zotero.rtfScan.mappedCitations.label "Mapped Citations">
|
||||
<!ENTITY zotero.rtfScan.introPage.label "Introduction">
|
||||
<!ENTITY zotero.rtfScan.introPage.description "Zotero can automatically extract and reformat citations and insert a bibliography into RTF files. To get started, choose an RTF file below.">
|
||||
<!ENTITY zotero.rtfScan.scanPage.label "Scanning for Citations">
|
||||
<!ENTITY zotero.rtfScan.scanPage.description "Zotero is scanning your document for citations. Please be patient.">
|
||||
<!ENTITY zotero.rtfScan.citationsPage.label "Verify Cited Items">
|
||||
<!ENTITY zotero.rtfScan.citationsPage.description "Please review the list of recognized citations below to ensure that Zotero has selected the corresponding items correctly. Any unmapped or ambiguous citations must be resolved before proceeding to the next step.">
|
||||
<!ENTITY zotero.rtfScan.stylePage.label "Document Formatting">
|
||||
<!ENTITY zotero.rtfScan.formatPage.label "Formatting Citations">
|
||||
<!ENTITY zotero.rtfScan.formatPage.description "Zotero is processing and formatting your RTF file. Please be patient.">
|
||||
<!ENTITY zotero.rtfScan.completePage.label "RTF Scan Complete">
|
||||
<!ENTITY zotero.rtfScan.completePage.description "Your document has now been scanned and processed. Please ensure that it is formatted correctly.">
|
||||
<!ENTITY zotero.rtfScan.inputFile.label "Input File">
|
||||
<!ENTITY zotero.rtfScan.outputFile.label "Output File">
|
||||
|
||||
<!ENTITY zotero.file.choose.label "Choose File...">
|
||||
<!ENTITY zotero.file.noneSelected.label "No file selected">
|
|
@ -532,10 +532,11 @@ recognizePDF.limit = Query limit reached. Try again later.
|
|||
recognizePDF.complete.label = Metadata Retrieval Complete.
|
||||
recognizePDF.close.label = Close
|
||||
|
||||
rtfScan.boxTitle = Select a file to scan
|
||||
rtfScan.openTitle = Select a file to scan
|
||||
rtfScan.scanning.label = Scanning RTF Document...
|
||||
rtfScan.saving.label = Formatting RTF Document...
|
||||
rtfScan.rtf = Rich Text Format (.rtf)
|
||||
rtfScan.saveTitle = Select a location in which to save the formatted file
|
||||
|
||||
lookup.failure.title = Lookup Failed
|
||||
lookup.failure.description = Zotero could not find a record for the specified identifier. Please verify the identifier and try again.
|
||||
|
|
BIN
chrome/skin/default/zotero/rtfscan-accept.png
Executable file
BIN
chrome/skin/default/zotero/rtfscan-accept.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 516 B |
BIN
chrome/skin/default/zotero/rtfscan-link.png
Executable file
BIN
chrome/skin/default/zotero/rtfscan-link.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 614 B |
|
@ -76,6 +76,8 @@ pref("extensions.zotero.export.bibliographyLocale", '');
|
|||
pref("extensions.zotero.export.citePaperJournalArticleURL", false);
|
||||
pref("extensions.zotero.export.displayCharsetOption", false);
|
||||
pref("extensions.zotero.import.charset", "auto");
|
||||
pref("extensions.zotero.rtfScan.lastInputFile", "");
|
||||
pref("extensions.zotero.rtfScan.lastOutputFile", "");
|
||||
|
||||
pref("extensions.zotero.export.quickCopy.setting", 'bibliography=http://www.zotero.org/styles/chicago-note');
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue