Links and GET forms to wiki pages swap the next page into .shell instead of loading a new document: the server answers boosted requests and history restores with a partial (title, page actions out-of-band, shell content). The header stays, browsers without cross-document view transitions (Firefox) no longer flash between pages, and the swap runs as a same-document view transition. Files, the editor, internal endpoints and POST forms still navigate normally. Back/Forward refetch pages (no snapshots that could predate a move or delete); the tree rail keeps its scroll position and the content column returns to where it was. Mutation redirects swap their result in the same way. Page scripts that assumed a fresh document now also run after a swap (toc, contents, companion, scroll-sync, search actions) or register once (fitness). The e2e suite now also runs in Firefox. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
84 lines
3.3 KiB
JavaScript
84 lines
3.3 KiB
JavaScript
function rebuildIndex() {
|
|
openModal({ title: 'Rebuilding search index…', body: 'Walking the wiki tree.' });
|
|
fetch('/_reindex', { method: 'POST' })
|
|
.then(function (resp) {
|
|
if (!resp.ok) throw new Error('rebuild failed: ' + resp.status);
|
|
window.location.href = window.location.href;
|
|
})
|
|
.catch(function (err) {
|
|
closeModal();
|
|
openModal({ title: 'Rebuild failed', body: String(err), confirm: { label: 'OK' } });
|
|
});
|
|
}
|
|
|
|
function encodeSearchPath(p) {
|
|
if (p === '/' || p === '') return '/';
|
|
return '/' + p.replace(/^\/+/, '').split('/').map(encodeURIComponent).join('/');
|
|
}
|
|
|
|
// createSearchPage runs the new-page flow (pick a parent folder, then confirm
|
|
// the name) starting from the search query, so a query with no exact page can
|
|
// be turned into that page in one step. The name field is pre-filled with the
|
|
// query but stays editable.
|
|
function createSearchPage(name) {
|
|
var current = decodeURIComponent(window.location.pathname).replace(/\/+$/, '') || '/';
|
|
openTreePicker({
|
|
title: 'New page — where?',
|
|
mode: 'folder',
|
|
initialPath: current,
|
|
preselect: current,
|
|
hideFiles: true,
|
|
confirmLabel: 'NEXT',
|
|
onSelect: function (parentPath) {
|
|
var input = document.createElement('input');
|
|
input.type = 'text';
|
|
input.className = 'input';
|
|
input.placeholder = 'Page name';
|
|
input.value = name || '';
|
|
openModal({
|
|
title: 'New page — name?',
|
|
body: input,
|
|
confirm: {
|
|
label: 'CREATE',
|
|
onConfirm: function () {
|
|
var finalName = input.value.trim();
|
|
if (!finalName) return;
|
|
var base = parentPath === '/' ? '/' : encodeSearchPath(parentPath) + '/';
|
|
window.location.href = base + encodeURIComponent(finalName) + '/?edit';
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// The "create page" link on results pages; delegated, since boosted
|
|
// navigation swaps the results in without a new DOMContentLoaded.
|
|
document.addEventListener('click', function (e) {
|
|
var createLink = e.target.closest && e.target.closest('[data-create-page]');
|
|
if (!createLink) return;
|
|
e.preventDefault();
|
|
createSearchPage(createLink.getAttribute('data-create-page'));
|
|
});
|
|
|
|
// Focus the search input on results pages so Tab steps directly into the
|
|
// first match — the input sits immediately before the results in DOM order,
|
|
// so the natural tab sequence is input → first result → next, …
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
var input = document.querySelector('.search-input');
|
|
if (input && input.value) {
|
|
input.focus();
|
|
var end = input.value.length;
|
|
try { input.setSelectionRange(end, end); } catch (e) {}
|
|
}
|
|
});
|
|
|
|
// The header (and its search box) survives boosted navigation: show the
|
|
// current page's query, as a full load would.
|
|
document.addEventListener('page:swapped', function () {
|
|
var input = document.querySelector('.search-input');
|
|
if (input && document.activeElement !== input) {
|
|
input.value = new URLSearchParams(location.search).get('q') || '';
|
|
}
|
|
});
|