Checkpoint current interactive fiction state

This commit is contained in:
2026-05-14 21:17:43 +02:00
parent c745efd1d2
commit 873049f7e6
183 changed files with 13755 additions and 1459 deletions
+94 -102
View File
@@ -3,7 +3,6 @@
* Handles text formatting and typography enhancements like smart quotes and hyphenation
*/
import { BaseModule } from './base-module.js';
import Hyphenopoly from './hyphenopoly.module.js';
class TextProcessorModule extends BaseModule {
constructor() {
@@ -25,7 +24,9 @@ class TextProcessorModule extends BaseModule {
'isHyphenationAvailable',
'hyphenate',
'setLocale',
'handleLocaleChanged'
'handleLocaleChanged',
'loadHyphenopolyLoader',
'normalizeHyphenationLocale'
]);
}
@@ -161,104 +162,89 @@ class TextProcessorModule extends BaseModule {
}
/**
* Initialize hyphenation using Hyphenopoly module
* Initialize hyphenation using the browser Hyphenopoly loader used by the prototype.
* @returns {Promise<boolean>} - Resolves when hyphenation is initialized
*/
initializeHyphenation() {
return new Promise((resolve, reject) => {
try {
console.log("Initializing hyphenation with Hyphenopoly module");
// Configure Hyphenopoly with our requirements
const hyphenatorPromise = Hyphenopoly.config({
require: [this.locale],
hyphen: '\u00AD', // Soft hyphen character
minWordLength: 5,
leftmin: 2,
rightmin: 2,
compound: "hyphen",
// Define a custom loader for the patterns
loader: (file) => {
return new Promise((resolve, reject) => {
// Determine correct pattern file based on locale
let patternFile = file;
// Special handling for 'en' locale - use en-us.wasm if available
if (file === 'en.wasm') {
patternFile = 'en-us.wasm';
}
const patternPath = `/js/patterns/${patternFile}`;
console.log(`Loading hyphenation pattern: ${patternPath}`);
fetch(patternPath)
.then(response => {
if (!response.ok) {
throw new Error(`Failed to load ${file}: ${response.status} ${response.statusText}`);
}
return response.arrayBuffer();
})
.then(arrayBuffer => {
resolve(arrayBuffer);
})
.catch(error => {
console.error(`Error loading hyphenation pattern ${file}:`, error);
reject(error);
});
});
},
handleEvent: {
error: (e) => {
console.warn(`Hyphenopoly error: ${e.msg}`);
},
engineReady: (e) => {
console.log(`Hyphenopoly engine ready for ${e.msg}`);
}
async initializeHyphenation() {
try {
console.log("Initializing hyphenation with browser Hyphenopoly loader");
const locale = this.normalizeHyphenationLocale(this.locale);
this.hyphenator = null;
this.hyphenatorReady = false;
await this.loadHyphenopolyLoader();
window.Hyphenopoly.config({
require: {
[locale]: "FORCEHYPHENOPOLY"
},
paths: {
maindir: "/js/",
patterndir: "/js/patterns/"
},
setup: {
hide: "element",
selectors: {
".hyphenate": { hyphen: "\u00AD" },
".hyphenatePipe": { hyphen: "|" }
}
});
// Get the hyphenator for our locale
hyphenatorPromise.get(this.locale)
.then(hyphenator => {
this.hyphenator = hyphenator;
this.hyphenatorReady = true;
console.log(`Hyphenator ready for ${this.locale}`);
// Dispatch event that hyphenation is ready
document.dispatchEvent(new CustomEvent('hyphenation-loaded'));
resolve(true); // Successfully initialized
})
.catch(error => {
console.error(`Failed to initialize hyphenator for ${this.locale}:`, error);
// Try to fall back to en-us if the current locale failed
if (this.locale !== 'en-us') {
console.log("Falling back to en-us hyphenation");
return hyphenatorPromise.get('en-us');
}
throw error;
})
.then(fallbackHyphenator => {
if (fallbackHyphenator) {
this.hyphenator = fallbackHyphenator;
this.hyphenatorReady = true;
console.log("Using fallback en-us hyphenator");
// Dispatch event that hyphenation is ready
document.dispatchEvent(new CustomEvent('hyphenation-loaded'));
resolve(true); // Successfully initialized with fallback
}
})
.catch(error => {
console.error("Failed to initialize hyphenation even with fallback:", error);
reject(error); // Failed to initialize
});
} catch (error) {
console.error("Error setting up hyphenation:", error);
reject(error); // Failed to initialize
},
handleEvent: {
error: (event) => {
console.warn(`Hyphenopoly error: ${event.msg || event.message || event.type}`);
},
engineReady: (event) => {
console.log(`Hyphenopoly engine ready: ${event.msg || locale}`);
}
}
});
this.hyphenator = await window.Hyphenopoly.hyphenators[locale];
this.hyphenatorReady = true;
this.locale = locale;
console.log(`Hyphenator ready for ${locale}`);
document.dispatchEvent(new CustomEvent('hyphenation-loaded'));
return true;
} catch (error) {
this.hyphenator = null;
this.hyphenatorReady = false;
console.error("Failed to initialize Hyphenopoly browser hyphenation:", error);
throw error;
}
}
loadHyphenopolyLoader() {
return new Promise((resolve, reject) => {
if (window.Hyphenopoly && typeof window.Hyphenopoly.config === 'function') {
resolve();
return;
}
const existingScript = document.querySelector('script[src="/js/Hyphenopoly_Loader.js"]');
if (existingScript) {
existingScript.addEventListener('load', () => resolve(), { once: true });
existingScript.addEventListener('error', () => reject(new Error('Failed to load Hyphenopoly loader')), { once: true });
return;
}
const script = document.createElement('script');
script.src = '/js/Hyphenopoly_Loader.js';
script.async = true;
script.onload = () => resolve();
script.onerror = () => reject(new Error('Failed to load Hyphenopoly loader'));
document.head.appendChild(script);
});
}
normalizeHyphenationLocale(locale) {
const normalized = String(locale || 'en-us').toLowerCase();
if (normalized === 'en') return 'en-us';
if (normalized === 'de-de') return 'de';
return normalized;
}
/**
* Check if hyphenation is available
* @returns {boolean} - True if hyphenation is available
@@ -270,15 +256,17 @@ class TextProcessorModule extends BaseModule {
/**
* Hyphenate a text using the Hyphenopoly module
* @param {string} text - The text to hyphenate
* @param {string} selector - Optional selector for Hyphenopoly
* @returns {string} - The hyphenated text
*/
hyphenate(text) {
hyphenate(text, selector = null) {
if (!this.isHyphenationAvailable()) {
return text;
}
try {
return this.hyphenator(text);
// If selector provided, pass it to hyphenator
return selector ? this.hyphenator(text, selector) : this.hyphenator(text);
} catch (error) {
console.error("Error hyphenating text:", error);
return text;
@@ -291,27 +279,31 @@ class TextProcessorModule extends BaseModule {
* @param {Object} options - Processing options
* @param {boolean} [options.smartypants=true] - Whether to apply SmartyPants processing
* @param {boolean} [options.hyphenate=true] - Whether to apply hyphenation
* @param {string} [options.hyphenSelector=null] - Selector for hyphen character (e.g., '.hyphenatePipe')
* @returns {string} - The processed text
*/
process(text, options = {}) {
const opts = {
smartypants: true,
hyphenate: true,
hyphenSelector: null,
...options
};
let result = text;
// Apply SmartyPants if available and requested
if (opts.smartypants && this.smartyPants) {
if (opts.smartypants && this.smartypantsu) {
result = this.smartypantsu(result, 1);
} else if (opts.smartypants && this.smartyPants) {
result = this.smartyPants(result);
}
// Apply hyphenation if available and requested
if (opts.hyphenate && this.isHyphenationAvailable()) {
result = this.hyphenate(result);
result = this.hyphenate(result, opts.hyphenSelector);
}
return result;
}
}