Fix post-save textbox focusing bugs in right-hand pane

Fix a couple cases of lost text field focus after an edit, including
focusing of the Title field after using New Item when a field is already
being edited and has a changed value.

Also, in tests, select My Library and wait for items to load when using
the loadZoteroPane() support function. We could add a parameter to skip
that or move it to a separate function, but the code to detect it is a
bit convoluted and it's a prerequisite for many tests, so it's handy to
have a function for it.
This commit is contained in:
Dan Stillman 2015-05-04 02:00:52 -04:00
parent 590649fd49
commit 8fec5ace3a
7 changed files with 103 additions and 63 deletions

View File

@ -1682,8 +1682,6 @@
<parameter name="textbox"/> <parameter name="textbox"/>
<body><![CDATA[ <body><![CDATA[
return Zotero.spawn(function* () { return Zotero.spawn(function* () {
if (textbox.localName == 'textarea') return;
Zotero.debug('Hiding editor'); Zotero.debug('Hiding editor');
// Prevent autocomplete breakage in Firefox 3 // Prevent autocomplete breakage in Firefox 3
@ -1785,11 +1783,7 @@
} }
} }
elem = this.createValueElement( var newVal = val;
val,
fieldName,
tabindex
);
} }
// Fields // Fields
@ -1854,18 +1848,23 @@
} }
} }
this._modifyField(fieldName, value, this.saveOnEdit); yield this._modifyField(fieldName, value, this.saveOnEdit);
var newVal = this.item.getField(fieldName);
}
// If box is still open (due to field not being modified and there not being
// a refresh), close it manually
if (textbox && textbox.parentNode) {
elem = this.createValueElement( elem = this.createValueElement(
this.item.getField(fieldName), this.item.getField(fieldName),
fieldName, fieldName,
tabindex tabindex
); );
var box = textbox.parentNode;
box.replaceChild(elem,textbox);
} }
var box = textbox.parentNode;
box.replaceChild(elem,textbox);
if(field === 'creator') { if(field === 'creator') {
// Reset creator mode settings here so that flex attribute gets reset // Reset creator mode settings here so that flex attribute gets reset
this.switchCreatorMode(row, (otherFields.fieldMode ? 1 : 0), true); this.switchCreatorMode(row, (otherFields.fieldMode ? 1 : 0), true);
@ -1912,14 +1911,14 @@
<parameter name="field"/> <parameter name="field"/>
<parameter name="value"/> <parameter name="value"/>
<parameter name="save"/> <parameter name="save"/>
<body> <body><![CDATA[
<![CDATA[ return Zotero.spawn(function* () {
this.item.setField(field,value); this.item.setField(field, value);
if (save) { if (save) {
this.item.save(); yield this.item.save();
} }
]]> }, this);
</body> ]]></body>
</method> </method>
@ -1973,8 +1972,7 @@
throw ("Invalid transform mode '" + mode + "' in zoteroitembox.textTransform()"); throw ("Invalid transform mode '" + mode + "' in zoteroitembox.textTransform()");
} }
this._setFieldValue(label, newVal); this._setFieldValue(label, newVal);
this._modifyField(label.getAttribute('fieldname'), newVal, this.saveOnEdit); this._modifyField(label.getAttribute('fieldname'), newVal, this.saveOnEdit).done();
]]> ]]>
</body> </body>
</method> </method>
@ -2204,7 +2202,7 @@
return Zotero.spawn(function* () { return Zotero.spawn(function* () {
var textboxes = document.getAnonymousNodes(this)[0].getElementsByTagName('textbox'); var textboxes = document.getAnonymousNodes(this)[0].getElementsByTagName('textbox');
if (textboxes && textboxes.length) { if (textboxes && textboxes.length) {
yield this.blurHandler(textboxes[0].inputField); yield this.blurHandler(textboxes[0]);
} }
}, this); }, this);
]]></body> ]]></body>

View File

@ -153,6 +153,23 @@ var ZoteroItemPane = new function() {
}); });
this.blurOpenField = Zotero.Promise.coroutine(function* () {
var tabBox = document.getElementById('zotero-view-tabbox');
switch (tabBox.selectedIndex) {
case 0:
var box = _itemBox;
break;
case 2:
var box = _tagsBox;
break;
}
if (box) {
yield box.blurOpenField();
}
});
this.addNote = function (popup) { this.addNote = function (popup) {
ZoteroPane_Local.newNote(popup, _lastItem.key); ZoteroPane_Local.newNote(popup, _lastItem.key);
} }

View File

@ -751,6 +751,8 @@ var ZoteroPane = new function()
} }
} }
yield ZoteroItemPane.blurOpenField();
if (row !== undefined && row !== null) { if (row !== undefined && row !== null) {
var collectionTreeRow = this.collectionsView.getRow(row); var collectionTreeRow = this.collectionsView.getRow(row);
var libraryID = collectionTreeRow.ref.libraryID; var libraryID = collectionTreeRow.ref.libraryID;

View File

@ -32,20 +32,30 @@ function loadBrowserWindow() {
} }
/** /**
* Loads a Zotero pane in a new window. Returns the containing window. * Loads a Zotero pane in a new window and selects My Library. Returns the containing window.
*/ */
function loadZoteroPane() { var loadZoteroPane = Zotero.Promise.coroutine(function* () {
return loadBrowserWindow().then(function(win) { var win = yield loadBrowserWindow();
win.ZoteroOverlay.toggleDisplay(true); win.ZoteroOverlay.toggleDisplay(true);
// Hack to wait for pane load to finish. This is the same hack // Hack to wait for pane load to finish. This is the same hack
// we use in ZoteroPane.js, so either it's not good enough // we use in ZoteroPane.js, so either it's not good enough
// there or it should be good enough here. // there or it should be good enough here.
return Zotero.Promise.delay(52).then(function() { yield Zotero.Promise.delay(52);
return win;
}); var zp = win.ZoteroPane;
}); var cv = zp.collectionsView;
} var resolve1, resolve2;
var promise1 = new Zotero.Promise(() => resolve1 = arguments[0]);
var promise2 = new Zotero.Promise(() => resolve2 = arguments[0]);
cv.addEventListener('load', () => resolve1())
yield promise1;
cv.selection.select(0);
zp.addEventListener('itemsLoaded', () => resolve2());
yield promise2;
return win;
});
/** /**
* Waits for a window with a specific URL to open. Returns a promise for the window. * Waits for a window with a specific URL to open. Returns a promise for the window.

View File

@ -4,22 +4,10 @@ describe("Zotero.CollectionTreeView", function() {
// Load Zotero pane and select library // Load Zotero pane and select library
before(function* () { before(function* () {
win = yield loadZoteroPane(); win = yield loadZoteroPane();
var zp = win.ZoteroPane; collectionsView = win.ZoteroPane.collectionsView;
var cv = zp.collectionsView;
var resolve1, resolve2;
var promise1 = new Zotero.Promise(() => resolve1 = arguments[0]);
var promise2 = new Zotero.Promise(() => resolve2 = arguments[0]);
cv.addEventListener('load', () => resolve1())
yield promise1;
cv.selection.select(0);
zp.addEventListener('itemsLoaded', () => resolve2());
yield promise2;
collectionsView = zp.collectionsView;
}); });
after(function () { after(function () {
if (win) { win.close();
win.close();
}
}); });
// Select library // Select library

View File

@ -4,25 +4,13 @@ describe("Zotero.ItemTreeView", function() {
// Load Zotero pane and select library // Load Zotero pane and select library
before(function* () { before(function* () {
win = yield loadZoteroPane(); win = yield loadZoteroPane();
var zp = win.ZoteroPane; itemsView = win.ZoteroPane.itemsView;
var cv = zp.collectionsView;
var resolve1, resolve2;
var promise1 = new Zotero.Promise(() => resolve1 = arguments[0]);
var promise2 = new Zotero.Promise(() => resolve2 = arguments[0]);
cv.addEventListener('load', () => resolve1())
yield promise1;
cv.selection.select(0);
zp.addEventListener('itemsLoaded', () => resolve2());
yield promise2;
itemsView = zp.itemsView;
var item = new Zotero.Item('book'); var item = new Zotero.Item('book');
existingItemID = yield item.save(); existingItemID = yield item.save();
}); });
after(function () { after(function () {
if (win) { win.close();
win.close();
}
}); });
describe("#selectItem()", function () { describe("#selectItem()", function () {

View File

@ -0,0 +1,37 @@
describe("ZoteroPane", function() {
var win, doc, zp;
// Load Zotero pane and select library
before(function* () {
win = yield loadZoteroPane();
doc = win.document;
zp = win.ZoteroPane;
});
after(function () {
win.close();
});
describe("#newItem", function () {
it("should create an item and focus the title field", function* () {
yield zp.newItem(Zotero.ItemTypes.getID('book'), {}, null, true);
var itemBox = doc.getElementById('zotero-editpane-item-box');
var textboxes = doc.getAnonymousNodes(itemBox)[0].getElementsByTagName('textbox');
assert.lengthOf(textboxes, 1);
assert.equal(textboxes[0].getAttribute('fieldname'), 'title');
textboxes[0].blur();
yield Zotero.Promise.delay(1);
})
it("should save an entered value when New Item is used", function* () {
var value = "Test";
var item = yield zp.newItem(Zotero.ItemTypes.getID('book'), {}, null, true);
var itemBox = doc.getElementById('zotero-editpane-item-box');
var textbox = doc.getAnonymousNodes(itemBox)[0].getElementsByTagName('textbox')[0];
textbox.value = value;
yield itemBox.blurOpenField();
item = yield Zotero.Items.getAsync(item.id);
assert.equal(item.getField('title'), value);
})
});
})