mirror of
https://github.com/zotero/zotero.git
synced 2026-10-10 03:28:10 +00:00
Citation dialog: display preview of the citation (#5916)
In Add/Edit Citation mode, display a preview of the citation in the bottom section. The section can be hidden/displayed via the toggle in the right corner. Remove io.preview from editor instance, so that citation dialog knows not to show the preview even if the preference is set. A minor refactor to have resizeWindow() resolve when the animation is fully over, and clear minHeight on window in list mode before resizing, restoring it when resizing animation is done, same as in library mode. It allows us to fully expand the window in list mode before showing the preview. Fixes: zotero#5910
This commit is contained in:
parent
dcf5010415
commit
fa3e0f683f
9 changed files with 198 additions and 39 deletions
|
|
@ -131,6 +131,8 @@ async function onLoad() {
|
|||
await IOManager.toggleDialogMode(initialMode);
|
||||
// most of IO handling relies on currentLayout being defined so it must follow setInitialDialogMode
|
||||
IOManager.init();
|
||||
// set the text of the citation preview
|
||||
CitationPreview.update();
|
||||
// explicitly focus bubble input so one can begin typing right away
|
||||
_id("bubble-input").refocusInput();
|
||||
// wait to call functions that rely on io.getItems() or io.sort() till all cited data is loaded
|
||||
|
|
@ -258,8 +260,9 @@ async function setDialogType(type) {
|
|||
_id("keepSorted").disabled = !io.sortable || !DIALOG_STATE.isCitingItems();
|
||||
_id("keepSorted").checked = !_id("keepSorted").disabled && !io.citation.properties.unsorted;
|
||||
if (DIALOG_STATE.isCitingItems()) {
|
||||
_id("settings-button").hidden = !io.sortable;
|
||||
_id("keepSorted").disabled = !io.sortable;
|
||||
_id("keepSorted").parentElement.hidden = !io.sortable;
|
||||
CitationPreview.update();
|
||||
if (!DIALOG_STATE.loaded) {
|
||||
_id("keepSorted").checked = io.sortable && !io.citation.properties.unsorted;
|
||||
}
|
||||
|
|
@ -596,14 +599,16 @@ class LibraryLayout extends Layout {
|
|||
IOManager.updateBubbleInput();
|
||||
}
|
||||
|
||||
// Resolves once the resize animation has fully completed
|
||||
async resizeWindow() {
|
||||
await Helpers.smoothResizingPromise;
|
||||
let bubbleInputHeight = Helpers.getSearchRowHeight();
|
||||
let suggestedItemsHeight = _id("library-other-items").getBoundingClientRect().height;
|
||||
let minTableHeight = 400;
|
||||
let citationPreview = _id("citation-preview").getBoundingClientRect().height;
|
||||
let bottomHeight = _id("bottom-area-wrapper").getBoundingClientRect().height;
|
||||
|
||||
let minHeight = bubbleInputHeight + suggestedItemsHeight + bottomHeight + minTableHeight;
|
||||
let minHeight = bubbleInputHeight + suggestedItemsHeight + citationPreview + bottomHeight + minTableHeight;
|
||||
|
||||
let targetWidth = Math.max(window.innerWidth, this.MIN_WIDTH);
|
||||
let targetHeight = Math.max(minHeight, lastSetWindowHeight);
|
||||
|
|
@ -612,13 +617,16 @@ class LibraryLayout extends Layout {
|
|||
if (needsResize) {
|
||||
doc.documentElement.style.removeProperty('min-height');
|
||||
ignoreWindowResizing = true;
|
||||
Helpers.smoothResize(targetWidth, targetHeight, {
|
||||
onComplete: () => {
|
||||
_id("bubble-input").refocusInput();
|
||||
doc.documentElement.style.minHeight = `${minHeight}px`;
|
||||
document.documentElement.setAttribute("dialog-layout", this.type);
|
||||
ignoreWindowResizing = false;
|
||||
},
|
||||
await new Promise((resolve) => {
|
||||
Helpers.smoothResize(targetWidth, targetHeight, {
|
||||
onComplete: () => {
|
||||
_id("bubble-input").refocusInput();
|
||||
doc.documentElement.style.minHeight = `${minHeight}px`;
|
||||
document.documentElement.setAttribute("dialog-layout", this.type);
|
||||
ignoreWindowResizing = false;
|
||||
resolve();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
// ensure dialog-layout and min-height is set even if window does not need resizing
|
||||
|
|
@ -1092,6 +1100,7 @@ class ListLayout extends Layout {
|
|||
IOManager.updateBubbleInput();
|
||||
}
|
||||
|
||||
// Resolves only once the resize animation has fully completed
|
||||
async resizeWindow() {
|
||||
await Helpers.smoothResizingPromise;
|
||||
let bubbleInputHeight = Helpers.getSearchRowHeight();
|
||||
|
|
@ -1112,11 +1121,12 @@ class ListLayout extends Layout {
|
|||
marginOfError = Zotero.isWin ? 6 : 2;
|
||||
}
|
||||
|
||||
// height of the bottom section
|
||||
// height of citation preview (0 when hidden) and the bottom section
|
||||
let citationPreview = _id("citation-preview").getBoundingClientRect().height;
|
||||
let bottomHeight = _id("bottom-area-wrapper").getBoundingClientRect().height;
|
||||
|
||||
// set min height and resize the window
|
||||
let autoHeight = bubbleInputHeight + sectionsHeight + sectionsWrapperPadding + bottomHeight + marginOfError;
|
||||
let autoHeight = bubbleInputHeight + sectionsHeight + sectionsWrapperPadding + citationPreview + bottomHeight + marginOfError;
|
||||
// window.resizeTo(X,Y) resizes the window so that it's outerHeight == Y. On mac and windows,
|
||||
// innerHeight and outerHeight are the same. On linux, the outerHeight > innerHeight, perhaps
|
||||
// outerHeight there includes chrome, borders, etc. This difference is accounted for below, so that the dialog
|
||||
|
|
@ -1124,24 +1134,39 @@ class ListLayout extends Layout {
|
|||
if (Zotero.isLinux) {
|
||||
autoHeight += (window.outerHeight - window.innerHeight);
|
||||
}
|
||||
let minHeight = bubbleInputHeight + bottomHeight;
|
||||
doc.documentElement.style.minHeight = `${minHeight}px`;
|
||||
let minHeight = bubbleInputHeight + citationPreview + bottomHeight;
|
||||
|
||||
// cap window height at the height last set by the user
|
||||
autoHeight = Math.min(autoHeight, lastSetWindowHeight);
|
||||
let targetWidth = Math.min(window.innerWidth, this.MIN_WIDTH);
|
||||
|
||||
// Skip the resize animation if the window is already at the target size.
|
||||
let needsResize = Math.round(window.innerWidth) !== Math.round(targetWidth) || Math.round(window.innerHeight) !== Math.round(autoHeight);
|
||||
if (!needsResize) {
|
||||
doc.documentElement.style.minHeight = `${minHeight}px`;
|
||||
document.documentElement.setAttribute("dialog-layout", this.type);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the min-height floor so the window can animate freely (including shrinking);
|
||||
// it's restored to the new value in onComplete below.
|
||||
doc.documentElement.style.removeProperty("min-height");
|
||||
ignoreWindowResizing = true;
|
||||
|
||||
// Timeout is required likely to allow minHeight update to settle
|
||||
setTimeout(() => {
|
||||
Helpers.smoothResize(targetWidth, autoHeight, {
|
||||
onComplete: () => {
|
||||
_id("bubble-input").refocusInput();
|
||||
document.documentElement.setAttribute("dialog-layout", this.type);
|
||||
ignoreWindowResizing = false;
|
||||
},
|
||||
});
|
||||
}, 10);
|
||||
// Timeout is required likely to allow the min-height removal to settle
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
Helpers.smoothResize(targetWidth, autoHeight, {
|
||||
onComplete: () => {
|
||||
_id("bubble-input").refocusInput();
|
||||
doc.documentElement.style.minHeight = `${minHeight}px`;
|
||||
document.documentElement.setAttribute("dialog-layout", this.type);
|
||||
ignoreWindowResizing = false;
|
||||
resolve();
|
||||
},
|
||||
});
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
|
||||
_markRoundedCorners() {
|
||||
|
|
@ -1224,6 +1249,7 @@ const IOManager = {
|
|||
});
|
||||
|
||||
_id("includeComments").addEventListener("click", () => this._toggleIncludeComments());
|
||||
_id("display-preview-button").addEventListener("click", () => this._toggleDisplayPreview());
|
||||
|
||||
// open settings popup on btn click
|
||||
_id("settings-button").addEventListener("click", event => _id("settings-popup").openPopup(event.target, "before_end"));
|
||||
|
|
@ -1267,10 +1293,12 @@ const IOManager = {
|
|||
let isInitialModeSetting = currentLayout === undefined;
|
||||
currentLayout = newMode === "library" ? libraryLayout : listLayout;
|
||||
|
||||
// Reflect visibility of the citation preview after the layout switch.
|
||||
CitationPreview.update();
|
||||
|
||||
// Wait for window resize before running search to avoid stutter with large libraries
|
||||
if (!isInitialModeSetting) {
|
||||
await currentLayout.resizeWindow();
|
||||
await Helpers.smoothResizingPromise;
|
||||
}
|
||||
|
||||
// do not show View menubar with itemTree-specific options in list mode
|
||||
|
|
@ -1317,6 +1345,7 @@ const IOManager = {
|
|||
};
|
||||
}), DIALOG_STATE.type);
|
||||
_id("accept-button").disabled = !CitationDataManager.items.length;
|
||||
CitationPreview.update();
|
||||
},
|
||||
|
||||
async addItemsToCitation(items, { noInputRefocus, index } = { index: null }) {
|
||||
|
|
@ -1394,6 +1423,9 @@ const IOManager = {
|
|||
doc.querySelector("guidance-panel").setAttribute("x", Math.round(width / 2));
|
||||
IOManager.showFirstRunDialog();
|
||||
}
|
||||
// Render the preview before refreshing the list so resizeWindow measures its real height;
|
||||
// otherwise the debounced render lands after the resize and overflows the window.
|
||||
await CitationPreview.render();
|
||||
// Always refresh items list to make sure the opened and selected items are up to date
|
||||
await currentLayout.refreshItemsList();
|
||||
if (!noInputRefocus) {
|
||||
|
|
@ -1862,6 +1894,31 @@ const IOManager = {
|
|||
Zotero.Prefs.set("integration.annotationDialogIncludeComments", includeComments);
|
||||
},
|
||||
|
||||
async _toggleDisplayPreview() {
|
||||
let newShown = !Zotero.Prefs.get("integration.citationPreviewShown");
|
||||
Zotero.Prefs.set("integration.citationPreviewShown", newShown);
|
||||
// Reflect the pressed state right away, since revealing the preview is deferred until resize
|
||||
_id("display-preview-button").setAttribute("aria-pressed", newShown ? "true" : "false");
|
||||
let preview = _id("citation-preview");
|
||||
if (newShown) {
|
||||
// Lay the preview out off-flow via .measuring (real height, but invisible and not
|
||||
// pushing the list around) so resizeWindow grows the window to fit it; then drop it
|
||||
// into view once there's room, avoiding a momentary squeeze of the list.
|
||||
await CitationPreview.render();
|
||||
preview.classList.add("measuring");
|
||||
preview.hidden = false;
|
||||
await currentLayout.resizeWindow();
|
||||
preview.classList.remove("measuring");
|
||||
CitationPreview.update();
|
||||
}
|
||||
else {
|
||||
// Hide first, then shrink -- freeing the space before the window contracts looks clean.
|
||||
preview.classList.remove("measuring");
|
||||
CitationPreview.update();
|
||||
currentLayout.resizeWindow();
|
||||
}
|
||||
},
|
||||
|
||||
// Return focus to where it was before click moved focus.
|
||||
// If it's not possible, refocus the last input in bubble-input so that
|
||||
// focus is not just lost.
|
||||
|
|
@ -1939,6 +1996,52 @@ const IOManager = {
|
|||
}
|
||||
};
|
||||
|
||||
// Manages the citation preview shown in the bottom area of both layouts.
|
||||
const CitationPreview = {
|
||||
// Lazily create _renderDebounced on first use
|
||||
get _renderDebounced() {
|
||||
delete CitationPreview._renderDebounced;
|
||||
CitationPreview._renderDebounced = Zotero.Utilities.debounce(() => CitationPreview.render(), 250);
|
||||
return CitationPreview._renderDebounced;
|
||||
},
|
||||
|
||||
// The rendered text is kept in sync with the cited items even while the preview is hidden,
|
||||
// so it can be measured and revealed instantly when toggled on.
|
||||
update() {
|
||||
let prefShown = Zotero.Prefs.get("integration.citationPreviewShown");
|
||||
let isCitingItems = DIALOG_STATE.isCitingItems();
|
||||
let hasPreview = !!io.preview;
|
||||
let shouldShow = isCitingItems && prefShown && hasPreview;
|
||||
_id("citation-preview").hidden = !shouldShow;
|
||||
let isEmpty = !CitationDataManager.items.length;
|
||||
_id("citation-preview-empty").hidden = !isEmpty;
|
||||
_id("citation-preview-content").hidden = isEmpty;
|
||||
if (isEmpty) {
|
||||
_id("citation-preview-content").innerHTML = "";
|
||||
}
|
||||
// The toggle button only makes sense while citing items with a backing
|
||||
// preview function. It reflects the pref directly.
|
||||
let toggleBtn = _id("display-preview-button");
|
||||
toggleBtn.hidden = !(isCitingItems && hasPreview);
|
||||
toggleBtn.setAttribute("aria-pressed", prefShown ? "true" : "false");
|
||||
if (!isEmpty) {
|
||||
CitationPreview._renderDebounced();
|
||||
}
|
||||
},
|
||||
|
||||
async render() {
|
||||
if (!DIALOG_STATE.isCitingItems()) return;
|
||||
if (!CitationDataManager.items.length) return;
|
||||
if (!io.preview) return;
|
||||
|
||||
CitationDataManager.updateCitationObject();
|
||||
let html = await io.preview("html");
|
||||
// Re-check after the await in case the user cleared items
|
||||
if (!CitationDataManager.items.length) return;
|
||||
_id("citation-preview-content").innerHTML = html;
|
||||
},
|
||||
};
|
||||
|
||||
// Representation of a single entry in the citation.
|
||||
class BubbleItem {
|
||||
// Can be created from either Zotero.Item or citation item from io.citation.citationItems
|
||||
|
|
|
|||
|
|
@ -105,6 +105,14 @@
|
|||
</div>
|
||||
|
||||
<div id="bottom-area" class="layout">
|
||||
<div class="divider"></div>
|
||||
<div id="citation-preview" class="vbox" data-dialog-type="citation">
|
||||
<div id="citation-preview-wrapper" class="vbox">
|
||||
<div id="citation-preview-content"></div>
|
||||
<div id="citation-preview-empty" data-l10n-id="integration-citationDialog-preview-empty"></div>
|
||||
</div>
|
||||
<div class="divider subtle"></div>
|
||||
</div>
|
||||
<div id="bottom-area-wrapper" class="hbox">
|
||||
<div id="dialog-type-setting" class="segmented-switch" data-arrow-nav="horizontal" data-tabindex="70" role="radiogroup" aria-orientation="horizontal">
|
||||
<div id="dialog-type-citation" class="option keyboard-clickable" value="citation" role="radio" aria-checked="false" tabindex="-1" data-arrow-nav-enabled="true" data-l10n-id="integration-citationDialog-btn-type-citation">
|
||||
|
|
@ -119,7 +127,9 @@
|
|||
</div>
|
||||
<div class="hbox" style="flex:1"></div>
|
||||
<div id="bottom-btn-group" class="hbox">
|
||||
<div id="dialog-mode-setting" data-dialog-type="citation,add-note" class="segmented-switch" role="radiogroup" data-arrow-nav="horizontal" data-tabindex="80" aria-orientation="horizontal">
|
||||
<button id="display-preview-button" class="btn-icon" data-dialog-type="citation" data-l10n-id="integration-citationDialog-btn-displayPreview" aria-pressed="false" tabindex="-1" data-tabindex="80"></button>
|
||||
<button id="settings-button" class="btn-icon icon-citation-dialog-settings" data-l10n-id="integration-citationDialog-btn-settings" tabindex="-1" data-tabindex="81"></button>
|
||||
<div id="dialog-mode-setting" data-dialog-type="citation,add-note" class="segmented-switch" role="radiogroup" data-arrow-nav="horizontal" data-tabindex="82" aria-orientation="horizontal">
|
||||
<div id="dialog-mode-list" class="option keyboard-clickable" value="list" role="radio" aria-checked="false" tabindex="-1" data-arrow-nav-enabled="true">
|
||||
<span data-l10n-id="integration-citationDialog-mode-list"></span>
|
||||
</div>
|
||||
|
|
@ -127,7 +137,6 @@
|
|||
<span data-l10n-id="integration-citationDialog-mode-library"></span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="settings-button" class="btn-icon icon-citation-dialog-settings" data-l10n-id="integration-citationDialog-btn-settings" tabindex="-1" data-tabindex="81"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1226,14 +1226,6 @@ class EditorInstance {
|
|||
// Otherwise returns `undefined` which makes this function to be
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute a callback with a preview of the given citation
|
||||
* @return {Promise} A promise resolved with the previewed citation string
|
||||
*/
|
||||
preview: async function () {
|
||||
// Zotero.debug('CI: preview');
|
||||
},
|
||||
|
||||
/**
|
||||
* Sort the citationItems within citation (depends on this.citation.properties.unsorted)
|
||||
* @return {Promise} A promise resolved with the previewed citation string
|
||||
|
|
|
|||
|
|
@ -1564,7 +1564,7 @@ Zotero.Integration.Session.prototype.cite = async function (field, addNote=false
|
|||
this.updateFromDocument(FORCE_CITATIONS_FALSE).then(() => this.citationsByItemID);
|
||||
}
|
||||
|
||||
var previewFn = async function (citation) {
|
||||
var previewFn = async function (citation, format) {
|
||||
let idx = await fieldIndexPromise;
|
||||
await citationsByItemIDPromise;
|
||||
|
||||
|
|
@ -1580,7 +1580,7 @@ Zotero.Integration.Session.prototype.cite = async function (field, addNote=false
|
|||
let citationsPost = citations.slice(sliceIdx);
|
||||
let citationID = citation.citationID;
|
||||
try {
|
||||
var result = this.style.previewCitationCluster(citation, citationsPre, citationsPost, "rtf");
|
||||
var result = this.style.previewCitationCluster(citation, citationsPre, citationsPost, format || "rtf");
|
||||
} catch(e) {
|
||||
throw e;
|
||||
} finally {
|
||||
|
|
@ -1811,10 +1811,11 @@ Zotero.Integration.CitationEditInterface = function (items, sortable, fieldIndex
|
|||
Zotero.Integration.CitationEditInterface.prototype = {
|
||||
/**
|
||||
* Execute a callback with a preview of the given citation
|
||||
* @param {String} [format] Override the default output format (e.g. "html" for use in citation dialog)
|
||||
* @return {Promise} A promise resolved with the previewed citation string
|
||||
*/
|
||||
preview: function () {
|
||||
return this.previewFn(this.citation);
|
||||
preview: function (format) {
|
||||
return this.previewFn(this.citation, format);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ integration-citationDialog-lib-message-annotations = { $search ->
|
|||
*[other] No selected or open items with annotations
|
||||
}
|
||||
integration-citationDialog-settings-keepSorted = Keep sources sorted
|
||||
integration-citationDialog-preview-empty = Preview
|
||||
integration-citationDialog-btn-displayPreview =
|
||||
.title = Display citation preview
|
||||
integration-citationDialog-btn-settings =
|
||||
.title = { general-open-settings }
|
||||
integration-citationDialog-mode-library = Library
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.0005 4C14.1006 4.0002 17.6223 6.4688 19.1655 10C17.6223 13.5312 14.1006 15.9998 10.0005 16C5.90005 16 2.37673 13.5315 0.833496 10C2.37673 6.46847 5.90005 4 10.0005 4ZM10.0005 5.25C6.6116 5.25 3.67094 7.17741 2.21729 10C3.67094 12.8226 6.6116 14.75 10.0005 14.75C13.3886 14.7498 16.3271 12.8223 17.7808 10C16.3752 7.27113 13.5816 5.37828 10.3354 5.25586L10.0005 5.25ZM10.0005 6.75C11.7952 6.75026 13.2505 8.20524 13.2505 10C13.2505 11.7948 11.7952 13.2497 10.0005 13.25C8.20556 13.25 6.75049 11.7949 6.75049 10C6.75049 8.20507 8.20556 6.75 10.0005 6.75ZM10.0005 8C8.89592 8 8.00049 8.89543 8.00049 10C8.00049 11.1046 8.89592 12 10.0005 12C11.1048 11.9997 12.0005 11.1044 12.0005 10C12.0005 8.89559 11.1048 8.00026 10.0005 8Z" fill="context-fill"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 863 B |
|
|
@ -153,6 +153,7 @@ pref("extensions.zotero.integration.upgradeTemplateDelayedOn", 0);
|
|||
pref("extensions.zotero.integration.dontPromptMendeleyImport", false);
|
||||
pref("extensions.zotero.integration.citationDialogMode", "last-used");
|
||||
pref("extensions.zotero.integration.annotationDialogIncludeComments", true);
|
||||
pref("extensions.zotero.integration.citationPreviewShown", true);
|
||||
|
||||
// Connector settings
|
||||
pref("extensions.zotero.httpServer.enabled", true);
|
||||
|
|
|
|||
|
|
@ -110,6 +110,11 @@
|
|||
.divider {
|
||||
border-bottom: 1px solid var(--color-panedivider);
|
||||
margin: 0;
|
||||
|
||||
&.subtle {
|
||||
border-bottom-color: var(--fill-quinary);
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.add-all {
|
||||
|
|
@ -547,8 +552,42 @@
|
|||
}
|
||||
}
|
||||
|
||||
#citation-preview {
|
||||
padding-top: 6px;
|
||||
|
||||
// While the preview is being toggled on, lay it out off-flow so the window can grow to
|
||||
// fit it before it's revealed: absolute keeps a real, measurable height without pushing
|
||||
// the list around, and visibility:hidden keeps it invisible until there's room for it.
|
||||
// inset-inline: 0 matches the in-flow width (body is the flow parent), so the measured
|
||||
// height is accurate.
|
||||
&.measuring {
|
||||
position: absolute;
|
||||
inset-inline: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#citation-preview-wrapper {
|
||||
padding: 2px 12px 8px 12px;
|
||||
min-height: 20px;
|
||||
max-height: 160px;
|
||||
overflow-y: auto;
|
||||
-moz-window-dragging: no-drag;
|
||||
font-family: "Times New Roman";
|
||||
|
||||
#citation-preview-content {
|
||||
color: var(--fill-primary);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
#citation-preview-empty {
|
||||
padding-top: 2px;
|
||||
color: var(--fill-secondary);
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#bottom-area-wrapper {
|
||||
border-top: var(--material-panedivider);
|
||||
padding: 4px 8px;
|
||||
|
||||
.segmented-switch {
|
||||
|
|
@ -647,6 +686,12 @@
|
|||
height: 28px;
|
||||
gap: 8px;
|
||||
-moz-window-dragging: no-drag;
|
||||
#display-preview-button {
|
||||
@include svgicon("dialog-citation-preview", "universal", "20");
|
||||
&[aria-pressed="true"] {
|
||||
background-color: var(--fill-quinary);
|
||||
}
|
||||
}
|
||||
#settings-button {
|
||||
@include svgicon("dialog-options", "universal", "16");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ describe("Citation Dialog", function () {
|
|||
getItems() {
|
||||
return [];
|
||||
},
|
||||
preview: () => {},
|
||||
allCitedDataLoadedPromise: Promise.resolve(),
|
||||
};
|
||||
let dialog, win, doc, IOManager, CitationDataManager, SearchHandler;
|
||||
|
|
@ -661,6 +662,7 @@ describe("Citation Dialog", function () {
|
|||
getItems() {
|
||||
return new Zotero.Promise(() => {});
|
||||
},
|
||||
preview: () => {},
|
||||
allCitedDataLoadedPromise: new Zotero.Promise(() => {}),
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue