feat: add track point

This commit is contained in:
liuyuanchuang
2026-01-27 23:44:18 +08:00
parent 7c5409a6c7
commit d562d67203
71 changed files with 957 additions and 11 deletions

View File

@@ -5,6 +5,7 @@ import { convertMathmlToOmml, wrapOmmlForClipboard } from '../lib/ommlConverter'
import { generateImageFromElement, copyImageToClipboard, downloadImage } from '../lib/imageGenerator';
import { API_BASE_URL } from '../config/env';
import { tokenManager } from '../lib/api';
import { trackExportEvent } from '../lib/analytics';
import { useLanguage } from '../contexts/LanguageContext';
interface ExportSidebarProps {
@@ -24,6 +25,87 @@ interface ExportOption {
extension?: string;
}
// Helper function to add mml: prefix to MathML
const addMMLPrefix = (mathml: string): string | null => {
try {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(mathml, 'application/xml');
// Check for parse errors
const parseError = xmlDoc.getElementsByTagName("parsererror");
if (parseError.length > 0) {
return null;
}
// Create new document with mml namespace
const newDoc = document.implementation.createDocument(
'http://www.w3.org/1998/Math/MathML',
'mml:math',
null
);
const newMathElement = newDoc.documentElement;
// Copy display attribute if present
const displayAttr = xmlDoc.documentElement.getAttribute('display');
if (displayAttr) {
newMathElement.setAttribute('display', displayAttr);
}
// Recursive function to process nodes
const processNode = (node: Node, newParent: Element) => {
if (node.nodeType === Node.ELEMENT_NODE) {
const element = node as Element;
// Create new element with mml: prefix in the target document
const newElement = newDoc.createElementNS(
'http://www.w3.org/1998/Math/MathML',
'mml:' + element.localName
);
// Copy attributes
for (let i = 0; i < element.attributes.length; i++) {
const attr = element.attributes[i];
// Skip xmlns attributes as we handle them explicitly
if (attr.name.startsWith('xmlns')) continue;
newElement.setAttributeNS(
attr.namespaceURI,
attr.name,
attr.value
);
}
// Process children
Array.from(element.childNodes).forEach(child => {
processNode(child, newElement);
});
newParent.appendChild(newElement);
} else if (node.nodeType === Node.TEXT_NODE) {
newParent.appendChild(newDoc.createTextNode(node.nodeValue || ''));
}
};
// Process all children of the root math element
Array.from(xmlDoc.documentElement.childNodes).forEach(child => {
processNode(child, newMathElement);
});
// Serialize
const serializer = new XMLSerializer();
let prefixedMathML = serializer.serializeToString(newDoc);
// Clean up xmlns
prefixedMathML = prefixedMathML.replace(/ xmlns(:mml)?="[^"]*"/g, '');
prefixedMathML = prefixedMathML.replace(/<mml:math>/, '<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML">');
return prefixedMathML;
} catch (err) {
console.error('Failed to process MathML:', err);
return null;
}
};
export default function ExportSidebar({ isOpen, onClose, result }: ExportSidebarProps) {
const { t } = useLanguage();
const [copiedId, setCopiedId] = useState<string | null>(null);
@@ -62,6 +144,12 @@ export default function ExportSidebar({ isOpen, onClose, result }: ExportSidebar
category: 'Code',
getContent: (r) => r.mathml_content
},
{
id: 'mathml_mml',
label: 'MathML (MML)',
category: 'Code',
getContent: (r) => r.mathml_content ? addMMLPrefix(r.mathml_content) : null
},
{
id: 'mathml_word',
label: 'Word MathML',
@@ -169,6 +257,15 @@ export default function ExportSidebar({ isOpen, onClose, result }: ExportSidebar
};
const handleAction = async (option: ExportOption) => {
// Analytics tracking
if (result?.id) {
trackExportEvent(
result.id,
option.id,
exportOptions.map(o => o.id)
);
}
// Handle DOCX export via API
if (option.id === 'docx') {
await handleFileExport('docx');