mirror of
https://github.com/zotero/zotero.git
synced 2026-09-30 01:51:36 +00:00
citation dlg: clarify how locators can be added
- After a bubble is added, the focused input gets a placeholder indicating that typing a number will add it as a page to the just-added bubble. The placeholder will be truncated if it's too close to the edge in multi-item citations. - Add a hint to item details popup telling how to add a locator after adding a new item and linking to the documentation page.
This commit is contained in:
parent
edf951f1d7
commit
f798fc07a0
6 changed files with 96 additions and 6 deletions
|
|
@ -36,6 +36,7 @@
|
|||
this._body = this.querySelector('.bubble-input.body');
|
||||
this._body.addEventListener('click', this._onBodyClick.bind(this));
|
||||
this._lastFocusedInput = null;
|
||||
this.showJustAddedPlaceholder = false;
|
||||
|
||||
Utils.init(this);
|
||||
DragDropHandler.init(this);
|
||||
|
|
@ -123,11 +124,10 @@
|
|||
if (isOnlyInput) {
|
||||
document.l10n.setAttributes(this._body.firstChild, `integration-citationDialog-single-input-${dialogType}`);
|
||||
}
|
||||
// otherwise, add a regular aria descriptions and placeholders to all inputs
|
||||
// otherwise, set default placeholders for all inputs, with special handling
|
||||
// of the last input after a bubble is added with visible placeholder
|
||||
else {
|
||||
for (let input of [...this.querySelectorAll(".input")]) {
|
||||
document.l10n.setAttributes(input, `integration-citationDialog-input-${dialogType}`);
|
||||
}
|
||||
Utils.setupInputPlaceholders(this.showJustAddedPlaceholder, dialogType);
|
||||
}
|
||||
// If any two inputs end up next to each other (e.g. after bubble is deleted),
|
||||
// have them merged
|
||||
|
|
@ -604,6 +604,74 @@
|
|||
return spanWidth;
|
||||
},
|
||||
|
||||
getTextWidth(text) {
|
||||
let span = document.createElement("span");
|
||||
span.classList = "input";
|
||||
span.innerText = text;
|
||||
this.bubbleInput._body.appendChild(span);
|
||||
let spanWidth = span.getBoundingClientRect().width;
|
||||
span.remove();
|
||||
return spanWidth;
|
||||
},
|
||||
|
||||
// Return the longest prefix of `text` such that prefix + "…" fits within maxWidth,
|
||||
// or the original text if it already fits. Used for placeholder truncation, since
|
||||
// text-overflow:ellipsis doesn't work on <input> in Firefox chrome.
|
||||
truncateToWidth(text, maxWidth) {
|
||||
if (this.getTextWidth(text) <= maxWidth) return text;
|
||||
let ellipsis = "…";
|
||||
for (let i = text.length - 1; i > 0; i--) {
|
||||
let candidate = text.slice(0, i) + ellipsis;
|
||||
if (this.getTextWidth(candidate) <= maxWidth) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return ellipsis;
|
||||
},
|
||||
|
||||
// Set aria-descriptions and placeholders on every input in the bubble-input.
|
||||
// For the just-added input (the last one, when showJustAddedPlaceholder is set), the
|
||||
// placeholder is truncated to the space remaining on its line and passed to Fluent as
|
||||
// a variable.
|
||||
setupInputPlaceholders(showJustAddedPlaceholder, dialogType) {
|
||||
let allInputs = [...this.bubbleInput.querySelectorAll(".input")];
|
||||
let lastInput = allInputs[allInputs.length - 1];
|
||||
let bodyRight = this.bubbleInput._body.getBoundingClientRect().right;
|
||||
for (let input of allInputs) {
|
||||
let isJustAdded = showJustAddedPlaceholder && input === lastInput;
|
||||
if (!isJustAdded) {
|
||||
input.classList.remove("just-added-placeholder");
|
||||
document.l10n.setAttributes(input, `integration-citationDialog-input-${dialogType}`);
|
||||
// Clear any stale title and min-width left over from a previous just-added state
|
||||
input.removeAttribute("title");
|
||||
input.style.minWidth = "";
|
||||
}
|
||||
if (isJustAdded && !input.classList.contains("just-added-placeholder")) {
|
||||
input.classList.add("just-added-placeholder");
|
||||
// Leading NBSP gives a small visual gap between the cursor and the placeholder
|
||||
// text (CSS padding/text-indent on input or ::placeholder both move the cursor too)
|
||||
let fullPlaceholder = " " + Zotero.getString("integration-citationDialog-just-added-input-placeholder");
|
||||
let availableWidth = bodyRight - input.getBoundingClientRect().left - 20;
|
||||
let placeholderWidth = this.getTextWidth(fullPlaceholder);
|
||||
let placeholder, title, minWidth;
|
||||
if (availableWidth >= placeholderWidth) {
|
||||
placeholder = fullPlaceholder;
|
||||
title = "";
|
||||
minWidth = placeholderWidth;
|
||||
}
|
||||
else {
|
||||
placeholder = this.truncateToWidth(fullPlaceholder, availableWidth);
|
||||
title = fullPlaceholder;
|
||||
minWidth = availableWidth;
|
||||
}
|
||||
// min-width keeps the placeholder visible when the input is empty, but
|
||||
// lets the input grow to fit content the user types beyond the placeholder.
|
||||
input.style.minWidth = minWidth + 'px';
|
||||
document.l10n.setAttributes(input, "integration-citationDialog-just-added-input-citation", { placeholder, title });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// If a bubble is removed between two inputs we need to combine them
|
||||
combineNeighboringInputs(startingNode) {
|
||||
let node = startingNode;
|
||||
|
|
|
|||
|
|
@ -1375,6 +1375,7 @@ const IOManager = {
|
|||
// If no locator is provided, record which bubbles were just added.
|
||||
// If a locator is typed next, these bubbles will receive it.
|
||||
this._justAddedBubbles = bubbleItems;
|
||||
_id("bubble-input").showJustAddedPlaceholder = DIALOG_STATE.isCitingItems();
|
||||
}
|
||||
await CitationDataManager.addItems({ bubbleItems, index });
|
||||
// Refresh the itemTree if in library mode
|
||||
|
|
@ -1693,6 +1694,7 @@ const IOManager = {
|
|||
if (currentLayout.type == "library") {
|
||||
libraryLayout.refreshItemsView();
|
||||
}
|
||||
this._clearJustAddedBubbles();
|
||||
this.updateBubbleInput();
|
||||
// Always refresh items list to make sure the opened and selected items are up to date
|
||||
currentLayout.refreshItemsList();
|
||||
|
|
@ -1811,6 +1813,7 @@ const IOManager = {
|
|||
if (event && event.type == "keydown" && !navigationKeys.includes(event.key)) return;
|
||||
// clear just added bubbles and update bubble input to reflect that
|
||||
this._justAddedBubbles = null;
|
||||
_id("bubble-input").showJustAddedPlaceholder = false;
|
||||
this.updateBubbleInput();
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@
|
|||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
drawintitlebar-platforms="mac,win"
|
||||
resizable="false">
|
||||
resizable="false"
|
||||
windowtype="zotero:citation-dialog"
|
||||
>
|
||||
<head>
|
||||
<title data-l10n-id="integration-citationDialog"></title>
|
||||
<link rel="localization" href="zotero.ftl"/>
|
||||
|
|
@ -145,6 +147,9 @@
|
|||
<!--fx128: size="0" forces select have default native style -->
|
||||
<select name="locator" id="label" class="details-label" size="0"></select>
|
||||
<input id="locator" class="details-data" aria-labelledby="label" aria-describedby="itemDetails-combinedInfo"/>
|
||||
<div class="details-locator-info" data-l10n-id="integration-citationDialog-details-locator-info">
|
||||
<a data-l10n-name="docs-link" class="link" tabindex="0" href="https://www.zotero.org/support/word_processor_plugin_usage#page_and_other_locators" onclick="Zotero.launchURL(this.href)"/>
|
||||
</div>
|
||||
|
||||
<label class="details-label" for="prefix" data-l10n-id="integration-citationDialog-details-prefix"></label>
|
||||
<input id="prefix" class="details-data"/>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ integration-citationDialog-section-cited = { $count ->
|
|||
integration-citationDialog-details-suffix = Suffix
|
||||
integration-citationDialog-details-prefix = Prefix
|
||||
integration-citationDialog-details-suppressAuthor = Omit Author
|
||||
integration-citationDialog-details-locator-info = After adding an item, you can type page numbers directly into the main input field. You can type other locators (e.g. chapter 5) and add them via Enter. <a data-l10n-name="docs-link">Learn more</a>.
|
||||
integration-citationDialog-details-includeComments = Include Comments
|
||||
integration-citationDialog-details-remove = { general-remove }
|
||||
integration-citationDialog-details-done =
|
||||
|
|
@ -74,6 +75,11 @@ integration-citationDialog-aria-bubble =
|
|||
integration-citationDialog-single-input-citation =
|
||||
.placeholder = { integration-citationDialog-search-for-items }
|
||||
.aria-description = Press Tab to select items to add to this citation. Press Escape to discard the changes and close the dialog.
|
||||
integration-citationDialog-just-added-input-placeholder = type "10-15" for page
|
||||
integration-citationDialog-just-added-input-citation =
|
||||
.placeholder = { $placeholder }
|
||||
.title = { $title }
|
||||
.aria-description = { integration-citationDialog-general-instructions }
|
||||
integration-citationDialog-input-citation =
|
||||
.placeholder = { integration-citationDialog-search-for-items }
|
||||
.aria-description = { integration-citationDialog-general-instructions }
|
||||
|
|
|
|||
|
|
@ -741,6 +741,14 @@
|
|||
height: 24px; // same height as input
|
||||
}
|
||||
}
|
||||
.details-locator-info {
|
||||
padding-inline-start: 5px;
|
||||
grid-column: 2;
|
||||
// pull closer to the locator input above
|
||||
margin-top: -4px;
|
||||
color: var(--fill-secondary);
|
||||
font-size: .93rem;
|
||||
}
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ bubble-input {
|
|||
// inputs initially occupy no width so they don't misalign bubbles at the
|
||||
// start of each line. On focus, set their width for the cursor to appear
|
||||
// and offset it by negative margin to avoid bubbles shifting
|
||||
&.empty:not(.full-width):focus {
|
||||
&.empty:not(.full-width):not(.just-added-placeholder):focus {
|
||||
min-width: 1px;
|
||||
margin-inline-start: -1px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue