mirror of
https://github.com/lllin000/PaperForge.git
synced 2026-07-22 06:50:53 +00:00
feat: instant delete, back navigation, undo pill
This commit is contained in:
parent
180a3813fe
commit
ecbe505662
2 changed files with 130 additions and 1 deletions
|
|
@ -603,6 +603,9 @@ function deleteLocalAnnotation(vaultPath, annotationId) {
|
|||
let _overlayInstalled = false;
|
||||
let _currentVaultPath = null;
|
||||
let _currentPdfPath = null;
|
||||
var _pdfNavStack = [];
|
||||
var _pdfNavPos = -1;
|
||||
var _navProgrammatic = false;
|
||||
|
||||
function detectConflictingPdfPlugins(app) {
|
||||
try {
|
||||
|
|
@ -696,6 +699,9 @@ function injectPdfEventHooks(containerEl, view, vaultPath, pdfPath, plugin) {
|
|||
_currentContainerEl = containerEl;
|
||||
_pdfInternalHandle = null;
|
||||
_pdfEventSubscriptions = [];
|
||||
_pdfNavStack = [];
|
||||
_pdfNavPos = -1;
|
||||
_navProgrammatic = false;
|
||||
_invalidatePdfPageCaches();
|
||||
var anns = fetchAnnotationsForPaper(vaultPath, pdfPath);
|
||||
// Try resolving PDF.js internal viewer handle
|
||||
|
|
@ -765,16 +771,106 @@ function _subscribePdfEvents(handle, pdfPath, vaultPath, plugin) {
|
|||
_rebuildVisibleLayers(handle, pdfPath, vaultPath);
|
||||
}, 80);
|
||||
}
|
||||
var _lastNavPage = null;
|
||||
function onPageChanging(evt) {
|
||||
if (_navProgrammatic) { _navProgrammatic = false; return; }
|
||||
if (_lastNavPage !== null && Math.abs(evt.pageNumber - _lastNavPage) > 1) {
|
||||
_pushPdfNav(_lastNavPage);
|
||||
}
|
||||
_lastNavPage = evt.pageNumber;
|
||||
}
|
||||
bus.on('pagerendered', onPageRendered);
|
||||
bus.on('scalechanged', onScaleChanged);
|
||||
bus.on('pagechanging', onPageChanging);
|
||||
if (plugin && typeof plugin.register === 'function') {
|
||||
plugin.register(function () {
|
||||
try { bus.off('pagerendered', onPageRendered); } catch {}
|
||||
try { bus.off('scalechanged', onScaleChanged); } catch {}
|
||||
try { bus.off('pagechanging', onPageChanging); } catch {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ── PDF back/forward navigation ── */
|
||||
function _pushPdfNav(pageNumber) {
|
||||
if (_pdfNavPos < _pdfNavStack.length - 1) {
|
||||
_pdfNavStack = _pdfNavStack.slice(0, _pdfNavPos + 1);
|
||||
}
|
||||
_pdfNavStack.push(pageNumber);
|
||||
if (_pdfNavStack.length > 100) _pdfNavStack.shift();
|
||||
_pdfNavPos = _pdfNavStack.length - 1;
|
||||
_renderPdfNavButtons();
|
||||
}
|
||||
|
||||
function _renderPdfNavButtons() {
|
||||
var c = document.querySelector('.pdf-viewer-container');
|
||||
if (!c) return;
|
||||
var old = c.querySelectorAll('.pf-nav-btn');
|
||||
for (var oi = 0; oi < old.length; oi++) old[oi].remove();
|
||||
if (_pdfNavPos < 0) return;
|
||||
if (_pdfNavPos > 0) {
|
||||
var bk = document.createElement('button');
|
||||
bk.className = 'pf-nav-btn pf-nav-back';
|
||||
bk.textContent = '\u25C0';
|
||||
bk.title = 'Go back to page ' + _pdfNavStack[_pdfNavPos - 1];
|
||||
bk.addEventListener('click', function () {
|
||||
if (_pdfNavPos <= 0 || !_pdfInternalHandle) return;
|
||||
_navProgrammatic = true;
|
||||
_pdfNavPos--;
|
||||
_pdfInternalHandle.scrollPageIntoView({ pageNumber: _pdfNavStack[_pdfNavPos] });
|
||||
_renderPdfNavButtons();
|
||||
});
|
||||
c.appendChild(bk);
|
||||
}
|
||||
if (_pdfNavPos < _pdfNavStack.length - 1) {
|
||||
var fw = document.createElement('button');
|
||||
fw.className = 'pf-nav-btn pf-nav-forward';
|
||||
fw.textContent = '\u25B6';
|
||||
fw.title = 'Go forward to page ' + _pdfNavStack[_pdfNavPos + 1];
|
||||
fw.addEventListener('click', function () {
|
||||
if (_pdfNavPos >= _pdfNavStack.length - 1 || !_pdfInternalHandle) return;
|
||||
_navProgrammatic = true;
|
||||
_pdfNavPos++;
|
||||
_pdfInternalHandle.scrollPageIntoView({ pageNumber: _pdfNavStack[_pdfNavPos] });
|
||||
_renderPdfNavButtons();
|
||||
});
|
||||
c.appendChild(fw);
|
||||
}
|
||||
}
|
||||
/* ── Undo pill on delete ── */
|
||||
var _undoPillEl = null;
|
||||
var _undoTimer = null;
|
||||
|
||||
function _showUndoPill(undoEntry) {
|
||||
if (_undoPillEl) _undoPillEl.remove();
|
||||
if (_undoTimer) clearTimeout(_undoTimer);
|
||||
_undoPillEl = document.createElement('div');
|
||||
_undoPillEl.className = 'pf-undo-pill';
|
||||
_undoPillEl.innerHTML = '<span>Annotation deleted</span> <button>Undo</button>';
|
||||
_undoPillEl.querySelector('button').addEventListener('click', function () {
|
||||
_appendAnnotationToMemory(undoEntry.annotation);
|
||||
_renderAnnotationToPage(undoEntry.annotation);
|
||||
createLocalAnnotation(undoEntry.vaultPath, undoEntry.pdfPath, {
|
||||
type: undoEntry.annotation.type,
|
||||
page_index: undoEntry.annotation.page_index,
|
||||
page_label: undoEntry.annotation.page_label || '',
|
||||
selected_text: undoEntry.annotation.selected_text || '',
|
||||
comment: undoEntry.annotation.comment || '',
|
||||
color: undoEntry.annotation.color || '#ffd400',
|
||||
position_json: JSON.stringify(undoEntry.annotation.position),
|
||||
}).then(function () {
|
||||
_scheduleAnnotationCacheFlush(undoEntry.vaultPath);
|
||||
});
|
||||
_undoPillEl.remove();
|
||||
_undoPillEl = null;
|
||||
});
|
||||
var c = document.querySelector('.pdf-viewer-container');
|
||||
if (c) c.appendChild(_undoPillEl);
|
||||
_undoTimer = setTimeout(function () {
|
||||
if (_undoPillEl) { _undoPillEl.remove(); _undoPillEl = null; }
|
||||
}, 8000);
|
||||
}
|
||||
|
||||
function _getOrCreateAlignedLayer(pageView) {
|
||||
var pageDiv = pageView.div;
|
||||
if (!pageDiv) return null;
|
||||
|
|
@ -1296,7 +1392,11 @@ function showAnnotationPopover(event, ann, rectEl, vaultPath, pdfPath, container
|
|||
delBtn.className = 'pf-annotation-popover-btn pf-annotation-popover-btn--danger';
|
||||
delBtn.textContent = 'Delete';
|
||||
delBtn.addEventListener('click', function () {
|
||||
if (!confirm('Delete this annotation?')) return;
|
||||
_showUndoPill({
|
||||
annotation: JSON.parse(JSON.stringify(ann)),
|
||||
vaultPath: _currentVaultPath,
|
||||
pdfPath: _currentPdfPath,
|
||||
});
|
||||
_removeAnnotationRectsFromDom(ann.id);
|
||||
_removeAnnotationFromMemory(ann.id);
|
||||
deleteLocalAnnotation(_currentVaultPath, ann.id).then(function (result) {
|
||||
|
|
|
|||
|
|
@ -2743,3 +2743,32 @@
|
|||
background: var(--text-error);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
|
||||
/* $- PDF back/forward nav buttons -/
|
||||
.pf-nav-btn {
|
||||
position: absolute; top: 8px; z-index: 100;
|
||||
background: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px; color: var(--text-muted);
|
||||
cursor: pointer; padding: 2px 8px; font-size: 16px;
|
||||
line-height: 1.4; opacity: 0.5; transition: opacity 0.15s;
|
||||
}
|
||||
.pf-nav-btn:hover { opacity: 1; }
|
||||
.pf-nav-back { left: 8px; }
|
||||
.pf-nav-forward { left: 44px; }
|
||||
|
||||
|
||||
/* $- Undo pill -/
|
||||
.pf-undo-pill {
|
||||
position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%);
|
||||
z-index: 200; background: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 6px; padding: 6px 14px; font-size: 13px;
|
||||
display: flex; gap: 12px; align-items: center;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
.pf-undo-pill button {
|
||||
background: none; border: none; color: var(--text-accent);
|
||||
cursor: pointer; font-weight: 600; padding: 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue