提交
This commit is contained in:
@@ -150,49 +150,49 @@ export default {
|
||||
replaceWMathContent(inputHtml, callback) {
|
||||
// 正则逻辑:匹配整个 wmath 标签,并捕获内部所有的属性字符串
|
||||
var str = inputHtml.replace(/<wmath ([^>]+)>[^<]*<\/wmath>/g, function (match, allProps) {
|
||||
|
||||
|
||||
// 1. 从所有属性中提取 data-latex 的值
|
||||
const latexMatch = allProps.match(/data-latex="([^"]+)"/);
|
||||
const latexContent = latexMatch ? latexMatch[1] : '';
|
||||
|
||||
|
||||
// 2. 从所有属性中提取 data-wrap 的值
|
||||
const wrapMatch = allProps.match(/data-wrap="([^"]+)"/);
|
||||
const wrapAttr = wrapMatch ? ` data-wrap="${wrapMatch[1]}"` : '';
|
||||
|
||||
|
||||
// 3. 重新组装:只保留 data-latex 和 data-wrap
|
||||
// 注意:这里去掉了多余的 prefix/suffix,确保标签“干净”
|
||||
return `<wmath${wrapAttr} data-latex="${latexContent}">${latexContent}</wmath>`;
|
||||
});
|
||||
|
||||
|
||||
callback(str);
|
||||
} ,
|
||||
},
|
||||
// **解析 MathJax 公式,获取 LaTeX**
|
||||
async extractMathJaxLatex(cell, callback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Step 1: 获取初始 HTML
|
||||
let updatedContent = cell.innerHTML;
|
||||
|
||||
|
||||
// 查找所有 <wmath> 元素
|
||||
const wmathElements = cell.querySelectorAll('wmath');
|
||||
|
||||
|
||||
wmathElements.forEach((element) => {
|
||||
// 1. 提取 latex 内容
|
||||
const latexContent = element.getAttribute('data-latex') || '';
|
||||
|
||||
|
||||
// 2. 提取 wrap 模式 (只提取,不包裹)
|
||||
const wrapMode = element.getAttribute('data-wrap') || 'block';
|
||||
|
||||
|
||||
// 3. 重新组装标签:只保留属性,标签内部只放原始 latex 文本
|
||||
// 这里不加 $ 或 $$,保持数据的原始性
|
||||
const newWmathTag = `<wmath data-wrap="${wrapMode}" data-latex="${latexContent}">${latexContent}</wmath>`;
|
||||
|
||||
|
||||
// 4. 执行替换
|
||||
updatedContent = updatedContent.replace(element.outerHTML, newWmathTag);
|
||||
});
|
||||
|
||||
|
||||
// Step 2: 提取去掉外层 span 的内容
|
||||
updatedContent = this.extractContentWithoutOuterSpan(updatedContent);
|
||||
|
||||
|
||||
// Step 3: Resolve 结果
|
||||
resolve(updatedContent);
|
||||
});
|
||||
@@ -350,6 +350,21 @@ export default {
|
||||
console.error("❌ 找不到 word/document.xml,无法解析 Word 文件");
|
||||
return;
|
||||
}
|
||||
const relsFile = zip.file("word/_rels/document.xml.rels");
|
||||
let imageRelMap = {};
|
||||
if (relsFile) {
|
||||
const relsXml = await relsFile.async("string");
|
||||
const relDoc = new DOMParser().parseFromString(relsXml, "application/xml");
|
||||
const rels = relDoc.getElementsByTagName("Relationship");
|
||||
for (let r = 0; r < rels.length; r++) {
|
||||
const id = rels[r].getAttribute("Id");
|
||||
const target = rels[r].getAttribute("Target");
|
||||
if (target && target.includes("media/")) {
|
||||
// 补全路径,通常 rels 里的路径是相对 word 文件夹的
|
||||
imageRelMap[id] = `word/${target}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
const documentXml = await documentFile.async("string");
|
||||
const parser = new DOMParser();
|
||||
const documentDoc = parser.parseFromString(documentXml, "application/xml");
|
||||
@@ -458,14 +473,44 @@ export default {
|
||||
const drawings = run.getElementsByTagName("w:drawing");
|
||||
for (let d = 0; d < drawings.length; d++) {
|
||||
const drawing = drawings[d];
|
||||
// 使用命名空间提取 a:blip
|
||||
|
||||
// --- 1. 提取宽高 (EMUs 转 PX) ---
|
||||
// Word 存储尺寸的地方通常在 wp:extent
|
||||
const extent = drawing.getElementsByTagName("wp:extent")[0];
|
||||
let styleStr = "";
|
||||
if (extent) {
|
||||
const cx = parseInt(extent.getAttribute("cx"));
|
||||
const cy = parseInt(extent.getAttribute("cy"));
|
||||
// 9525 是 EMU 到像素的换算比例
|
||||
const widthPx = Math.round(cx / 9525);
|
||||
const heightPx = Math.round(cy / 9525);
|
||||
styleStr = `width="${widthPx}" height="${heightPx}"`;
|
||||
}
|
||||
|
||||
const blips = drawing.getElementsByTagNameNS("http://schemas.openxmlformats.org/drawingml/2006/main", "blip");
|
||||
for (let b = 0; b < blips.length; b++) {
|
||||
const blip = blips[b];
|
||||
const embedId = blip.getAttribute("r:embed");
|
||||
if (embedId) {
|
||||
textContent += `<img data-embed="${embedId}"/>`;
|
||||
|
||||
|
||||
if (embedId && imageRelMap[embedId]) {
|
||||
// const imagePath = imageRelMap[embedId];
|
||||
// const imgFile = zip.file(imagePath);
|
||||
|
||||
// if (imgFile) {
|
||||
// const fileSize = imgFile._data.uncompressedSize;
|
||||
|
||||
// // 依然保留 1MB 限制,保护浏览器不卡死
|
||||
// if (fileSize <= 1048576) {
|
||||
// const base64 = await imgFile.async("base64");
|
||||
// const ext = imagePath.split('.').pop().toLowerCase();
|
||||
// // <img src="data:image/${ext};base64,${base64}" ${styleStr} />
|
||||
// // --- 2. 直接拼接带宽高的 img 标签 ---
|
||||
// textContent += ``;
|
||||
// } else {
|
||||
// // console.warn(`跳过大图片: ${imagePath}, 大小: ${(fileSize / 1024 / 1024).toFixed(2)}MB`);
|
||||
// textContent += ``;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2062,12 +2107,12 @@ export default {
|
||||
// 插入自定义表格到编辑器中
|
||||
ed.setContent('');
|
||||
const customCallback = ed.getParam('clear_custom_action');
|
||||
if (typeof customCallback === 'function') {
|
||||
customCallback(ed, vueInstance);
|
||||
} else {
|
||||
// 3. 如果没有自定义逻辑,执行默认逻辑
|
||||
vueInstance.$emit('onClear');
|
||||
}
|
||||
if (typeof customCallback === 'function') {
|
||||
customCallback(ed, vueInstance);
|
||||
} else {
|
||||
// 3. 如果没有自定义逻辑,执行默认逻辑
|
||||
vueInstance.$emit('onClear');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
@@ -2079,11 +2124,11 @@ export default {
|
||||
onAction: function () {
|
||||
// 必须获取带 HTML 的内容,否则里面的 em/i 标签在拼接前就丢了
|
||||
var selectedText = ed.selection.getContent({ format: 'html' });
|
||||
|
||||
|
||||
if (selectedText) {
|
||||
// 这就是你想要的:直接外层套一个 blue
|
||||
var wrappedText = `<blue>${selectedText}</blue>`;
|
||||
|
||||
|
||||
// 使用 setContent 强行回写
|
||||
ed.selection.setContent(wrappedText);
|
||||
}
|
||||
@@ -2166,29 +2211,29 @@ export default {
|
||||
ed.ui.registry.addMenuButton('MoreSymbols', {
|
||||
text: '···', // 按钮显示的三个点
|
||||
tooltip: 'More Special Characters',
|
||||
onAction: () => {}, // 菜单主按钮点击通常不执行操作,由子菜单执行
|
||||
onAction: () => { }, // 菜单主按钮点击通常不执行操作,由子菜单执行
|
||||
fetch: (callback) => {
|
||||
const items = [
|
||||
{
|
||||
type: 'menuitem',
|
||||
text: 'en-dash (短划线)',//短划线
|
||||
onAction: () => ed.insertContent('–')
|
||||
},
|
||||
{
|
||||
type: 'menuitem',
|
||||
text: 'minus sign (减号)',//减号
|
||||
onAction: () => ed.insertContent('−')
|
||||
},
|
||||
{
|
||||
type: 'menuitem',
|
||||
text: 'hyphen (连接符)',
|
||||
onAction: () => ed.insertContent('-')
|
||||
},
|
||||
|
||||
];
|
||||
callback(items);
|
||||
const items = [
|
||||
{
|
||||
type: 'menuitem',
|
||||
text: 'en-dash (短划线)',//短划线
|
||||
onAction: () => ed.insertContent('–')
|
||||
},
|
||||
{
|
||||
type: 'menuitem',
|
||||
text: 'minus sign (减号)',//减号
|
||||
onAction: () => ed.insertContent('−')
|
||||
},
|
||||
{
|
||||
type: 'menuitem',
|
||||
text: 'hyphen (连接符)',
|
||||
onAction: () => ed.insertContent('-')
|
||||
},
|
||||
|
||||
];
|
||||
callback(items);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ed.ui.registry.addButton('removeBlue', {
|
||||
text: 'Blue', // 按钮文本
|
||||
|
||||
Reference in New Issue
Block a user