fx-compat: Item box: Fix menu actions, plus/minus buttons

This commit is contained in:
Abe Jellinek 2022-05-31 11:23:19 -07:00
parent 496f34117c
commit 59d5013952

View file

@ -62,91 +62,15 @@
this.content = MozXULElement.parseXULToFragment(`
<div id="item-box" xmlns="http://www.w3.org/1999/xhtml">
<popupset xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menupopup id="creator-type-menu" position="after_start"
onpopupshowing="var typeBox = document.popupNode.localName == 'hbox' ? document.popupNode : document.popupNode.parentNode;
var index = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
var item = this.item;
var exists = item.hasCreatorAt(index);
var moreCreators = item.numCreators() > index + 1;
var hideMoveToTop = !exists || index &lt; 2;
var hideMoveUp = !exists || index == 0;
var hideMoveDown = !exists || !moreCreators;
var hideMoveSep = hideMoveUp &amp;&amp; hideMoveDown;
document.getElementById('zotero-creator-move-sep').setAttribute('hidden', hideMoveSep);
document.getElementById('zotero-creator-move-to-top').setAttribute('hidden', hideMoveToTop);
document.getElementById('zotero-creator-move-up').setAttribute('hidden', hideMoveUp);
document.getElementById('zotero-creator-move-down').setAttribute('hidden', hideMoveDown);"
oncommand="return async function () {
var typeBox = document.popupNode.localName == 'hbox' ? document.popupNode : document.popupNode.parentNode;
var index = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
if (event.explicitOriginalTarget.className == 'zotero-creator-move') {
let dir;
switch (event.explicitOriginalTarget.id) {
case 'zotero-creator-move-to-top':
dir = 'top';
break;
case 'zotero-creator-move-up':
dir = 'up';
break;
case 'zotero-creator-move-down':
dir = 'down';
break;
}
this.moveCreator(index, dir);
return;
}
var typeID = event.explicitOriginalTarget.getAttribute('typeid');
var row = typeBox.parentNode;
var fields = this.getCreatorFields(row);
fields.creatorTypeID = typeID;
typeBox.getElementsByTagName('label')[0].setAttribute(
'value',
Zotero.getString(
'creatorTypes.' + Zotero.CreatorTypes.getName(typeID)
)
);
typeBox.setAttribute('typeid', typeID);
/* If a creator textbox is already open, we need to
change its autocomplete parameters so that it
completes on a creator with a different creator type */
var changedParams = {
creatorTypeID: typeID
};
this._updateAutoCompleteParams(row, changedParams);
this.modifyCreator(index, fields);
if (this.saveOnEdit) {
await this.blurOpenField();
await this.item.saveTx();
}
}.bind(this)();"/>
<menupopup id="creator-type-menu" position="after_start"/>
<menupopup id="zotero-field-transform-menu">
<menuitem label="&zotero.item.textTransform.titlecase;" class="menuitem-non-iconic"
oncommand="this.textTransform(document.popupNode, 'title')"/>
<menuitem label="&zotero.item.textTransform.sentencecase;" class="menuitem-non-iconic"
oncommand="this.textTransform(document.popupNode, 'sentence')"/>
<menuitem id="creator-transform-title-case" label="&zotero.item.textTransform.titlecase;"
class="menuitem-non-iconic"/>
<menuitem id="creator-transform-sentence-case" label="&zotero.item.textTransform.sentencecase;"
class="menuitem-non-iconic"/>
</menupopup>
<menupopup id="zotero-creator-transform-menu"
onpopupshowing="var row = document.popupNode.closest('tr');
var typeBox = row.querySelector('.creator-type-label');
var index = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
var item = this.item;
var exists = item.hasCreatorAt(index);
if (exists) {
var fieldMode = item.getCreator(index).name !== undefined ? 1 : 0;
}
var hideTransforms = !exists || !!fieldMode;
return !hideTransforms;">
<menuitem label="&zotero.item.creatorTransform.nameSwap;"
oncommand="this.swapNames(event);"/>
<menupopup id="zotero-creator-transform-menu">
<menuitem id="creator-transform-swap-names" label="&zotero.item.creatorTransform.nameSwap;"/>
</menupopup>
<menupopup id="zotero-doi-menu">
<menuitem id="zotero-doi-menu-view-online" label="&zotero.item.viewOnline;"/>
@ -198,6 +122,98 @@
shadow.append(s2);
shadow.appendChild(document.importNode(this.content, true));
this._creatorTypeMenu.addEventListener('popupshowing', () => {
var typeBox = document.popupNode.localName == 'th' ? document.popupNode : document.popupNode.parentNode;
var index = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
var item = this.item;
var exists = item.hasCreatorAt(index);
var moreCreators = item.numCreators() > index + 1;
var hideMoveToTop = !exists || index < 2;
var hideMoveUp = !exists || index == 0;
var hideMoveDown = !exists || !moreCreators;
var hideMoveSep = hideMoveUp && hideMoveDown;
this._id('zotero-creator-move-sep').setAttribute('hidden', hideMoveSep);
this._id('zotero-creator-move-to-top').setAttribute('hidden', hideMoveToTop);
this._id('zotero-creator-move-up').setAttribute('hidden', hideMoveUp);
this._id('zotero-creator-move-down').setAttribute('hidden', hideMoveDown);
});
this._creatorTypeMenu.addEventListener('command', async (event) => {
var typeBox = document.popupNode.localName == 'th' ? document.popupNode : document.popupNode.parentNode;
var index = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
if (event.explicitOriginalTarget.className == 'zotero-creator-move') {
let dir;
switch (event.explicitOriginalTarget.id) {
case 'zotero-creator-move-to-top':
dir = 'top';
break;
case 'zotero-creator-move-up':
dir = 'up';
break;
case 'zotero-creator-move-down':
dir = 'down';
break;
}
this.moveCreator(index, dir);
return;
}
var typeID = event.explicitOriginalTarget.getAttribute('typeid');
var row = typeBox.parentNode;
var fields = this.getCreatorFields(row);
fields.creatorTypeID = typeID;
typeBox.getElementsByTagName('label')[0].setAttribute(
'value',
Zotero.getString(
'creatorTypes.' + Zotero.CreatorTypes.getName(typeID)
)
);
typeBox.setAttribute('typeid', typeID);
/* If a creator textbox is already open, we need to
change its autocomplete parameters so that it
completes on a creator with a different creator type */
var changedParams = {
creatorTypeID: typeID
};
this._updateAutoCompleteParams(row, changedParams);
this.modifyCreator(index, fields);
if (this.saveOnEdit) {
await this.blurOpenField();
await this.item.saveTx();
}
});
this._id('creator-transform-title-case').addEventListener('command',
() => this.textTransform(document.popupNode, 'title'));
this._id('creator-transform-sentence-case').addEventListener('command',
() => this.textTransform(document.popupNode, 'sentence'));
this._id('zotero-creator-transform-menu').addEventListener('popupshowing', (event) => {
var row = document.popupNode.closest('tr');
var typeBox = row.querySelector('.creator-type-label');
var index = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
var item = this.item;
var exists = item.hasCreatorAt(index);
if (exists) {
var fieldMode = item.getCreator(index).name !== undefined ? 1 : 0;
}
var hideTransforms = !exists || !!fieldMode;
if (hideTransforms) {
event.preventDefault();
}
});
this._id('creator-transform-swap-names').addEventListener('command',
event => this.swapNames(event));
this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'itembox');
}
@ -687,9 +703,9 @@
// Place, in order of preference, after title, after type,
// or at beginning
var titleFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(this.item.itemTypeID, 'title');
var field = this._infoTable.getElementsByAttribute('fieldname', Zotero.ItemFields.getName(titleFieldID)).item(0);
var field = this._infoTable.querySelector(`[fieldname="${Zotero.ItemFields.getName(titleFieldID)}"]`);
if (!field) {
var field = this._infoTable.getElementsByAttribute('fieldname', 'itemType').item(0);
var field = this._infoTable.querySelector('[fieldName="itemType"]');
}
if (field) {
this._beforeRow = field.parentNode.nextSibling;
@ -832,15 +848,20 @@
? Zotero.CreatorTypes.getID(creatorTypeIDOrName)
: this._creatorTypeMenu.childNodes[0].getAttribute('typeid');
var rowIndex = this._creatorCount;
var th = document.createElement("th");
th.setAttribute("typeid", typeID);
th.setAttribute("popup", "creator-type-menu");
th.setAttribute("fieldname", 'creator-' + this._creatorCount + '-typeID');
th.setAttribute("fieldname", 'creator-' + rowIndex + '-typeID');
if (this.editable) {
th.className = 'creator-type-label zotero-clicky';
let span = document.createElement('span');
span.className = 'creator-type-dropmarker';
th.appendChild(span);
th.addEventListener('click', () => {
document.popupNode = th;
this._creatorTypeMenu.openPopup(th);
});
}
else {
th.className = 'creator-type-label';
@ -858,8 +879,8 @@
var firstlast = document.createElement("span");
firstlast.className = 'creator-name-box';
firstlast.setAttribute("flex","1");
var tabindex = this._tabIndexMinCreators + (this._creatorCount * 2);
var fieldName = 'creator-' + this._creatorCount + '-lastName';
var tabindex = this._tabIndexMinCreators + (rowIndex * 2);
var fieldName = 'creator-' + rowIndex + '-lastName';
var lastNameElem = firstlast.appendChild(
this.createValueElement(
lastName,
@ -874,7 +895,7 @@
comma.className = 'comma';
firstlast.appendChild(comma);
var fieldName = 'creator-' + this._creatorCount + '-firstName';
var fieldName = 'creator-' + rowIndex + '-firstName';
firstlast.appendChild(
this.createValueElement(
firstName,
@ -900,7 +921,7 @@
// Single/double field toggle
var toggleButton = document.createElement('span');
toggleButton.setAttribute('fieldname',
'creator-' + this._creatorCount + '-fieldMode');
'creator-' + rowIndex + '-fieldMode');
toggleButton.className = 'zotero-field-toggle zotero-clicky';
td.appendChild(toggleButton);
@ -913,10 +934,9 @@
this.disableButton(removeButton);
}
else {
removeButton.setAttribute("onclick",
"this.removeCreator("
+ this._creatorCount
+ ", this.parentNode.parentNode)");
removeButton.addEventListener("click", () => {
this.removeCreator(rowIndex, td.parentNode);
});
}
td.appendChild(removeButton);
@ -1276,23 +1296,22 @@
disableButton(button) {
button.setAttribute('disabled', true);
button.setAttribute('onclick', false);
button.setAttribute('onclick', false);
}
_enablePlusButton(button, creatorTypeID, fieldMode) {
button.setAttribute('disabled', false);
button.onclick = function () {
var parent = this;
parent.disableButton(this);
parent.addCreatorRow(null, creatorTypeID, true);
button.onclick = () => {
this.disableButton(button);
this.addCreatorRow(null, creatorTypeID, true);
};
}
disableCreatorAddButtons() {
// Disable the "+" button on all creator rows
var elems = this._infoTable.getElementsByAttribute('value', '+');
for (var i = 0, len = elems.length; i < len; i++) {
this.disableButton(elems[i]);
var elems = this._infoTable.getElementsByClassName('zotero-clicky-plus');
for (let elem of elems) {
this.disableButton(elem);
}
}
@ -1433,7 +1452,7 @@
labelToDelete.parentNode.removeChild(labelToDelete);
// Enable the "+" button on the previous row
var elems = this._infoTable.getElementsByAttribute('value', '+');
var elems = this._infoTable.getElementsByClassName('zotero-clicky-plus');
var button = elems[elems.length-1];
var creatorFields = this.getCreatorFields(button.closest('tr'));
this._enablePlusButton(button, creatorFields.creatorTypeID, creatorFields.fieldMode);
@ -1552,8 +1571,9 @@
}
});
// Tab/Shift-Tab
t.setAttribute('onchange',
'this.handleCreatorAutoCompleteSelect(this)');
t.addEventListener('change', () => {
this.handleCreatorAutoCompleteSelect(t, true);
});
if (creatorField == 'lastName') {
t.setAttribute('fieldMode', elem.getAttribute('fieldMode'));
@ -2021,43 +2041,41 @@
/**
* TODO: work with textboxes too
*/
textTransform(label, mode) {
return (async 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);
var fieldName = label.getAttribute('fieldname');
this._modifyField(fieldName, newVal);
// If this is a title field, convert the Short Title too
var isTitle = Zotero.ItemFields.getBaseIDFromTypeAndField(
this.item.itemTypeID, fieldName) == Zotero.ItemFields.getID('title');
var shortTitleVal = this.item.getField('shortTitle');
if (isTitle && newVal.toLowerCase().startsWith(shortTitleVal.toLowerCase())) {
this._modifyField('shortTitle', newVal.substr(0, shortTitleVal.length));
}
if (this.saveOnEdit) {
// If a field is open, blur it, which will trigger a save and cause
// the saveTx() to be a no-op
await this.blurOpenField();
await this.item.saveTx();
}
});
async textTransform(label, mode) {
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 new Error("Invalid transform mode '" + mode + "' in ItemBox.textTransform()");
}
this._setFieldValue(label, newVal);
var fieldName = label.getAttribute('fieldname');
this._modifyField(fieldName, newVal);
// If this is a title field, convert the Short Title too
var isTitle = Zotero.ItemFields.getBaseIDFromTypeAndField(
this.item.itemTypeID, fieldName) == Zotero.ItemFields.getID('title');
var shortTitleVal = this.item.getField('shortTitle');
if (isTitle && newVal.toLowerCase().startsWith(shortTitleVal.toLowerCase())) {
this._modifyField('shortTitle', newVal.substr(0, shortTitleVal.length));
}
if (this.saveOnEdit) {
// If a field is open, blur it, which will trigger a save and cause
// the saveTx() to be a no-op
await this.blurOpenField();
await this.item.saveTx();
}
}
getCreatorFields(row) {
@ -2434,7 +2452,7 @@
}
_id(id) {
return this.shadowRoot.querySelector(`[id=${id}]`);
return this.shadowRoot.getElementById(id);
}
}
customElements.define("item-box", ItemBox);