commit 2a55e56f3fee41f2f3526f21a64eb6eb349ec052
parent 2cce099928101ac43015e6c8ff51afc9aff4afdb
Author: Dan Stillman <dstillman@zotero.org>
Date: Wed, 29 Jun 2016 05:24:14 -0400
Save open field when selecting from an item pane context menu
If a field is open and the user right-clicks on another field (e.g., swap
names, creator type, transform text), any changed value in the open field was
lost.
Also:
- Don't show swap-names menu in single-field mode
I can't quite get programmatic access to context menus to work correctly, so
tests are disabled for now. (They work individually, but not together.)
Diffstat:
2 files changed, 129 insertions(+), 32 deletions(-)
diff --git a/chrome/content/zotero/bindings/itembox.xml b/chrome/content/zotero/bindings/itembox.xml
@@ -786,7 +786,7 @@
firstlast.lastChild.setAttribute('hidden', true);
}
- if (this.editable) {
+ if (this.editable && fieldMode == 0) {
firstlast.setAttribute('contextmenu', 'zotero-creator-transform-menu');
}
@@ -2021,28 +2021,32 @@
<method name="textTransform">
<parameter name="label"/>
<parameter name="mode"/>
- <body>
- <![CDATA[
- var val = this._getFieldValue(label);
- switch (mode) {
- case 'title':
- var newVal = Zotero.Utilities.capitalizeTitle(val.toLowerCase(), true);
- break;
- case 'sentence':
- // capitalize the first letter, including after beginning punctuation
- // capitalize after ?, ! and remove space(s) before those as well as colon analogous to capitalizeTitle function
- // also deal with initial punctuation here - open quotes and Spanish beginning punctuation marks
- newVal = val.toLowerCase().replace(/\s*:/, ":");
- newVal = newVal.replace(/(([\?!]\s*|^)([\'\"¡¿“‘„«\s]+)?[^\s])/g, function (x) {
- return x.replace(/\s+/m, " ").toUpperCase();});
- break;
- default:
- throw ("Invalid transform mode '" + mode + "' in zoteroitembox.textTransform()");
- }
- this._setFieldValue(label, newVal);
- this._modifyField(label.getAttribute('fieldname'), newVal, this.saveOnEdit).done();
- ]]>
- </body>
+ <body><![CDATA[
+ return Zotero.spawn(function* () {
+ var val = this._getFieldValue(label);
+ switch (mode) {
+ case 'title':
+ var newVal = Zotero.Utilities.capitalizeTitle(val.toLowerCase(), true);
+ break;
+ case 'sentence':
+ // capitalize the first letter, including after beginning punctuation
+ // capitalize after ?, ! and remove space(s) before those as well as colon analogous to capitalizeTitle function
+ // also deal with initial punctuation here - open quotes and Spanish beginning punctuation marks
+ newVal = val.toLowerCase().replace(/\s*:/, ":");
+ newVal = newVal.replace(/(([\?!]\s*|^)([\'\"¡¿“‘„«\s]+)?[^\s])/g, function (x) {
+ return x.replace(/\s+/m, " ").toUpperCase();});
+ break;
+ default:
+ throw ("Invalid transform mode '" + mode + "' in zoteroitembox.textTransform()");
+ }
+ this._setFieldValue(label, newVal);
+ if (this.saveOnEdit) {
+ // See note in modifyCreator()
+ yield this.blurOpenField();
+ }
+ return this._modifyField(label.getAttribute('fieldname'), newVal, this.saveOnEdit);
+ }, this);
+ ]]></body>
</method>
@@ -2083,7 +2087,7 @@
<parameter name="fields"/>
<parameter name="skipSave"/>
<body><![CDATA[
- return Zotero.Promise.try(function () {
+ return Zotero.spawn(function* () {
var libraryID = this.item.libraryID;
var firstName = fields.firstName;
var lastName = fields.lastName;
@@ -2099,6 +2103,11 @@
}
this.item.removeCreator(index);
if (this.saveOnEdit && !skipSave) {
+ // Make sure any open field is saved, since a blur() isn't otherwise
+ // triggered clicking directly to a popup menu. (If a field is open, the
+ // saveTx() below will become a no-op.)
+ yield this.blurOpenField();
+
return this.item.saveTx();
}
return;
@@ -2106,9 +2115,12 @@
var changed = this.item.setCreator(index, fields);
if (changed && this.saveOnEdit && !skipSave) {
+ // See note above
+ yield this.blurOpenField();
+
return this.item.saveTx();
}
- }.bind(this));
+ }, this);
]]></body>
</method>
@@ -2117,6 +2129,7 @@
@return {Promise}
-->
<method name="swapNames">
+ <parameter name="event"/>
<body><![CDATA[
return Zotero.Promise.try(function () {
var row = Zotero.getAncestorByTagName(document.popupNode, 'row');
@@ -2138,9 +2151,8 @@
<method name="moveCreator">
<parameter name="index"/>
<parameter name="moveUp"/>
- <body>
- <![CDATA[
- return Zotero.Promise.try(function () {
+ <body><![CDATA[
+ return Zotero.spawn(function* () {
if (index == 0 && moveUp) {
Zotero.debug("Can't move up creator 0");
return;
@@ -2156,11 +2168,13 @@
this.item.setCreator(newIndex, a);
this.item.setCreator(index, b);
if (this.saveOnEdit) {
+ // See note in modifyCreator()
+ yield this.blurOpenField();
+
return this.item.saveTx();
}
- }.bind(this));
- ]]>
- </body>
+ }, this);
+ ]]></body>
</method>
@@ -2394,7 +2408,7 @@
var hideTransforms = !exists || !!fieldMode;
return !hideTransforms;">
<menuitem label="&zotero.item.creatorTransform.nameSwap;"
- oncommand="document.getBindingParent(this).swapNames();"/>
+ oncommand="document.getBindingParent(this).swapNames(event);"/>
</menupopup>
<menupopup id="zotero-doi-menu">
<menuitem id="zotero-doi-menu-view-online" label="&zotero.item.viewOnline;"/>
diff --git a/test/tests/itemPaneTest.js b/test/tests/itemPaneTest.js
@@ -27,6 +27,89 @@ describe("Item pane", function () {
yield Zotero.Items.erase(id);
})
+
+
+ it.skip("should swap creator names", function* () {
+ var item = new Zotero.Item('book');
+ item.setCreators([
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "author"
+ }
+ ]);
+ yield item.saveTx();
+
+ var itemBox = doc.getElementById('zotero-editpane-item-box');
+ var label = doc.getAnonymousNodes(itemBox)[0].getElementsByAttribute('fieldname', 'creator-0-lastName')[0];
+ var parent = label.parentNode;
+ assert.isTrue(parent.hasAttribute('contextmenu'));
+
+ var menupopup = doc.getAnonymousNodes(itemBox)[0]
+ .getElementsByAttribute('id', 'zotero-creator-transform-menu')[0];
+ // Fake a right-click
+ doc.popupNode = parent;
+ menupopup.openPopup(
+ parent, "after_start", 0, 0, true, false, new MouseEvent('click', { button: 2 })
+ );
+ var menuitem = menupopup.getElementsByTagName('menuitem')[0];
+ menuitem.click();
+ yield waitForItemEvent('modify');
+
+ var creator = item.getCreators()[0];
+ assert.propertyVal(creator, 'firstName', 'Last');
+ assert.propertyVal(creator, 'lastName', 'First');
+ });
+
+
+ it("shouldn't show Swap Names menu for single-field mode", function* () {
+ var item = new Zotero.Item('book');
+ item.setCreators([
+ {
+ name: "Name",
+ creatorType: "author"
+ }
+ ]);
+ yield item.saveTx();
+
+ var itemBox = doc.getElementById('zotero-editpane-item-box');
+ var label = doc.getAnonymousNodes(itemBox)[0].getElementsByAttribute('fieldname', 'creator-0-lastName')[0];
+ assert.isFalse(label.parentNode.hasAttribute('contextmenu'));
+ });
+
+
+ // Note: This issue applies to all context menus in the item box (text transform, name swap),
+ // though the others aren't tested. This might go away with the XUL->HTML transition.
+ it.skip("should save open field after changing creator type", function* () {
+ var item = new Zotero.Item('book');
+ item.setCreators([
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "author"
+ }
+ ]);
+ var id = yield item.saveTx();
+
+ var itemBox = doc.getElementById('zotero-editpane-item-box');
+ var label = doc.getAnonymousNodes(itemBox)[0].getElementsByAttribute('fieldname', 'place')[1];
+ label.click();
+ var textbox = doc.getAnonymousNodes(itemBox)[0].getElementsByAttribute('fieldname', 'place')[1];
+ textbox.value = "Place";
+
+ var menuLabel = doc.getAnonymousNodes(itemBox)[0].getElementsByAttribute('fieldname', 'creator-0-typeID')[0];
+ menuLabel.click();
+ var menupopup = itemBox._creatorTypeMenu;
+ var menuItems = menupopup.getElementsByTagName('menuitem');
+ menuItems[1].click();
+ yield waitForItemEvent('modify');
+
+ assert.equal(item.getField('place'), 'Place');
+ assert.equal(Zotero.CreatorTypes.getName(item.getCreators()[0].creatorTypeID), 'contributor');
+
+ // Wait for no-op saveTx()
+ yield Zotero.Promise.delay(1);
+ });
})
describe("Attachment pane", function () {