1
0

add initial marp implementation with sample content and build configuration

This commit is contained in:
2025-09-13 18:13:22 +02:00
parent dcacc9b409
commit e5f219507f
10319 changed files with 1402023 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
import * as EnrichAttr from '../enrich_mathml/enrich_attr.js';
import { AxisMap } from '../rule_engine/dynamic_cstr.js';
import { RebuildStree } from '../walker/rebuild_stree.js';
import { SpeechGenerator } from './speech_generator.js';
export declare abstract class AbstractSpeechGenerator implements SpeechGenerator {
modality: EnrichAttr.Attribute;
private rebuilt_;
private options_;
abstract getSpeech(node: Element, xml: Element, root?: Element): string;
getRebuilt(): RebuildStree;
setRebuilt(rebuilt: RebuildStree): void;
computeRebuilt(xml: Element, force?: boolean): RebuildStree;
setOptions(options: AxisMap): void;
setOption(key: string, value: string): void;
getOptions(): {
[key: string]: string;
};
generateSpeech(_node: Node, xml: Element): string;
nextRules(): void;
nextStyle(id: string): void;
private nextStyle_;
getLevel(depth: string): string;
getActionable(actionable: number): string;
}

View File

@@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractSpeechGenerator = void 0;
const engine_setup_js_1 = require("../common/engine_setup.js");
const EnrichAttr = require("../enrich_mathml/enrich_attr.js");
const rebuild_stree_js_1 = require("../walker/rebuild_stree.js");
const SpeechGeneratorUtil = require("./speech_generator_util.js");
const EngineConst = require("../common/engine_const.js");
const locale_js_1 = require("../l10n/locale.js");
const clearspeak_preferences_js_1 = require("../speech_rules/clearspeak_preferences.js");
class AbstractSpeechGenerator {
constructor() {
this.modality = EnrichAttr.addPrefix('speech');
this.rebuilt_ = null;
this.options_ = {};
}
getRebuilt() {
return this.rebuilt_;
}
setRebuilt(rebuilt) {
this.rebuilt_ = rebuilt;
}
computeRebuilt(xml, force = false) {
if (!this.rebuilt_ || force) {
this.rebuilt_ = new rebuild_stree_js_1.RebuildStree(xml);
}
return this.rebuilt_;
}
setOptions(options) {
this.options_ = options || {};
this.modality = EnrichAttr.addPrefix(this.options_.modality || 'speech');
}
setOption(key, value) {
const options = this.getOptions();
options[key] = value;
this.setOptions(options);
}
getOptions() {
return this.options_;
}
generateSpeech(_node, xml) {
if (!this.rebuilt_) {
this.rebuilt_ = new rebuild_stree_js_1.RebuildStree(xml);
}
(0, engine_setup_js_1.setup)(this.options_);
return SpeechGeneratorUtil.computeMarkup(this.getRebuilt().xml);
}
nextRules() {
const options = this.getOptions();
if (options.modality !== 'speech') {
return;
}
const prefs = clearspeak_preferences_js_1.ClearspeakPreferences.getLocalePreferences();
if (!prefs[options.locale]) {
return;
}
EngineConst.DOMAIN_TO_STYLES[options.domain] = options.style;
options.domain =
options.domain === 'mathspeak' ? 'clearspeak' : 'mathspeak';
options.style = EngineConst.DOMAIN_TO_STYLES[options.domain];
this.setOptions(options);
}
nextStyle(id) {
this.setOption('style', this.nextStyle_(this.getRebuilt().nodeDict[id]));
}
nextStyle_(node) {
const { modality: modality, domain: domain, style: style } = this.getOptions();
if (modality !== 'speech') {
return style;
}
if (domain === 'mathspeak') {
const styles = ['default', 'brief', 'sbrief'];
const index = styles.indexOf(style);
if (index === -1) {
return style;
}
return index >= styles.length - 1 ? styles[0] : styles[index + 1];
}
if (domain === 'clearspeak') {
const prefs = clearspeak_preferences_js_1.ClearspeakPreferences.getLocalePreferences();
const loc = prefs['en'];
if (!loc) {
return 'default';
}
const smart = clearspeak_preferences_js_1.ClearspeakPreferences.relevantPreferences(node);
const current = clearspeak_preferences_js_1.ClearspeakPreferences.findPreference(style, smart);
const options = loc[smart].map(function (x) {
return x.split('_')[1];
});
const index = options.indexOf(current);
if (index === -1) {
return style;
}
const next = index >= options.length - 1 ? options[0] : options[index + 1];
const result = clearspeak_preferences_js_1.ClearspeakPreferences.addPreference(style, smart, next);
return result;
}
return style;
}
getLevel(depth) {
return locale_js_1.LOCALE.MESSAGES.navigate.LEVEL + ' ' + depth;
}
getActionable(actionable) {
return actionable
? actionable < 0
? locale_js_1.LOCALE.MESSAGES.navigate.EXPANDABLE
: locale_js_1.LOCALE.MESSAGES.navigate.COLLAPSIBLE
: '';
}
}
exports.AbstractSpeechGenerator = AbstractSpeechGenerator;

View File

@@ -0,0 +1,4 @@
import { AbstractSpeechGenerator } from './abstract_speech_generator.js';
export declare class AdhocSpeechGenerator extends AbstractSpeechGenerator {
getSpeech(node: Element, xml: Element): string;
}

View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdhocSpeechGenerator = void 0;
const abstract_speech_generator_js_1 = require("./abstract_speech_generator.js");
class AdhocSpeechGenerator extends abstract_speech_generator_js_1.AbstractSpeechGenerator {
getSpeech(node, xml) {
const speech = this.generateSpeech(node, xml);
node.setAttribute(this.modality, speech);
return speech;
}
}
exports.AdhocSpeechGenerator = AdhocSpeechGenerator;

View File

@@ -0,0 +1,10 @@
import { AbstractSpeechGenerator } from './abstract_speech_generator.js';
export declare class ColorGenerator extends AbstractSpeechGenerator {
modality: any;
contrast: any;
private static visitStree_;
getSpeech(node: Element, _xml: Element): string;
generateSpeech(node: Element, xml: Element | string): string;
private colorLeaves_;
private colorLeave_;
}

View File

@@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ColorGenerator = void 0;
const DomUtil = require("../common/dom_util.js");
const enrich_attr_js_1 = require("../enrich_mathml/enrich_attr.js");
const color_picker_js_1 = require("../highlighter/color_picker.js");
const rebuild_stree_js_1 = require("../walker/rebuild_stree.js");
const WalkerUtil = require("../walker/walker_util.js");
const abstract_speech_generator_js_1 = require("./abstract_speech_generator.js");
class ColorGenerator extends abstract_speech_generator_js_1.AbstractSpeechGenerator {
constructor() {
super(...arguments);
this.modality = (0, enrich_attr_js_1.addPrefix)('foreground');
this.contrast = new color_picker_js_1.ContrastPicker();
}
static visitStree_(tree, leaves, ignore) {
if (!tree.childNodes.length) {
if (!ignore[tree.id]) {
leaves.push(tree.id);
}
return;
}
if (tree.contentNodes.length) {
if (tree.type === 'punctuated') {
tree.contentNodes.forEach((x) => (ignore[x.id] = true));
}
if (tree.role !== 'implicit') {
leaves.push(tree.contentNodes.map((x) => x.id));
}
}
if (tree.childNodes.length) {
if (tree.role === 'implicit') {
const factors = [];
let rest = [];
for (const child of tree.childNodes) {
const tt = [];
ColorGenerator.visitStree_(child, tt, ignore);
if (tt.length <= 2) {
factors.push(tt.shift());
}
rest = rest.concat(tt);
}
leaves.push(factors);
rest.forEach((x) => leaves.push(x));
return;
}
tree.childNodes.forEach((x) => ColorGenerator.visitStree_(x, leaves, ignore));
}
}
getSpeech(node, _xml) {
return WalkerUtil.getAttribute(node, this.modality);
}
generateSpeech(node, xml) {
if (!this.getRebuilt()) {
this.setRebuilt(new rebuild_stree_js_1.RebuildStree(DomUtil.parseInput(xml)));
}
this.colorLeaves_(node);
return WalkerUtil.getAttribute(node, this.modality);
}
colorLeaves_(node) {
const leaves = [];
ColorGenerator.visitStree_(this.getRebuilt().streeRoot, leaves, {});
for (const id of leaves) {
const color = this.contrast.generate();
let success = false;
if (Array.isArray(id)) {
success = id
.map((x) => this.colorLeave_(node, x, color))
.reduce((x, y) => x || y, false);
}
else {
success = this.colorLeave_(node, id.toString(), color);
}
if (success) {
this.contrast.increment();
}
}
}
colorLeave_(node, id, color) {
const aux = WalkerUtil.getBySemanticId(node, id);
if (aux) {
aux.setAttribute(this.modality, color);
return true;
}
return false;
}
}
exports.ColorGenerator = ColorGenerator;

View File

@@ -0,0 +1,4 @@
import { AbstractSpeechGenerator } from './abstract_speech_generator.js';
export declare class DirectSpeechGenerator extends AbstractSpeechGenerator {
getSpeech(node: Element, _xml: Element): string;
}

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DirectSpeechGenerator = void 0;
const WalkerUtil = require("../walker/walker_util.js");
const abstract_speech_generator_js_1 = require("./abstract_speech_generator.js");
class DirectSpeechGenerator extends abstract_speech_generator_js_1.AbstractSpeechGenerator {
getSpeech(node, _xml) {
return WalkerUtil.getAttribute(node, this.modality);
}
}
exports.DirectSpeechGenerator = DirectSpeechGenerator;

View File

@@ -0,0 +1,4 @@
import { AbstractSpeechGenerator } from './abstract_speech_generator.js';
export declare class DummySpeechGenerator extends AbstractSpeechGenerator {
getSpeech(_node: Element, _xml: Element): string;
}

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DummySpeechGenerator = void 0;
const abstract_speech_generator_js_1 = require("./abstract_speech_generator.js");
class DummySpeechGenerator extends abstract_speech_generator_js_1.AbstractSpeechGenerator {
getSpeech(_node, _xml) {
return '';
}
}
exports.DummySpeechGenerator = DummySpeechGenerator;

View File

@@ -0,0 +1,4 @@
import { TreeSpeechGenerator } from './tree_speech_generator.js';
export declare class NodeSpeechGenerator extends TreeSpeechGenerator {
getSpeech(node: Element, _xml: Element): string;
}

View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeSpeechGenerator = void 0;
const WalkerUtil = require("../walker/walker_util.js");
const tree_speech_generator_js_1 = require("./tree_speech_generator.js");
class NodeSpeechGenerator extends tree_speech_generator_js_1.TreeSpeechGenerator {
getSpeech(node, _xml) {
super.getSpeech(node, _xml);
return WalkerUtil.getAttribute(node, this.modality);
}
}
exports.NodeSpeechGenerator = NodeSpeechGenerator;

View File

@@ -0,0 +1,18 @@
import { Attribute } from '../enrich_mathml/enrich_attr.js';
import { AxisMap } from '../rule_engine/dynamic_cstr.js';
import { RebuildStree } from '../walker/rebuild_stree.js';
export interface SpeechGenerator {
modality: Attribute;
getSpeech(node: Element, xml: Element, root?: Element): string;
generateSpeech(node: Element, xml: Element): string;
getRebuilt(): RebuildStree;
setRebuilt(rebuilt: RebuildStree): void;
computeRebuilt(xml: Element, force?: boolean): RebuildStree;
setOptions(options: AxisMap): void;
setOption(key: string, value: string): void;
getOptions(): AxisMap;
nextRules(): void;
nextStyle(id: string): void;
getActionable(actionable: number): string;
getLevel(depth: string): string;
}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,2 @@
import { SpeechGenerator } from './speech_generator.js';
export declare function generator(type: string): SpeechGenerator;

View File

@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generator = generator;
const adhoc_speech_generator_js_1 = require("./adhoc_speech_generator.js");
const color_generator_js_1 = require("./color_generator.js");
const direct_speech_generator_js_1 = require("./direct_speech_generator.js");
const dummy_speech_generator_js_1 = require("./dummy_speech_generator.js");
const node_speech_generator_js_1 = require("./node_speech_generator.js");
const summary_speech_generator_js_1 = require("./summary_speech_generator.js");
const tree_speech_generator_js_1 = require("./tree_speech_generator.js");
function generator(type) {
const constructor = generatorMapping[type] || generatorMapping.Direct;
return constructor();
}
const generatorMapping = {
Adhoc: () => new adhoc_speech_generator_js_1.AdhocSpeechGenerator(),
Color: () => new color_generator_js_1.ColorGenerator(),
Direct: () => new direct_speech_generator_js_1.DirectSpeechGenerator(),
Dummy: () => new dummy_speech_generator_js_1.DummySpeechGenerator(),
Node: () => new node_speech_generator_js_1.NodeSpeechGenerator(),
Summary: () => new summary_speech_generator_js_1.SummarySpeechGenerator(),
Tree: () => new tree_speech_generator_js_1.TreeSpeechGenerator()
};

View File

@@ -0,0 +1,14 @@
import { AuditoryDescription } from '../audio/auditory_description.js';
import { SemanticNode } from '../semantic_tree/semantic_node.js';
export declare function computeSpeech(xml: Element): AuditoryDescription[];
export declare function computeMarkup(tree: Element): string;
export declare function recomputeMarkup(semantic: SemanticNode): string;
export declare function addSpeech(mml: Element, semantic: SemanticNode, snode: Element): void;
export declare function addModality(mml: Element, semantic: SemanticNode, modality: string): void;
export declare function addPrefix(mml: Element, semantic: SemanticNode): void;
export declare function retrievePrefix(semantic: SemanticNode): string;
export declare function connectMactions(node: Element, mml: Element, stree: Element): void;
export declare function connectAllMactions(mml: Element, stree: Element): void;
export declare function retrieveSummary(node: Element, options?: {
[key: string]: string;
}): string;

View File

@@ -0,0 +1,155 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeSpeech = computeSpeech;
exports.computeMarkup = computeMarkup;
exports.recomputeMarkup = recomputeMarkup;
exports.addSpeech = addSpeech;
exports.addModality = addModality;
exports.addPrefix = addPrefix;
exports.retrievePrefix = retrievePrefix;
exports.connectMactions = connectMactions;
exports.connectAllMactions = connectAllMactions;
exports.retrieveSummary = retrieveSummary;
const AuralRendering = require("../audio/aural_rendering.js");
const DomUtil = require("../common/dom_util.js");
const XpathUtil = require("../common/xpath_util.js");
const enrich_attr_js_1 = require("../enrich_mathml/enrich_attr.js");
const speech_rule_engine_js_1 = require("../rule_engine/speech_rule_engine.js");
const semantic_tree_js_1 = require("../semantic_tree/semantic_tree.js");
const WalkerUtil = require("../walker/walker_util.js");
function computeSpeech(xml) {
return speech_rule_engine_js_1.SpeechRuleEngine.getInstance().evaluateNode(xml);
}
function recomputeSpeech(semantic) {
const tree = semantic_tree_js_1.SemanticTree.fromNode(semantic);
return computeSpeech(tree.xml());
}
function computeMarkup(tree) {
const descrs = computeSpeech(tree);
return AuralRendering.markup(descrs);
}
function recomputeMarkup(semantic) {
const descrs = recomputeSpeech(semantic);
return AuralRendering.markup(descrs);
}
function addSpeech(mml, semantic, snode) {
const sxml = DomUtil.querySelectorAllByAttrValue(snode, 'id', semantic.id.toString())[0];
const speech = sxml
? AuralRendering.markup(computeSpeech(sxml))
: recomputeMarkup(semantic);
mml.setAttribute(enrich_attr_js_1.Attribute.SPEECH, speech);
}
function addModality(mml, semantic, modality) {
const markup = recomputeMarkup(semantic);
mml.setAttribute(modality, markup);
}
function addPrefix(mml, semantic) {
const speech = retrievePrefix(semantic);
if (speech) {
mml.setAttribute(enrich_attr_js_1.Attribute.PREFIX, speech);
}
}
function retrievePrefix(semantic) {
const descrs = computePrefix(semantic);
return AuralRendering.markup(descrs);
}
function computePrefix(semantic) {
const tree = semantic_tree_js_1.SemanticTree.fromRoot(semantic);
const nodes = XpathUtil.evalXPath('.//*[@id="' + semantic.id + '"]', tree.xml());
let node = nodes[0];
if (nodes.length > 1) {
node = nodeAtPosition(semantic, nodes) || node;
}
return node
? speech_rule_engine_js_1.SpeechRuleEngine.getInstance().runInSetting({
modality: 'prefix',
domain: 'default',
style: 'default',
strict: true,
speech: true
}, function () {
return speech_rule_engine_js_1.SpeechRuleEngine.getInstance().evaluateNode(node);
})
: [];
}
function nodeAtPosition(semantic, nodes) {
const node = nodes[0];
if (!semantic.parent) {
return node;
}
const path = [];
while (semantic) {
path.push(semantic.id);
semantic = semantic.parent;
}
const pathEquals = function (xml, path) {
while (path.length &&
path.shift().toString() === xml.getAttribute('id') &&
xml.parentNode &&
xml.parentNode.parentNode) {
xml = xml.parentNode.parentNode;
}
return !path.length;
};
for (let i = 0, xml; (xml = nodes[i]); i++) {
if (pathEquals(xml, path.slice())) {
return xml;
}
}
return node;
}
function connectMactions(node, mml, stree) {
const mactions = DomUtil.querySelectorAll(mml, 'maction');
for (let i = 0, maction; (maction = mactions[i]); i++) {
const aid = maction.getAttribute('id');
const span = DomUtil.querySelectorAllByAttrValue(node, 'id', aid)[0];
if (!span) {
continue;
}
const lchild = maction.childNodes[1];
const mid = lchild.getAttribute(enrich_attr_js_1.Attribute.ID);
let cspan = WalkerUtil.getBySemanticId(node, mid);
if (cspan && cspan.getAttribute(enrich_attr_js_1.Attribute.TYPE) !== 'dummy') {
continue;
}
cspan = span.childNodes[0];
if (cspan.getAttribute('sre-highlighter-added')) {
continue;
}
const pid = lchild.getAttribute(enrich_attr_js_1.Attribute.PARENT);
if (pid) {
cspan.setAttribute(enrich_attr_js_1.Attribute.PARENT, pid);
}
cspan.setAttribute(enrich_attr_js_1.Attribute.TYPE, 'dummy');
cspan.setAttribute(enrich_attr_js_1.Attribute.ID, mid);
cspan.setAttribute('role', 'treeitem');
cspan.setAttribute('aria-level', lchild.getAttribute('aria-level'));
const cst = DomUtil.querySelectorAllByAttrValue(stree, 'id', mid)[0];
cst.setAttribute('alternative', mid);
}
}
function connectAllMactions(mml, stree) {
const mactions = DomUtil.querySelectorAll(mml, 'maction');
for (let i = 0, maction; (maction = mactions[i]); i++) {
const lchild = maction.childNodes[1];
const mid = lchild.getAttribute(enrich_attr_js_1.Attribute.ID);
const cst = DomUtil.querySelectorAllByAttrValue(stree, 'id', mid)[0];
cst.setAttribute('alternative', mid);
}
}
function retrieveSummary(node, options = {}) {
const descrs = computeSummary(node, options);
return AuralRendering.markup(descrs);
}
function computeSummary(node, options = {}) {
const preOption = options.locale ? { locale: options.locale } : {};
return node
? speech_rule_engine_js_1.SpeechRuleEngine.getInstance().runInSetting(Object.assign(preOption, {
modality: 'summary',
strict: false,
speech: true
}), function () {
return speech_rule_engine_js_1.SpeechRuleEngine.getInstance().evaluateNode(node);
})
: [];
}

View File

@@ -0,0 +1,4 @@
import { AbstractSpeechGenerator } from './abstract_speech_generator.js';
export declare class SummarySpeechGenerator extends AbstractSpeechGenerator {
getSpeech(node: Element, _xml: Element): string;
}

View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SummarySpeechGenerator = void 0;
const abstract_speech_generator_js_1 = require("./abstract_speech_generator.js");
const SpeechGeneratorUtil = require("./speech_generator_util.js");
const engine_setup_js_1 = require("../common/engine_setup.js");
const enrich_attr_js_1 = require("../enrich_mathml/enrich_attr.js");
class SummarySpeechGenerator extends abstract_speech_generator_js_1.AbstractSpeechGenerator {
getSpeech(node, _xml) {
(0, engine_setup_js_1.setup)(this.getOptions());
const id = node.getAttribute(enrich_attr_js_1.Attribute.ID);
const snode = this.getRebuilt().streeRoot.querySelectorAll((x) => x.id.toString() === id)[0];
SpeechGeneratorUtil.addModality(node, snode, this.modality);
const speech = node.getAttribute(enrich_attr_js_1.Attribute.SUMMARY);
return speech;
}
}
exports.SummarySpeechGenerator = SummarySpeechGenerator;

View File

@@ -0,0 +1,4 @@
import { AbstractSpeechGenerator } from './abstract_speech_generator.js';
export declare class TreeSpeechGenerator extends AbstractSpeechGenerator {
getSpeech(node: Element, xml: Element, root?: Element): string;
}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TreeSpeechGenerator = void 0;
const enrich_attr_js_1 = require("../enrich_mathml/enrich_attr.js");
const WalkerUtil = require("../walker/walker_util.js");
const abstract_speech_generator_js_1 = require("./abstract_speech_generator.js");
const SpeechGeneratorUtil = require("./speech_generator_util.js");
class TreeSpeechGenerator extends abstract_speech_generator_js_1.AbstractSpeechGenerator {
getSpeech(node, xml, root = null) {
if (this.getRebuilt()) {
SpeechGeneratorUtil.connectMactions(node, xml, this.getRebuilt().xml);
}
const speech = this.generateSpeech(node, xml);
const nodes = this.getRebuilt().nodeDict;
for (const [key, snode] of Object.entries(nodes)) {
const innerMml = WalkerUtil.getBySemanticId(xml, key);
const innerNode = WalkerUtil.getBySemanticId(node, key) ||
(root && WalkerUtil.getBySemanticId(root, key));
if (!innerMml || !innerNode) {
continue;
}
if (!this.modality || this.modality === enrich_attr_js_1.Attribute.SPEECH) {
SpeechGeneratorUtil.addSpeech(innerNode, snode, this.getRebuilt().xml);
}
else {
SpeechGeneratorUtil.addModality(innerNode, snode, this.modality);
}
if (this.modality === enrich_attr_js_1.Attribute.SPEECH) {
SpeechGeneratorUtil.addPrefix(innerNode, snode);
}
}
return speech;
}
}
exports.TreeSpeechGenerator = TreeSpeechGenerator;