Implemented HTML Tools (#240)
Co-authored-by: widlam <mikolaj.widla@gmail.com> Reviewed-on: #240 Reviewed-by: Adam Bem <bema@noreply.example.com> Co-authored-by: Mikolaj Widla <widlam@noreply.example.com> Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
This commit is contained in:
@@ -1,7 +1,28 @@
|
|||||||
from lxml import etree
|
from lxml import etree, html
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
|
||||||
|
def convertHTML(source: str, sourceFrom: str):
|
||||||
|
htmlParser = html.HTMLParser(remove_comments=True, remove_blank_text=True)
|
||||||
|
xmlParser = etree.XMLParser(remove_comments=True, remove_blank_text=True)
|
||||||
|
|
||||||
|
if sourceFrom == "xml":
|
||||||
|
xmldoc = etree.parse(BytesIO(source.encode("utf-8")), xmlParser)
|
||||||
|
return html.tostring(xmldoc, method="html", pretty_print=True).decode()
|
||||||
|
elif sourceFrom == "html":
|
||||||
|
htmldoc = html.parse(BytesIO(source.encode("utf-8")), htmlParser)
|
||||||
|
return etree.tostring(htmldoc, method="xml", pretty_print=True, doctype="", xml_declaration=True, encoding="utf-8").decode()
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def formatHTML(source: str, prettify: bool) -> str:
|
||||||
|
parser = html.HTMLParser(remove_blank_text=True, remove_comments=True, remove_pis=True)
|
||||||
|
htmlDoc = html.parse(BytesIO(source.encode("utf-8")),parser=parser)
|
||||||
|
if not prettify:
|
||||||
|
return html.tostring(htmlDoc).decode().replace("\n", "").replace("> ", ">")
|
||||||
|
return etree.tostring(htmlDoc, encoding='unicode', pretty_print=True)
|
||||||
|
|
||||||
def formatXML(source: str, prettify: bool) -> str:
|
def formatXML(source: str, prettify: bool) -> str:
|
||||||
"""Method used to format XML
|
"""Method used to format XML
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ def process_xml(request: request, type: str) -> str:
|
|||||||
response_json['result'] = Parser.formatXML(data, True)
|
response_json['result'] = Parser.formatXML(data, True)
|
||||||
elif (type == "minimize"):
|
elif (type == "minimize"):
|
||||||
response_json['result'] = Parser.formatXML(data, False)
|
response_json['result'] = Parser.formatXML(data, False)
|
||||||
|
elif (type == "prettifyHtml"):
|
||||||
|
response_json['result'] = Parser.formatHTML(data, True)
|
||||||
|
elif (type == "minimizeHtml"):
|
||||||
|
response_json['result'] = Parser.formatHTML(data, False)
|
||||||
|
elif (type == "convertHTML"):
|
||||||
|
response_json['result'] = Parser.convertHTML(data, process)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Valid operation types are: xsd, xslt, xpath")
|
raise ValueError("Valid operation types are: xsd, xslt, xpath")
|
||||||
|
|
||||||
@@ -79,5 +85,17 @@ def prettify():
|
|||||||
def minimize():
|
def minimize():
|
||||||
return process_xml(request, "minimize")
|
return process_xml(request, "minimize")
|
||||||
|
|
||||||
|
@app.route("/html/prettify",methods=["POST"])
|
||||||
|
def prettifyHtml():
|
||||||
|
return process_xml(request, "prettifyHtml")
|
||||||
|
|
||||||
|
@app.route("/html/minimize",methods=["POST"])
|
||||||
|
def minimizeHtml():
|
||||||
|
return process_xml(request, "minimizeHtml")
|
||||||
|
|
||||||
|
@app.route("/html/convert",methods=["POST"])
|
||||||
|
def XMLToHTMLConvertion():
|
||||||
|
return process_xml(request, "convertHTML")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run()
|
app.run()
|
||||||
14
Frontend/src/assets/sampleHtml.html
Normal file
14
Frontend/src/assets/sampleHtml.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Example Page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>That's paragraph</p>
|
||||||
|
<br>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -4,7 +4,7 @@ import sampleXML from "@/assets/sampleXml.xml?raw"
|
|||||||
import sampleXSLT from "@/assets/sampleXslt.xml?raw"
|
import sampleXSLT from "@/assets/sampleXslt.xml?raw"
|
||||||
import sampleXSD from "@/assets/sampleXsd.xml?raw"
|
import sampleXSD from "@/assets/sampleXsd.xml?raw"
|
||||||
import sampleXQuery from "@/assets/sampleXQuery.xquery?raw"
|
import sampleXQuery from "@/assets/sampleXQuery.xquery?raw"
|
||||||
|
import sampleHTML from "@assets/sampleHtml.html?raw"
|
||||||
|
|
||||||
const props = defineProps(
|
const props = defineProps(
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,9 @@ function setDefault() {
|
|||||||
case "xquery":
|
case "xquery":
|
||||||
emit(emitName, sampleXQuery)
|
emit(emitName, sampleXQuery)
|
||||||
break;
|
break;
|
||||||
|
case "html":
|
||||||
|
emit(emitName,sampleHTML);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
emit(emitName, sampleXML)
|
emit(emitName, sampleXML)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps(
|
||||||
|
{
|
||||||
|
formatType: {type:String,required:true},
|
||||||
|
code: {type:String,required:true},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function chooseType(formatType: String){
|
||||||
|
if (formatType == "XML Converter"){
|
||||||
|
return "convert";
|
||||||
|
}
|
||||||
|
return formatType.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTypeInfo(){
|
||||||
|
if( props.code.startsWith("<!DOCTYPE") ){
|
||||||
|
return "html"
|
||||||
|
}else{
|
||||||
|
return "xml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBody(){
|
||||||
|
return JSON.stringify({
|
||||||
|
"data": props.code,
|
||||||
|
"process": getTypeInfo(),
|
||||||
|
"processor": "libxml",
|
||||||
|
"version": "1.0"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchLink = document.location.protocol + "//" + document.location.hostname + "/libxml/html/" + chooseType(props.formatType);
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'update:result'
|
||||||
|
])
|
||||||
|
|
||||||
|
function processResponse(formattedCode : any){
|
||||||
|
var result = formattedCode.result;
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function process(){
|
||||||
|
fetch(fetchLink, {body:createBody(), method: "POST"})
|
||||||
|
.then( response => response.json() )
|
||||||
|
.then( formattedCode => emit('update:result', processResponse(formattedCode) ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button class="tool-button" @click="process()">{{ formatType }}</button>
|
||||||
|
</template>
|
||||||
@@ -5,6 +5,7 @@ const restMock = import("@views/RestMockView.vue")
|
|||||||
|
|
||||||
const jsonFormatter = import("@views/JsonFormatterView.vue")
|
const jsonFormatter = import("@views/JsonFormatterView.vue")
|
||||||
const xmlFormatter = import("@views/XmlFormatterView.vue")
|
const xmlFormatter = import("@views/XmlFormatterView.vue")
|
||||||
|
const HtmlFormatterView = import("@views/HtmlFormatterView.vue")
|
||||||
|
|
||||||
const xsltTool = import("@views/XSLTView.vue")
|
const xsltTool = import("@views/XSLTView.vue")
|
||||||
const xsdTool = import("@views/XSDView.vue")
|
const xsdTool = import("@views/XSDView.vue")
|
||||||
@@ -27,6 +28,11 @@ const routes = [
|
|||||||
name: 'jsonFormatter',
|
name: 'jsonFormatter',
|
||||||
component: () => jsonFormatter
|
component: () => jsonFormatter
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/format/html',
|
||||||
|
name: 'htmlFormatter',
|
||||||
|
component: () => HtmlFormatterView
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/xml/xpath',
|
path: '/xml/xpath',
|
||||||
name: 'xpath',
|
name: 'xpath',
|
||||||
|
|||||||
34
Frontend/src/views/HtmlFormatterView.vue
Normal file
34
Frontend/src/views/HtmlFormatterView.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue';
|
||||||
|
import CodeEditorComponent from '@/components/CodeEditorComponent.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import HtmlButtonFormatterComponent from '@/components/formatter/HtmlButtonFormatterComponent.vue';
|
||||||
|
|
||||||
|
|
||||||
|
const html = ref('');
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
html.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTextFieldValue(data: string) {
|
||||||
|
html.value = data.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="layout" class="flex flex-col w-full h-full gap-4">
|
||||||
|
<div id="toolbar" class="flex flex-col gap-4 items-center lg:flex-row place-content-between">
|
||||||
|
<span class="dark:text-slate-100">HTML Formatter</span>
|
||||||
|
<div class="flex flex-wrap gap-2 justify-center">
|
||||||
|
<InsertTemplateComponent stylized-name="HTML" @update:defaultData="setTextFieldValue"></InsertTemplateComponent>
|
||||||
|
<button class="tool-button" @click="clear()">Clear</button>
|
||||||
|
<HtmlButtonFormatterComponent @update:result="setTextFieldValue" :code="html" format-type="Minimize" />
|
||||||
|
<HtmlButtonFormatterComponent @update:result="setTextFieldValue" :code="html" format-type="Prettify" />
|
||||||
|
<HtmlButtonFormatterComponent @update:result="setTextFieldValue" :code="html" format-type="XML Converter" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CodeEditorComponent @update:updated-code="setTextFieldValue" :code="html" :config="{disabled:false,language:'html'}" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user