Manuscript Workstation - Source Excerpt 16
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
return null;
}
const paddingX = Math.max(2, Math.round(width * 0.01));
const paddingY = Math.max(2, Math.round(height * 0.01));
return normalizeCropRect({
x: Math.max(0, (minX - paddingX) / width),
y: Math.max(0, (minY - paddingY) / height),
width: Math.min(width, maxX - minX + paddingX * 2) / width,
height: Math.min(height, maxY - minY + paddingY * 2) / height,
});
}
drawImageToCanvas(image) {
if (!image || !image.naturalWidth || !image.naturalHeight) {
return null;
}
const scale = Math.min(256 / image.naturalWidth, 256 / image.naturalHeight, 1);
const width = Math.max(1, Math.round(image.naturalWidth * scale));
const height = Math.max(1, Math.round(image.naturalHeight * scale));
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d', { willReadFrequently: true });
if (!context) {
return null;
}
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
return { canvas, context, width, height };
}
warmRoute(url) {
if (!url) {
return;
}
const nextUrl = createUrlOr(url, null, { context: 'workstation-warm-route' });
if (!nextUrl) {
return;
}
if (nextUrl.origin !== window.location.origin) {
return;
}
const cacheKey = `route:${nextUrl.href}`;
if (warmCache.has(cacheKey) || typeof window.fetch !== 'function') {
return;
}
warmCache.add(cacheKey);
runWorkstationAction(
() => window.fetch(nextUrl.href, {
credentials: 'same-origin',
cache: 'force-cache',
}),
{
context: 'workstation-route-warm',
onError: () => {
warmCache.delete(cacheKey);
},
}
);
}
warmImage(url) {
if (!url) {
return;
}
const cacheKey = `image:${url}`;
if (warmCache.has(cacheKey)) {
return;
}
warmCache.add(cacheKey);
preloadImageAsset(url);
}
applyOverlayVisibility(visible, options = {}) {
const announce = options.announce !== false;
this.state.overlayVisible = Boolean(visible);
if (this.state.overlayVisible) {
this.renderStudyOverlay();
}
this.folios.forEach((folio) => {
if (!folio.studyLayer) {
return;
}
folio.studyLayer.hidden = !this.state.overlayVisible;
folio.studyLayer.setAttribute('aria-hidden', this.state.overlayVisible ? 'false' : 'true');
});
this.syncButtons();
if (announce) {
this.updateStatus(
this.state.overlayVisible
? 'Study overlay shown. Visible folios now expose contextual notes, signal terms, and any linked symbolic nodes.'
: 'Study overlay hidden.'
);
}
}
async applyInitialViewerState() {
const seed = this.initialViewerState || {};
if (this.isBrowserRoute && Number.isFinite(seed.currentSequence) && seed.currentSequence > 0) {
const targetIndex = this.folioRecords.findIndex((record) => record.sequence === seed.currentSequence);
if (targetIndex >= 0 && targetIndex !== this.getCurrentFolioRecordIndex()) {
const currentRecord = this.renderFolioWindow(targetIndex);
if (currentRecord) {
this.syncCurrentFolioChrome(currentRecord, targetIndex);
}
}
}
const initialFitMode =
seed.fitMode === 'height' || seed.fitMode === 'actual'
? seed.fitMode
: 'width';
this.isApplyingViewerState = true;
this.fitTo(initialFitMode, false);
if (Number.isFinite(seed.scale) && seed.scale > 0) {
const bounds = this.getScaleBounds();
this.state.fitMode = 'custom';
this.state.scale = clamp(seed.scale, bounds.min, bounds.max);
} else if (seed.fitMode === 'custom') {
this.state.fitMode = 'custom';
}
if (Number.isFinite(seed.panRatioX) || Number.isFinite(seed.panRatioY)) {
this.applyNormalizedPan(seed.panRatioX || 0, seed.panRatioY || 0);
}
this.renderSurface();
if (seed.overlayVisible) {
await runWorkstationAction(async () => {
await this.ensureStudyOverlay();
this.applyOverlayVisibility(true, { announce: false });
}, {
context: 'workstation-initial-overlay',
onError: () => {
this.applyOverlayVisibility(false, { announce: false });
},
});
} else {
this.applyOverlayVisibility(false, { announce: false });
}
this.viewerStateReady = true;
this.isApplyingViewerState = false;
this.syncNavigationStateUrls();
this.requestViewerStateSync({ immediate: true });
}
async copyTextToClipboard(value) {
const nextValue = `${value || ''}`.trim();
if (!nextValue) {
return false;
}
await copyText(nextValue);
return true;
}
setCopyFeedback(copied = false) {
window.clearTimeout(this.copyFeedbackTimer);
this.copyButtons.forEach((button) => {
const copy = button.querySelector('[data-workstation-copy-copy]');
if (copy) {
copy.textContent = copied ? 'Link Copied' : 'Copy Deep Link';
}
});
if (!copied) {
return;
}
this.copyFeedbackTimer = window.setTimeout(() => {
this.setCopyFeedback(false);
}, 1800);
}
async copyDeepLink() {
const shareUrl = this.buildViewerStateUrl(window.location.href, { mode: 'share' });
await runWorkstationAction(async () => {
const copied = await this.copyTextToClipboard(shareUrl);
if (!copied) {
throw new Error('Clipboard copy failed.');
}