Manuscript Workstation - Source Excerpt 11
Back to Manuscript Workstation
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/ns12-manuscript/assets/js/manuscript-workstation.js so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/ns12-manuscript/assets/js/manuscript-workstation.js
const visibleCount = this.applyThumbFilter(query);
const totalLabel = `${total} result${total === 1 ? '' : 's'}`;
const thumbLabel = `${visibleCount} thumbnail${visibleCount === 1 ? '' : 's'}`;
this.setSearchStatus(`${totalLabel} in the manuscript index. ${thumbLabel} matched locally in the folio rail.`);
}
performSearch(query = '') {
const normalizedQuery = `${query || ''}`.trim();
if (!normalizedQuery || !config.searchUrl || typeof window.fetch !== 'function') {
this.clearSearchResults();
return;
}
if (this.searchAbortController) {
this.searchAbortController.abort();
}
const requestUrl = createUrlOr(config.searchUrl, null, { context: 'workstation-search-url' });
if (!requestUrl) {
this.clearSearchResults();
this.setSearchStatus('Manuscript search is temporarily unavailable.');
return;
}
requestUrl.searchParams.set('q', normalizedQuery);
requestUrl.searchParams.set('limit', '8');
this.searchAbortController = new AbortController();
runWorkstationAction(
async () => {
const response = await window.fetch(requestUrl.toString(), {
credentials: 'same-origin',
headers: config.restNonce ? { 'X-WP-Nonce': `${config.restNonce}` } : {},
signal: this.searchAbortController.signal,
});
if (!response.ok) {
throw new Error(`Search request failed with ${response.status}`);
}
const payload = await response.json();
if (this.lastSearchQuery !== normalizedQuery) {
return;
}
this.renderSearchResults(normalizedQuery, payload);
if (!Array.isArray(payload.results) || !payload.results.length) {
const visibleCount = this.applyThumbFilter(normalizedQuery);
if (visibleCount > 0) {
this.setSearchStatus(`No deep manuscript hits yet. ${visibleCount} thumbnail${visibleCount === 1 ? '' : 's'} still matched locally.`);
} else {
this.setSearchStatus(`No manuscript matches for "${normalizedQuery}".`);
}
}
},
{
context: 'workstation-search',
shouldIgnoreError: (error) => error && error.name === 'AbortError',
onError: () => {
this.clearSearchResults();
this.setSearchStatus('Manuscript search is temporarily unavailable.');
},
}
);
}
bindSearch() {
if (!this.searchInput) {
return;
}
const runSearch = () => {
const query = `${this.searchInput.value || ''}`.trim();
this.lastSearchQuery = query;
this.requestViewerStateSync();
if (this.searchClear) {
this.searchClear.hidden = query === '';
}
window.clearTimeout(this.searchTimer);
if (!query) {
if (this.searchAbortController) {
this.searchAbortController.abort();
}
this.applyThumbFilter('');
this.clearSearchResults();
this.setSearchStatus(this.getSearchIdleCopy());
return;
}
const visibleCount = this.applyThumbFilter(query);
if (query.length < 2) {
this.clearSearchResults();
this.setSearchStatus(
`${visibleCount} thumbnail${visibleCount === 1 ? '' : 's'} matched locally. Keep typing to search summaries, keywords, and transcript text across the codex.`
);
return;
}
this.setSearchStatus('Searching the manuscript index...');
this.searchTimer = window.setTimeout(() => {
this.performSearch(query);
}, 180);
};
this.runSearch = runSearch;
this.searchInput.addEventListener('input', runSearch);
this.searchInput.addEventListener('search', runSearch);
this.searchInput.addEventListener('keydown', (event) => {
if (event.key !== 'Enter' || !this.searchResults || this.searchResults.hidden) {
return;
}
const firstResult = this.searchResults.querySelector('[data-workstation-search-link]');
if (!(firstResult instanceof HTMLElement)) {
return;
}
const href = `${firstResult.getAttribute('href') || ''}`.trim();
if (!href) {
return;
}
event.preventDefault();
const targetSequence = Number.parseInt(`${firstResult.dataset.pageSequence || ''}`.trim(), 10) || 0;
const direction = targetSequence && this.currentSequence && targetSequence < this.currentSequence ? 'prev' : 'next';
this.closeSearchModal();
this.navigateToPage(href, direction);
});
if (this.searchClear) {
this.searchClear.addEventListener('click', () => {
this.searchInput.value = '';
runSearch();
this.searchInput.focus();
});
}
if (this.searchResults) {
this.searchResults.addEventListener('click', (event) => {
const target = event.target;
if (!(target instanceof HTMLElement)) {
return;
}
const link = target.closest('[data-workstation-search-link]');
if (!(link instanceof HTMLElement)) {
return;
}
if (
event.defaultPrevented ||
event.button !== 0 ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey
) {
return;
}
const href = `${link.getAttribute('href') || ''}`.trim();
if (!href) {
return;
}
event.preventDefault();
const targetSequence = Number.parseInt(`${link.dataset.pageSequence || ''}`.trim(), 10) || 0;
const direction = targetSequence && this.currentSequence && targetSequence < this.currentSequence ? 'prev' : 'next';
this.closeSearchModal();
this.navigateToPage(href, direction);
});
}
const seededQuery = `${this.initialViewerState.searchQuery || ''}`.trim();
if (seededQuery) {
this.searchInput.value = seededQuery;
runSearch();
} else if (this.searchClear) {
this.searchClear.hidden = true;
}
}
bindBeforeUnload() {
window.addEventListener('beforeunload', (event) => {
if (!this.canEdit || !this.dirtyFolios.size) {
return;
}
event.preventDefault();
event.returnValue = '';
});
}
bindViewport() {
this.viewport.addEventListener('dragstart', (event) => {
event.preventDefault();
});
this.viewport.addEventListener(
'wheel',
(event) => {
event.preventDefault();
const nextScale = this.state.scale + (event.deltaY < 0 ? 0.18 : -0.18);
this.zoomTo(nextScale, event.clientX, event.clientY);
},
{ passive: false }
);
this.viewport.addEventListener('dblclick', (event) => {
if (this.state.scale <= this.getFitScale(this.state.fitMode) + 0.01) {
this.zoomTo(Math.max(2, this.state.scale + 1), event.clientX, event.clientY);
} else {
this.fitTo(this.getResetFitMode());
}
});
this.viewport.addEventListener('pointerdown', (event) => {
if (event.button !== 0) {
return;
}
const target = event.target;
const edgeLink =
target instanceof HTMLElement ? target.closest('[data-workstation-prev], [data-workstation-next]') : null;
if (
!(target instanceof HTMLElement) ||
target.closest('[data-workstation-crop-handle]') ||
(!edgeLink && target.closest('a, button'))
) {
return;
}
event.preventDefault();
const lockedTurnDirection = edgeLink ? this.getLinkDirection(edgeLink) : 'none';
this.suppressViewportClick = false;
this.viewportDrag = {
pointerId: event.pointerId,
startX: event.clientX,
startY: event.clientY,
startPanX: this.state.panX,
startPanY: this.state.panY,
activated: false,
mode: lockedTurnDirection !== 'none' ? 'turn' : 'pending',
turnDistance: 0,
turnDirection: lockedTurnDirection !== 'none' ? lockedTurnDirection : 'none',
lockedTurnDirection,
};
this.viewport.classList.add('is-dragging');
this.resetDragTurnOffset();
if (lockedTurnDirection !== 'none') {
this.setEdgeHint(lockedTurnDirection);
}
setPointerCapture(this.viewport, event.pointerId);
});