import { Plugin, ButtonView } from 'ckeditor5'; import ckeditor5Icon from '../theme/icons/ckeditor.svg'; import ckeditor5Iconn from '../theme/icons/ckeditorr.svg'; // import { asBlob } from 'html-docx-js-typescript'; // import { saveAs } from 'file-saver'; // import Temml from 'temml'; import { MathMLToLaTeX } from 'mathml-to-latex'; export default class Import extends Plugin { public static get pluginName() { return 'Import' as const; } public init(): void { const editor = this.editor; const t = editor.t; const model = editor.model; // Add the "importButton" to feature components. editor.ui.componentFactory.add( 'importDocx', locale => { const view = new ButtonView( locale ); view.set( { label: t( 'Import Docx' ), icon: ckeditor5Iconn, tooltip: true } ); // POST fetch html from docx this.listenTo( view, 'execute', async () => { // curl -X 'POST' \ // 'http://localhost:8080/aspose/word-to-html' \ // -H 'accept: text/plain' \ // -H 'Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document' \ // --data-binary '@stou(207).docx' // file accpt docx const input = document.createElement('input'); input.type = 'file'; input.accept = '.docx'; input.click(); input.addEventListener('change', async () => { const file = input.files![0]; const formData = new FormData(); formData.append("file", file); try { const response = await fetch("http://localhost:8080/aspose/word-to-html", { method: "POST", headers: { // Do not set `Content-Type` manually when using FormData; // the browser will automatically set the correct boundary for multipart/form-data. }, body: file, // directly sending file bytes as the backend expects byte[] }); if (!response.ok) { throw new Error(`Failed to upload file: ${response.statusText}`); } const htmlText = await response.text(); // console.log("Converted HTML:", htmlText); const htmlDoc = new DOMParser().parseFromString(htmlText, "text/html"); const body = htmlDoc.body; // pre-process mathml to latex // get all mathml elements // replace all mathml element in the body with script type math/tex with inside content latex const mathmlElements = body.querySelectorAll("math"); mathmlElements.forEach(mathmlElement => { const latex = MathMLToLaTeX.convert(mathmlElement.outerHTML); const scriptElement = document.createElement("script"); scriptElement.type = "math/tex"; scriptElement.textContent = latex; const spanElement = document.createElement("span"); spanElement.appendChild(scriptElement); mathmlElement.replaceWith(spanElement); }); // font-family for concat with , serif const spans = body.querySelectorAll("span"); spans.forEach(span => { // span.style.fontFamily += ", serif"; // check if it's

tag has font-size attribute, then apply to tag const p = span.parentElement; if (p && p.tagName === "P") { const fontSize = p.style.fontSize; if (fontSize && span.style.fontSize === "") { span.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } const li = span.parentElement; if (li && li.tagName === "LI") { const outerli = li.parentElement?.parentElement; if (outerli && outerli.tagName === "LI") { const fontSize = outerli.style.fontSize; if (fontSize && li.style.fontSize === "") { li.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } const fontSize = li.style.fontSize; if (fontSize && span.style.fontSize === "") { span.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } const pp = span.parentElement?.parentElement; if (pp && span.parentElement.tagName === "A") { const fontSize = pp.style.fontSize; if (fontSize && span.style.fontSize === "") { span.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } }); console.log("Converted HTML:", body.innerHTML); this.editor.setData(body.innerHTML); } catch (error) { console.error("Error uploading file:", error); throw error; } editor.editing.view.focus(); }); } ); return view; } ); // Add the "insertButton" to feature components. editor.ui.componentFactory.add( 'insertDocx', locale => { const view = new ButtonView( locale ); view.set( { label: t( 'Insert Docx' ), icon: ckeditor5Icon, tooltip: true } ); // POST fetch html from docx this.listenTo( view, 'execute', async () => { // curl -X 'POST' \ // 'http://localhost:8080/aspose/word-to-html' \ // -H 'accept: text/plain' \ // -H 'Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document' \ // --data-binary '@stou(207).docx' // file accpt docx const input = document.createElement('input'); input.type = 'file'; input.accept = '.docx'; input.click(); input.addEventListener('change', async () => { const file = input.files![0]; const formData = new FormData(); formData.append("file", file); try { const response = await fetch("http://localhost:8080/aspose/word-to-html", { method: "POST", headers: { // Do not set `Content-Type` manually when using FormData; // the browser will automatically set the correct boundary for multipart/form-data. }, body: file, // directly sending file bytes as the backend expects byte[] }); if (!response.ok) { throw new Error(`Failed to upload file: ${response.statusText}`); } const htmlText = await response.text(); // console.log("Converted HTML:", htmlText); const htmlDoc = new DOMParser().parseFromString(htmlText, "text/html"); const body = htmlDoc.body; // pre-process mathml to latex // get all mathml elements // replace all mathml element in the body with script type math/tex with inside content latex const mathmlElements = body.querySelectorAll("math"); mathmlElements.forEach(mathmlElement => { const latex = MathMLToLaTeX.convert(mathmlElement.outerHTML); const scriptElement = document.createElement("script"); scriptElement.type = "math/tex"; scriptElement.textContent = latex; const spanElement = document.createElement("span"); spanElement.appendChild(scriptElement); mathmlElement.replaceWith(spanElement); }); // font-family for concat with , serif const spans = body.querySelectorAll("span"); spans.forEach(span => { // span.style.fontFamily += ", serif"; // check if it's

tag has font-size attribute, then apply to tag const p = span.parentElement; if (p && p.tagName === "P") { const fontSize = p.style.fontSize; if (fontSize && span.style.fontSize === "") { span.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } const li = span.parentElement; if (li && li.tagName === "LI") { const outerli = li.parentElement?.parentElement; if (outerli && outerli.tagName === "LI") { const fontSize = outerli.style.fontSize; if (fontSize && li.style.fontSize === "") { li.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } const fontSize = li.style.fontSize; if (fontSize && span.style.fontSize === "") { span.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } const pp = span.parentElement?.parentElement; if (pp && span.parentElement.tagName === "A") { const fontSize = pp.style.fontSize; if (fontSize && span.style.fontSize === "") { span.setAttribute("style", `${span.getAttribute("style")}; font-size: ${fontSize}`); } } }); console.log("Converted HTML:", body.innerHTML); // this.editor.setData(body.innerHTML); const viewFragment = editor.data.processor.toView(body.innerHTML); const modelFragment = editor.data.toModel(viewFragment); model.insertContent(modelFragment); } catch (error) { console.error("Error uploading file:", error); throw error; } editor.editing.view.focus(); }); } ); return view; } ); } }