Compare commits
No commits in common. "859554e3453a2ac49558ed53f5793f40cd1104b9" and "ff2b0bc11fb910f9e1653badcb27bc869fdb1762" have entirely different histories.
859554e345
...
ff2b0bc11f
1 changed files with 4 additions and 73 deletions
|
|
@ -71,13 +71,7 @@ function startApp() {
|
||||||
document.getElementById('authScreen').style.display = 'none';
|
document.getElementById('authScreen').style.display = 'none';
|
||||||
document.querySelector('.container').style.display = '';
|
document.querySelector('.container').style.display = '';
|
||||||
if (!appStarted) { setupEventListeners(); appStarted = true; }
|
if (!appStarted) { setupEventListeners(); appStarted = true; }
|
||||||
selectedScope = scopeFromHash();
|
loadData();
|
||||||
const model = modelFromHash(); // read now: drawing the page rewrites the address
|
|
||||||
loadData().then(() => {
|
|
||||||
if (!model) return;
|
|
||||||
if (findModel(model)) openModelDetail(model, { push: false });
|
|
||||||
else syncAddress(); // gone, or in the trash: drop it from the address
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAuth(mode) {
|
function showAuth(mode) {
|
||||||
|
|
@ -466,9 +460,8 @@ function scopeTitle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateScopeChrome() {
|
function updateScopeChrome() {
|
||||||
syncAddress(); // e.g. a deleted collection falling back to All Models
|
|
||||||
contentTitle.textContent = scopeTitle();
|
contentTitle.textContent = scopeTitle();
|
||||||
const panel = ['duplicates', 'ai', 'watch', 'filament', 'printers'].includes(selectedScope); // pages without the model grid
|
const panel = ['duplicates', 'ai', 'watch', 'printers'].includes(selectedScope); // pages without the model grid
|
||||||
document.getElementById('filterBar').hidden = panel;
|
document.getElementById('filterBar').hidden = panel;
|
||||||
document.querySelector('.view-options').hidden = panel;
|
document.querySelector('.view-options').hidden = panel;
|
||||||
emptyTrashBtn.hidden = !(selectedScope === 'trash' && trashModels.length);
|
emptyTrashBtn.hidden = !(selectedScope === 'trash' && trashModels.length);
|
||||||
|
|
@ -984,60 +977,12 @@ function setupEventListeners() {
|
||||||
document.getElementById('addFilesInput').addEventListener('change', handleAddFiles);
|
document.getElementById('addFilesInput').addEventListener('change', handleAddFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The page you're on lives in the address — #filament, #collection/12, and
|
async function selectScope(scope) {
|
||||||
// /model/34 on the end while a model is open — so a refresh or a bookmark comes
|
|
||||||
// back to it, and Back and Forward move between pages and models.
|
|
||||||
let shownModelId = null; // the model open in the detail view
|
|
||||||
let modelStepPushed = false; // opening it here added a Back step
|
|
||||||
|
|
||||||
function scopeHash(scope, modelId = null) {
|
|
||||||
const page = scope === 'all' ? '' : SPECIAL_SCOPES.includes(scope) ? scope : `collection/${scope}`;
|
|
||||||
const parts = [page, modelId ? `model/${modelId}` : ''].filter(Boolean);
|
|
||||||
return parts.length ? `#${parts.join('/')}` : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function hashParts() {
|
|
||||||
const h = decodeURIComponent(location.hash.slice(1));
|
|
||||||
const m = h.match(/^(.*?)\/?model\/(\d+)$/);
|
|
||||||
return { page: m ? m[1] : h, model: m ? Number(m[2]) : null };
|
|
||||||
}
|
|
||||||
|
|
||||||
function scopeFromHash() {
|
|
||||||
const { page } = hashParts();
|
|
||||||
const collection = page.match(/^collection\/(\d+)$/);
|
|
||||||
if (collection) return collection[1];
|
|
||||||
return SPECIAL_SCOPES.includes(page) ? page : 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
const modelFromHash = () => hashParts().model;
|
|
||||||
|
|
||||||
// Keeps the address in step with what's shown; `push` makes a Back step.
|
|
||||||
function syncAddress(push = false) {
|
|
||||||
const hash = scopeHash(String(selectedScope), shownModelId);
|
|
||||||
if (location.hash === hash || (!hash && !location.hash)) return;
|
|
||||||
history[push ? 'pushState' : 'replaceState']({ model: shownModelId }, '', `${location.pathname}${location.search}${hash}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function selectScope(scope, { push = true } = {}) {
|
|
||||||
selectedScope = scope;
|
selectedScope = scope;
|
||||||
syncAddress(push);
|
|
||||||
if (scope === 'trash') await loadTrash();
|
if (scope === 'trash') await loadTrash();
|
||||||
renderModels();
|
renderModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('popstate', () => {
|
|
||||||
if (!appStarted) return;
|
|
||||||
const scope = scopeFromHash();
|
|
||||||
const model = modelFromHash();
|
|
||||||
if (String(scope) !== String(selectedScope)) selectScope(scope, { push: false });
|
|
||||||
if (model && model !== shownModelId) {
|
|
||||||
openModelDetail(model, { push: false });
|
|
||||||
} else if (!model && shownModelId) {
|
|
||||||
modelStepPushed = false; // Back already took the step away
|
|
||||||
closeModal(fileDetailModal);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Tracks the file currently shown in the detail viewer (for thumbnail regen).
|
// Tracks the file currently shown in the detail viewer (for thumbnail regen).
|
||||||
let currentDetailFile = null;
|
let currentDetailFile = null;
|
||||||
let currentDetailThumb = null; // model image, used as a viewer fallback
|
let currentDetailThumb = null; // model image, used as a viewer fallback
|
||||||
|
|
@ -1045,13 +990,6 @@ let currentDetailThumb = null; // model image, used as a viewer fallback
|
||||||
function closeModal(modal) {
|
function closeModal(modal) {
|
||||||
modal.classList.remove('active');
|
modal.classList.remove('active');
|
||||||
if (modal === slicerModal) pendingHandoff = null;
|
if (modal === slicerModal) pendingHandoff = null;
|
||||||
if (modal === fileDetailModal && shownModelId) {
|
|
||||||
shownModelId = null;
|
|
||||||
// Undo the step opening it added, so Back doesn't reopen what was just closed.
|
|
||||||
if (modelStepPushed && history.state && history.state.model) history.back();
|
|
||||||
else syncAddress();
|
|
||||||
modelStepPushed = false;
|
|
||||||
}
|
|
||||||
if (modal === fileDetailModal) {
|
if (modal === fileDetailModal) {
|
||||||
hideSlicerNotice();
|
hideSlicerNotice();
|
||||||
flushNotes();
|
flushNotes();
|
||||||
|
|
@ -1187,16 +1125,9 @@ function openImportModal() {
|
||||||
importModal.classList.add('active');
|
importModal.classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function openModelDetail(modelId, { push = true } = {}) {
|
function openModelDetail(modelId) {
|
||||||
const model = findModel(modelId);
|
const model = findModel(modelId);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
// Reopening the same model (to refresh it) leaves the address alone.
|
|
||||||
if (shownModelId !== Number(model.id)) {
|
|
||||||
const replacing = shownModelId !== null; // one model to the next: no extra Back step
|
|
||||||
shownModelId = Number(model.id);
|
|
||||||
syncAddress(push && !replacing);
|
|
||||||
if (push && !replacing) modelStepPushed = true;
|
|
||||||
}
|
|
||||||
flushNotes(); // save any edit still pending for the previously open model
|
flushNotes(); // save any edit still pending for the previously open model
|
||||||
fileDetailModal.dataset.currentModelId = modelId;
|
fileDetailModal.dataset.currentModelId = modelId;
|
||||||
currentDetailThumb = model.thumbnailUrl || null;
|
currentDetailThumb = model.thumbnailUrl || null;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue