Issue
I'm new to Django. In Django i would like to compare two texts, between frontend and backend, and receive a message if they are the same or different. In reality these two texts are two short HTML codes. The page can reload easily, I'm only interested in the logic and code behind comparing the two texts (and not the use of Ajax, jQuery, JS, but if it doesn't reload it's obviously better).
INPUT USER. A text will be inserted in the front-end by the user, in a black div
(no textarea) with contenteditable="true"
which is already present in my code. I have already prepared an example text in the black panel, so I would like to compare the entire block of html text (from <!DOCTYPE html>
up to </html>
). For several reasons i want to use a div, and not a textarea.
TEXT TO COMPARE IN THE BACKEND. While the other text will be contained in the backend (in a variable or something similar), and it will be the same html code (considering that the purpose is precisely comparison). I inserted the text to be compared into a variable named corrected_text_backend
, but I don't know if it's a good idea, because in the future I would like to add conditions to the comparison, for example comparing only small parts of code (and not the entire code). So I would like to use a better way if it exists.
COMPARISION RESULT. Then i will click on the button and in the gray rectangle i would like to print CORRECT: the two texts are the same
or ERROR: the two texts are different
.
Important is that i don't want to use textarea, but as already said I want to use the div with contenteditable="true" that I already have in my code.
I'm having problems with the logic and code and can't proceed with the code in views.py
. Can you help me and show me how? I'm new to Django, sorry.
INDEX.HTML
{% load static %}
<!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>University</title>
<link rel="stylesheet" href ="{% static 'css/styleparagone.css' %}" type="text/css">
</head>
<body>
<div class="test">
<div>Input User</div>
<div class="hilite row">
<pre class="hilite-colors"><code class="language-html"></code></pre>
<div
data-lang="html"
class="hilite-editor"
contenteditable="true"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
><!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1 class="heading">This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html></div>
</div>
<div>Comparison Result</div>
<div class="result row2 rowstyle2"></div>
</div>
<form action="{% url 'function_comparison' %}" method="post">
{% csrf_token %}
<button type="submit" name='mybtn'>Button</button>
</form>
</div>
<script src="{% static 'js/editor.js' %}"></script>
</body>
</html>
EDITOR.JS
/// CODE EDITOR ///
const elHTML = document.querySelector(`[data-lang="html"]`);
const elCSS = document.querySelector(`[data-lang="css"]`);
const elJS = document.querySelector(`[data-lang="js"]`);
const elPreview = document.querySelector("#preview");
const hilite = (el) => {
const elCode = el.previousElementSibling.querySelector("code");
elCode.textContent = el.textContent;
delete elCode.dataset.highlighted;
hljs.highlightElement(elCode);
};
const preview = () => {
const encodedCSS = encodeURIComponent(`<style>${elCSS.textContent}</style>`);
const encodedHTML = encodeURIComponent(elHTML.textContent);
const encodedJS = encodeURIComponent(`<scr` + `ipt>${elJS.textContent}</scr` + `ipt>`);
const dataURL = `data:text/html;charset=utf-8,${encodedCSS + encodedHTML + encodedJS}`;
elPreview.src = dataURL;
};
// Initialize!
[elHTML, elCSS, elJS].forEach((el) => {
el.addEventListener("input", () => {
hilite(el);
preview();
});
hilite(el);
});
preview();
CSS
.row {
width: 500px;
padding: 10px;
height: 150px; /* Should be removed. Only for demonstration */
}
.rowstyle1 {
background-color: black;
color: white;
}
.row2 {
margin-top: 20px;
width: 500px;
padding: 10px;
height: 15px; /* Should be removed. Only for demonstration */
}
.rowstyle2 {
background-color: #ededed;;
color: black;
}
/******** CODE EDITOR CSS **********/
/* Scrollbars */
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 0px;
}
::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.3);
border-radius: 1rem;
}
.hilite {
position: relative;
background: #1e1e1e;
height: 120px;
overflow: auto;
width: 500px;
height: 250px;
}
.hilite-colors code,
.hilite-editor {
padding: 1rem !important;
top: 0;
left: 0;
right: 0;
bottom: 0;
white-space: pre-wrap;
font: 13px/1.4 monospace;
width: 100%;
background: transparent;
border: 0;
outline: 0;
}
/* THE OVERLAYING CONTENTEDITABLE WITH TRANSPARENT TEXT */
.hilite-editor {
display: inline-block;
position: relative;
color: transparent; /* Make text invisible */
caret-color: hsl( 50, 75%, 70%); /* But keep caret visible */
width: 100%;
}
/* THE UNDERLAYING DIV WITH HIGHLIGHT COLORS */
.hilite-colors {
position: absolute;
user-select: none;
width: 100%;
color: white;
MYAPP/URLS.PY
from django.urls import path
from . import views
from . import views as function_comparison
urlpatterns=[
path('', views.index, name='index'),
path('function_comparison/', function_comparison,name="function_comparison"),
]
PROJECT/URLS.PY
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('App1.urls')),
]
MYAPP/VIEWS.PY
from django.shortcuts import render, redirect
from django.http import HttpResponse
def index(request):
"""View function for home page of site."""
return render(request, 'index.html')
def function_comparison(request):
if request.method == "GET":
corrected_text_backend = """
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1 class="heading">This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>"""
.....
return render(request, "index.html")
Solution
Ok, so here is a working example of what i think you meant: (There was a lot of stuff to change, which i will explain per section)
<!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>University</title>
<style>
.row {
width: 500px;
padding: 10px;
height: 150px; /* Should be removed. Only for demonstration */
}
.rowstyle1 {
background-color: black;
color: white;
}
.row2 {
margin-top: 20px;
width: 100%;
}
.rowstyle2 {
background-color: #ededed;;
color: black;
}
/******** CODE EDITOR CSS **********/
/* Scrollbars */
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 0px;
}
::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.3);
border-radius: 1rem;
}
.hilite {
position: relative;
background: #1e1e1e;
height: 120px;
overflow: auto;
width: 500px;
height: 250px;
}
.hilite-colors code,
.hilite-editor {
padding: 1rem !important;
top: 0;
left: 0;
right: 0;
bottom: 0;
white-space: pre-wrap;
font: 13px/1.4 monospace;
width: 100%;
background: transparent;
border: 0;
outline: 0;
}
/* THE OVERLAYING CONTENTEDITABLE WITH TRANSPARENT TEXT */
.hilite-editor {
display: inline-block;
position: relative;
color: white;
caret-color: hsl( 50, 75%, 70%); /* But keep caret visible */
width: 100%;
}
/* THE UNDERLAYING DIV WITH HIGHLIGHT COLORS */
.hilite-colors {
position: absolute;
user-select: none;
width: 100%;
color: white;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
</head>
<body>
<div class="test">
<div>Input User</div>
<div class="hilite row">
<pre class="hilite-colors"><code class="language-html"></code></pre>
<div
id="userinput"
data-lang="html"
class="hilite-editor"
contenteditable="true"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
><!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1 class="heading">This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
</div>
</div>
</div>
<button type="submit" onclick="getFormData();">Button</button>
<br><br>
<div>Comparison Result</div>
<div class="result row2 rowstyle2" id="result">
{% comment %} Ajax innerHTML result {% endcomment %}
</div>
</div>
{% comment %} script to disable "want to send form again" popup {% endcomment %}
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>
<script>
function getFormData() {
$.ajax({
type:"GET",
url: "{% url 'function_comparison' %}",
data:{
"formData": document.getElementById("userinput").innerText
},
success: function (response) {
document.getElementById("result").innerHTML = response.message;
},
error: function (response) {
console.log(response)
}
});
}
</script>
</body>
</html>
Here I used AJAX to process the request, this allows us to collect the information which was previously in a form.
The reason I used AJAX was because you want to use a div instead of an input field (textarea), and if you send a form to the backend it expects input-field data, which we did not have. So now it collects the div-data and sends that as if you were sending a form.
After sending the AJAX request to views.py
:
from django.http import JsonResponse
from django.shortcuts import render
import difflib
from django.conf import settings
import re
def index(request):
return render(request, "index.html")
def function_comparison(request):
context = {}
if request.method == "GET":
user_form_data = request.GET.get("formData", None)
with open('user_input.html', 'w') as outfile:
outfile.write(user_form_data)
file1 = open('source_compare.html', 'r').readlines()
file2 = open('user_input.html', 'r').readlines()
file1_stripped = []
file2_stripped = []
for file1_text in file1:
file1_text = re.sub("\s\s+", "", file1_text)
file1_stripped.append(file1_text)
for file2_text in file2:
file2_text = re.sub("\s\s+", "", file2_text)
file2_stripped.append(file2_text)
# re sub here checks for each item in the list, and replace a space, or multiple space depending, with an empty string
if file2_stripped[-1] == "":
file2_stripped.pop()
# check if the last item in the user input's list is an empty line with no additional text and remove it if thats the case.
htmlDiffer = difflib.HtmlDiff(linejunk=difflib.IS_LINE_JUNK, charjunk=difflib.IS_CHARACTER_JUNK)
htmldiffs = htmlDiffer.make_file(file1_stripped, file2_stripped, context=True)
if "No Differences Found" in htmldiffs:
context["message"] = "Yes, it is the same!"
if settings.DEBUG:
if "No Differences Found" not in htmldiffs:
context["message"] = htmldiffs
else:
if "No Differences Found" not in htmldiffs:
context["message"] = "No, it is not the same!"
return JsonResponse(context, status=200)
Here the source_compare.html would look like this:
And the user_input.html
is empty.
And that's it.
Here are the results:
If it is the same (where tabs, spaces and trailing and leading spaces don't matter):
You could tweak it to your liking to not show the left html, and only the right one in case of a difference, but that is up to preference. More information on how to tweak the result can be found here: https://docs.python.org/3/library/difflib.html
This is also a solution to what you said about wanting to compare only the <head>
tag, because the difference html result will only show the parts that have changed.
EDIT 2:
To change if you want to show tables or text, you could check in your views.py
if the setting DEBUG
in your settings.py
is set to True
or False
See updated views.py
above.
Answered By - Tim-Bolhoeve
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.