Macos integration progress bar (#5016)

* Display the progress bar on macOS integration commands more

Avoid displaying before Add/Edit Citations, Add Note and Doc Prefs
since that brings Zotero window to the foreground along with the
relevant dialog, but display the progress bar after confirming those
dialogs, which will bring Zotero to the front, but is still better than
no progress indication.

Display the progress bar for Refresh, Doc Prefs, Unlink and Add/Edit
Bibliography

* Fix progress bar indeterminate state not being visible and not working.

- Update _progressMeter.scss for fx115+
- Some adjustments/resizing to progress bar display in quick format
This commit is contained in:
Adomas Ven 2025-02-12 08:43:11 +02:00 committed by GitHub
parent 87f8229b32
commit 8dbc6177ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 127 additions and 120 deletions

View file

@ -9,11 +9,6 @@ window.citation-dialog {
padding: 0;
}
.citation-dialog.progress-bar .citation-dialog.deck {
height: 37px;
}
.citation-dialog.entry {
background: -moz-linear-gradient(-90deg, rgb(243,123,119) 0, rgb(180,47,38) 50%, rgb(156,36,27) 50%);

View file

@ -55,17 +55,17 @@
</linkset>
<box orient="horizontal" class="citation-dialog entry">
<deck class="citation-dialog deck" selectedIndex="0" flex="1">
<hbox class="citation-dialog main" flex="1" align="start">
<hbox flex="1">
<html:div flex="1" spellcheck="false" class="citation-dialog editor insert-note" role="application"></html:div>
<vbox class="citation-dialog icons end">
<image class="icon zotero-spinner-16"/>
</vbox>
</hbox>
<hbox class="citation-dialog main" flex="1" align="start">
<hbox flex="1">
<html:div flex="1" spellcheck="false" class="citation-dialog editor insert-note" role="application"></html:div>
<vbox class="citation-dialog icons end">
<image class="icon zotero-spinner-16"/>
</vbox>
</hbox>
<html:progress class="citation-dialog progress-meter" max="100"/>
</deck>
</hbox>
<hbox class="citation-dialog progress-container" hidden="true">
<html:progress class="citation-dialog progress-meter downloadProgress" style="display: none" max="100"/>
</hbox>
</box>
<panel class="citation-dialog reference-panel" noautofocus="true" norestorefocus="true"
height="0" width="0" flip="none">

View file

@ -24,8 +24,8 @@
***** END LICENSE BLOCK *****
-->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://global/skin/browser.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/zotero.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/integration.css" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
@ -44,8 +44,6 @@
<script src="progressBar.js" type="text/javascript"/>
<box orient="horizontal" class="citation-dialog entry">
<deck class="citation-dialog deck" selectedIndex="0" flex="1">
<html:progress class="citation-dialog progress-meter" max="100"/>
</deck>
<html:progress class="citation-dialog progress-meter downloadProgress" max="100"/>
</box>
</window>

View file

@ -1295,10 +1295,10 @@ var Zotero_QuickFormat = new function () {
editor.style.width = `${editorDesiredWidth}px`;
}
}
async function _resizeWindow() {
async function _resizeWindow(height, width) {
let box = document.querySelector(".citation-dialog.entry");
let height = box.getBoundingClientRect().height;
let width = WINDOW_WIDTH;
height = height || box.getBoundingClientRect().height;
width = width || WINDOW_WIDTH;
// Force resizing if there is no max height set on the window
let maySkip = !!document.documentElement.style.maxHeight;
if (Math.abs(height - window.innerHeight) < 5 && maySkip) {
@ -1524,9 +1524,12 @@ var Zotero_QuickFormat = new function () {
/**
* Called when progress changes
*/
function _onProgress(percent) {
async function _onProgress(percent) {
var meter = document.querySelector(".citation-dialog.progress-meter");
if(percent === null) {
meter.style.display = "";
await Zotero.Promise.delay(10);
_resizeWindow(meter.parentElement.parentElement.getBoundingClientRect().height);
if (percent === null) {
meter.removeAttribute('value');
} else {
meter.value = Math.round(percent);
@ -1541,7 +1544,9 @@ var Zotero_QuickFormat = new function () {
accepted = true;
try {
_updateCitationObject();
document.querySelector(".citation-dialog.deck").selectedIndex = 1;
document.querySelector(".citation-dialog.main").hidden = true;
document.querySelector(".citation-dialog.progress-container").hidden = false;
_onProgress(null);
io.accept(_onProgress);
} catch(e) {
Zotero.debug(e);

View file

@ -54,32 +54,32 @@
</linkset>
<box orient="horizontal" class="citation-dialog entry">
<deck class="citation-dialog deck" selectedIndex="0" flex="1">
<hbox class="citation-dialog main" flex="1" align="start">
<hbox flex="1">
<vbox class="citation-dialog icons start">
<toolbarbutton id="zotero-icon" data-l10n-id="quickformat-citation-options" type="menu" tabindex="0" disabled="true">
<menupopup>
<menuitem id="keep-sorted" label="&zotero.citation.keepSorted.label;"
oncommand="Zotero_QuickFormat.onKeepSortedCommand()" type="checkbox"
hidden="true"/>
<menuitem id="show-editor" label="&zotero.integration.showEditor.label;"
oncommand="Zotero_QuickFormat.onShowEditorCommand()" type="checkbox"
hidden="true"/>
<menuitem id="classic-view" label="&zotero.integration.classicView.label;"
oncommand="Zotero_QuickFormat.onClassicViewCommand()"/>
</menupopup>
</toolbarbutton>
</vbox>
<html:div flex="1" spellcheck="false" class="citation-dialog editor" role="application"></html:div>
<vbox class="citation-dialog icons end">
<image class="icon zotero-spinner-16"/>
<toolbarbutton class="icon accept-button" onclick="Zotero_QuickFormat.accept()" data-l10n-id="quickformat-accept"></toolbarbutton>
</vbox>
</hbox>
<hbox class="citation-dialog main" flex="1" align="start">
<hbox flex="1">
<vbox class="citation-dialog icons start">
<toolbarbutton id="zotero-icon" data-l10n-id="quickformat-citation-options" type="menu" tabindex="0" disabled="true">
<menupopup>
<menuitem id="keep-sorted" label="&zotero.citation.keepSorted.label;"
oncommand="Zotero_QuickFormat.onKeepSortedCommand()" type="checkbox"
hidden="true"/>
<menuitem id="show-editor" label="&zotero.integration.showEditor.label;"
oncommand="Zotero_QuickFormat.onShowEditorCommand()" type="checkbox"
hidden="true"/>
<menuitem id="classic-view" label="&zotero.integration.classicView.label;"
oncommand="Zotero_QuickFormat.onClassicViewCommand()"/>
</menupopup>
</toolbarbutton>
</vbox>
<html:div flex="1" spellcheck="false" class="citation-dialog editor" role="application"></html:div>
<vbox class="citation-dialog icons end">
<image class="icon zotero-spinner-16"/>
<toolbarbutton class="icon accept-button" onclick="Zotero_QuickFormat.accept()" data-l10n-id="quickformat-accept"></toolbarbutton>
</vbox>
</hbox>
<html:progress class="citation-dialog progress-meter" max="100"/>
</deck>
</hbox>
<hbox class="citation-dialog progress-container" hidden="true">
<html:progress class="citation-dialog progress-meter downloadProgress" max="100"/>
</hbox>
</box>
<html:div id="bubble-description" class="aria-hidden" role="tooltip" data-l10n-id="quickformat-aria-bubble"></html:div>
<html:div id="input-description" class="aria-hidden" role="tooltip" data-l10n-id="quickformat-aria-input"></html:div>

View file

@ -276,7 +276,7 @@ Zotero.Integration = new function() {
}
Zotero.Integration.currentDoc = document = await documentPromise;
[session, documentImported] = await Zotero.Integration.getSession(application, document, agent, command == 'addNote');
[session, documentImported] = await Zotero.Integration.getSession(application, document, agent, command);
Zotero.Integration.currentSession = session;
// TODO: figure this out
// Zotero.Notifier.trigger('delete', 'collection', 'document');
@ -441,7 +441,7 @@ Zotero.Integration = new function() {
// So we make sure cleanup is finished before the dialog is closed, but otherwise
// we should not delay the dialog display
let cleanupPromise = Zotero.Integration.currentDoc.cleanup();
Zotero.Integration.currentSession && await Zotero.Integration.currentSession.progressBar.hide(true);
await Zotero.Integration.currentSession?.progressBar.hide(true);
var allOptions = 'chrome,centerscreen';
// without this, Firefox gets raised with our windows under Compiz
@ -471,14 +471,8 @@ Zotero.Integration = new function() {
window.addEventListener("unload", listener, false);
await deferred.promise;
Zotero.Integration.currentSession?.progressBar.show();
await cleanupPromise;
// We do not want to redisplay the progress bar if this window close
// was the final close of the integration command
await Zotero.Promise.delay(10);
if (Zotero.Integration.currentDoc && Zotero.Integration.currentSession
&& Zotero.Integration.currentSession.progressBar) {
Zotero.Integration.currentSession.progressBar.show();
}
};
/**
@ -486,11 +480,16 @@ Zotero.Integration = new function() {
* Either loads a cached session if doc communicated since restart or creates a new one
* @return {Zotero.Integration.Session} Promise
*/
this.getSession = async function (app, doc, agent, isNote) {
this.getSession = async function (app, doc, agent, command) {
let documentImported = false;
try {
var progressBar = new Zotero.Integration.Progress(4, isNote, Zotero.isMac && agent != 'http');
progressBar.show();
var progressBar = new Zotero.Integration.Progress(4, command == "addNote");
// Avoid showing the progress bar on macOS when initiating commands that
// display an UI interface, otherwise the Zotero window is brought to the front
// along with the UI when the progress bar is closed.
if (!Zotero.isMac || ["refresh", "removeCodes", "addEditBibliography"].includes(command)) {
progressBar.show();
}
var dataString = await doc.getDocumentData(),
data, session;
@ -3464,19 +3463,11 @@ Zotero.Integration.Timer = class {
Zotero.Integration.Progress = class {
/**
* @param {Number} segmentCount
* @param {Boolean} dontDisplay
* On macOS closing an application window switches focus to the topmost window of the same application
* instead of the previous window of any application. Since the progress window is opened and closed
* between showing other integration windows, macOS will switch focus to the main Zotero window (and
* move the word processor window to the background). Thus we avoid showing the progress window on macOS
* except for http agents (i.e. google docs), where even opening the citation dialog may potentially take
* a long time and having no indication of progress is worse than bringing the Zotero window to the front
*/
constructor(segmentCount=4, isNote=false, dontDisplay=false) {
constructor(segmentCount=4, isNote=false) {
this.segments = Array.from({length: segmentCount}, () => undefined);
this.timer = new Zotero.Integration.Timer();
this.segmentIdx = 0;
this.dontDisplay = dontDisplay;
this.isNote = isNote;
}
@ -3506,7 +3497,6 @@ Zotero.Integration.Progress = class {
this.segmentIdx = 0;
}
show() {
if (this.dontDisplay) return;
var options = 'chrome,centerscreen';
// without this, Firefox gets raised with our windows under Compiz
if (Zotero.isLinux) options += ',dialog=no';
@ -3524,7 +3514,7 @@ Zotero.Integration.Progress = class {
Zotero.Utilities.Internal.activate(this.window);
}
async hide(fast=false) {
if (this.dontDisplay || !this.window) return;
if (!this.window) return;
if (!fast) {
this.onProgress && this.onProgress(100);
this.onProgress = null;

View file

@ -216,8 +216,16 @@ span.zotero-bubble-input {
-moz-window-dragging: no-drag;
}
.citation-dialog.progress-meter[value] {
.citation-dialog .progress-container {
flex: 1;
}
.citation-dialog progress {
visibility: visible;
border-radius: 10px;
margin: 0;
flex: 1;
height: 10px;
}
.citation-dialog .accept-button {

View file

@ -1,67 +1,78 @@
// From https://dxr.mozilla.org/mozilla-esr60/source/browser/themes/shared/downloads/progressmeter.inc.css
//// From https://dxr.mozilla.org/mozilla-esr60/source/browser/themes/shared/downloads/progressmeter.inc.css
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*** Common-styled progressmeter ***/
:root {
--download-progress-fill-color: AccentColor;
--download-progress-paused-color: GrayText;
--download-progress-flare-color: rgba(255,255,255,0.75);
}
@media (prefers-color-scheme: dark) {
#contentAreaDownloadsView {
--download-progress-fill-color: var(--in-content-item-selected);
}
}
/*
* Styling "html:progress" is limited by the fact that a number of properties
* are intentionally locked at the UA stylesheet level. We have to use a border
* instead of an outline because the latter would be drawn over the progress
* bar and we cannot change its z-index. This means we have to use a negative
* margin, except when the value is zero, and adjust the width calculation for
* the indeterminate state.
*/
.downloadProgress {
height: 8px;
border-radius: 1px;
margin: 4px 0 0;
margin-inline-end: 12px;
/* for overriding rules in progressmeter.css */
-moz-appearance: none;
border-style: none;
background-color: transparent;
min-width: initial;
min-height: initial;
appearance: none;
display: flex;
margin-block: 5px 1px;
/* This value is kinda odd, it's used to align with the edge of the badge,
* if shown, which is inside the edge of the image (the image gets 16px
* margin). */
margin-inline-end: 18px;
border: none;
height: 4px;
border-radius: 2px;
background-color: color-mix(in srgb, currentColor 15%, transparent);
}
.downloadProgress[mode="undetermined"] {
/* for overriding rules on global.css in Linux. */
-moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter");
/* Ensure we have contrast in selected download items */
#downloadsListBox.allDownloadsListBox richlistitem[selected] .downloadProgress::-moz-progress-bar {
--download-progress-fill-color: currentColor;
--download-progress-flare-color: AccentColor;
}
.downloadProgress > .progress-bar {
background-color: Highlight;
/* for overriding rules in progressmeter.css */
-moz-appearance: none;
.downloadProgress::-moz-progress-bar {
appearance: none;
background-color: var(--download-progress-fill-color);
border-radius: 2px;
}
.downloadProgress[paused="true"] > .progress-bar {
background-color: GrayText;
.downloadProgress[paused]::-moz-progress-bar {
background-color: var(--download-progress-paused-color);
}
.downloadProgress[mode="undetermined"] > .progress-bar {
.downloadProgress:indeterminate::-moz-progress-bar {
width: calc(100% + 2px);
/* Make a white reflecting animation.
Create a gradient with 2 identical pattern, and enlarge the size to 200%.
Create a gradient with 2 identical patterns, and enlarge the size to 200%.
This allows us to animate background-position with percentage. */
background-color: var(--download-progress-fill-color);
background-image: linear-gradient(90deg, transparent 0%,
rgba(255,255,255,0.5) 25%,
transparent 50%,
rgba(255,255,255,0.5) 75%,
transparent 100%);
background-blend-mode: lighten;
var(--download-progress-flare-color) 25%,
transparent 50%,
var(--download-progress-flare-color) 75%,
transparent 100%);
background-blend-mode: normal;
background-size: 200% 100%;
animation: downloadProgressSlideX 1.5s linear infinite;
}
.downloadProgress > .progress-remainder {
border: solid ButtonShadow;
border-block-start-width: 1px;
border-block-end-width: 1px;
border-inline-start-width: 0;
border-inline-end-width: 1px;
background-color: ButtonFace;
}
.downloadProgress[value="0"] > .progress-remainder {
border-width: 1px;
}
.downloadProgress > .progress-remainder[mode="undetermined"] {
border: none;
}
@keyframes downloadProgressSlideX {
0% {
background-position: 0 0;