From da1553920b84dac58706ae69de35e6a616de1278 Mon Sep 17 00:00:00 2001 From: kl Date: Fri, 25 Dec 2020 20:41:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E4=BA=86xml=E7=9A=84?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/config/freemarker_implicit.ftl | 5 + .../main/java/cn/keking/model/FileType.java | 1 + .../service/impl/MarkdownFilePreviewImpl.java | 2 +- .../service/impl/SimTextFilePreviewImpl.java | 9 + .../service/impl/XmlFilePreviewImpl.java | 27 ++ .../main/java/cn/keking/utils/FileUtils.java | 3 + .../resources/static/css/img/Collapsed.gif | Bin 0 -> 215 bytes .../resources/static/css/img/Expanded.gif | Bin 0 -> 206 bytes .../resources/static/css/xmlTreeViewer.css | 110 ++++++ .../main/resources/static/js/base64.min.js | 8 + .../main/resources/static/js/xmlTreeViewer.js | 373 ++++++++++++++++++ .../src/main/resources/web/txt.ftl | 56 ++- 12 files changed, 585 insertions(+), 9 deletions(-) create mode 100644 jodconverter-web/src/main/java/cn/keking/service/impl/XmlFilePreviewImpl.java create mode 100644 jodconverter-web/src/main/resources/static/css/img/Collapsed.gif create mode 100644 jodconverter-web/src/main/resources/static/css/img/Expanded.gif create mode 100644 jodconverter-web/src/main/resources/static/css/xmlTreeViewer.css create mode 100644 jodconverter-web/src/main/resources/static/js/base64.min.js create mode 100644 jodconverter-web/src/main/resources/static/js/xmlTreeViewer.js diff --git a/jodconverter-web/src/main/config/freemarker_implicit.ftl b/jodconverter-web/src/main/config/freemarker_implicit.ftl index ba502ddd..a0442ad6 100644 --- a/jodconverter-web/src/main/config/freemarker_implicit.ftl +++ b/jodconverter-web/src/main/config/freemarker_implicit.ftl @@ -1,5 +1,10 @@ [#ftl] [#-- @implicitly included --] +[#-- @ftlvariable name="xmlContent" type="java.lang.String" --] +[#-- @ftlvariable name="textContent" type="java.lang.String" --] +[#-- @ftlvariable name="textType" type="java.lang.String" --] +[#-- @ftlvariable name="markdown" type="String" --] +[#-- @ftlvariable name="xml" type="String" --] [#-- @ftlvariable name="switchDisabled" type="String" --] [#-- @ftlvariable name="imgurls" type="String" --] [#-- @ftlvariable name="watermarkAngle" type="String" --] diff --git a/jodconverter-web/src/main/java/cn/keking/model/FileType.java b/jodconverter-web/src/main/java/cn/keking/model/FileType.java index 1f03e6e9..b6ce0df3 100644 --- a/jodconverter-web/src/main/java/cn/keking/model/FileType.java +++ b/jodconverter-web/src/main/java/cn/keking/model/FileType.java @@ -13,6 +13,7 @@ public enum FileType { other("otherFilePreviewImpl"), media("mediaFilePreviewImpl"), markdown("markdownFilePreviewImpl"), + xml("xmlFilePreviewImpl"), cad("cadFilePreviewImpl"); diff --git a/jodconverter-web/src/main/java/cn/keking/service/impl/MarkdownFilePreviewImpl.java b/jodconverter-web/src/main/java/cn/keking/service/impl/MarkdownFilePreviewImpl.java index a5cf24a6..683c703e 100644 --- a/jodconverter-web/src/main/java/cn/keking/service/impl/MarkdownFilePreviewImpl.java +++ b/jodconverter-web/src/main/java/cn/keking/service/impl/MarkdownFilePreviewImpl.java @@ -21,7 +21,7 @@ public class MarkdownFilePreviewImpl implements FilePreview { @Override public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { - model.addAttribute("markdown","true"); + model.addAttribute("textType","markdown"); return simTextFilePreview.filePreviewHandle(url, model, fileAttribute); } } diff --git a/jodconverter-web/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java b/jodconverter-web/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java index aaf612e8..8df63d1c 100644 --- a/jodconverter-web/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java +++ b/jodconverter-web/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java @@ -1,14 +1,18 @@ package cn.keking.service.impl; import cn.keking.model.FileAttribute; +import cn.keking.model.FileType; import cn.keking.model.ReturnResponse; import cn.keking.service.FilePreview; import cn.keking.utils.DownloadUtils; +import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Service; import org.springframework.ui.Model; +import org.springframework.util.Base64Utils; import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; /** @@ -40,6 +44,11 @@ public class SimTextFilePreviewImpl implements FilePreview { previewFile.delete(); } Files.copy(originFile.toPath(), previewFile.toPath()); + if(fileAttribute.getType().equals(FileType.xml)){ + String xmlString = FileUtils.readFileToString(previewFile, StandardCharsets.UTF_8); + + model.addAttribute("xmlContent", Base64Utils.encodeToString(xmlString.getBytes())); + } } catch (IOException e) { model.addAttribute("msg", e.getLocalizedMessage()); model.addAttribute("fileType",fileAttribute.getSuffix()); diff --git a/jodconverter-web/src/main/java/cn/keking/service/impl/XmlFilePreviewImpl.java b/jodconverter-web/src/main/java/cn/keking/service/impl/XmlFilePreviewImpl.java new file mode 100644 index 00000000..b05fd5d7 --- /dev/null +++ b/jodconverter-web/src/main/java/cn/keking/service/impl/XmlFilePreviewImpl.java @@ -0,0 +1,27 @@ +package cn.keking.service.impl; + +import cn.keking.model.FileAttribute; +import cn.keking.service.FilePreview; +import org.springframework.stereotype.Service; +import org.springframework.ui.Model; + +/** + * @author kl (http://kailing.pub) + * @since 2020/12/25 + */ +@Service +public class XmlFilePreviewImpl implements FilePreview { + + private final SimTextFilePreviewImpl simTextFilePreview; + + public XmlFilePreviewImpl(SimTextFilePreviewImpl simTextFilePreview) { + this.simTextFilePreview = simTextFilePreview; + } + + + @Override + public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { + model.addAttribute("textType","xml"); + return simTextFilePreview.filePreviewHandle(url, model, fileAttribute); + } +} diff --git a/jodconverter-web/src/main/java/cn/keking/utils/FileUtils.java b/jodconverter-web/src/main/java/cn/keking/utils/FileUtils.java index c528cc35..794fabf4 100644 --- a/jodconverter-web/src/main/java/cn/keking/utils/FileUtils.java +++ b/jodconverter-web/src/main/java/cn/keking/utils/FileUtils.java @@ -83,6 +83,9 @@ public class FileUtils { if("md".equalsIgnoreCase(fileType)){ return FileType.markdown; } + if("xml".equalsIgnoreCase(fileType)){ + return FileType.xml; + } if (Arrays.asList(simText).contains(fileType.toLowerCase())) { return FileType.simText; } diff --git a/jodconverter-web/src/main/resources/static/css/img/Collapsed.gif b/jodconverter-web/src/main/resources/static/css/img/Collapsed.gif new file mode 100644 index 0000000000000000000000000000000000000000..17cbc27b321c010dc7f8e118c3a9fdddd26aec9d GIT binary patch literal 215 zcmZ?wbhEHblwsgzIKsg2|NsAg|9=1Z^XJ>Quiw6Y`1tYd`wy=_et7xz&9j#;AHR5Z z<*?;Ebt__E-?BBcL(2nJ`vv(L98#90n0g_mO;!hSvb_Q_< z9gr-@P6pPH2daH3ne)P3*6N5Z+~C1j!W&@d!@1|E@Qyp3MjBCU?XCe4iv)B6G?Fz} yg{->XJ=H~1L}1#HMUGd~wx_LIba8`)+ytY~PK_RF6?^8a%vu{)+}NbZU=09HV`3Qq literal 0 HcmV?d00001 diff --git a/jodconverter-web/src/main/resources/static/css/img/Expanded.gif b/jodconverter-web/src/main/resources/static/css/img/Expanded.gif new file mode 100644 index 0000000000000000000000000000000000000000..2aa74410fc1d4b5ff2eddf807c2fea896858e81a GIT binary patch literal 206 zcmZ?wbhEHblwsgzIKsg2|NsAg|9=1Z^XJ>Quiw6Y`1tYd`wy=_et7xz&9j#;A3u0- z@9wROH*Q?KdG+-5%SWzVICkmG{xc_cZ8&sg|K1IUb}X-*y@LU42#~}I6o0ZXvNMP? z=zwHFb~3PfKTz#U$(%PmWNnV>!VM9OCA=YqF`SO~g?HRpX`~^>-?d;vh+@RN^Q}de pt32+|j2UHq`XK`Aba)o9_4yDyin+FDin{)zyDH2~alU^@T+ literal 0 HcmV?d00001 diff --git a/jodconverter-web/src/main/resources/static/css/xmlTreeViewer.css b/jodconverter-web/src/main/resources/static/css/xmlTreeViewer.css new file mode 100644 index 00000000..bc4afe92 --- /dev/null +++ b/jodconverter-web/src/main/resources/static/css/xmlTreeViewer.css @@ -0,0 +1,110 @@ +/* Copyright 2014 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +div.header { + border-bottom: 2px solid black; + padding-bottom: 5px; + margin: 10px; +} + +div.collapsible > div.hidden { + display:none; +} + +.pretty-print { + margin-top: 1em; + margin-left: 20px; + font-family: monospace; + font-size: 13px; +} + +#xml-viewer-source-xml { + display: none; +} + +.collapsible-content { + margin-left: 2em; +} +.comment { + white-space: pre; +} + +.button { + -webkit-user-select: none; + cursor: pointer; + display: inline-block; + margin-left: -10px; + width: 10px; + background-repeat: no-repeat; + background-position: left top; + vertical-align: bottom; +} + +.collapse-button { + /*background: url("data:image/svg+xml,");*/ + background: url("./img/Expanded.gif"); + height: 12px; +} + +.expand-button { + /*background: url("data:image/svg+xml,");*/ + background: url("./img/Collapsed.gif"); + height: 12px; +} + +.line-content { + padding: 0 5px !important; +} + +.highlight { + background-color: rgb(100%, 42%, 42%); + border: 2px solid rgb(100%, 31%, 31%); +} + +.html-tag { + /* Keep this in sync with inspector.css (.webkit-html-tag) */ + color: rgb(136, 18, 128); +} + +.html-attribute-name { + /* Keep this in sync with inspector.css (.webkit-html-attribute-name) */ + color: rgb(153, 69, 0); +} + +.html-attribute-value { + /* Keep this in sync with inspector.css (.webkit-html-attribute-value) */ + color: rgb(26, 26, 166); +} + +.html-external-link, .html-resource-link { + /* Keep this in sync with inspectorSyntaxHighlight.css (.webkit-html-external-link, .webkit-html-resource-link) */ + color: #00e; +} + +.html-external-link { + /* Keep this in sync with inspectorSyntaxHighlight.css (.webkit-html-external-link) */ + text-decoration: none; +} + +.html-external-link:hover { + /* Keep this in sync with inspectorSyntaxHighlight.css (.webkit-html-external-link:hover) */ + text-decoration: underline; +} + +.html-comment { + /* Keep this in sync with inspectorSyntaxHighlight.css (.webkit-html-comment) */ + color: rgb(35, 110, 37); +} + +.html-doctype { + /* Keep this in sync with inspectorSyntaxHighlight.css (.webkit-html-doctype) */ + color: rgb(192, 192, 192); +} + +.html-end-of-file { + /* Keep this in sync with inspectorSyntaxHighlight.css (.webkit-html-end-of-file) */ + color: rgb(255, 0, 0); + font-weight: bold; +} \ No newline at end of file diff --git a/jodconverter-web/src/main/resources/static/js/base64.min.js b/jodconverter-web/src/main/resources/static/js/base64.min.js new file mode 100644 index 00000000..f2cc36af --- /dev/null +++ b/jodconverter-web/src/main/resources/static/js/base64.min.js @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using Terser v5.3.5. + * Original file: /npm/js-base64@3.6.0/base64.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):function(){const r=e.Base64,o=t();o.noConflict=()=>(e.Base64=r,o),e.Meteor&&(Base64=o),e.Base64=o}()}("undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this,(function(){"use strict";const e="3.6.0",t="function"==typeof atob,r="function"==typeof btoa,o="function"==typeof Buffer,n="function"==typeof TextDecoder?new TextDecoder:void 0,a="function"==typeof TextEncoder?new TextEncoder:void 0,f=[..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="],i=(e=>{let t={};return e.forEach(((e,r)=>t[e]=r)),t})(f),c=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/,u=String.fromCharCode.bind(String),s="function"==typeof Uint8Array.from?Uint8Array.from.bind(Uint8Array):(e,t=(e=>e))=>new Uint8Array(Array.prototype.slice.call(e,0).map(t)),d=e=>e.replace(/[+\/]/g,(e=>"+"==e?"-":"_")).replace(/=+$/m,""),l=e=>e.replace(/[^A-Za-z0-9\+\/]/g,""),h=e=>{let t,r,o,n,a="";const i=e.length%3;for(let i=0;i255||(o=e.charCodeAt(i++))>255||(n=e.charCodeAt(i++))>255)throw new TypeError("invalid character found");t=r<<16|o<<8|n,a+=f[t>>18&63]+f[t>>12&63]+f[t>>6&63]+f[63&t]}return i?a.slice(0,i-3)+"===".substring(i):a},p=r?e=>btoa(e):o?e=>Buffer.from(e,"binary").toString("base64"):h,y=o?e=>Buffer.from(e).toString("base64"):e=>{let t=[];for(let r=0,o=e.length;rt?d(y(e)):y(e),b=e=>{if(e.length<2)return(t=e.charCodeAt(0))<128?e:t<2048?u(192|t>>>6)+u(128|63&t):u(224|t>>>12&15)+u(128|t>>>6&63)+u(128|63&t);var t=65536+1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320);return u(240|t>>>18&7)+u(128|t>>>12&63)+u(128|t>>>6&63)+u(128|63&t)},g=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,B=e=>e.replace(g,b),x=o?e=>Buffer.from(e,"utf8").toString("base64"):a?e=>y(a.encode(e)):e=>p(B(e)),C=(e,t=!1)=>t?d(x(e)):x(e),m=e=>C(e,!0),U=/[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g,F=e=>{switch(e.length){case 4:var t=((7&e.charCodeAt(0))<<18|(63&e.charCodeAt(1))<<12|(63&e.charCodeAt(2))<<6|63&e.charCodeAt(3))-65536;return u(55296+(t>>>10))+u(56320+(1023&t));case 3:return u((15&e.charCodeAt(0))<<12|(63&e.charCodeAt(1))<<6|63&e.charCodeAt(2));default:return u((31&e.charCodeAt(0))<<6|63&e.charCodeAt(1))}},w=e=>e.replace(U,F),S=e=>{if(e=e.replace(/\s+/g,""),!c.test(e))throw new TypeError("malformed base64.");e+="==".slice(2-(3&e.length));let t,r,o,n="";for(let a=0;a>16&255):64===o?u(t>>16&255,t>>8&255):u(t>>16&255,t>>8&255,255&t);return n},E=t?e=>atob(l(e)):o?e=>Buffer.from(e,"base64").toString("binary"):S,v=o?e=>s(Buffer.from(e,"base64")):e=>s(E(e),(e=>e.charCodeAt(0))),D=e=>v(z(e)),R=o?e=>Buffer.from(e,"base64").toString("utf8"):n?e=>n.decode(v(e)):e=>w(E(e)),z=e=>l(e.replace(/[-_]/g,(e=>"-"==e?"+":"/"))),T=e=>R(z(e)),Z=e=>({value:e,enumerable:!1,writable:!0,configurable:!0}),j=function(){const e=(e,t)=>Object.defineProperty(String.prototype,e,Z(t));e("fromBase64",(function(){return T(this)})),e("toBase64",(function(e){return C(this,e)})),e("toBase64URI",(function(){return C(this,!0)})),e("toBase64URL",(function(){return C(this,!0)})),e("toUint8Array",(function(){return D(this)}))},I=function(){const e=(e,t)=>Object.defineProperty(Uint8Array.prototype,e,Z(t));e("toBase64",(function(e){return A(this,e)})),e("toBase64URI",(function(){return A(this,!0)})),e("toBase64URL",(function(){return A(this,!0)}))},O={version:e,VERSION:"3.6.0",atob:E,atobPolyfill:S,btoa:p,btoaPolyfill:h,fromBase64:T,toBase64:C,encode:C,encodeURI:m,encodeURL:m,utob:B,btou:w,decode:T,isValid:e=>{if("string"!=typeof e)return!1;const t=e.replace(/\s+/g,"").replace(/=+$/,"");return!/[^\s0-9a-zA-Z\+/]/.test(t)||!/[^\s0-9a-zA-Z\-_]/.test(t)},fromUint8Array:A,toUint8Array:D,extendString:j,extendUint8Array:I,extendBuiltins:()=>{j(),I()},Base64:{}};return Object.keys(O).forEach((e=>O.Base64[e]=O[e])),O})); +//# sourceMappingURL=/sm/8bca8602e2256d240cef904e1c1df432ccfdd2a2a73f6911c60be79e526e3e1e.map \ No newline at end of file diff --git a/jodconverter-web/src/main/resources/static/js/xmlTreeViewer.js b/jodconverter-web/src/main/resources/static/js/xmlTreeViewer.js new file mode 100644 index 00000000..46eeb7f3 --- /dev/null +++ b/jodconverter-web/src/main/resources/static/js/xmlTreeViewer.js @@ -0,0 +1,373 @@ +window.xmlTreeViewer = (function() { + + var documentNode = null; + var nodeParentPairs = []; + var tree; + var container; + + function prepareXMLViewer(node) { + documentNode = node; + var body = createHTMLElement('div'); + var sourceXML = createHTMLElement('div'); + sourceXML.id = 'xml-viewer-source-xml'; + body.appendChild(sourceXML); + + var child; + while (child = documentNode.firstChild) { + documentNode.removeChild(child); + if (child.nodeType != Node.DOCUMENT_TYPE_NODE) + sourceXML.appendChild(child); + } + + tree = createHTMLElement('div'); + body.appendChild(tree); + tree.classList.add('pretty-print'); + //window.onload = sourceXMLLoaded; + container = body; + sourceXMLLoaded(); + return body; + } + + function sourceXMLLoaded() { + //var sourceXML = container.getElementById('webkit-xml-viewer-source-xml'); + var sourceXML = container.firstChild; + if (!sourceXML) + return; // Stop if some XML tree extension is already processing this document + + for (var child = sourceXML.firstChild; child; child = child.nextSibling) + nodeParentPairs.push({parentElement: tree, node: child}); + + for (var i = 0; i < nodeParentPairs.length; i++) + processNode(nodeParentPairs[i].parentElement, nodeParentPairs[i].node); + + initButtons(); + + return false; + } + + // Tree processing. + + function processNode(parentElement, node) { + var map = processNode.processorsMap; + if (!map) { + map = {}; + processNode.processorsMap = map; + map[Node.PROCESSING_INSTRUCTION_NODE] = processProcessingInstruction; + map[Node.ELEMENT_NODE] = processElement; + map[Node.COMMENT_NODE] = processComment; + map[Node.TEXT_NODE] = processText; + map[Node.CDATA_SECTION_NODE] = processCDATA; + } + if (processNode.processorsMap[node.nodeType]) + processNode.processorsMap[node.nodeType].call(this, parentElement, node); + } + + function processElement(parentElement, node) { + if (!node.firstChild) + processEmptyElement(parentElement, node); + else { + var child = node.firstChild; + if (child.nodeType == Node.TEXT_NODE && isShort(child.nodeValue) && !child.nextSibling) + processShortTextOnlyElement(parentElement, node); + else + processComplexElement(parentElement, node); + } + } + + function processEmptyElement(parentElement, node) { + var line = createLine(); + line.appendChild(createTag(node, false, true)); + parentElement.appendChild(line); + } + + function processShortTextOnlyElement(parentElement, node) { + var line = createLine(); + line.appendChild(createTag(node, false, false)); + for (var child = node.firstChild; child; child = child.nextSibling) + line.appendChild(createText(child.nodeValue)); + line.appendChild(createTag(node, true, false)); + parentElement.appendChild(line); + } + + function processComplexElement(parentElement, node) { + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createTag(node, false, false)); + for (var child = node.firstChild; child; child = child.nextSibling) + nodeParentPairs.push({parentElement: collapsible.expanded.content, node: child}); + collapsible.expanded.end.appendChild(createTag(node, true, false)); + + collapsible.collapsed.content.appendChild(createTag(node, false, false)); + collapsible.collapsed.content.appendChild(createText('...')); + collapsible.collapsed.content.appendChild(createTag(node, true, false)); + parentElement.appendChild(collapsible); + } + + function processComment(parentElement, node) { + if (isShort(node.nodeValue)) { + var line = createLine(); + line.appendChild(createComment('')); + parentElement.appendChild(line); + } else { + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createComment('')); + + collapsible.collapsed.content.appendChild(createComment('')); + parentElement.appendChild(collapsible); + } + } + + function processCDATA(parentElement, node) { + if (isShort(node.nodeValue)) { + var line = createLine(); + line.appendChild(createText('')); + parentElement.appendChild(line); + } else { + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createText('')); + + collapsible.collapsed.content.appendChild(createText('')); + parentElement.appendChild(collapsible); + } + } + + function processProcessingInstruction(parentElement, node) { + if (isShort(node.nodeValue)) { + var line = createLine(); + line.appendChild(createComment('')); + parentElement.appendChild(line); + } else { + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createComment('')); + + collapsible.collapsed.content.appendChild(createComment('')); + parentElement.appendChild(collapsible); + } + } + + function processText(parentElement, node) { + parentElement.appendChild(createText(node.nodeValue)); + } + + // Processing utils. + + function trim(value) { + return value.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + } + + function isShort(value) { + return trim(value).length <= 50; + } + + // Tree rendering. + + function createHTMLElement(elementName) { + //return document.createElementNS('http://www.w3.org/1999/xhtml', elementName); + return document.createElement(elementName); + } + + function createCollapsible() { + var collapsible = createHTMLElement('div'); + collapsible.classList.add('collapsible'); + collapsible.expanded = createHTMLElement('div'); + collapsible.expanded.classList.add('expanded'); + collapsible.appendChild(collapsible.expanded); + + collapsible.expanded.start = createLine(); + collapsible.expanded.start.appendChild(createCollapseButton()); + collapsible.expanded.appendChild(collapsible.expanded.start); + + collapsible.expanded.content = createHTMLElement('div'); + collapsible.expanded.content.classList.add('collapsible-content'); + collapsible.expanded.appendChild(collapsible.expanded.content); + + collapsible.expanded.end = createLine(); + collapsible.expanded.appendChild(collapsible.expanded.end); + + collapsible.collapsed = createHTMLElement('div'); + collapsible.collapsed.classList.add('collapsed'); + collapsible.collapsed.classList.add('hidden'); + collapsible.appendChild(collapsible.collapsed); + collapsible.collapsed.content = createLine(); + collapsible.collapsed.content.appendChild(createExpandButton()); + collapsible.collapsed.appendChild(collapsible.collapsed.content); + + return collapsible; + } + + function createButton() { + var button = createHTMLElement('span'); + button.classList.add('button'); + return button; + } + + function createCollapseButton(str) { + var button = createButton(); + button.classList.add('collapse-button'); + return button; + } + + function createExpandButton(str) { + var button = createButton(); + button.classList.add('expand-button'); + return button; + } + + function createComment(commentString) { + var comment = createHTMLElement('span'); + comment.classList.add('comment'); + comment.classList.add('html-comment'); + comment.textContent = commentString; + return comment; + } + + function createText(value) { + var text = createHTMLElement('span'); + text.textContent = trim(value); + text.classList.add('html-text'); + return text; + } + + function createLine() { + var line = createHTMLElement('div'); + line.classList.add('line'); + return line; + } + + function createTag(node, isClosing, isEmpty) { + var tag = createHTMLElement('span'); + tag.classList.add('html-tag'); + + var stringBeforeAttrs = '<'; + if (isClosing) + stringBeforeAttrs += '/'; + //stringBeforeAttrs += node.nodeName; + var textBeforeAttrs = document.createTextNode(stringBeforeAttrs); + tag.appendChild(textBeforeAttrs); + var tagNode = createHTMLElement('span'); + tagNode.classList.add('html-tag-name'); + tagNode.textContent = node.nodeName; + tag.appendChild(tagNode); + + if (!isClosing) { + for (var i = 0; i < node.attributes.length; i++) + tag.appendChild(createAttribute(node.attributes[i])); + } + + var stringAfterAttrs = ''; + if (isEmpty) + stringAfterAttrs += '/'; + stringAfterAttrs += '>'; + var textAfterAttrs = document.createTextNode(stringAfterAttrs); + tag.appendChild(textAfterAttrs); + + return tag; + } + + function createAttribute(attributeNode) { + var attribute = createHTMLElement('span'); + attribute.classList.add('html-attribute'); + + var attributeName = createHTMLElement('span'); + attributeName.classList.add('html-attribute-name'); + attributeName.textContent = attributeNode.name; + + var textBefore = document.createTextNode(' '); + var textBetween = document.createTextNode('="'); + + var attributeValue = createHTMLElement('span'); + attributeValue.classList.add('html-attribute-value'); + attributeValue.textContent = attributeNode.value; + + var textAfter = document.createTextNode('"'); + + attribute.appendChild(textBefore); + attribute.appendChild(attributeName); + attribute.appendChild(textBetween); + attribute.appendChild(attributeValue); + attribute.appendChild(textAfter); + return attribute; + } + + function expandFunction(sectionId) { + return function () { + container.querySelector('#' + sectionId + ' > .expanded').className = 'expanded'; + container.querySelector('#' + sectionId + ' > .collapsed').className = 'collapsed hidden'; + }; + } + + function collapseFunction(sectionId) { + return function () { + container.querySelector('#' + sectionId + ' > .expanded').className = 'expanded hidden'; + container.querySelector('#' + sectionId + ' > .collapsed').className = 'collapsed'; + }; + } + + function initButtons() { + var sections = container.querySelectorAll('.collapsible'); + for (var i = 0; i < sections.length; i++) { + var sectionId = 'collapsible' + i; + sections[i].id = sectionId; + + var expandedPart = sections[i].querySelector('#' + sectionId + ' > .expanded'); + var collapseButton = expandedPart.querySelector('.collapse-button'); + collapseButton.onclick = collapseFunction(sectionId); + collapseButton.onmousedown = handleButtonMouseDown; + + var collapsedPart = sections[i].querySelector('#' + sectionId + ' > .collapsed'); + var expandButton = collapsedPart.querySelector('.expand-button'); + expandButton.onclick = expandFunction(sectionId); + expandButton.onmousedown = handleButtonMouseDown; + } + + } + + function handleButtonMouseDown(e) { + // To prevent selection on double click + e.preventDefault(); + } + + var parseXML = function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new window.DOMParser(); + xml = tmp.parseFromString( data, "text/xml" ); + } else { // IE + xml = new window.ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch ( e ) { + xml = undefined; + } + var errMsg; + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + errMsg = xml.getElementsByTagName( "parsererror" )[0].textContent; + } + return {xml: xml, errMsg: errMsg}; + }; + + return { + getXMLViewerNode: prepareXMLViewer, + parseXML: parseXML + } +})(); \ No newline at end of file diff --git a/jodconverter-web/src/main/resources/web/txt.ftl b/jodconverter-web/src/main/resources/web/txt.ftl index 0e976613..0bb0579d 100644 --- a/jodconverter-web/src/main/resources/web/txt.ftl +++ b/jodconverter-web/src/main/resources/web/txt.ftl @@ -6,28 +6,38 @@ 普通文本预览 + -
- <#if markdown??> +
+ <#if textType?? && textType == "markdown">

+ <#elseif textType?? && textType == "xml" > + +
<#else>
+ + + +