www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 05583b199220a7eab41f2af209c969f61029ec3b
parent 68c4a47bf3cf13228ae0a71b1e8f626d8a446a46
Author: Simon Kornblith <simon@simonster.com>
Date:   Mon, 28 Jun 2010 02:38:48 +0000

closes #1099, Add cancel button to Edit Bibliography
closes #744, Select multiple items/entire collection in edit bibliography dialog

- adds "Cancel", "Revert", and "Revert All" buttons to edit bibliography dialog
- permits multiple item selections in edit bibliography dialog
- removing items in the edit bibliography dialog now leaves the citations intact, but removes them from the document


Diffstat:
Mchrome/content/zotero/integration/editBibliographyDialog.js | 252++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mchrome/content/zotero/integration/editBibliographyDialog.xul | 19++++++++++++-------
Mchrome/content/zotero/xpcom/cite.js | 20+++++++++++++++++++-
Mchrome/content/zotero/xpcom/integration.js | 145++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
4 files changed, 349 insertions(+), 87 deletions(-)

diff --git 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 + + // 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; + } + } + } - // disable add if item already in itemSet - document.getElementById("add").disabled = selectedItems.length && bibEditInterface.bibliography[0].entry_ids.indexOf(selectedItems[0].id) !== -1; + _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(); } - /* - * called when an item in the reference list is clicked + /** + * Called when an item in the reference list is clicked */ - function listItemSelected() { - var selectedListItem = document.getElementById("item-list").getSelectedItem(0); + this.listItemSelected = function() { + if(_suppressAllSelectEvents) return; - // enable remove if item is selected - document.getElementById("remove").disabled = !selectedListItem; + // enable remove if at least one item is selected + _addButton.disabled = true; + _removeButton.disabled = !_itemList.selectedItems.length; - if(selectedListItem) { - _updatePreview(selectedListItem.value); - } else { - _updatePreview(); + 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 a citation to the reference list + /** + * Adds references to the reference list */ - function add() { - var selectedItem = itemsView.getSelectedItems()[0]; // treeview from selectItemsDialog.js - Zotero.debug(selectedItem); - - bibEditInterface.add(selectedItem.id); + 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); + + 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(); - if(bibEditInterface.isCited(itemID)) { + _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 @@ -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()"> <script src="../include.js"/> <script src="../selectItemsDialog.js"/> @@ -72,7 +76,7 @@ </tree> <tree id="zotero-items-tree" - flex="1" hidecolumnpicker="true" seltype="single" + flex="1" hidecolumnpicker="true" seltype="multiple" onselect="Zotero_Bibliography_Dialog.treeItemSelected();"> <treecols> <treecol @@ -101,14 +105,15 @@ </vbox> <hbox id="source-list"> - <vbox align="center" pack="center"> + <vbox align="center" pack="center" id="citation-buttons"> <toolbarbutton id="add" oncommand="Zotero_Bibliography_Dialog.add()" disabled="true"/> <toolbarbutton id="remove" oncommand="Zotero_Bibliography_Dialog.remove()" disabled="true"/> </vbox> <vbox> <label value="&zotero.integration.references.label;"/> - <listbox id="item-list" flex="1" align="stretch" seltype="single" - style="width: 250px;" onselect="Zotero_Bibliography_Dialog.listItemSelected();"/> + <listbox id="item-list" flex="1" align="stretch" seltype="multiple" + style="width: 250px;" onselect="Zotero_Bibliography_Dialog.listItemSelected();" + onchanged="Zotero_Bibliography_Dialog.textChanged()"/> </vbox> </hbox> </hbox> diff --git 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 @@ -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<this.session.citationsByItemID[itemID].length; j++) { - var citation = this.session.citationsByItemID[itemID][j]; - this.session.updateIndices[citation.properties.index] = true; - citation.properties["delete"] = true; - } - delete this.session.citationsByItemID[itemID]; - this.session.updateCitations(); + if(this.session.uncitedItems[itemID]) { + delete this.session.uncitedItems[itemID]; + } else { + this.session.omittedItems[itemID] = true; } - - // delete uncited if neceessary - if(this.session.uncitedItems[itemID]) delete this.session.uncitedItems[itemID]; this._update(); }