commit 78d46dc0f0a98b64bb8d971472b071280e69bd97
parent 40b6ed19f802f839aa7c657a75fbd8cb0e1c936e
Author: Simon Kornblith <simon@simonster.com>
Date: Tue, 29 Jun 2010 06:34:20 +0000
closes #1680, Allow repeat use of item in a citation (patch due entirely to Frank)
see notes at referenced ticket for information re: modifications in behavior
Diffstat:
2 files changed, 255 insertions(+), 112 deletions(-)
diff --git a/chrome/content/zotero/integration/addCitationDialog.js b/chrome/content/zotero/integration/addCitationDialog.js
@@ -24,12 +24,14 @@
*/
var Zotero_Citation_Dialog = new function () {
+ // Array value [0] is property name.
+ // Array value [1] is default value of property.
var _preserveData = {
- "prefix":"value",
- "suffix":"value",
- "label":"selectedIndex",
- "locator":"value",
- "suppress-author":"checked"
+ "prefix":["value", ""],
+ "suffix":["value", ""],
+ "label":["selectedIndex", 0],
+ "locator":["value", ""],
+ "suppress-author":["checked", false]
};
var _itemData = new Object();
@@ -42,9 +44,11 @@ var Zotero_Citation_Dialog = new function () {
var _locatorNameArray = {};
var _autoRegeneratePref;
var _acceptButton;
+ var _multipleSourceButton;
var _sortCheckbox;
var _citationList;
var _originalHTML;
+ var serial_number;
var io;
this.load = load;
@@ -56,7 +60,8 @@ var Zotero_Citation_Dialog = new function () {
this.down = down;
this.add = add;
this.remove = remove;
- this.sortCitation = sortCitation;
+ this.setSortToggle = setSortToggle;
+ this.citationSortUnsort = citationSortUnsort;
this.confirmRegenerate = confirmRegenerate;
this.accept = accept;
this.cancel = cancel;
@@ -72,9 +77,15 @@ var Zotero_Citation_Dialog = new function () {
// find accept button
_acceptButton = document.getElementById("zotero-add-citation-dialog").getButton("accept");
+ _multipleSourceButton = document.documentElement.getButton("extra1");
_autoRegeneratePref = Zotero.Prefs.get("integration.autoRegenerate");
_citationList = document.getElementById("citation-list");
+ // Manipulated by _addItem(). Discriminates between cite instances
+ // based on the same item in the same citation. Internal throwaway variable,
+ // reset each time _multipleSourcesOn is set to true.
+ serial_number = 0;
+
// if a style with sortable citations, present checkbox
if(io.sortable) {
_sortCheckbox = document.getElementById("keepSorted");
@@ -85,16 +96,16 @@ var Zotero_Citation_Dialog = new function () {
// load locators
var locators = Zotero.Cite.labels;
var menu = document.getElementById("label");
- var popup = document.getElementById("locator-type-popup");
+ var label_list = document.getElementById("locator-type-popup");
var i = 0;
for(var value in locators) {
var locator = locators[value];
var locatorLabel = locator[0].toUpperCase()+locator.substr(1);
- // add to popup
+ // add to list of labels
var child = document.createElement("menuitem");
child.setAttribute("value", value);
child.setAttribute("label", locatorLabel);
- popup.appendChild(child);
+ label_list.appendChild(child);
// add to array
_locatorIndexArray[locator] = i;
_locatorNameArray[i] = locator;
@@ -108,29 +119,54 @@ var Zotero_Citation_Dialog = new function () {
// if we already have a citation, load data from it
document.getElementById('editor').format = "RTF";
if(io.citation.citationItems.length) {
- if(io.citation.citationItems.length == 1) {
+ if(io.citation.citationItems.length === 1) {
// single citation
+ toggleMultipleSources(false);
_suppressNextTreeSelect = true;
- itemsView.selectItem(io.citation.citationItems[0].id); // treeview from selectItemsDialog.js
- for(var property in _preserveData) {
- if(io.citation.citationItems[0][property]) {
- if(property == "label") {
- document.getElementById(property)[_preserveData[property]] = _locatorIndexArray[io.citation.citationItems[0][property]];
+ itemsView.selectItem(io.citation.citationItems[0].id); // treeview from xpcom/itemTreeView.js
+ for(var box in _preserveData) {
+ var property = _preserveData[box][0];
+ if(io.citation.citationItems[0][box]) {
+ if(box === "label") {
+ document.getElementById(box)[property] = _locatorIndexArray[io.citation.citationItems[0][box]];
} else {
- document.getElementById(property)[_preserveData[property]] = io.citation.citationItems[0][property];
+ document.getElementById(box)[property] = io.citation.citationItems[0][box];
}
}
}
} else {
// multiple citations
- toggleMultipleSources();
+ toggleMultipleSources(true);
+ var _itemData = {};
+ // There is a little thrashing here, with repeated writes and
+ // overwrites of node content. But sticking to the same
+ // workflow for all updates (node -> array -> io.citation) makes
+ // debugging a little less painful.
for(var i=0; i<io.citation.citationItems.length; i++) {
var item = Zotero.Items.get(io.citation.citationItems[i].id);
if(item) {
- _addItem(item);
- _itemData[io.citation.citationItems[i].id] = io.citation.citationItems[i];
+ var itemNode = _addItem(item);
+ var itemDataID = itemNode.getAttribute("value");
+ _itemData[itemDataID] = {};
+ for(var box in _preserveData) {
+ var domBox = document.getElementById(box);
+ var property = _preserveData[box][0];
+ if("undefined" !== typeof io.citation.citationItems[i][box]) {
+ if(box === "label") {
+ domBox[property] = _locatorIndexArray[io.citation.citationItems[i][box]];
+ } else {
+ domBox[property] = io.citation.citationItems[i][box];
+ }
+ } else {
+ domBox[property] = _preserveData[box][1];
+ }
+ }
+ _itemSelected(itemDataID, true);
}
}
+ for (var box in _preserveData) {
+ document.getElementById(box).disabled = true;
+ }
}
// show user-editable edited citation
@@ -140,57 +176,65 @@ var Zotero_Citation_Dialog = new function () {
}
_updateAccept();
+ } else {
+ toggleMultipleSources(false);
}
}
/*
* turn on/off multiple sources item list
*/
- function toggleMultipleSources() {
+ function toggleMultipleSources(mode) {
+ if (mode === false || mode === true) {
+ _multipleSourcesOn = !mode;
+ }
_multipleSourcesOn = !_multipleSourcesOn;
+ var popup = document.defaultView;
+ var dialog = document.getElementById("zotero-add-citation-dialog");
+ if (dialog.getAttribute("height") == 1) {
+ popup.sizeToContent();
+ }
if(_multipleSourcesOn) {
- var items = itemsView.getSelectedItems(true);
- var itemID = (items.length ? items[0] : false);
- // var itemDataID = itemID+"::"+0;
- document.getElementById("multiple-sources").hidden = undefined;
- document.getElementById("zotero-add-citation-dialog").width = "750";
- document.documentElement.getButton("extra1").label = Zotero.getString("citation.singleSource");
- // move user field content to multiple before adding XXXXX
- if (itemID) {
- // _itemData[itemDataID] = new Object();
- _itemData[itemID] = new Object();
- var element;
- for (var box in _preserveData) {
- element = document.getElementById(box);
- // _itemData[itemDataID][box] = element[_preserveData[box]];
- _itemData[itemID][box] = element[_preserveData[box]];
- }
- }
- treeItemSelected();
- // disable adding info until citation added
- _itemSelected(false);
- // add current selection
- if (itemID) {
- this.add();
- } else {
- _updateAccept();
- _updatePreview();
+ _multipleSourceButton.label = Zotero.getString("citation.singleSource");
+ document.getElementById("multiple-sources").setAttribute("hidden", false);
+ popup.resizeTo(750, dialog.getAttribute("height"));
+ //popup.moveBy((600 - 750)/2, 0);
+
+ serial_number = 0;
+
+
+ // The mode is forced only when run from load(), in which case
+ // the adding of items is done separately.
+ if (mode !== true) {
+ this.add(true);
}
} else {
- document.getElementById("multiple-sources").hidden = true;
- document.getElementById("zotero-add-citation-dialog").width = "600";
- document.documentElement.getButton("extra1").label = Zotero.getString("citation.multipleSources");
+ _multipleSourceButton.label = Zotero.getString("citation.multipleSources");
+ document.getElementById("multiple-sources").setAttribute("hidden", true);
+ popup.resizeTo(600, dialog.getAttribute("height"));
+ //popup.moveBy((750 - 600)/2, 0);
// enable all fields
- for(var i in _preserveData) {
- document.getElementById(i).disabled = false;
+ for(var box in _preserveData) {
+ document.getElementById(box).disabled = false;
}
+ var itemID = false;
+ if (_citationList.selectedIndex > -1) {
+ var itemDataID = _citationList.getSelectedItem(0).getAttribute("value");
+ itemID = itemDataID.slice(0, itemDataID.indexOf(":"));
+ }
+
// delete item list
_itemData = new Object();
// delete all items
_clearCitationList();
+
+ // refresh
+ if (itemID) {
+ itemsView.wrappedJSObject.selectItem(itemID);
+ }
_updateAccept();
_updatePreview();
}
@@ -205,23 +249,32 @@ var Zotero_Citation_Dialog = new function () {
_updateAccept();
return;
}
- var items = itemsView.getSelectedItems(true); // treeview from selectItemsDialog.js
+ var items = itemsView.getSelectedItems(true); // treeview from xpcom/itemTreeView.js
var itemID = (items.length ? items[0] : false);
if(_multipleSourcesOn) {
- // if item is also on right side, show info
- var hasBeenAdded = itemID && _itemData[itemID] !== undefined;
- // disable boxes if item not added; otherwise, enable
- _itemSelected(hasBeenAdded ? itemID : false);
+ // We can safely use itemID here, because none of these operations
+ // affect selected items; this is all about the tree and navigation.
+
// turn off highlight in selected item list
_suppressNextListSelect = true;
document.getElementById("citation-list").selectedIndex = -1;
- // disable adding nothing, or things already added
- document.getElementById("add").disabled = !itemID || hasBeenAdded;
+
+ // disable all fields
+
+ for(var box in _preserveData) {
+ document.getElementById(box).disabled = true;
+ }
+
+ // disable adding nothing
+ document.getElementById("add").disabled = !itemID;
document.getElementById("remove").disabled = true;
document.getElementById("up").disabled = true;
document.getElementById("down").disabled = true;
} else {
+ for(var box in _preserveData) {
+ document.getElementById(box).disabled = !itemID;
+ }
_updateAccept();
_updatePreview();
}
@@ -238,14 +291,14 @@ var Zotero_Citation_Dialog = new function () {
}
var selectedListItem = _citationList.getSelectedItem(0);
var selectedListIndex = _citationList.selectedIndex;
- var itemID = (selectedListItem ? selectedListItem.value : false);
- _itemSelected(itemID);
+ var itemDataID = (selectedListItem ? selectedListItem.getAttribute("value") : false);
+ _itemSelected(itemDataID);
// turn off highlight in item tree
_suppressNextTreeSelect = true;
document.getElementById("zotero-items-tree").view.selection.clearSelection();
- document.getElementById("remove").disabled = !itemID;
+ document.getElementById("remove").disabled = !itemDataID;
document.getElementById("add").disabled = true;
- _configListPosition(!itemID, selectedListIndex);
+ _configListPosition(!itemDataID, selectedListIndex);
}
function _configListPosition(flag, selectedListIndex) {
@@ -265,13 +318,13 @@ var Zotero_Citation_Dialog = new function () {
// automatically uncheck sorted checkbox if user is rearranging citation
if(_sortCheckbox && _sortCheckbox.checked) {
_sortCheckbox.checked = false;
- sortCitation();
+ setSortToggle();
}
var insertBeforeItem;
var selectedListItem = _citationList.getSelectedItem(0);
var selectedListIndex = _citationList.selectedIndex;
- var itemID = selectedListItem.value;
+ var itemDataID = selectedListItem.getAttribute("value");
if (direction === -1) {
insertBeforeItem = selectedListItem.previousSibling;
} else {
@@ -280,7 +333,7 @@ var Zotero_Citation_Dialog = new function () {
var listItem = _citationList.removeChild(selectedListItem);
_citationList.insertBefore(listItem, insertBeforeItem);
_citationList.selectedIndex = (selectedListIndex + direction);
- _itemSelected(itemID);
+ _itemSelected(itemDataID);
_updatePreview();
_configListPosition(false, (selectedListIndex + direction));
}
@@ -294,20 +347,51 @@ var Zotero_Citation_Dialog = new function () {
}
/*
- * Adds a citation to the multipleSources list
+ * Adds an item to the multipleSources list
*/
- function add() {
- var item = itemsView.getSelectedItems()[0]; // treeview from selectItemsDialog.js
- _itemSelected(item.id);
- _citationList.ensureElementIsVisible(_addItem(item));
+ function add(first_item) {
- // don't let someone select it again
- document.getElementById("add").disabled = true;
+ var pos, len;
+ var item = itemsView.getSelectedItems()[0]; // treeview from xpcom/itemTreeView.js
+ if (!item) {
+ sortCitation();
+ _updateAccept();
+ _updatePreview();
+ return;
+ }
+
+ // Add to selection list and generate a new itemDataID for this cite.
+ var selectionNode = _addItem(item);
+ var itemDataID = selectionNode.getAttribute("value");
+ document.getElementById("add").disabled = !itemDataID;
+
+ // Save existing locator and affix field content, if any.
+ if (first_item) {
+ _itemSelected(itemDataID, true);
+ } else {
+ _itemSelected();
+ // set to defaults
+ for(var box in _preserveData) {
+ var property = _preserveData[box][0];
+ var default_value = _preserveData[box][1];
+ document.getElementById(box)[property] = default_value;
+ }
+ // Save default locator and affix element values to this multi-item.
+ _itemSelected(itemDataID, true);
+ }
+
+ for(var box in _preserveData) {
+ document.getElementById(box).disabled = true;
+ }
+
+ _citationList.ensureElementIsVisible(selectionNode);
+
// allow user to press OK
+ selectionNode = sortCitation(selectionNode);
+ _citationList.selectItem(selectionNode);
_updateAccept();
_updatePreview();
- sortCitation(item.id);
}
/*
@@ -316,11 +400,11 @@ var Zotero_Citation_Dialog = new function () {
function remove() {
var selectedListItem = _citationList.getSelectedItem(0);
var selectedListIndex = _citationList.selectedIndex;
- var itemID = selectedListItem.value;
+ var itemDataID = selectedListItem.getAttribute("value");
// remove from _itemData
- delete _itemData[itemID];
- _itemData[itemID] = undefined;
+ delete _itemData[itemDataID];
+ _itemData[itemDataID] = undefined;
_lastSelected = null;
// remove from list
@@ -336,17 +420,40 @@ var Zotero_Citation_Dialog = new function () {
}
/*
- * Sorts the list of citations
+ * Sorts preview citations, if preview is open.
+ */
+ function citationSortUnsort() {
+ setSortToggle();
+ sortCitation();
+ _updatePreview();
+ }
+
+ /*
+ * Sets the current sort toggle state persistently on the citation.
*/
- function sortCitation(scrollToItemID) {
+ function setSortToggle() {
if(!_sortCheckbox) return;
if(!_sortCheckbox.checked) {
io.citation.properties.unsorted = true;
- return;
+ } else {
+ io.citation.properties.unsorted = false;
}
+ return;
+ }
- var selectedItemID = (_citationList.selectedItem ? _citationList.selectedItem.value : null);
- Zotero.debug("item "+selectedItemID+" selected");
+ /*
+ * Sorts the list of citations
+ */
+ function sortCitation(scrollToItem) {
+ if(!_sortCheckbox) return scrollToItem;
+ if(!_sortCheckbox.checked) {
+ io.citation.properties.unsorted = true;
+ return scrollToItem;
+ }
+ var scrollToItemID = false;
+ if (scrollToItem) {
+ scrollToItemID = scrollToItem.getAttribute("value");
+ }
_getCitation();
// delete all existing items from list
@@ -357,20 +464,24 @@ var Zotero_Citation_Dialog = new function () {
io.previewFunction();
// add items back to list
- var scrollTo = null;
+ scrollToItem = null;
for(var i=0; i<io.citation.sortedItems.length; i++) {
var itemID = io.citation.sortedItems[i][0].id;
+ var itemDataID = io.citation.sortedItems[i][1].tmpItemDataID;
var item = Zotero.Items.get(itemID);
- var itemNode = _addItem(item);
- if(itemID == selectedItemID) _citationList.selectedIndex = i;
- if(scrollToItemID && itemID == scrollToItemID) scrollTo = itemNode;
+ // Don't increment serial_number, and use the
+ // existing itemDataID stored on the item in sortedItems
+ var itemNode = _addItem(item, itemDataID);
+ if(itemDataID == scrollToItemID) _citationList.selectedIndex = i;
+ if(scrollToItemID && itemDataID == scrollToItemID) scrollToItem = itemNode;
}
- if(scrollTo) _citationList.ensureElementIsVisible(scrollTo);
+ if(scrollToItem) _citationList.ensureElementIsVisible(scrollToItem);
+ return scrollToItem;
}
/*
- * Ask whether to modfiy the preview
+ * Ask whether to modifiy the preview
*/
function confirmRegenerate(focusShifted) {
if(document.getElementById('editor').value == _originalHTML || _originalHTML === undefined) {
@@ -491,23 +602,39 @@ var Zotero_Citation_Dialog = new function () {
function _updateAccept(status) {
if(_multipleSourcesOn) {
_acceptButton.disabled = !_citationList.getRowCount();
+ // To prevent accidental data loss, do not allow change to
+ // single citation mode if multiple items are in selection
+ // list.
+ if (_citationList.getRowCount() > 1) {
+ _multipleSourceButton.disabled = true;
} else {
- _acceptButton.disabled = !itemsView.getSelectedItems().length; // treeview from selectItemsDialog.js
+ _multipleSourceButton.disabled = false;
}
+ } else {
+ _acceptButton.disabled = !itemsView.getSelectedItems().length; // treeview from xpcom/itemTreeView.js
+ }
}
/*
- * called when an item is selected; if itemID is false, disables fields; if
- * itemID is undefined, only updates _itemData array
+ * called when an item is selected; if itemDataID is false, disables fields; if
+ * itemDataID is undefined, only updates _itemData array
+ *
+ * Note: This function no longer disables fields. That operation is
+ * now performed separately by explicit code.
*/
- function _itemSelected(itemID) {
+ function _itemSelected(itemDataID, forceSave) {
+
+ if (forceSave) {
+ _lastSelected = itemDataID;
+ }
+
if(_lastSelected && !_itemData[_lastSelected]) {
_itemData[_lastSelected] = new Object();
}
for(var box in _preserveData) {
var domBox = document.getElementById(box);
- var property = _preserveData[box];
+ var property = _preserveData[box][0];
// save property
if(_lastSelected) {
@@ -518,28 +645,26 @@ var Zotero_Citation_Dialog = new function () {
}
}
// restore previous property
- if(itemID) {
+ if(itemDataID) {
domBox.disabled = false;
- if(_itemData[itemID] && _itemData[itemID][box] !== undefined) {
+ if(_itemData[itemDataID] && _itemData[itemDataID][box] !== undefined) {
if(property == "label") {
- domBox[property] = _locatorIndexArray[_itemData[itemID][box]];
+ domBox[property] = _locatorIndexArray[_itemData[itemDataID][box]];
} else {
- domBox[property] = _itemData[itemID][box];
+ domBox[property] = _itemData[itemDataID][box];
}
}
- } else if(itemID !== undefined) {
- domBox.disabled = true;
- domBox[property] = "";
}
}
- if(itemID !== undefined) _lastSelected = itemID;
+ if(itemDataID !== undefined) _lastSelected = itemDataID;
}
/*
* updates io.citation to reflect selected items
*/
function _getCitation() {
+ var key;
io.citation.citationItems = new Array();
// use to map selectedIndexes back to page/paragraph/line
@@ -547,28 +672,37 @@ var Zotero_Citation_Dialog = new function () {
if(_multipleSourcesOn) {
_itemSelected(); // store locator info
var listLength = _citationList.getRowCount();
- var citationItems = new Array();
if(listLength) {
// generate citationItems
for(var i=0; i<listLength; i++) {
- var itemID = _citationList.getItemAtIndex(i).getAttribute("value");
-
- var citationItem = _itemData[itemID];
+ var itemDataID = _citationList.getItemAtIndex(i).getAttribute("value");
+ var citationItem = {};
+ for (key in _itemData[itemDataID]) {
+ // label is special everywhere
+ if (key === "label") {
+ citationItem.label = _locatorNameArray[_itemData[itemDataID].label];
+ } else if (_itemData[itemDataID][key]) {
+ citationItem[key] = _itemData[itemDataID][key];
+ }
+ }
+ citationItem["tmpItemDataID"] = itemDataID;
+ var itemID = itemDataID.slice(0, itemDataID.indexOf(":"));
citationItem.id = itemID;
io.citation.citationItems.push(citationItem);
}
}
} else {
- var items = itemsView.getSelectedItems(true); // treeview from selectItemsDialog.js
+ var items = itemsView.getSelectedItems(true); // treeview from xpcom/itemTreeView.js
if(items.length) {
var citationItem = {};
citationItem.id = items[0];
- for(var property in _preserveData) {
- if(property == "label") {
- citationItem[property] = _locatorNameArray[document.getElementById(property).selectedIndex];
+ for(var box in _preserveData) {
+ var property = _preserveData[box][0];
+ if(box == "label") {
+ citationItem[box] = _locatorNameArray[document.getElementById(box).selectedIndex];
} else {
- citationItem[property] = document.getElementById(property)[_preserveData[property]];
+ citationItem[box] = document.getElementById(box)[property];
}
}
@@ -586,9 +720,18 @@ var Zotero_Citation_Dialog = new function () {
/*
* Add an item to the item list (multiple sources only)
*/
- function _addItem(item) {
+ function _addItem(item, forceID) {
var itemNode = document.createElement("listitem");
- itemNode.setAttribute("value", item.id);
+
+ var itemDataID;
+ if (!forceID) {
+ serial_number += 1;
+ itemDataID = item.id + ":" + serial_number;
+ } else {
+ itemDataID = forceID;
+ }
+
+ itemNode.setAttribute("value", itemDataID);
itemNode.setAttribute("label", item.getField("title"));
itemNode.setAttribute("class", "listitem-iconic");
itemNode.setAttribute("image", item.getImageSrc());
diff --git a/chrome/content/zotero/integration/addCitationDialog.xul b/chrome/content/zotero/integration/addCitationDialog.xul
@@ -167,7 +167,7 @@
<toolbarbutton id="down" oncommand="Zotero_Citation_Dialog.down()" disabled="true"/>
</vbox>
<vbox align="left">
- <checkbox id="keepSorted" hidden="true" checked="false" oncommand="Zotero_Citation_Dialog.sortCitation()" label="&zotero.citation.keepSorted.label;"/>
+ <checkbox id="keepSorted" hidden="true" checked="false" oncommand="Zotero_Citation_Dialog.citationSortUnsort()" label="&zotero.citation.keepSorted.label;"/>
<listbox id="citation-list" flex="1" align="stretch" seltype="single"
onselect="Zotero_Citation_Dialog.listItemSelected();"/>
</vbox>