domtranslator
Version:
Simple and powerful DOM translator.
103 lines (101 loc) • 3.47 kB
JavaScript
import { getNodeImportanceScore } from './utils/nodes';
/**
* Manages translation state of DOM nodes.
*
* Class is purposed for translate primitive nodes.
* It manages only node values itself, with no recursive processing nested nodes.
*/
export class NodesTranslator {
translateCallback;
idCounter = 0;
nodeStorage = new WeakMap();
config;
constructor(translateCallback, { nodeImportanceScore = getNodeImportanceScore } = {}) {
this.translateCallback = translateCallback;
this.config = {
nodeImportanceScore,
};
}
has(node) {
return this.nodeStorage.has(node);
}
getState(node) {
const nodeData = this.nodeStorage.get(node);
if (!nodeData)
return null;
const { originalText } = nodeData;
return { originalText };
}
/**
* Translates nodes that contain text (e.g., Text, Attr)
* After translation calls the callback with the translated node
*/
translate = (node, callback) => {
if (this.has(node))
throw new Error('This node has already been translated');
if (node.nodeType !== Node.ATTRIBUTE_NODE && node.nodeType !== Node.TEXT_NODE) {
throw new Error('Cannot translate node: only Text and Attr nodes are supported');
}
// Skip empty text
if (node.nodeValue === null || node.nodeValue.trim().length == 0)
return;
this.nodeStorage.set(node, {
id: this.idCounter++,
updateId: 1,
originalText: null,
importanceScore: this.config.nodeImportanceScore(node),
});
this.translateNodeContent(node, callback);
};
/**
* Restores the original node text
*/
restore(node) {
const nodeData = this.nodeStorage.get(node);
if (!nodeData)
return;
if (nodeData.originalText !== null) {
node.nodeValue = nodeData.originalText;
}
this.nodeStorage.delete(node);
}
/**
* Translates node after it has been modified
* After translation calls the callback with the translated node
*/
update(node, callback) {
const nodeData = this.nodeStorage.get(node);
if (!nodeData)
throw new Error('Node cannot be updated because it was never translated');
nodeData.updateId++;
this.translateNodeContent(node, callback);
}
/**
* Call only for new and updated nodes
*/
translateNodeContent(node, callback) {
const nodeData = this.nodeStorage.get(node);
if (!nodeData) {
throw new Error('Node is not register');
}
if (node.nodeValue === null)
return;
const nodeId = nodeData.id;
const nodeContext = nodeData.updateId;
return this.translateCallback(node.nodeValue, nodeData.importanceScore).then((text) => {
const actualNodeData = this.nodeStorage.get(node);
if (!actualNodeData || nodeId !== actualNodeData.id) {
return;
}
if (nodeContext !== actualNodeData.updateId) {
return;
}
actualNodeData.originalText =
node.nodeValue !== null ? node.nodeValue : '';
node.nodeValue = text;
if (callback)
callback(node);
});
}
}
//# sourceMappingURL=sourcemaps/NodesTranslator.js.map