diff options
| -rw-r--r-- | blog/feed.py | 31 | ||||
| -rw-r--r-- | blog/views.py | 5 | ||||
| -rw-r--r-- | static/css/styles.css | 5 | ||||
| -rw-r--r-- | templates/blog/partials/base.html | 3 | ||||
| -rw-r--r-- | templates/blog/post.html | 2 | ||||
| -rw-r--r-- | templates/blog_admin/edit_post.html | 290 |
6 files changed, 175 insertions, 161 deletions
diff --git a/blog/feed.py b/blog/feed.py index 93a8b060..67389a86 100644 --- a/blog/feed.py +++ b/blog/feed.py @@ -1,8 +1,6 @@ import re import requests -# from .context_processors import add_excerpt -from bs4 import BeautifulSoup from django.conf import settings from django.contrib.syndication.views import Feed from django.utils import feedgenerator @@ -11,19 +9,6 @@ from django.utils.feedgenerator import Enclosure from .models import Post request_domain = settings.DEBUG and 'https://preview.thatcomputerscientist.com' or 'https://thatcomputerscientist.com' -mathjax_path = f'{request_domain}/static/js/MathJax/MathJax.js?config=default' -mathjax_config = ''' -<script type="text/x-mathjax-config"> - MathJax.Hub.Config({ - jax: ["input/TeX", "output/HTML-CSS"], - tex2jax: { - inlineMath: [['$','$'], ['\\(','\\)']], - processEscapes: true - }, - "HTML-CSS": { availableFonts: ["TeX"] }, - }); -</script> -''' class RSSFeed(Feed): title = 'That Computer Scientist' @@ -32,24 +17,14 @@ class RSSFeed(Feed): feed_type = feedgenerator.Rss201rev2Feed def items(self): - return Post.objects.all().filter(is_public=True).order_by('-date') + return Post.objects.all().filter(is_public=True).order_by('-date')[:10] def item_title(self, item): return item.title def item_description(self, item): - r = requests.get(f'{request_domain}/weblog/{item.slug}') - soup = BeautifulSoup(r.text, 'html.parser') - article_body = soup.find(id='article-body') - for img in article_body.find_all('img'): - if not img.get('id'): - img['style'] = 'float: left; margin: 5px 11px 5px 0px; max-width: 710px;' + img.get('style', '') - - article_body = str(article_body) - article_body = re.sub(r"[\x00-\x08\x0B-\x1F\x7F-\x9F]", "", str(article_body)) - article_body += f'<script type="text/javascript" src="{mathjax_path}"></script>' - article_body += mathjax_config - return article_body + body = re.sub(r"[\x00-\x08\x0B-\x1F\x7F-\x9F]", "", str(item.body)) + return body def item_link(self, item): return f'{request_domain}/weblog/{item.slug}' diff --git a/blog/views.py b/blog/views.py index f24ade8d..b253db6e 100644 --- a/blog/views.py +++ b/blog/views.py @@ -159,7 +159,10 @@ def post(request, slug): soup = BeautifulSoup(post.body, 'html.parser') code_blocks = soup.find_all('pre', class_='ql-syntax') for code_block in code_blocks: - code_block.replace_with(BeautifulSoup(highlight_code_blocks(code_block), 'html.parser')) + data_language = code_block.get('data-language') + if data_language == 'true': + data_language = None + code_block.replace_with(BeautifulSoup(highlight_code_blocks(code_block, language=data_language), 'html.parser')) # float: right every other image images = soup.find_all('img') diff --git a/static/css/styles.css b/static/css/styles.css index 526a4fc9..8639081b 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -387,14 +387,14 @@ blockquote { #editor-container img { float: left; margin: 5px 11px 5px 0px; - max-width: 710px; } #article-body img.block, #editor-container img.block { margin: 5px auto; display: block; - height: auto; + max-height: none; + max-width: 710px; } #article-body h2, @@ -514,5 +514,6 @@ blockquote { #article-body img, #editor-container img { max-height: 300px; + max-width: 300px; } }
\ No newline at end of file diff --git a/templates/blog/partials/base.html b/templates/blog/partials/base.html index 12c4d6ea..b9c4b48d 100644 --- a/templates/blog/partials/base.html +++ b/templates/blog/partials/base.html @@ -155,7 +155,8 @@ <script src="{% static 'js/tl.js' %}"></script> {% if request.COOKIES.summonOneko == 'true' %} <script src="{% static 'js/oneko.js' %}"></script> - {% endif %} {% block scripts %} {% endblock %} + {% endif %} + {% block scripts %} {% endblock %} <!-- Google tag (gtag.js) --> <script async diff --git a/templates/blog/post.html b/templates/blog/post.html index 8ecb1a29..2a927c3d 100644 --- a/templates/blog/post.html +++ b/templates/blog/post.html @@ -49,7 +49,7 @@ <div id="article-body"> {{ post.first_paragraph | safe }} - <img style="width: 100%; height: 473.3333px; max-height: 473.3333px; margin: 20px auto; display: block; border-radius: 8px;" src="{% url 'ignis:post_image' '710' post.id %}.gif" alt="Post Image for {{ post.title }}" id="arpi_"> + <img style="border-radius: 8px;" src="{% url 'ignis:post_image' '710' post.id %}.gif" alt="Post Image for {{ post.title }}" id="arpi_" class="block"> <hr> {{ post.body | safe }} </div> diff --git a/templates/blog_admin/edit_post.html b/templates/blog_admin/edit_post.html index 452565ba..164bd1a1 100644 --- a/templates/blog_admin/edit_post.html +++ b/templates/blog_admin/edit_post.html @@ -1,144 +1,177 @@ -{% extends 'blog/partials/base.html' %} {% block content %} -{% load static %} - +{% extends 'blog/partials/base.html' %} {% block content %} {% load static %} <link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet" /> -<div class="main"> - <div style="position: relative;"> - <h2>Editing Post: {{ post.title }}</h2> - <br> - <div id="math-formula-block" style=" - position: absolute; - top: 95px; - left: 185px; - width: 320px; - background: #121212; - padding: 10px 20px 15px 20px; - z-index: 3; - display: none; - "> - <textarea id="math_formula" placeholder="Type MathJax Formula to Insert..." style="width: 300px; display: block; margin: 0px 0px 20px 0px;" rows="5"></textarea> - <input type="radio" name="math_formula_type" value="inline" checked /> <span style="margin-right: 10px; position: relative; top: -2.5px;">Inline</span> - <input type="radio" name="math_formula_type" value="block" style="margin-left: 10px;"> <span style="margin-right: 10px; position: relative; top: -2.5px;">Block</span> - <button id="math_formula_insert" style="float: right; margin-top: -5px;" class="button button-special">Insert</button> - <button id="math_formula_cancel" style="float: right; margin-top: -5px; margin-right: 10px;" class="button">Cancel</button> - </div> - <form action="{% url 'blog-admin:edit-post' post.slug %}" method="post" enctype="multipart/form-data"> - {% csrf_token %} - - <div class="form-group"> - <div id="toolbar-container"> - <span class="ql-formats"> - <button class="ql-header" value="1"></button> - <button class="ql-header" value="2"></button> - </span> - <span class="ql-formats"> - <button class="ql-bold"></button> - <button class="ql-italic"></button> - <button class="ql-underline"></button> - <button class="ql-strike"></button> - </span> - <span class="ql-formats"> - <button class="ql-blockquote"></button> - <button class="ql-code-block"></button> - </span> - <span class="ql-formats"> - <button class="ql-script" value="sub"></button> - <button class="ql-script" value="super"></button> - </span> - - <span class="ql-formats"> - <button class="ql-list" value="ordered"></button> - <button class="ql-list" value="bullet"></button> - </span> - <span class="ql-formats"> - <select class="ql-align"></select> - </span> - <span class="ql-formats"> - <button class="ql-link"></button> - <button class="ql-image"></button> - <button class="ql-formula"></button> - </span> - <span class="ql-formats"> - <button class="ql-clean"></button> - </span> - </div> - <div id="editor-container" style="width: 730px;"></div> - </div> - <div class="form-group" style="display: none;"> - <textarea name="body" id="body">{{ post.body }}</textarea> - </div> - <br> - <div class="form-group"> - <button type="submit" class="button button-special">Save</button> - </div> - </form> +<style> + button { + color: #444; + } + textarea#body { + margin: 10px 0 0 0; + width: 710px; + height: 400px; + } +</style> +<h1>Editing Post: {{ post.title }}</h1> +<div style="max-width: 730px"> + <div id="toolbar-container"> + <span class="ql-formats"> + <button class="ql-header" value="1"></button> + <button class="ql-header" value="2"></button> + </span> + <span class="ql-formats"> + <button class="ql-bold"></button> + <button class="ql-italic"></button> + <button class="ql-underline"></button> + <button class="ql-strike"></button> + </span> + <span class="ql-formats"> + <button class="ql-blockquote"></button> + <button class="ql-code-block"></button> + </span> + <span class="ql-formats"> + <button class="ql-script" value="sub"></button> + <button class="ql-script" value="super"></button> + </span> + <span class="ql-formats"> + <button class="ql-list" value="ordered"></button> + <button class="ql-list" value="bullet"></button> + </span> + <span class="ql-formats"> + <select class="ql-align"></select> + </span> + <span class="ql-formats"> + <button class="ql-link"></button> + <button class="ql-image"></button> + </span> + <span class="ql-formats"> + <button class="ql-clean"></button> + <button class="ql-html" onclick="toggleHTML()">HTML</button> + </span> </div> + <div id="editor-container"></div> + <form action="{% url 'blog-admin:edit-post' post.slug %}" method="post"> + {% csrf_token %} + <div style="display: none" id="HTMLContent"> + <textarea name="body" id="body">{{ post.body }}</textarea> + </div> + <br /> + <button type="submit" class="button button-special">Save</button> + </form> </div> +{% endblock %} {% block scripts %} <script src="https://cdn.quilljs.com/1.3.6/quill.min.js"></script> <script> const Delta = Quill.import("delta"); - function showFormulaInsert(quill) { - var formulaInsert = document.getElementById("math_formula_insert"); - var formulaCancel = document.getElementById("math_formula_cancel"); - var formulaInput = document.getElementById("math_formula"); - var formulaContainer = document.getElementById("math-formula-block"); - formulaContainer.style.display = "block"; - formulaInsert.onclick = function () { - var formula = formulaInput.value; - var formulaType = document.querySelector('input[name="math_formula_type"]:checked').value; - if (formulaType == "inline") { - quill.insertText(quill.getSelection().index, " $" + formula + "$ "); - } else { - quill.insertText(quill.getSelection().index, " $$" + formula + "$$ "); + let BlockEmbed = Quill.import("blots/block/embed"); + + class ImageBlock extends BlockEmbed { + static create(value) { + let node = super.create(); + node.setAttribute("src", value.url); + + if (value.size == "block") { + node.classList.add("block"); } - formulaContainer.style.display = "none"; + + return node; + } + + static value(node) { + return { + url: node.getAttribute("src"), + }; + } + + html() { + const { url } = this.value(); + return `<img src="${url}">`; } - formulaCancel.onclick = function () { - formulaContainer.style.display = "none"; + + static blotName = "image"; + static tagName = "img"; + } + + Quill.register(ImageBlock); + + function imageUpload(formData, quill, range, size) { + const imageURL = "{% url 'ignis:upload_image' %}"; + const headers = { + "X-CSRFToken": "{{ csrf_token }}", + }; + $.ajax({ + url: imageURL, + type: "POST", + headers: headers, + data: formData, + processData: false, + contentType: false, + success: function (data) { + const imageURL = data.url; + quill.updateContents( + new Delta() + .retain(range.index) + .delete(range.length) + .insert({ image: { url: imageURL, size: size } }) + ); + }, + error: function (err) { + console.log(err); + }, + }); + } + + class CodeBlock extends Quill.import("formats/code-block") { + static create(value) { + let domNode = super.create(); + domNode.setAttribute("data-language", value); + return domNode; } } - var quill = new Quill("#editor-container", { + CodeBlock.blotName = "code-block"; + CodeBlock.tagName = "pre"; + Quill.register(CodeBlock); + + const quill = new Quill("#editor-container", { modules: { toolbar: { container: "#toolbar-container", handlers: { - formula: function () { - showFormulaInsert(quill); + "code-block": function() { + const language = prompt("Enter language", "text"); + this.quill.format("code-block", language); + }, image: function () { - // open image upload dialog - let fileInput = this.container.querySelector('input.ql-image[type=file]'); + var size = prompt( + "Set Image Size: 0 (default) for inline, 1 for block", + "0" + ); + if (size == "0") { + size = ""; + } else if (size == "1") { + size = "block"; + } else { + size = ""; + } + let fileInput = this.container.querySelector( + "input.ql-image[type=file]" + ); if (fileInput == null) { - fileInput = document.createElement('input'); - fileInput.setAttribute('type', 'file'); - fileInput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon'); - fileInput.classList.add('ql-image'); - fileInput.addEventListener('change', () => { + fileInput = document.createElement("input"); + fileInput.setAttribute("type", "file"); + fileInput.setAttribute( + "accept", + "image/png, image/gif, image/jpeg, image/bmp, image/x-icon" + ); + fileInput.classList.add("ql-image"); + fileInput.addEventListener("change", () => { if (fileInput.files != null && fileInput.files[0] != null) { let range = this.quill.getSelection(true); - const url = "/ignis/upload"; const formData = new FormData(); formData.append("image", fileInput.files[0]); - formData.append("id", {{ post.id }}); - // append csrf token in header - const headers = new Headers(); - headers.append("X-CSRFToken", "{{ csrf_token }}"); - - fetch(url, { - method: "POST", - headers: headers, - body: formData, - }).then((response) => response.json()).then((result) => { - this.quill.updateContents(new Delta() - .retain(range.index) - .delete(range.length) - .insert({ image: result.url }) - , Quill.sources.USER); - fileInput.value = ""; - }).catch((error) => { - console.error("Error:", error); - }); + formData.append("id", "{{ post.id }}"); + const imageURL = imageUpload(formData, this.quill, range, size); + fileInput.value = ""; } }); this.container.appendChild(fileInput); @@ -152,18 +185,19 @@ theme: "snow", }); - // update body on text change + var content = $("#body").val(); + content = content.replace(/<p><br><\/p>/g, ""); + console.log(content); + //quill.setContents(quill.clipboard.convert(content), "silent"); + quill.clipboard.dangerouslyPasteHTML(0, content); quill.on("text-change", function (delta, oldDelta, source) { document.getElementById("body").value = quill.root.innerHTML; }); - try { - const value = document.getElementById("body").value; - const newValue = value.replace(/<p><br><\/p>/g, ""); - const delta = quill.clipboard.convert(value); - quill.setContents(delta, "silent"); - } catch (e) { - console.log(e); + function toggleHTML() { + $("#HTMLContent").toggle(); } + + </script> -{% endblock %} +{% endblock %}
\ No newline at end of file |
