Checkpoint current interactive fiction state
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user