site/node_modules/speech-rule-engine/js/walker/abstract_walker.js

509 lines
18 KiB
JavaScript
Raw Permalink Normal View History

2024-10-14 06:09:33 +00:00
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractWalker = void 0;
const auditory_description_1 = require("../audio/auditory_description");
const AuralRendering = require("../audio/aural_rendering");
const DomUtil = require("../common/dom_util");
const EngineConst = require("../common/engine_const");
const engine_setup_1 = require("../common/engine_setup");
const event_util_1 = require("../common/event_util");
const enrich_attr_1 = require("../enrich_mathml/enrich_attr");
const locale_1 = require("../l10n/locale");
const grammar_1 = require("../rule_engine/grammar");
const semantic_skeleton_1 = require("../semantic_tree/semantic_skeleton");
const SpeechGeneratorFactory = require("../speech_generator/speech_generator_factory");
const SpeechGeneratorUtil = require("../speech_generator/speech_generator_util");
const clearspeak_preferences_1 = require("../speech_rules/clearspeak_preferences");
const focus_1 = require("./focus");
const rebuild_stree_1 = require("./rebuild_stree");
const walker_1 = require("./walker");
const WalkerUtil = require("./walker_util");
const XpathUtil = require("../common/xpath_util");
class AbstractWalker {
constructor(node, generator, highlighter, xml) {
this.node = node;
this.generator = generator;
this.highlighter = highlighter;
this.modifier = false;
this.keyMapping = new Map([
[event_util_1.KeyCode.UP, this.up.bind(this)],
[event_util_1.KeyCode.DOWN, this.down.bind(this)],
[event_util_1.KeyCode.RIGHT, this.right.bind(this)],
[event_util_1.KeyCode.LEFT, this.left.bind(this)],
[event_util_1.KeyCode.TAB, this.repeat.bind(this)],
[event_util_1.KeyCode.DASH, this.expand.bind(this)],
[event_util_1.KeyCode.SPACE, this.depth.bind(this)],
[event_util_1.KeyCode.HOME, this.home.bind(this)],
[event_util_1.KeyCode.X, this.summary.bind(this)],
[event_util_1.KeyCode.Z, this.detail.bind(this)],
[event_util_1.KeyCode.V, this.virtualize.bind(this)],
[event_util_1.KeyCode.P, this.previous.bind(this)],
[event_util_1.KeyCode.U, this.undo.bind(this)],
[event_util_1.KeyCode.LESS, this.previousRules.bind(this)],
[event_util_1.KeyCode.GREATER, this.nextRules.bind(this)]
]);
this.cursors = [];
this.xml_ = null;
this.rebuilt_ = null;
this.focus_ = null;
this.active_ = false;
if (this.node.id) {
this.id = this.node.id;
}
else if (this.node.hasAttribute(AbstractWalker.SRE_ID_ATTR)) {
this.id = this.node.getAttribute(AbstractWalker.SRE_ID_ATTR);
}
else {
this.node.setAttribute(AbstractWalker.SRE_ID_ATTR, AbstractWalker.ID_COUNTER.toString());
this.id = AbstractWalker.ID_COUNTER++;
}
this.rootNode = WalkerUtil.getSemanticRoot(node);
this.rootId = this.rootNode.getAttribute(enrich_attr_1.Attribute.ID);
this.xmlString_ = xml;
this.moved = walker_1.WalkerMoves.ENTER;
}
getXml() {
if (!this.xml_) {
this.xml_ = DomUtil.parseInput(this.xmlString_);
}
return this.xml_;
}
getRebuilt() {
if (!this.rebuilt_) {
this.rebuildStree();
}
return this.rebuilt_;
}
isActive() {
return this.active_;
}
activate() {
if (this.isActive()) {
return;
}
this.generator.start();
this.toggleActive_();
}
deactivate() {
if (!this.isActive()) {
return;
}
walker_1.WalkerState.setState(this.id, this.primaryId());
this.generator.end();
this.toggleActive_();
}
getFocus(update = false) {
if (!this.focus_) {
this.focus_ = this.singletonFocus(this.rootId);
}
if (update) {
this.updateFocus();
}
return this.focus_;
}
setFocus(focus) {
this.focus_ = focus;
}
getDepth() {
return this.levels.depth() - 1;
}
isSpeech() {
return this.generator.modality === enrich_attr_1.Attribute.SPEECH;
}
focusDomNodes() {
return this.getFocus().getDomNodes();
}
focusSemanticNodes() {
return this.getFocus().getSemanticNodes();
}
speech() {
const nodes = this.focusDomNodes();
if (!nodes.length) {
return '';
}
const special = this.specialMove();
if (special !== null) {
return special;
}
switch (this.moved) {
case walker_1.WalkerMoves.DEPTH:
return this.depth_();
case walker_1.WalkerMoves.SUMMARY:
return this.summary_();
case walker_1.WalkerMoves.DETAIL:
return this.detail_();
default: {
const speech = [];
const snodes = this.focusSemanticNodes();
for (let i = 0, l = nodes.length; i < l; i++) {
const node = nodes[i];
const snode = snodes[i];
speech.push(node
? this.generator.getSpeech(node, this.getXml())
: SpeechGeneratorUtil.recomputeMarkup(snode));
}
return this.mergePrefix_(speech);
}
}
}
move(key) {
const direction = this.keyMapping.get(key);
if (!direction) {
return null;
}
const focus = direction();
if (!focus || focus === this.getFocus()) {
return false;
}
this.setFocus(focus);
if (this.moved === walker_1.WalkerMoves.HOME) {
this.levels = this.initLevels();
}
return true;
}
up() {
this.moved = walker_1.WalkerMoves.UP;
return this.getFocus();
}
down() {
this.moved = walker_1.WalkerMoves.DOWN;
return this.getFocus();
}
left() {
this.moved = walker_1.WalkerMoves.LEFT;
return this.getFocus();
}
right() {
this.moved = walker_1.WalkerMoves.RIGHT;
return this.getFocus();
}
repeat() {
this.moved = walker_1.WalkerMoves.REPEAT;
return this.getFocus().clone();
}
depth() {
this.moved = this.isSpeech() ? walker_1.WalkerMoves.DEPTH : walker_1.WalkerMoves.REPEAT;
return this.getFocus().clone();
}
home() {
this.moved = walker_1.WalkerMoves.HOME;
const focus = this.singletonFocus(this.rootId);
return focus;
}
getBySemanticId(id) {
return WalkerUtil.getBySemanticId(this.node, id);
}
primaryId() {
return this.getFocus().getSemanticPrimary().id.toString();
}
expand() {
const primary = this.getFocus().getDomPrimary();
const expandable = this.actionable_(primary);
if (!expandable) {
return this.getFocus();
}
this.moved = walker_1.WalkerMoves.EXPAND;
expandable.dispatchEvent(new Event('click'));
return this.getFocus().clone();
}
expandable(node) {
const parent = !!this.actionable_(node);
return parent && node.childNodes.length === 0;
}
collapsible(node) {
const parent = !!this.actionable_(node);
return parent && node.childNodes.length > 0;
}
restoreState() {
if (!this.highlighter) {
return;
}
const state = walker_1.WalkerState.getState(this.id);
if (!state) {
return;
}
let node = this.getRebuilt().nodeDict[state];
const path = [];
while (node) {
path.push(node.id);
node = node.parent;
}
path.pop();
while (path.length > 0) {
this.down();
const id = path.pop();
const focus = this.findFocusOnLevel(id);
if (!focus) {
break;
}
this.setFocus(focus);
}
this.moved = walker_1.WalkerMoves.ENTER;
}
updateFocus() {
this.setFocus(focus_1.Focus.factory(this.getFocus().getSemanticPrimary().id.toString(), this.getFocus()
.getSemanticNodes()
.map((x) => x.id.toString()), this.getRebuilt(), this.node));
}
rebuildStree() {
this.rebuilt_ = new rebuild_stree_1.RebuildStree(this.getXml());
this.rootId = this.rebuilt_.stree.root.id.toString();
this.generator.setRebuilt(this.rebuilt_);
this.skeleton = semantic_skeleton_1.SemanticSkeleton.fromTree(this.rebuilt_.stree);
this.skeleton.populate();
this.focus_ = this.singletonFocus(this.rootId);
this.levels = this.initLevels();
SpeechGeneratorUtil.connectMactions(this.node, this.getXml(), this.rebuilt_.xml);
}
previousLevel() {
const dnode = this.getFocus().getDomPrimary();
return dnode
? WalkerUtil.getAttribute(dnode, enrich_attr_1.Attribute.PARENT)
: this.getFocus().getSemanticPrimary().parent.id.toString();
}
nextLevel() {
const dnode = this.getFocus().getDomPrimary();
let children;
let content;
if (dnode) {
children = WalkerUtil.splitAttribute(WalkerUtil.getAttribute(dnode, enrich_attr_1.Attribute.CHILDREN));
content = WalkerUtil.splitAttribute(WalkerUtil.getAttribute(dnode, enrich_attr_1.Attribute.CONTENT));
const type = WalkerUtil.getAttribute(dnode, enrich_attr_1.Attribute.TYPE);
const role = WalkerUtil.getAttribute(dnode, enrich_attr_1.Attribute.ROLE);
return this.combineContentChildren(type, role, content, children);
}
const toIds = (x) => x.id.toString();
const snode = this.getRebuilt().nodeDict[this.primaryId()];
children = snode.childNodes.map(toIds);
content = snode.contentNodes.map(toIds);
if (children.length === 0) {
return [];
}
return this.combineContentChildren(snode.type, snode.role, content, children);
}
singletonFocus(id) {
this.getRebuilt();
const ids = this.retrieveVisuals(id);
return this.focusFromId(id, ids);
}
retrieveVisuals(id) {
if (!this.skeleton) {
return [id];
}
const num = parseInt(id, 10);
const semStree = this.skeleton.subtreeNodes(num);
if (!semStree.length) {
return [id];
}
semStree.unshift(num);
const mmlStree = {};
const result = [];
XpathUtil.updateEvaluator(this.getXml());
for (const child of semStree) {
if (mmlStree[child]) {
continue;
}
result.push(child.toString());
mmlStree[child] = true;
this.subtreeIds(child, mmlStree);
}
return result;
}
subtreeIds(id, nodes) {
const xmlRoot = XpathUtil.evalXPath(`//*[@data-semantic-id="${id}"]`, this.getXml());
const xpath = XpathUtil.evalXPath('*//@data-semantic-id', xmlRoot[0]);
xpath.forEach((x) => (nodes[parseInt(x.textContent, 10)] = true));
}
focusFromId(id, ids) {
return focus_1.Focus.factory(id, ids, this.getRebuilt(), this.node);
}
summary() {
this.moved = this.isSpeech() ? walker_1.WalkerMoves.SUMMARY : walker_1.WalkerMoves.REPEAT;
return this.getFocus().clone();
}
detail() {
this.moved = this.isSpeech() ? walker_1.WalkerMoves.DETAIL : walker_1.WalkerMoves.REPEAT;
return this.getFocus().clone();
}
specialMove() {
return null;
}
virtualize(opt_undo) {
this.cursors.push({
focus: this.getFocus(),
levels: this.levels,
undo: opt_undo || !this.cursors.length
});
this.levels = this.levels.clone();
return this.getFocus().clone();
}
previous() {
const previous = this.cursors.pop();
if (!previous) {
return this.getFocus();
}
this.levels = previous.levels;
return previous.focus;
}
undo() {
let previous;
do {
previous = this.cursors.pop();
} while (previous && !previous.undo);
if (!previous) {
return this.getFocus();
}
this.levels = previous.levels;
return previous.focus;
}
update(options) {
this.generator.setOptions(options);
(0, engine_setup_1.setup)(options).then(() => SpeechGeneratorFactory.generator('Tree').getSpeech(this.node, this.getXml()));
}
nextRules() {
const options = this.generator.getOptions();
if (options.modality !== 'speech') {
return this.getFocus();
}
EngineConst.DOMAIN_TO_STYLES[options.domain] = options.style;
options.domain =
options.domain === 'mathspeak' ? 'clearspeak' : 'mathspeak';
options.style = EngineConst.DOMAIN_TO_STYLES[options.domain];
this.update(options);
this.moved = walker_1.WalkerMoves.REPEAT;
return this.getFocus().clone();
}
nextStyle(domain, 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_1.ClearspeakPreferences.getLocalePreferences();
const loc = prefs['en'];
if (!loc) {
return 'default';
}
const smart = clearspeak_preferences_1.ClearspeakPreferences.relevantPreferences(this.getFocus().getSemanticPrimary());
const current = clearspeak_preferences_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_1.ClearspeakPreferences.addPreference(style, smart, next);
return result;
}
return style;
}
previousRules() {
const options = this.generator.getOptions();
if (options.modality !== 'speech') {
return this.getFocus();
}
options.style = this.nextStyle(options.domain, options.style);
this.update(options);
this.moved = walker_1.WalkerMoves.REPEAT;
return this.getFocus().clone();
}
refocus() {
let focus = this.getFocus();
let last;
while (!focus.getNodes().length) {
last = this.levels.peek();
const up = this.up();
if (!up) {
break;
}
this.setFocus(up);
focus = this.getFocus(true);
}
this.levels.push(last);
this.setFocus(focus);
}
toggleActive_() {
this.active_ = !this.active_;
}
mergePrefix_(speech, pre = []) {
const prefix = this.isSpeech() ? this.prefix_() : '';
if (prefix) {
speech.unshift(prefix);
}
const postfix = this.isSpeech() ? this.postfix_() : '';
if (postfix) {
speech.push(postfix);
}
return AuralRendering.finalize(AuralRendering.merge(pre.concat(speech)));
}
prefix_() {
const nodes = this.getFocus().getDomNodes();
const snodes = this.getFocus().getSemanticNodes();
return nodes[0]
? WalkerUtil.getAttribute(nodes[0], enrich_attr_1.Attribute.PREFIX)
: SpeechGeneratorUtil.retrievePrefix(snodes[0]);
}
postfix_() {
const nodes = this.getFocus().getDomNodes();
return nodes[0]
? WalkerUtil.getAttribute(nodes[0], enrich_attr_1.Attribute.POSTFIX)
: '';
}
depth_() {
const oldDepth = grammar_1.Grammar.getInstance().getParameter('depth');
grammar_1.Grammar.getInstance().setParameter('depth', true);
const primary = this.getFocus().getDomPrimary();
const expand = this.expandable(primary)
? locale_1.LOCALE.MESSAGES.navigate.EXPANDABLE
: this.collapsible(primary)
? locale_1.LOCALE.MESSAGES.navigate.COLLAPSIBLE
: '';
const level = locale_1.LOCALE.MESSAGES.navigate.LEVEL + ' ' + this.getDepth();
const snodes = this.getFocus().getSemanticNodes();
const prefix = SpeechGeneratorUtil.retrievePrefix(snodes[0]);
const audio = [
new auditory_description_1.AuditoryDescription({ text: level, personality: {} }),
new auditory_description_1.AuditoryDescription({ text: prefix, personality: {} }),
new auditory_description_1.AuditoryDescription({ text: expand, personality: {} })
];
grammar_1.Grammar.getInstance().setParameter('depth', oldDepth);
return AuralRendering.finalize(AuralRendering.markup(audio));
}
actionable_(node) {
const parent = node === null || node === void 0 ? void 0 : node.parentNode;
return parent && this.highlighter.isMactionNode(parent) ? parent : null;
}
summary_() {
const sprimary = this.getFocus().getSemanticPrimary();
const sid = sprimary.id.toString();
const snode = this.getRebuilt().xml.getAttribute('id') === sid
? this.getRebuilt().xml
: DomUtil.querySelectorAllByAttrValue(this.getRebuilt().xml, 'id', sid)[0];
const summary = SpeechGeneratorUtil.retrieveSummary(snode);
const speech = this.mergePrefix_([summary]);
return speech;
}
detail_() {
const sprimary = this.getFocus().getSemanticPrimary();
const sid = sprimary.id.toString();
const snode = this.getRebuilt().xml.getAttribute('id') === sid
? this.getRebuilt().xml
: DomUtil.querySelectorAllByAttrValue(this.getRebuilt().xml, 'id', sid)[0];
const oldAlt = snode.getAttribute('alternative');
snode.removeAttribute('alternative');
const detail = SpeechGeneratorUtil.computeMarkup(snode);
const speech = this.mergePrefix_([detail]);
snode.setAttribute('alternative', oldAlt);
return speech;
}
}
exports.AbstractWalker = AbstractWalker;
AbstractWalker.ID_COUNTER = 0;
AbstractWalker.SRE_ID_ATTR = 'sre-explorer-id';