diff --git a/chrome/content/zotero/integration/editBibliographyDialog.js b/chrome/content/zotero/integration/editBibliographyDialog.js
index ca46708619..168ca35fef 100644
--- a/chrome/content/zotero/integration/editBibliographyDialog.js
+++ b/chrome/content/zotero/integration/editBibliographyDialog.js
@@ -28,22 +28,31 @@ var Zotero_Bibliography_Dialog = new function () {
var _lastSelectedItemID = false;
var _lastSelectedIndex = false;
var _lastSelectedValue = false;
+ var _accepted = false;
+ var _revertButton, _revertAllButton, _addButton, _removeButton;
+ var _itemList;
+ var _suppressAllSelectEvents = false;
- this.load = load;
- this.treeItemSelected = treeItemSelected;
- this.listItemSelected = listItemSelected;
- this.add = add;
- this.remove = remove;
- this.accept = accept;
-
- /*
- * initialize add citation dialog
+ /**
+ * Initializes add citation dialog
*/
- function load() {
- document.getElementById('editor').format = "RTF";
-
+ this.load = function() {
bibEditInterface = window.arguments[0].wrappedJSObject;
+ _revertAllButton = document.documentElement.getButton("extra2");
+ _revertButton = document.documentElement.getButton("extra1");
+ _addButton = document.getElementById("add");
+ _removeButton = document.getElementById("remove");
+ _itemList = document.getElementById("item-list");
+ _itemTree = document.getElementById("zotero-items-tree");
+
+ _revertAllButton.label = Zotero.getString("integration.revertAll.button");
+ _revertAllButton.disabled = bibEditInterface.isAnyEdited();
+ _revertButton.label = Zotero.getString("integration.revert.button");
+ _revertButton.disabled = true;
+
+ document.getElementById('editor').format = "RTF";
+
// load (from selectItemsDialog.js)
doLoad();
@@ -51,93 +60,230 @@ var Zotero_Bibliography_Dialog = new function () {
_loadItems();
}
- /*
- * called when an item in the item selection tree is clicked
+ /**
+ * Called when an item in the item selection tree is clicked
*/
- function treeItemSelected() {
- var selectedItems = itemsView.getSelectedItems(true); // treeview from selectItemsDialog.js
+ this.treeItemSelected = function() {
+ if(_suppressAllSelectEvents) return;
+ var selectedItemIDs = itemsView.getSelectedItems(true); // treeview from selectItemsDialog.js
- // disable add if item already in itemSet
- document.getElementById("add").disabled = selectedItems.length && bibEditInterface.bibliography[0].entry_ids.indexOf(selectedItems[0].id) !== -1;
- }
-
- /*
- * called when an item in the reference list is clicked
- */
- function listItemSelected() {
- var selectedListItem = document.getElementById("item-list").getSelectedItem(0);
-
- // enable remove if item is selected
- document.getElementById("remove").disabled = !selectedListItem;
-
- if(selectedListItem) {
- _updatePreview(selectedListItem.value);
- } else {
- _updatePreview();
+ // if all selected items are available in the list box on the right, select them there
+ // otherwise, clear the list box selection
+ var clearListItems = false;
+ var itemsToSelect = [];
+ if(selectedItemIDs.length) {
+ for each(var itemID in selectedItemIDs) {
+ var itemIndexToSelect = false;
+ for(var i in bibEditInterface.bibliography[0].entry_ids) {
+ if(bibEditInterface.bibliography[0].entry_ids[i].indexOf(itemID) !== -1) {
+ itemIndexToSelect = i;
+ continue;
+ }
+ }
+
+ if(itemIndexToSelect !== false) {
+ itemsToSelect.push(_itemList.getItemAtIndex(itemIndexToSelect));
+ } else {
+ clearListItems = true;
+ break;
+ }
+ }
}
+
+ _suppressAllSelectEvents = true;
+ _itemList.clearSelection();
+ if(clearListItems) {
+ _addButton.disabled = (itemsToSelect.length > 0);
+ _revertButton.disabled = _removeButton.disabled = true;
+ } else {
+ _addButton.disabled = true;
+ _removeButton.disabled = false;
+ _updateRevertButtonStatus();
+ [_itemList.toggleItemSelection(item) for each(item in itemsToSelect)];
+ _itemList.ensureIndexIsVisible(itemsToSelect[0]);
+ }
+ _suppressAllSelectEvents = false;
+
+ _updatePreview();
}
- /*
- * Adds a citation to the reference list
+ /**
+ * Called when an item in the reference list is clicked
*/
- function add() {
- var selectedItem = itemsView.getSelectedItems()[0]; // treeview from selectItemsDialog.js
- Zotero.debug(selectedItem);
+ this.listItemSelected = function() {
+ if(_suppressAllSelectEvents) return;
- bibEditInterface.add(selectedItem.id);
+ // enable remove if at least one item is selected
+ _addButton.disabled = true;
+ _removeButton.disabled = !_itemList.selectedItems.length;
+
+ if(_itemList.selectedItems.length) {
+ _suppressAllSelectEvents = true;
+ _itemTree.view.selection.clearSelection();
+ _suppressAllSelectEvents = false;
+
+ // only show revert button if at least one selected item has been edited
+ _updateRevertButtonStatus();
+ }
+
+ // update preview to blank if no items or multiple items are selected; otherwise show
+ // preview for selected items
+ _updatePreview();
+ }
+
+ /**
+ * Adds references to the reference list
+ */
+ this.add = function() {
+ for each(var itemID in itemsView.getSelectedItems(true)) {
+ bibEditInterface.add(itemID);
+ }
document.getElementById("add").disabled = true;
_loadItems();
}
- /*
- * Deletes a citation from the reference list
+ /**
+ * Clears all customizations
*/
- function remove() {
- var selectedListItem = document.getElementById("item-list").getSelectedItem(0);
- var itemID = bibEditInterface.bibliography[0].entry_ids[selectedListItem.value];
+ this.revertAll = function() {
+ var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Components.interfaces.nsIPromptService);
- if(bibEditInterface.isCited(itemID)) {
+ var out = {};
+ var regenerate = promptService.confirmEx(
+ window,
+ Zotero.getString('integration.revertAll.title'),
+ Zotero.getString('integration.revertAll.body'),
+ promptService.STD_OK_CANCEL_BUTTONS+promptService.BUTTON_POS_1_DEFAULT,
+ null, null, null, null, out
+ );
+
+ if(regenerate != 0) return;
+
+ bibEditInterface.revertAll();
+
+ _loadItems();
+ _updatePreview(true);
+ }
+
+ /**
+ * Clears customizations to selected entry
+ */
+ this.revert = function() {
+ var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Components.interfaces.nsIPromptService);
+
+ var out = {};
+ var regenerate = promptService.confirmEx(
+ window,
+ Zotero.getString('integration.revert.title'),
+ Zotero.getString('integration.revert.body'),
+ promptService.STD_OK_CANCEL_BUTTONS+promptService.BUTTON_POS_1_DEFAULT,
+ null, null, null, null, out
+ );
+
+ if(regenerate != 0) return;
+
+ for each(var itemID in _getSelectedListItemIDs()) {
+ bibEditInterface.revert(itemID);
+ }
+
+ _updatePreview();
+ }
+
+ /**
+ * Deletes selected references from the reference list
+ */
+ this.remove = function() {
+ var selectedListItemIDs = _getSelectedListItemIDs();
+
+ // if cited in bibliography, warn before removing
+ var isCited = false;
+ for each(var itemID in selectedListItemIDs) {
+ isCited |= bibEditInterface.isCited(itemID);
+ }
+ if(isCited) {
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var out = {};
var regenerate = promptService.confirmEx(
window,
- Zotero.getString('integration.deleteCitedItem.title'),
- Zotero.getString('integration.deleteCitedItem.body'),
+ Zotero.getString('integration.removeBibEntry.title'),
+ Zotero.getString('integration.removeBibEntry.body'),
promptService.STD_OK_CANCEL_BUTTONS+promptService.BUTTON_POS_1_DEFAULT,
null, null, null, null, out
);
-
if(regenerate != 0) return;
}
- bibEditInterface.remove(itemID);
+ // remove
+ for each(var itemID in selectedListItemIDs) {
+ bibEditInterface.remove(itemID);
+ }
_loadItems();
}
- function accept() {
- _updatePreview();
+ /**
+ * Called when the user edits the currently selected bibliography entry
+ */
+ this.textChanged = function() {
+ _revertButton.disabled = _revertAllButton.disabled = false;
}
- /*
+ /**
+ * Called when OK button is pressed
+ */
+ this.accept = function() {
+ _accepted = true;
+ _updatePreview(true);
+ }
+
+ /**
+ * Called when Cancel button is pressed
+ */
+ this.close = function() {
+ if(!_accepted) bibEditInterface.cancel();
+ }
+
+ /**
+ * Gets selected item IDs from list box on right
+ */
+ function _getSelectedListItemIDs() {
+ return [bibEditInterface.bibliography[0].entry_ids[item.value][0]
+ for each(item in _itemList.selectedItems)];
+ }
+
+ /**
+ * Update status of "Revert" button to match modification status of current item
+ */
+ function _updateRevertButtonStatus() {
+ _revertButton.disabled = true;
+ var selectedListItemIDs = _getSelectedListItemIDs();
+ for each(var itemID in selectedListItemIDs) {
+ if(bibEditInterface.isEdited(itemID)) {
+ _revertButton.disabled = false;
+ break;
+ }
+ }
+ }
+
+ /**
* Updates the contents of the preview pane
*/
- function _updatePreview(index) {
- Zotero.debug("_updatePreview called");
+ function _updatePreview(ignoreSelection) {
+ var index = !ignoreSelection && _itemList.selectedItems.length == 1 ? _itemList.selectedIndex : undefined;
var editor = document.getElementById('editor');
if(_lastSelectedItemID) {
var newValue = editor.value;
if(_lastSelectedValue != newValue) {
- Zotero.debug("setting bibliography for "+_lastSelectedItemID+" to "+newValue);
bibEditInterface.setCustomText(_lastSelectedItemID, newValue);
}
}
editor.readonly = index === undefined;
if(index !== undefined) {
- Zotero.debug("updating preview of "+index);
var itemID = bibEditInterface.bibliography[0].entry_ids[index];
editor.value = bibEditInterface.bibliography[1][index];
_lastSelectedIndex = index;
@@ -147,6 +293,8 @@ var Zotero_Bibliography_Dialog = new function () {
editor.value = "";
_lastSelectedIndex = _lastSelectedItemID = _lastSelectedValue = false;
}
+
+ _revertAllButton.disabled = !bibEditInterface.isAnyEdited();
}
/*
diff --git a/chrome/content/zotero/integration/editBibliographyDialog.xul b/chrome/content/zotero/integration/editBibliographyDialog.xul
index 9f4be1a804..8c51b6eeca 100644
--- a/chrome/content/zotero/integration/editBibliographyDialog.xul
+++ b/chrome/content/zotero/integration/editBibliographyDialog.xul
@@ -35,13 +35,17 @@
title="&zotero.integration.editBibliography.title;"
width="750" height="450"
onload="Zotero_Bibliography_Dialog.load();"
- onunload="doUnload();"
ondialogaccept="Zotero_Bibliography_Dialog.accept();"
- buttons="accept" buttonpack="end"
+ ondialogcancel="Zotero_Bibliography_Dialog.close();"
+ onclose="Zotero_Bibliography_Dialog.close();"
+ onunload="doUnload();"
+ buttons="extra1,extra2,accept,cancel" buttonpack="end"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
persist="screenX screenY width height"
- resizable="true">
+ resizable="true"
+ ondialogextra1="Zotero_Bibliography_Dialog.revert()"
+ ondialogextra2="Zotero_Bibliography_Dialog.revertAll()">
@@ -72,7 +76,7 @@
-
+
-
+
diff --git a/chrome/content/zotero/xpcom/cite.js b/chrome/content/zotero/xpcom/cite.js
index e0280b20b3..c2d385e419 100644
--- a/chrome/content/zotero/xpcom/cite.js
+++ b/chrome/content/zotero/xpcom/cite.js
@@ -215,9 +215,27 @@ Zotero.Cite.System.getAbbreviations = function() {
return {};
}
-Zotero.Cite.makeFormattedBibliography = function(cslEngine, format, customBibliographyText) {
+Zotero.Cite.removeFromBibliography = function(bib, itemsToRemove) {
+ var removeItems = [];
+ for(let i in bib[0].entry_ids) {
+ for(let j in bib[0].entry_ids[i]) {
+ if(itemsToRemove[bib[0].entry_ids[i][j]]) {
+ removeItems.push(i);
+ break;
+ }
+ }
+ }
+ for(let i=removeItems.length-1; i>=0; i--) {
+ bib[0].entry_ids.splice(removeItems[i], 1);
+ bib[1].splice(removeItems[i], 1);
+ }
+}
+
+Zotero.Cite.makeFormattedBibliography = function(cslEngine, format, customBibliographyText, omittedItems) {
if(format) cslEngine.setOutputFormat(format);
var bib = cslEngine.makeBibliography();
+ if(omittedItems) this.removeFromBibliography(bib, omittedItems);
+
if(format == "html") {
// TODO CSS
return bib[0].bibstart+bib[1].join("")+bib[0].bibend;
diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js
index 9cfe5d6dc0..a073c0ae26 100644
--- a/chrome/content/zotero/xpcom/integration.js
+++ b/chrome/content/zotero/xpcom/integration.js
@@ -596,7 +596,10 @@ Zotero.Integration.Document.prototype._updateSession = function(newField, editFi
// if we are reloading this session, assume no item IDs to be updated except for edited items
if(this._reloadSession) {
- this._session.restoreProcessorState();
+ //this._session.restoreProcessorState(); TODO doesn't appear to be working properly
+ this._session.updateUpdateIndices();
+ var deleteCitations = this._session.updateCitations();
+ this._deleteFields = this._deleteFields.concat([i for(i in deleteCitations)]);
this._session.updateIndices = {};
this._session.updateItemIDs = {};
this._session.bibliographyHasChanged = false;
@@ -627,7 +630,7 @@ Zotero.Integration.Document.prototype._updateSession = function(newField, editFi
*/
Zotero.Integration.Document.prototype._updateDocument = function(forceCitations, forceBibliography) {
// update citations
- this._session.updateUpdateIndices(forceCitations);
+ this._session.updateUpdateIndices();
var deleteCitations = this._session.updateCitations();
this._deleteFields = this._deleteFields.concat([i for(i in deleteCitations)]);
for(var i in this._session.updateIndices) {
@@ -658,7 +661,7 @@ Zotero.Integration.Document.prototype._updateDocument = function(forceCitations,
if(this._bibliographyFields.length // if blbliography exists
&& (this._session.bibliographyHasChanged // and bibliography changed
|| forceBibliography)) { // or if we should generate regardless of changes
- if(this._session.bibliographyDataHasChanged) {
+ if(forceBibliography || this._session.bibliographyDataHasChanged) {
var bibliographyData = this._session.getBibliographyData();
for each(var field in this._bibliographyFields) {
field.setCode(BIBLIOGRAPHY_CODE+" "+bibliographyData);
@@ -865,6 +868,7 @@ Zotero.Integration.Document.JSEnumerator.prototype.getNext = function() {
Zotero.Integration.Session = function() {
// holds items not in document that should be in bibliography
this.uncitedItems = new Object();
+ this.omittedItems = new Object();
this.customBibliographyText = new Object();
this.reselectedItems = new Object();
this.citationIDs = new Object();
@@ -1280,13 +1284,16 @@ Zotero.Integration.Session.prototype.deleteCitation = function(index) {
*/
Zotero.Integration.Session.prototype.getBibliography = function() {
// use real RTF, but chop off the first \n
- return Zotero.Cite.makeFormattedBibliography(this.style, "rtf", this.customBibliographyText);
+ this.updateUncitedItems();
+ return Zotero.Cite.makeFormattedBibliography(this.style, "rtf", this.customBibliographyText, this.omittedItems);
}
/**
* Calls CSL.Engine.updateUncitedItems() to reconcile list of uncited items
*/
Zotero.Integration.Session.prototype.updateUncitedItems = function() {
+ // There appears to be a bug somewhere here.
+ Zotero.debug("UPDATING UNCITED ITEMS WITH "+this.uncitedItems.toSource());
this.style.updateUncitedItems([parseInt(i) for(i in this.uncitedItems)]);
}
@@ -1414,7 +1421,7 @@ Zotero.Integration.Session.prototype.updateCitations = function() {
}
/**
- * Updates the list of citations to be serialized to the document
+ * Restores processor state from document, without requesting citation updates
*/
Zotero.Integration.Session.prototype.restoreProcessorState = function() {
var citations = [];
@@ -1423,7 +1430,6 @@ Zotero.Integration.Session.prototype.restoreProcessorState = function() {
citations.push(this.citationsByIndex[i]);
}
}
-
this.style.restoreProcessorState(citations);
}
@@ -1441,15 +1447,21 @@ Zotero.Integration.Session.prototype.loadBibliographyData = function(json) {
}
}
+ var needUpdate;
+
// set uncited
if(documentData.uncited) {
if(documentData.uncited[0]) {
// new style array of arrays with URIs
- var zoteroItem, needUpdate;
+ let zoteroItem, needUpdate;
for each(var uris in documentData.uncited) {
- [zoteroItem, needUpdate] = this.uriMap.getZoteroItemForURIs(uris);
- if(zoteroItem) this.uncitedItems[zoteroItem.id] = true;
- if(needUpdate) this.bibliographyDataHasChanged = true;
+ [zoteroItem, update] = this.uriMap.getZoteroItemForURIs(uris);
+ if(zoteroItem && !this.citationsByItemID[zoteroItem.id]) {
+ this.uncitedItems[zoteroItem.id] = true;
+ } else {
+ needUpdate = true;
+ }
+ this.bibliographyDataHasChanged |= needUpdate;
}
} else {
for(var itemID in documentData.uncited) {
@@ -1493,6 +1505,20 @@ Zotero.Integration.Session.prototype.loadBibliographyData = function(json) {
}
}
+ // set entries to be omitted from bibliography
+ if(documentData.omitted) {
+ let zoteroItem, needUpdate;
+ for each(var uris in documentData.omitted) {
+ [zoteroItem, update] = this.uriMap.getZoteroItemForURIs(uris);
+ if(zoteroItem && this.citationsByItemID[zoteroItem.id]) {
+ this.omittedItems[zoteroItem.id] = true;
+ } else {
+ needUpdate = true;
+ }
+ this.bibliographyDataHasChanged |= needUpdate;
+ }
+ }
+
this.bibliographyData = json;
}
@@ -1509,6 +1535,12 @@ Zotero.Integration.Session.prototype.getBibliographyData = function() {
bibliographyData.uncited.push(this.uriMap.getURIsForItemID(item));
}
}
+ for(var item in this.omittedItems) {
+ if(item) {
+ if(!bibliographyData.omitted) bibliographyData.omitted = [];
+ bibliographyData.omitted.push(this.uriMap.getURIsForItemID(item));
+ }
+ }
// look for custom bibliography entries
bibliographyData.custom = [[this.uriMap.getURIsForItemID(id), this.customBibliographyText[id]]
@@ -1609,6 +1641,18 @@ Zotero.Integration.Session.prototype.editBibliography = function() {
*/
Zotero.Integration.Session.BibliographyEditInterface = function(session) {
this.session = session;
+
+ this._changed = {
+ "customBibliographyText":{},
+ "uncitedItems":{},
+ "omittedItems":{}
+ }
+ for(var list in this._changed) {
+ for(var key in this.session[list]) {
+ this._changed[list][key] = this.session[list][key];
+ }
+ }
+
this._update();
}
@@ -1619,18 +1663,70 @@ Zotero.Integration.Session.BibliographyEditInterface.prototype._update = functio
this.session.updateUncitedItems();
this.session.style.setOutputFormat("rtf");
this.bibliography = this.session.style.makeBibliography();
+ Zotero.Cite.removeFromBibliography(this.bibliography, this.session.omittedItems);
+
for(var i in this.bibliography[0].entry_ids) {
- if(this.session.customBibliographyText[this.bibliography[0].entry_ids[i]]) {
- this.bibliography[1][i] = this.session.customBibliographyText[this.bibliography[0].entry_ids[i]];
+ if(this.bibliography[0].entry_ids[i].length != 1) continue;
+ var itemID = this.bibliography[0].entry_ids[i][0];
+ if(this.session.customBibliographyText[itemID]) {
+ this.bibliography[1][i] = this.session.customBibliographyText[itemID];
}
}
}
/**
- * Checks whether an item ID is cited in the bibliography being edited
+ * Reverts the text of an individual bibliography entry
+ */
+Zotero.Integration.Session.BibliographyEditInterface.prototype.revert = function(itemID) {
+ delete this.session.customBibliographyText[itemID];
+ this._update();
+}
+
+/**
+ * Reverts bibliography to condition in which no edits have been made
+ */
+Zotero.Integration.Session.BibliographyEditInterface.prototype.revertAll = function() {
+ for(var list in this._changed) {
+ this.session[list] = {};
+ }
+ this._update();
+}
+
+/**
+ * Reverts bibliography to condition before BibliographyEditInterface was opened
+ * Does not run _update automatically, since this will usually only happen with a cancel request
+ */
+Zotero.Integration.Session.BibliographyEditInterface.prototype.cancel = function() {
+ for(var list in this._changed) {
+ this.session[list] = this._changed[list];
+ }
+ this.session.updateUncitedItems();
+}
+
+/**
+ * Checks whether a given reference is cited within the main document text
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.isCited = function(item) {
if(this.session.citationsByItemID[item]) return true;
+}
+
+/**
+ * Checks whether an item ID is cited in the bibliography being edited
+ */
+Zotero.Integration.Session.BibliographyEditInterface.prototype.isEdited = function(itemID) {
+ if(this.session.customBibliographyText[itemID]) return true;
+ return false;
+}
+
+/**
+ * Checks whether any citations in the bibliography have been edited
+ */
+Zotero.Integration.Session.BibliographyEditInterface.prototype.isAnyEdited = function() {
+ for(var list in this._changed) {
+ for(var a in this.session[list]) {
+ return true;
+ }
+ }
return false;
}
@@ -1638,8 +1734,11 @@ Zotero.Integration.Session.BibliographyEditInterface.prototype.isCited = functio
* Adds an item to the bibliography
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.add = function(itemID) {
- // create new item
- this.session.uncitedItems[itemID] = true;
+ if(this.session.omittedItems[itemID]) {
+ delete this.session.omittedItems[itemID];
+ } else {
+ this.session.uncitedItems[itemID] = true;
+ }
this._update();
}
@@ -1647,19 +1746,11 @@ Zotero.Integration.Session.BibliographyEditInterface.prototype.add = function(it
* Removes an item from the bibliography being edited
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.remove = function(itemID) {
- // delete citations if necessary
- if(this.session.citationsByItemID[itemID]) {
- for(var j=0; j