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