Preserve tree scroll position
This commit is contained in:
@@ -1 +0,0 @@
|
||||
d7824cd92520205e3dafdd4681a4bcbe51f943f530785c8d8d4d7af88358a069 urbm-2026.06.22.r001-x86_64-1.txz
|
||||
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
1fda0986918fa5838cbd8f56ce013e1c5a2add51c41fb5cee14fe77c0e33c0b4 urbm-2026.06.22.r002-x86_64-1.txz
|
||||
Vendored
+6
-2
@@ -2,13 +2,17 @@
|
||||
<!DOCTYPE PLUGIN [
|
||||
<!ENTITY name "urbm">
|
||||
<!ENTITY author "Michael Roll">
|
||||
<!ENTITY version "2026.06.22.r001">
|
||||
<!ENTITY version "2026.06.22.r002">
|
||||
<!ENTITY pluginURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm.plg">
|
||||
<!ENTITY packageURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm-&version;-x86_64-1.txz">
|
||||
<!ENTITY packageSHA256 "d7824cd92520205e3dafdd4681a4bcbe51f943f530785c8d8d4d7af88358a069">
|
||||
<!ENTITY packageSHA256 "1fda0986918fa5838cbd8f56ce013e1c5a2add51c41fb5cee14fe77c0e33c0b4">
|
||||
]>
|
||||
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="&pluginURL;" min="7.0.0" support="https://git.casaderoll.de/michael/URBM/issues" icon="urbm.png">
|
||||
<CHANGES>
|
||||
### 2026.06.22.r002
|
||||
- Preserve page and tree-container scroll positions after expanding deeply nested folders in source, target, settings, repository, and snapshot trees.
|
||||
- Restore scroll positions after the browser has processed focus/layout changes to prevent jumps back to the root.
|
||||
|
||||
### 2026.06.22.r001
|
||||
- Prevent Unraid's global button styles from stretching folder tree disclosure controls over folder names.
|
||||
- Reserve fixed columns for tree arrows and checkboxes so folder names no longer overlap with controls.
|
||||
|
||||
+5
-1
@@ -2,13 +2,17 @@
|
||||
<!DOCTYPE PLUGIN [
|
||||
<!ENTITY name "urbm">
|
||||
<!ENTITY author "Michael Roll">
|
||||
<!ENTITY version "2026.06.22.r001">
|
||||
<!ENTITY version "2026.06.22.r002">
|
||||
<!ENTITY pluginURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm.plg">
|
||||
<!ENTITY packageURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm-&version;-x86_64-1.txz">
|
||||
<!ENTITY packageSHA256 "REPLACE_DURING_RELEASE">
|
||||
]>
|
||||
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="&pluginURL;" min="7.0.0" support="https://git.casaderoll.de/michael/URBM/issues" icon="urbm.png">
|
||||
<CHANGES>
|
||||
### 2026.06.22.r002
|
||||
- Preserve page and tree-container scroll positions after expanding deeply nested folders in source, target, settings, repository, and snapshot trees.
|
||||
- Restore scroll positions after the browser has processed focus/layout changes to prevent jumps back to the root.
|
||||
|
||||
### 2026.06.22.r001
|
||||
- Prevent Unraid's global button styles from stretching folder tree disclosure controls over folder names.
|
||||
- Reserve fixed columns for tree arrows and checkboxes so folder names no longer overlap with controls.
|
||||
|
||||
+4
-4
@@ -9,12 +9,12 @@ Tag="URBM Unraid Restic Backup Manager backup snapshots restore"
|
||||
<?php
|
||||
$pluginRoot = '/plugins/urbm';
|
||||
?>
|
||||
<link rel="stylesheet" href="<?= $pluginRoot ?>/assets/urbm.css?v=20260622r001">
|
||||
<link rel="stylesheet" href="<?= $pluginRoot ?>/assets/urbm.css?v=20260622r002">
|
||||
<div id="urbm-app" data-api="<?= $pluginRoot ?>/api.php">
|
||||
<header class="bu-header">
|
||||
<div class="bu-brand">
|
||||
<img class="bu-logo" src="<?= $pluginRoot ?>/images/urbm.png?v=20260622r001" alt="URBM-Logo">
|
||||
<div><h1>URBM <span class="bu-version">2026.06.22.r001</span></h1><p>Restic Backup Manager für Unraid</p></div>
|
||||
<img class="bu-logo" src="<?= $pluginRoot ?>/images/urbm.png?v=20260622r002" alt="URBM-Logo">
|
||||
<div><h1>URBM <span class="bu-version">2026.06.22.r002</span></h1><p>Restic Backup Manager für Unraid</p></div>
|
||||
</div>
|
||||
<div id="bu-health" class="bu-health" tabindex="0" data-tooltip="Zeigt, ob die URBM-Hintergrundkomponente erreichbar ist. Beispiel: 'Daemon online' bedeutet, dass Jobs gestartet werden können.">Verbindung wird hergestellt...</div>
|
||||
</header>
|
||||
@@ -32,4 +32,4 @@ $pluginRoot = '/plugins/urbm';
|
||||
<div id="bu-tooltip" role="tooltip" aria-hidden="true"></div>
|
||||
</div>
|
||||
<script>window.URBM_CSRF = <?= json_encode($var['csrf_token'] ?? '') ?>;</script>
|
||||
<script src="<?= $pluginRoot ?>/assets/urbm-2026.06.22.r001.js"></script>
|
||||
<script src="<?= $pluginRoot ?>/assets/urbm-2026.06.22.r002.js"></script>
|
||||
|
||||
+28
-10
@@ -375,6 +375,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
function captureScrollState(root=document) {
|
||||
const trees=[...root.querySelectorAll('.bu-tree')].map((tree,index)=>({index,top:tree.scrollTop,left:tree.scrollLeft}));
|
||||
return {windowX:window.scrollX,windowY:window.scrollY,trees};
|
||||
}
|
||||
|
||||
function restoreScrollState(snapshot, root=document) {
|
||||
if(!snapshot) return;
|
||||
const apply=()=>{
|
||||
const trees=[...root.querySelectorAll('.bu-tree')];
|
||||
snapshot.trees.forEach(item=>{
|
||||
const tree=trees[item.index];
|
||||
if(tree) {
|
||||
tree.scrollTop=item.top;
|
||||
tree.scrollLeft=item.left;
|
||||
}
|
||||
});
|
||||
window.scrollTo(snapshot.windowX, snapshot.windowY);
|
||||
};
|
||||
apply();
|
||||
requestAnimationFrame(()=>{ apply(); setTimeout(apply, 0); });
|
||||
}
|
||||
|
||||
function renderDashboard() {
|
||||
const active = state.runs.filter(r => ['queued','running','paused'].includes(r.status)).length;
|
||||
const orderedRuns = newestRuns(state.runs);
|
||||
@@ -517,15 +539,13 @@
|
||||
function renderSourceBrowser() {
|
||||
const host=document.getElementById('bu-source-browser');
|
||||
if(!host) return;
|
||||
const windowX=window.scrollX, windowY=window.scrollY;
|
||||
const previousScroll=host.querySelector('.bu-tree')?.scrollTop || 0;
|
||||
const scrollSnapshot=captureScrollState(host);
|
||||
const chosen=state.backupSelections.length?state.backupSelections.map(path=>`<span class="bu-selection">${esc(path)}</span>`).join(''):'<span class="bu-muted">Keine Ordner ausgewählt.</span>';
|
||||
const tree=state.sourceTreeRoots.map(item=>sourceTreeNode(item,0)).join('');
|
||||
host.innerHTML=`<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>Backup-Quellen auswählen</h3><span class="bu-muted">Ordner mit dem Dreieck aufklappen. Unterordner werden erst bei Bedarf geladen.</span></div><span class="bu-count">Ausgewählt: ${state.backupSelections.length}</span></div><div class="bu-selection-list">${chosen}</div><div class="bu-tree" role="tree">${tree||'<div class="bu-empty">Keine Ordner verfügbar.</div>'}</div></section>`;
|
||||
const treeElement=host.querySelector('.bu-tree'); if(treeElement) treeElement.scrollTop=previousScroll;
|
||||
host.querySelectorAll('.bu-source-select[data-partial="true"]').forEach(box=>{box.indeterminate=true;box.setAttribute('aria-checked','mixed');});
|
||||
enhanceTooltips(host);
|
||||
window.scrollTo(windowX, windowY);
|
||||
restoreScrollState(scrollSnapshot, host);
|
||||
}
|
||||
|
||||
async function toggleSourceTree(path, forceOpen=false) {
|
||||
@@ -569,13 +589,11 @@
|
||||
function renderDirectoryTree(key) {
|
||||
const tree=state.directoryTrees[key]; const host=document.getElementById(`bu-dir-tree-${key}`);
|
||||
if(!tree||!host) return;
|
||||
const windowX=window.scrollX, windowY=window.scrollY;
|
||||
const previousScroll=host.querySelector('.bu-tree')?.scrollTop || 0;
|
||||
const scrollSnapshot=captureScrollState(host);
|
||||
const html=tree.roots.map(item=>directoryTreeNode(key,item,0)).join('');
|
||||
host.innerHTML=`<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>${esc(tree.title)}</h3><span class="bu-muted">Ordner mit dem Dreieck aufklappen und den gewünschten Zielordner auswählen.</span></div></div><div class="bu-tree" role="tree">${html||'<div class="bu-empty">Keine Ordner verfügbar.</div>'}</div></section>`;
|
||||
const treeElement=host.querySelector('.bu-tree'); if(treeElement) treeElement.scrollTop=previousScroll;
|
||||
enhanceTooltips(host);
|
||||
window.scrollTo(windowX, windowY);
|
||||
restoreScrollState(scrollSnapshot, host);
|
||||
}
|
||||
|
||||
async function toggleDirectoryTree(key, path, forceOpen=false) {
|
||||
@@ -755,9 +773,9 @@
|
||||
return state.config;
|
||||
}
|
||||
function renderPreservingScroll() {
|
||||
const windowX=window.scrollX, windowY=window.scrollY;
|
||||
const scrollSnapshot=captureScrollState(content);
|
||||
render();
|
||||
window.scrollTo(windowX, windowY);
|
||||
restoreScrollState(scrollSnapshot, content);
|
||||
}
|
||||
const lines = (value) => value.split('\n').map(v=>v.trim()).filter(Boolean);
|
||||
const runTime = run => new Date(run.createdAt || run.startedAt || run.finishedAt || 0).getTime() || 0;
|
||||
|
||||
Reference in New Issue
Block a user