fx-compat: Item box: Disable guidancepanel trigger + cleanup
This commit is contained in:
parent
6f8c5d7c51
commit
8ff75607a5
1 changed files with 446 additions and 463 deletions
|
@ -1185,97 +1185,95 @@
|
||||||
elem.scrollIntoView();
|
elem.scrollIntoView();
|
||||||
}
|
}
|
||||||
|
|
||||||
changeTypeTo(itemTypeID, menu) {
|
async changeTypeTo(itemTypeID, menu) {
|
||||||
return (async function () {
|
var functionsToRun = [];
|
||||||
var functionsToRun = [];
|
if (this.eventHandlers.itemtypechange && this.eventHandlers.itemtypechange.length) {
|
||||||
if (this.eventHandlers.itemtypechange && this.eventHandlers.itemtypechange.length) {
|
functionsToRun = [...this.eventHandlers.itemtypechange];
|
||||||
functionsToRun = [...this.eventHandlers.itemtypechange];
|
}
|
||||||
|
|
||||||
|
if (itemTypeID == this.item.itemTypeID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.saveOnEdit) {
|
||||||
|
await this.blurOpenField();
|
||||||
|
await this.item.saveTx();
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldsToDelete = this.item.getFieldsNotInType(itemTypeID, true);
|
||||||
|
|
||||||
|
// Special cases handled below
|
||||||
|
var bookTypeID = Zotero.ItemTypes.getID('book');
|
||||||
|
var bookSectionTypeID = Zotero.ItemTypes.getID('bookSection');
|
||||||
|
|
||||||
|
// Add warning for shortTitle when moving from book to bookSection
|
||||||
|
// when title will be transferred
|
||||||
|
if (this.item.itemTypeID == bookTypeID && itemTypeID == bookSectionTypeID) {
|
||||||
|
var titleFieldID = Zotero.ItemFields.getID('title');
|
||||||
|
var shortTitleFieldID = Zotero.ItemFields.getID('shortTitle');
|
||||||
|
if (this.item.getField(titleFieldID) && this.item.getField(shortTitleFieldID)) {
|
||||||
|
if (!fieldsToDelete) {
|
||||||
|
fieldsToDelete = [];
|
||||||
|
}
|
||||||
|
fieldsToDelete.push(shortTitleFieldID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate list of localized field names for display in pop-up
|
||||||
|
if (fieldsToDelete) {
|
||||||
|
// Ignore warning for bookTitle when going from bookSection to book
|
||||||
|
// if there's not also a title, since the book title is transferred
|
||||||
|
// to title automatically in Zotero.Item.setType()
|
||||||
|
if (this.item.itemTypeID == bookSectionTypeID && itemTypeID == bookTypeID) {
|
||||||
|
var titleFieldID = Zotero.ItemFields.getID('title');
|
||||||
|
var bookTitleFieldID = Zotero.ItemFields.getID('bookTitle');
|
||||||
|
var shortTitleFieldID = Zotero.ItemFields.getID('shortTitle');
|
||||||
|
if (this.item.getField(bookTitleFieldID) && !this.item.getField(titleFieldID)) {
|
||||||
|
var index = fieldsToDelete.indexOf(bookTitleFieldID);
|
||||||
|
fieldsToDelete.splice(index, 1);
|
||||||
|
// But warn for short title, which will be removed
|
||||||
|
if (this.item.getField(shortTitleFieldID)) {
|
||||||
|
fieldsToDelete.push(shortTitleFieldID);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemTypeID == this.item.itemTypeID) {
|
var fieldNames = "";
|
||||||
return true;
|
for (var i=0; i<fieldsToDelete.length; i++) {
|
||||||
|
fieldNames += "\n - " +
|
||||||
|
Zotero.ItemFields.getLocalizedString(fieldsToDelete[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPromptService);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fieldsToDelete || fieldsToDelete.length == 0 ||
|
||||||
|
promptService.confirm(null,
|
||||||
|
Zotero.getString('pane.item.changeType.title'),
|
||||||
|
Zotero.getString('pane.item.changeType.text') + "\n" + fieldNames)) {
|
||||||
|
this.item.setType(itemTypeID);
|
||||||
|
|
||||||
if (this.saveOnEdit) {
|
if (this.saveOnEdit) {
|
||||||
|
// See note in transformText()
|
||||||
await this.blurOpenField();
|
await this.blurOpenField();
|
||||||
await this.item.saveTx();
|
await this.item.saveTx();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
var fieldsToDelete = this.item.getFieldsNotInType(itemTypeID, true);
|
this.refresh();
|
||||||
|
|
||||||
// Special cases handled below
|
|
||||||
var bookTypeID = Zotero.ItemTypes.getID('book');
|
|
||||||
var bookSectionTypeID = Zotero.ItemTypes.getID('bookSection');
|
|
||||||
|
|
||||||
// Add warning for shortTitle when moving from book to bookSection
|
|
||||||
// when title will be transferred
|
|
||||||
if (this.item.itemTypeID == bookTypeID && itemTypeID == bookSectionTypeID) {
|
|
||||||
var titleFieldID = Zotero.ItemFields.getID('title');
|
|
||||||
var shortTitleFieldID = Zotero.ItemFields.getID('shortTitle');
|
|
||||||
if (this.item.getField(titleFieldID) && this.item.getField(shortTitleFieldID)) {
|
|
||||||
if (!fieldsToDelete) {
|
|
||||||
fieldsToDelete = [];
|
|
||||||
}
|
|
||||||
fieldsToDelete.push(shortTitleFieldID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate list of localized field names for display in pop-up
|
functionsToRun.forEach(f => f.bind(this)());
|
||||||
if (fieldsToDelete) {
|
|
||||||
// Ignore warning for bookTitle when going from bookSection to book
|
|
||||||
// if there's not also a title, since the book title is transferred
|
|
||||||
// to title automatically in Zotero.Item.setType()
|
|
||||||
if (this.item.itemTypeID == bookSectionTypeID && itemTypeID == bookTypeID) {
|
|
||||||
var titleFieldID = Zotero.ItemFields.getID('title');
|
|
||||||
var bookTitleFieldID = Zotero.ItemFields.getID('bookTitle');
|
|
||||||
var shortTitleFieldID = Zotero.ItemFields.getID('shortTitle');
|
|
||||||
if (this.item.getField(bookTitleFieldID) && !this.item.getField(titleFieldID)) {
|
|
||||||
var index = fieldsToDelete.indexOf(bookTitleFieldID);
|
|
||||||
fieldsToDelete.splice(index, 1);
|
|
||||||
// But warn for short title, which will be removed
|
|
||||||
if (this.item.getField(shortTitleFieldID)) {
|
|
||||||
fieldsToDelete.push(shortTitleFieldID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fieldNames = "";
|
|
||||||
for (var i=0; i<fieldsToDelete.length; i++) {
|
|
||||||
fieldNames += "\n - " +
|
|
||||||
Zotero.ItemFields.getLocalizedString(fieldsToDelete[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIPromptService);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fieldsToDelete || fieldsToDelete.length == 0 ||
|
return true;
|
||||||
promptService.confirm(null,
|
}
|
||||||
Zotero.getString('pane.item.changeType.title'),
|
|
||||||
Zotero.getString('pane.item.changeType.text') + "\n" + fieldNames)) {
|
// Revert the menu (which changes before the pop-up)
|
||||||
this.item.setType(itemTypeID);
|
if (menu) {
|
||||||
|
menu.value = this.item.itemTypeID;
|
||||||
if (this.saveOnEdit) {
|
}
|
||||||
// See note in transformText()
|
|
||||||
await this.blurOpenField();
|
return false;
|
||||||
await this.item.saveTx();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
functionsToRun.forEach(f => f.bind(this)());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Revert the menu (which changes before the pop-up)
|
|
||||||
if (menu) {
|
|
||||||
menu.value = this.item.itemTypeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}.bind(this))();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleAbstractExpand(label, valueElement) {
|
toggleAbstractExpand(label, valueElement) {
|
||||||
|
@ -1455,192 +1453,182 @@
|
||||||
return valueElement;
|
return valueElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeCreator(index, labelToDelete) {
|
async removeCreator(index, labelToDelete) {
|
||||||
return (async function () {
|
// If unsaved row, just remove element
|
||||||
// If unsaved row, just remove element
|
if (!this.item.hasCreatorAt(index)) {
|
||||||
if (!this.item.hasCreatorAt(index)) {
|
labelToDelete.parentNode.removeChild(labelToDelete);
|
||||||
labelToDelete.parentNode.removeChild(labelToDelete);
|
|
||||||
|
// Enable the "+" button on the previous row
|
||||||
// Enable the "+" button on the previous row
|
var elems = this._infoTable.getElementsByClassName('zotero-clicky-plus');
|
||||||
var elems = this._infoTable.getElementsByClassName('zotero-clicky-plus');
|
var button = elems[elems.length-1];
|
||||||
var button = elems[elems.length-1];
|
var creatorFields = this.getCreatorFields(button.closest('tr'));
|
||||||
var creatorFields = this.getCreatorFields(button.closest('tr'));
|
this._enablePlusButton(button, creatorFields.creatorTypeID, creatorFields.fieldMode);
|
||||||
this._enablePlusButton(button, creatorFields.creatorTypeID, creatorFields.fieldMode);
|
|
||||||
|
this._creatorCount--;
|
||||||
this._creatorCount--;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
this.item.removeCreator(index);
|
||||||
this.item.removeCreator(index);
|
await this.blurOpenField();
|
||||||
await this.blurOpenField();
|
await this.item.saveTx();
|
||||||
await this.item.saveTx();
|
|
||||||
}.bind(this))();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showEditor(elem) {
|
async showEditor(elem) {
|
||||||
return (async () => {
|
Zotero.debug(`Showing editor for ${elem.getAttribute('fieldname')}`);
|
||||||
Zotero.debug(`Showing editor for ${elem.getAttribute('fieldname')}`);
|
|
||||||
|
var label = elem.closest('tr').querySelector('th');
|
||||||
var label = elem.closest('tr').querySelector('th');
|
var lastTabIndex = this._lastTabIndex = parseInt(elem.getAttribute('ztabindex'));
|
||||||
var lastTabIndex = this._lastTabIndex = parseInt(elem.getAttribute('ztabindex'));
|
|
||||||
|
// If a field is open, hide it before selecting the new field, which might
|
||||||
// If a field is open, hide it before selecting the new field, which might
|
// trigger a refresh
|
||||||
// trigger a refresh
|
var activeField = this._infoTable.querySelector('input');
|
||||||
var activeField = this._infoTable.querySelector('input');
|
if (activeField) {
|
||||||
if (activeField) {
|
this._refreshed = false;
|
||||||
this._refreshed = false;
|
await this.blurOpenField();
|
||||||
await this.blurOpenField();
|
this._lastTabIndex = lastTabIndex;
|
||||||
this._lastTabIndex = lastTabIndex;
|
// If the box was refreshed, the clicked element is no longer valid,
|
||||||
// If the box was refreshed, the clicked element is no longer valid,
|
// so just focus by tab index
|
||||||
// so just focus by tab index
|
if (this._refreshed) {
|
||||||
if (this._refreshed) {
|
this._focusNextField(this._lastTabIndex);
|
||||||
this._focusNextField(this._lastTabIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In Firefox 45, when clicking a multiline field such as Extra, the event is
|
|
||||||
// triggered on the inner 'description' element instead of the 'vbox'.
|
|
||||||
if (elem.tagName == 'description') {
|
|
||||||
elem = elem.parentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fieldName = elem.getAttribute('fieldname');
|
|
||||||
var tabindex = elem.getAttribute('ztabindex');
|
|
||||||
|
|
||||||
var [field, creatorIndex, creatorField] = fieldName.split('-');
|
|
||||||
if (field == 'creator') {
|
|
||||||
var value = this.item.getCreator(creatorIndex)[creatorField];
|
|
||||||
if (value === undefined) {
|
|
||||||
value = "";
|
|
||||||
}
|
|
||||||
var itemID = this.item.id;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var value = this.item.getField(fieldName);
|
|
||||||
var itemID = this.item.id;
|
|
||||||
|
|
||||||
// Access date needs to be converted from UTC
|
|
||||||
if (value != '') {
|
|
||||||
switch (fieldName) {
|
|
||||||
case 'accessDate':
|
|
||||||
|
|
||||||
// TEMP - NSF
|
|
||||||
case 'dateSent':
|
|
||||||
case 'dateDue':
|
|
||||||
case 'accepted':
|
|
||||||
// If no time, interpret as local, not UTC
|
|
||||||
if (Zotero.Date.isSQLDate(value)) {
|
|
||||||
var localDate = Zotero.Date.sqlToDate(value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var localDate = Zotero.Date.sqlToDate(value, true);
|
|
||||||
}
|
|
||||||
var value = Zotero.Date.dateToSQL(localDate);
|
|
||||||
|
|
||||||
// Don't show time in editor
|
|
||||||
value = value.replace(' 00:00:00', '');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var t;
|
|
||||||
if (Zotero.ItemFields.isMultiline(fieldName) || Zotero.ItemFields.isLong(fieldName)) {
|
|
||||||
t = document.createElement("textarea");
|
|
||||||
t.setAttribute('rows', 8);
|
|
||||||
}
|
|
||||||
// Add auto-complete for certain fields
|
|
||||||
else if (Zotero.ItemFields.isAutocompleteField(fieldName)
|
|
||||||
|| fieldName == 'creator') {
|
|
||||||
t = document.createElement("input", { is: 'shadow-autocomplete-input' });
|
|
||||||
t.setAttribute('autocompletesearch', 'zotero');
|
|
||||||
|
|
||||||
let params = {
|
|
||||||
fieldName: fieldName,
|
|
||||||
libraryID: this.item.libraryID
|
|
||||||
};
|
|
||||||
if (field == 'creator') {
|
|
||||||
params.fieldMode = parseInt(elem.getAttribute('fieldMode'));
|
|
||||||
|
|
||||||
// Include itemID and creatorTypeID so the autocomplete can
|
|
||||||
// avoid showing results for creators already set on the item
|
|
||||||
let row = elem.closest('tr');
|
|
||||||
let creatorTypeID = parseInt(
|
|
||||||
row.getElementsByClassName('creator-type-label')[0]
|
|
||||||
.getAttribute('typeid')
|
|
||||||
);
|
|
||||||
if (itemID) {
|
|
||||||
params.itemID = itemID;
|
|
||||||
params.creatorTypeID = creatorTypeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
t.addEventListener('keydown', (event) => {
|
|
||||||
if (event.key == 'Enter') {
|
|
||||||
this.handleCreatorAutoCompleteSelect(t, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Tab/Shift-Tab
|
|
||||||
t.addEventListener('change', () => {
|
|
||||||
this.handleCreatorAutoCompleteSelect(t, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (creatorField == 'lastName') {
|
|
||||||
t.setAttribute('fieldMode', elem.getAttribute('fieldMode'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.setAttribute(
|
|
||||||
'autocompletesearchparam', JSON.stringify(params)
|
|
||||||
);
|
|
||||||
t.setAttribute('completeselectedindex', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!t) {
|
|
||||||
t = document.createElement("input");
|
|
||||||
}
|
|
||||||
|
|
||||||
t.id = `itembox-field-textbox-${fieldName}`;
|
|
||||||
t.value = value;
|
|
||||||
t.dataset.originalValue = value;
|
|
||||||
t.style.mozBoxFlex = 1;
|
|
||||||
t.setAttribute('fieldname', fieldName);
|
|
||||||
t.setAttribute('ztabindex', tabindex);
|
|
||||||
|
|
||||||
var box = elem.parentNode;
|
|
||||||
box.replaceChild(t, elem);
|
|
||||||
|
|
||||||
// Associate textbox with label
|
|
||||||
label.setAttribute('control', t.getAttribute('id'));
|
|
||||||
|
|
||||||
// Prevent error when clicking between a changed field
|
|
||||||
// and another -- there's probably a better way
|
|
||||||
if (!t.select) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldName = elem.getAttribute('fieldname');
|
||||||
|
var tabindex = elem.getAttribute('ztabindex');
|
||||||
|
|
||||||
|
var [field, creatorIndex, creatorField] = fieldName.split('-');
|
||||||
|
if (field == 'creator') {
|
||||||
|
var value = this.item.getCreator(creatorIndex)[creatorField];
|
||||||
|
if (value === undefined) {
|
||||||
|
value = "";
|
||||||
|
}
|
||||||
|
var itemID = this.item.id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var value = this.item.getField(fieldName);
|
||||||
|
var itemID = this.item.id;
|
||||||
|
|
||||||
t.select();
|
// Access date needs to be converted from UTC
|
||||||
|
if (value != '') {
|
||||||
|
switch (fieldName) {
|
||||||
|
case 'accessDate':
|
||||||
|
|
||||||
|
// TEMP - NSF
|
||||||
|
case 'dateSent':
|
||||||
|
case 'dateDue':
|
||||||
|
case 'accepted':
|
||||||
|
// If no time, interpret as local, not UTC
|
||||||
|
if (Zotero.Date.isSQLDate(value)) {
|
||||||
|
var localDate = Zotero.Date.sqlToDate(value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var localDate = Zotero.Date.sqlToDate(value, true);
|
||||||
|
}
|
||||||
|
var value = Zotero.Date.dateToSQL(localDate);
|
||||||
|
|
||||||
|
// Don't show time in editor
|
||||||
|
value = value.replace(' 00:00:00', '');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var t;
|
||||||
|
if (Zotero.ItemFields.isMultiline(fieldName) || Zotero.ItemFields.isLong(fieldName)) {
|
||||||
|
t = document.createElement("textarea");
|
||||||
|
t.setAttribute('rows', 8);
|
||||||
|
}
|
||||||
|
// Add auto-complete for certain fields
|
||||||
|
else if (Zotero.ItemFields.isAutocompleteField(fieldName)
|
||||||
|
|| fieldName == 'creator') {
|
||||||
|
t = document.createElement("input", { is: 'shadow-autocomplete-input' });
|
||||||
|
t.setAttribute('autocompletesearch', 'zotero');
|
||||||
|
|
||||||
// Leave text field open when window loses focus
|
let params = {
|
||||||
var ignoreBlur = () => {
|
fieldName: fieldName,
|
||||||
this.ignoreBlur = true;
|
libraryID: this.item.libraryID
|
||||||
};
|
};
|
||||||
var unignoreBlur = () => {
|
if (field == 'creator') {
|
||||||
this.ignoreBlur = false;
|
params.fieldMode = parseInt(elem.getAttribute('fieldMode'));
|
||||||
};
|
|
||||||
addEventListener("deactivate", ignoreBlur);
|
|
||||||
addEventListener("activate", unignoreBlur);
|
|
||||||
|
|
||||||
t.addEventListener('blur', () => {
|
|
||||||
if (this.ignoreBlur) return;
|
|
||||||
|
|
||||||
removeEventListener("deactivate", ignoreBlur);
|
// Include itemID and creatorTypeID so the autocomplete can
|
||||||
removeEventListener("activate", unignoreBlur);
|
// avoid showing results for creators already set on the item
|
||||||
this.blurHandler(t);
|
let row = elem.closest('tr');
|
||||||
});
|
let creatorTypeID = parseInt(
|
||||||
t.onkeypress = (event) => this.handleKeyPress(event);
|
row.getElementsByClassName('creator-type-label')[0]
|
||||||
|
.getAttribute('typeid')
|
||||||
|
);
|
||||||
|
if (itemID) {
|
||||||
|
params.itemID = itemID;
|
||||||
|
params.creatorTypeID = creatorTypeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return
|
||||||
|
t.addEventListener('keydown', (event) => {
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
this.handleCreatorAutoCompleteSelect(t, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Tab/Shift-Tab
|
||||||
|
t.addEventListener('change', () => {
|
||||||
|
this.handleCreatorAutoCompleteSelect(t, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (creatorField == 'lastName') {
|
||||||
|
t.setAttribute('fieldMode', elem.getAttribute('fieldMode'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.setAttribute(
|
||||||
|
'autocompletesearchparam', JSON.stringify(params)
|
||||||
|
);
|
||||||
|
t.setAttribute('completeselectedindex', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!t) {
|
||||||
|
t = document.createElement("input");
|
||||||
|
}
|
||||||
|
|
||||||
|
t.id = `itembox-field-textbox-${fieldName}`;
|
||||||
|
t.value = value;
|
||||||
|
t.dataset.originalValue = value;
|
||||||
|
t.style.mozBoxFlex = 1;
|
||||||
|
t.setAttribute('fieldname', fieldName);
|
||||||
|
t.setAttribute('ztabindex', tabindex);
|
||||||
|
|
||||||
|
var box = elem.parentNode;
|
||||||
|
box.replaceChild(t, elem);
|
||||||
|
|
||||||
|
// Associate textbox with label
|
||||||
|
label.setAttribute('control', t.getAttribute('id'));
|
||||||
|
|
||||||
|
// Prevent error when clicking between a changed field
|
||||||
|
// and another -- there's probably a better way
|
||||||
|
if (!t.select) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.select();
|
||||||
|
|
||||||
|
// Leave text field open when window loses focus
|
||||||
|
var ignoreBlur = () => {
|
||||||
|
this.ignoreBlur = true;
|
||||||
|
};
|
||||||
|
var unignoreBlur = () => {
|
||||||
|
this.ignoreBlur = false;
|
||||||
|
};
|
||||||
|
addEventListener("deactivate", ignoreBlur);
|
||||||
|
addEventListener("activate", unignoreBlur);
|
||||||
|
|
||||||
|
t.addEventListener('blur', () => {
|
||||||
|
if (this.ignoreBlur) return;
|
||||||
|
|
||||||
return t;
|
removeEventListener("deactivate", ignoreBlur);
|
||||||
})();
|
removeEventListener("activate", unignoreBlur);
|
||||||
|
this.blurHandler(t);
|
||||||
|
});
|
||||||
|
t.addEventListener('keypress', event => this.handleKeyPress(event));
|
||||||
|
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1815,207 +1803,206 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hideEditor(textbox) {
|
async hideEditor(textbox) {
|
||||||
return (async function () {
|
// Handle cases where creator autocomplete doesn't trigger
|
||||||
// Handle cases where creator autocomplete doesn't trigger
|
// the textentered and change events handled in showEditor
|
||||||
// the textentered and change events handled in showEditor
|
if (textbox.getAttribute('fieldname').startsWith('creator-')) {
|
||||||
if (textbox.getAttribute('fieldname').startsWith('creator-')) {
|
this.handleCreatorAutoCompleteSelect(textbox);
|
||||||
this.handleCreatorAutoCompleteSelect(textbox);
|
}
|
||||||
}
|
|
||||||
|
Zotero.debug(`Hiding editor for ${textbox.getAttribute('fieldname')}`);
|
||||||
|
|
||||||
|
var label = textbox.closest('tr').querySelector('th');
|
||||||
|
this._lastTabIndex = -1;
|
||||||
|
|
||||||
|
// Prevent autocomplete breakage in Firefox 3
|
||||||
|
if (textbox.mController) {
|
||||||
|
textbox.mController.input = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldName = textbox.getAttribute('fieldname');
|
||||||
|
var tabindex = textbox.getAttribute('ztabindex');
|
||||||
|
|
||||||
|
//var value = t.value;
|
||||||
|
var value = textbox.value.trim();
|
||||||
|
|
||||||
|
var elem;
|
||||||
|
var [field, creatorIndex, creatorField] = fieldName.split('-');
|
||||||
|
var newVal;
|
||||||
|
|
||||||
|
// Creator fields
|
||||||
|
if (field == 'creator') {
|
||||||
|
var row = textbox.closest('tr');
|
||||||
|
|
||||||
Zotero.debug(`Hiding editor for ${textbox.getAttribute('fieldname')}`);
|
var otherFields = this.getCreatorFields(row);
|
||||||
|
otherFields[creatorField] = value;
|
||||||
|
var lastName = otherFields.lastName.trim();
|
||||||
|
|
||||||
var label = textbox.closest('tr').querySelector('th');
|
//Handle \n\r and \n delimited entries and a single line containing a tab
|
||||||
this._lastTabIndex = -1;
|
var rawNameArray = lastName.split(/\r\n?|\n/);
|
||||||
|
if (rawNameArray.length > 1 || rawNameArray[0].includes('\t')) {
|
||||||
// Prevent autocomplete breakage in Firefox 3
|
//Save tab direction and add creator flags since they are reset in the
|
||||||
if (textbox.mController) {
|
//process of adding multiple authors
|
||||||
textbox.mController.input = null;
|
var tabDirectionBuffer = this._tabDirection;
|
||||||
}
|
var addCreatorRowBuffer = this._addCreatorRow;
|
||||||
|
var tabIndexBuffer = this._lastTabIndex;
|
||||||
var fieldName = textbox.getAttribute('fieldname');
|
this._tabDirection = false;
|
||||||
var tabindex = textbox.getAttribute('ztabindex');
|
this._addCreatorRow = false;
|
||||||
|
|
||||||
//var value = t.value;
|
|
||||||
var value = textbox.value.trim();
|
|
||||||
|
|
||||||
var elem;
|
|
||||||
var [field, creatorIndex, creatorField] = fieldName.split('-');
|
|
||||||
var newVal;
|
|
||||||
|
|
||||||
// Creator fields
|
|
||||||
if (field == 'creator') {
|
|
||||||
var row = textbox.closest('tr');
|
|
||||||
|
|
||||||
var otherFields = this.getCreatorFields(row);
|
//Filter out bad names
|
||||||
otherFields[creatorField] = value;
|
var nameArray = rawNameArray.filter(name => name);
|
||||||
var lastName = otherFields.lastName.trim();
|
|
||||||
|
|
||||||
//Handle \n\r and \n delimited entries and a single line containing a tab
|
//If not adding names at the end of the creator list, make new creator
|
||||||
var rawNameArray = lastName.split(/\r\n?|\n/);
|
//entries and then shift down existing creators.
|
||||||
if (rawNameArray.length > 1 || rawNameArray[0].includes('\t')) {
|
var initNumCreators = this.item.numCreators();
|
||||||
//Save tab direction and add creator flags since they are reset in the
|
var creatorsToShift = initNumCreators - creatorIndex;
|
||||||
//process of adding multiple authors
|
if (creatorsToShift > 0) {
|
||||||
var tabDirectionBuffer = this._tabDirection;
|
//Add extra creators
|
||||||
var addCreatorRowBuffer = this._addCreatorRow;
|
for (var i=0;i<nameArray.length;i++) {
|
||||||
var tabIndexBuffer = this._lastTabIndex;
|
this.modifyCreator(i + initNumCreators, otherFields);
|
||||||
this._tabDirection = false;
|
|
||||||
this._addCreatorRow = false;
|
|
||||||
|
|
||||||
//Filter out bad names
|
|
||||||
var nameArray = rawNameArray.filter(name => name);
|
|
||||||
|
|
||||||
//If not adding names at the end of the creator list, make new creator
|
|
||||||
//entries and then shift down existing creators.
|
|
||||||
var initNumCreators = this.item.numCreators();
|
|
||||||
var creatorsToShift = initNumCreators - creatorIndex;
|
|
||||||
if (creatorsToShift > 0) {
|
|
||||||
//Add extra creators
|
|
||||||
for (var i=0;i<nameArray.length;i++) {
|
|
||||||
this.modifyCreator(i + initNumCreators, otherFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Shift existing creators
|
|
||||||
for (var i=initNumCreators-1; i>=creatorIndex; i--) {
|
|
||||||
let shiftedCreatorData = this.item.getCreator(i);
|
|
||||||
this.item.setCreator(nameArray.length + i, shiftedCreatorData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add the creators in lastNameArray one at a time
|
//Shift existing creators
|
||||||
for (let tempName of nameArray) {
|
for (var i=initNumCreators-1; i>=creatorIndex; i--) {
|
||||||
// Check for tab to determine creator name format
|
let shiftedCreatorData = this.item.getCreator(i);
|
||||||
otherFields.fieldMode = (tempName.indexOf('\t') == -1) ? 1 : 0;
|
this.item.setCreator(nameArray.length + i, shiftedCreatorData);
|
||||||
if (otherFields.fieldMode == 0) {
|
|
||||||
otherFields.lastName=tempName.split('\t')[0];
|
|
||||||
otherFields.firstName=tempName.split('\t')[1];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
otherFields.lastName=tempName;
|
|
||||||
otherFields.firstName='';
|
|
||||||
}
|
|
||||||
this.modifyCreator(creatorIndex, otherFields);
|
|
||||||
creatorIndex++;
|
|
||||||
}
|
|
||||||
this._tabDirection = tabDirectionBuffer;
|
|
||||||
this._addCreatorRow = (creatorsToShift==0) ? addCreatorRowBuffer : false;
|
|
||||||
if (this._tabDirection == 1) {
|
|
||||||
this._lastTabIndex = parseInt(tabIndexBuffer,10) + 2*(nameArray.length-1);
|
|
||||||
if (otherFields.fieldMode == 0) {
|
|
||||||
this._lastTabIndex++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
//Add the creators in lastNameArray one at a time
|
||||||
|
for (let tempName of nameArray) {
|
||||||
|
// Check for tab to determine creator name format
|
||||||
|
otherFields.fieldMode = (tempName.indexOf('\t') == -1) ? 1 : 0;
|
||||||
|
if (otherFields.fieldMode == 0) {
|
||||||
|
otherFields.lastName=tempName.split('\t')[0];
|
||||||
|
otherFields.firstName=tempName.split('\t')[1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
otherFields.lastName=tempName;
|
||||||
|
otherFields.firstName='';
|
||||||
|
}
|
||||||
this.modifyCreator(creatorIndex, otherFields);
|
this.modifyCreator(creatorIndex, otherFields);
|
||||||
|
creatorIndex++;
|
||||||
}
|
}
|
||||||
|
this._tabDirection = tabDirectionBuffer;
|
||||||
var val = this.item.getCreator(creatorIndex);
|
this._addCreatorRow = (creatorsToShift==0) ? addCreatorRowBuffer : false;
|
||||||
val = val ? val[creatorField] : null;
|
if (this._tabDirection == 1) {
|
||||||
|
this._lastTabIndex = parseInt(tabIndexBuffer,10) + 2*(nameArray.length-1);
|
||||||
if (!val) {
|
if (otherFields.fieldMode == 0) {
|
||||||
// Reset to '(first)'/'(last)'/'(name)'
|
this._lastTabIndex++;
|
||||||
if (creatorField == 'lastName') {
|
|
||||||
val = otherFields.fieldMode
|
|
||||||
? this._defaultFullName : this._defaultLastName;
|
|
||||||
}
|
|
||||||
else if (creatorField == 'firstName') {
|
|
||||||
val = this._defaultFirstName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
newVal = val;
|
else {
|
||||||
|
this.modifyCreator(creatorIndex, otherFields);
|
||||||
// Reset creator mode settings here so that flex attribute gets reset
|
}
|
||||||
this.switchCreatorMode(row, (otherFields.fieldMode ? 1 : 0), true);
|
|
||||||
if (Zotero.ItemTypes.getName(this.item.itemTypeID) === "bookSection") {
|
var val = this.item.getCreator(creatorIndex);
|
||||||
var creatorTypeLabels = this.getElementsByClassName("creator-type-label");
|
val = val ? val[creatorField] : null;
|
||||||
Zotero.debug(creatorTypeLabels[creatorTypeLabels.length-1] + "");
|
|
||||||
document.getElementById("zotero-author-guidance").show({
|
if (!val) {
|
||||||
forEl: creatorTypeLabels[creatorTypeLabels.length-1]
|
// Reset to '(first)'/'(last)'/'(name)'
|
||||||
});
|
if (creatorField == 'lastName') {
|
||||||
|
val = otherFields.fieldMode
|
||||||
|
? this._defaultFullName : this._defaultLastName;
|
||||||
|
}
|
||||||
|
else if (creatorField == 'firstName') {
|
||||||
|
val = this._defaultFirstName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields
|
newVal = val;
|
||||||
else {
|
|
||||||
// Access date needs to be parsed and converted to UTC SQL date
|
// Reset creator mode settings here so that flex attribute gets reset
|
||||||
if (value != '') {
|
this.switchCreatorMode(row, (otherFields.fieldMode ? 1 : 0), true);
|
||||||
switch (fieldName) {
|
if (Zotero.ItemTypes.getName(this.item.itemTypeID) === "bookSection") {
|
||||||
case 'accessDate':
|
var creatorTypeLabels = this.getElementsByClassName("creator-type-label");
|
||||||
|
Zotero.debug(creatorTypeLabels[creatorTypeLabels.length-1] + "");
|
||||||
|
// fx-compat TODO: Re-enable this
|
||||||
|
// document.getElementById("zotero-author-guidance").show({
|
||||||
|
// forEl: creatorTypeLabels[creatorTypeLabels.length-1]
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
else {
|
||||||
|
// Access date needs to be parsed and converted to UTC SQL date
|
||||||
|
if (value != '') {
|
||||||
|
switch (fieldName) {
|
||||||
|
case 'accessDate':
|
||||||
|
// Parse 'yesterday'/'today'/'tomorrow'
|
||||||
|
value = Zotero.Date.parseDescriptiveString(value);
|
||||||
|
|
||||||
|
// Allow "now" to use current time
|
||||||
|
if (value == 'now') {
|
||||||
|
value = Zotero.Date.dateToSQL(new Date(), true);
|
||||||
|
}
|
||||||
|
// If just date, don't convert to UTC
|
||||||
|
else if (Zotero.Date.isSQLDate(value)) {
|
||||||
|
var localDate = Zotero.Date.sqlToDate(value);
|
||||||
|
value = Zotero.Date.dateToSQL(localDate).replace(' 00:00:00', '');
|
||||||
|
}
|
||||||
|
else if (Zotero.Date.isSQLDateTime(value)) {
|
||||||
|
var localDate = Zotero.Date.sqlToDate(value);
|
||||||
|
value = Zotero.Date.dateToSQL(localDate, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var d = Zotero.Date.strToDate(value);
|
||||||
|
value = null;
|
||||||
|
if (d.year && d.month != undefined && d.day) {
|
||||||
|
d = new Date(d.year, d.month, d.day);
|
||||||
|
value = Zotero.Date.dateToSQL(d).replace(' 00:00:00', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TEMP - NSF
|
||||||
|
case 'dateSent':
|
||||||
|
case 'dateDue':
|
||||||
|
case 'accepted':
|
||||||
|
if (Zotero.Date.isSQLDate(value)) {
|
||||||
|
var localDate = Zotero.Date.sqlToDate(value);
|
||||||
|
value = Zotero.Date.dateToSQL(localDate).replace(' 00:00:00', '');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var d = Zotero.Date.strToDate(value);
|
||||||
|
value = null;
|
||||||
|
if (d.year && d.month != undefined && d.day) {
|
||||||
|
d = new Date(d.year, d.month, d.day);
|
||||||
|
value = Zotero.Date.dateToSQL(d).replace(' 00:00:00', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// TODO: generalize to all date rows/fields
|
||||||
|
if (Zotero.ItemFields.isFieldOfBase(fieldName, 'date')) {
|
||||||
// Parse 'yesterday'/'today'/'tomorrow'
|
// Parse 'yesterday'/'today'/'tomorrow'
|
||||||
value = Zotero.Date.parseDescriptiveString(value);
|
value = Zotero.Date.parseDescriptiveString(value);
|
||||||
|
}
|
||||||
// Allow "now" to use current time
|
|
||||||
if (value == 'now') {
|
|
||||||
value = Zotero.Date.dateToSQL(new Date(), true);
|
|
||||||
}
|
|
||||||
// If just date, don't convert to UTC
|
|
||||||
else if (Zotero.Date.isSQLDate(value)) {
|
|
||||||
var localDate = Zotero.Date.sqlToDate(value);
|
|
||||||
value = Zotero.Date.dateToSQL(localDate).replace(' 00:00:00', '');
|
|
||||||
}
|
|
||||||
else if (Zotero.Date.isSQLDateTime(value)) {
|
|
||||||
var localDate = Zotero.Date.sqlToDate(value);
|
|
||||||
value = Zotero.Date.dateToSQL(localDate, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var d = Zotero.Date.strToDate(value);
|
|
||||||
value = null;
|
|
||||||
if (d.year && d.month != undefined && d.day) {
|
|
||||||
d = new Date(d.year, d.month, d.day);
|
|
||||||
value = Zotero.Date.dateToSQL(d).replace(' 00:00:00', '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TEMP - NSF
|
|
||||||
case 'dateSent':
|
|
||||||
case 'dateDue':
|
|
||||||
case 'accepted':
|
|
||||||
if (Zotero.Date.isSQLDate(value)) {
|
|
||||||
var localDate = Zotero.Date.sqlToDate(value);
|
|
||||||
value = Zotero.Date.dateToSQL(localDate).replace(' 00:00:00', '');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var d = Zotero.Date.strToDate(value);
|
|
||||||
value = null;
|
|
||||||
if (d.year && d.month != undefined && d.day) {
|
|
||||||
d = new Date(d.year, d.month, d.day);
|
|
||||||
value = Zotero.Date.dateToSQL(d).replace(' 00:00:00', '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// TODO: generalize to all date rows/fields
|
|
||||||
if (Zotero.ItemFields.isFieldOfBase(fieldName, 'date')) {
|
|
||||||
// Parse 'yesterday'/'today'/'tomorrow'
|
|
||||||
value = Zotero.Date.parseDescriptiveString(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._modifyField(fieldName, value);
|
|
||||||
newVal = this.item.getField(fieldName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close box
|
this._modifyField(fieldName, value);
|
||||||
elem = this.createValueElement(
|
newVal = this.item.getField(fieldName);
|
||||||
newVal,
|
}
|
||||||
fieldName,
|
|
||||||
tabindex
|
// Close box
|
||||||
);
|
elem = this.createValueElement(
|
||||||
var box = textbox.parentNode;
|
newVal,
|
||||||
box.replaceChild(elem, textbox);
|
fieldName,
|
||||||
|
tabindex
|
||||||
// Disassociate textbox from label
|
);
|
||||||
label.setAttribute('control', elem.getAttribute('id'));
|
var box = textbox.parentNode;
|
||||||
|
box.replaceChild(elem, textbox);
|
||||||
if (this.saveOnEdit) {
|
|
||||||
await this.item.saveTx();
|
// Disassociate textbox from label
|
||||||
}
|
label.setAttribute('control', elem.getAttribute('id'));
|
||||||
}.bind(this))();
|
|
||||||
|
if (this.saveOnEdit) {
|
||||||
|
await this.item.saveTx();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_rowIsClickable(fieldName) {
|
_rowIsClickable(fieldName) {
|
||||||
|
@ -2137,23 +2124,21 @@
|
||||||
/**
|
/**
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
swapNames(event) {
|
async swapNames(event) {
|
||||||
return (async function () {
|
var row = document.popupNode.closest('tr');
|
||||||
var row = document.popupNode.closest('tr');
|
var typeBox = row.querySelector('.creator-type-label');
|
||||||
var typeBox = row.querySelector('.creator-type-label');
|
var creatorIndex = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
|
||||||
var creatorIndex = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
|
var fields = this.getCreatorFields(row);
|
||||||
var fields = this.getCreatorFields(row);
|
var lastName = fields.lastName;
|
||||||
var lastName = fields.lastName;
|
var firstName = fields.firstName;
|
||||||
var firstName = fields.firstName;
|
fields.lastName = firstName;
|
||||||
fields.lastName = firstName;
|
fields.firstName = lastName;
|
||||||
fields.firstName = lastName;
|
this.modifyCreator(creatorIndex, fields);
|
||||||
this.modifyCreator(creatorIndex, fields);
|
if (this.saveOnEdit) {
|
||||||
if (this.saveOnEdit) {
|
// See note in transformText()
|
||||||
// See note in transformText()
|
await this.blurOpenField();
|
||||||
await this.blurOpenField();
|
await this.item.saveTx();
|
||||||
await this.item.saveTx();
|
}
|
||||||
}
|
|
||||||
}.bind(this))();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2292,14 +2277,12 @@
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
blurOpenField() {
|
async blurOpenField() {
|
||||||
return (async function () {
|
var activeField = this._infoTable.querySelector('input, textarea');
|
||||||
var activeField = this._infoTable.querySelector('input, textarea');
|
if (!activeField) {
|
||||||
if (!activeField) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
return this.blurHandler(activeField);
|
||||||
return this.blurHandler(activeField);
|
|
||||||
}.bind(this))();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue