增加toc目录支持,close #509

sh_branch
liangliangyy 4 years ago
parent 7e96de0d42
commit 79a0651c39

@ -13,12 +13,8 @@
@time: 2017/10/25 下午10:16
"""
from django.test import Client, RequestFactory, TestCase
from blog.models import Article, Category, Tag
from django.contrib.auth import get_user_model
from DjangoBlog.utils import get_current_site
from django.urls import reverse
import datetime
from django.test import TestCase
from DjangoBlog.utils import *
@ -49,8 +45,3 @@ class DjangoBlogTest(TestCase):
}
data = parse_dict_to_url(d)
self.assertIsNotNone(data)
render = BlogMarkDownRenderer()
s = render.autolink('http://www.baidu.com')
self.assertTrue(s.find('nofollow') > 0)
s = render.link('http://www.baidu.com', 'test', 'test')
self.assertTrue(s.find('nofollow') > 0)

@ -9,14 +9,9 @@ import string
import uuid
from hashlib import sha256
import mistune
import requests
from django.contrib.sites.models import Site
from django.core.cache import cache
from mistune import escape, escape_link
from pygments import highlight
from pygments.formatters import html
from pygments.lexers import get_lexer_by_name
logger = logging.getLogger(__name__)
@ -93,82 +88,37 @@ def expire_view_cache(path, servername, serverport, key_prefix=None):
return False
def block_code(text, lang, inlinestyles=False, linenos=False):
'''
markdown代码高亮
:param text:
:param lang:
:param inlinestyles:
:param linenos:
:return:
'''
if not lang:
text = text.strip()
return u'<pre><code>%s</code></pre>\n' % mistune.escape(text)
try:
lexer = get_lexer_by_name(lang, stripall=True)
formatter = html.HtmlFormatter(
noclasses=inlinestyles, linenos=linenos
)
code = highlight(text, lexer, formatter)
if linenos:
return '<div class="highlight">%s</div>\n' % code
return code
except BaseException:
return '<pre class="%s"><code>%s</code></pre>\n' % (
lang, mistune.escape(text)
)
@cache_decorator()
def get_current_site():
site = Site.objects.get_current()
return site
class BlogMarkDownRenderer(mistune.Renderer):
'''
markdown渲染
'''
class CommonMarkdown:
@staticmethod
def _convert_markdown(value):
import markdown
md = markdown.Markdown(
extensions=[
'extra',
'codehilite',
'toc',
'tables',
]
)
body = md.convert(value)
toc = md.toc
return body, toc
def block_code(self, text, lang=None):
# renderer has an options
inlinestyles = self.options.get('inlinestyles')
linenos = self.options.get('linenos')
return block_code(text, lang, inlinestyles, linenos)
def autolink(self, link, is_email=False):
text = link = escape(link)
if is_email:
link = 'mailto:%s' % link
if not link:
link = "#"
site = get_current_site()
nofollow = "" if link.find(site.domain) > 0 else "rel='nofollow'"
return '<a href="%s" %s>%s</a>' % (link, nofollow, text)
def link(self, link, title, text):
link = escape_link(link)
site = get_current_site()
nofollow = "" if link.find(site.domain) > 0 else "rel='nofollow'"
if not link:
link = "#"
if not title:
return '<a href="%s" %s>%s</a>' % (link, nofollow, text)
title = escape(title, quote=True)
return '<a href="%s" title="%s" %s>%s</a>' % (
link, title, nofollow, text)
class CommonMarkdown():
@staticmethod
def get_markdown(value):
renderer = BlogMarkDownRenderer(inlinestyles=False)
def get_markdown_with_toc(value):
body, toc = CommonMarkdown._convert_markdown(value)
return body, toc
mdp = mistune.Markdown(escape=True, renderer=renderer)
return mdp(value)
@staticmethod
def get_markdown(value):
body, toc = CommonMarkdown._convert_markdown(value)
return body
def send_email(emailto, title, content):

@ -1,16 +1,17 @@
import logging
from abc import ABCMeta, abstractmethod, abstractproperty
from abc import abstractmethod
from django.db import models
from django.urls import reverse
from django.conf import settings
from uuslug import slugify
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from DjangoBlog.utils import get_current_site
from DjangoBlog.utils import cache_decorator, cache
from django.db import models
from django.urls import reverse
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from mdeditor.fields import MDTextField
from uuslug import slugify
from DjangoBlog.utils import cache_decorator, cache
from DjangoBlog.utils import get_current_site
logger = logging.getLogger(__name__)
@ -94,6 +95,7 @@ class Article(BaseModel):
on_delete=models.CASCADE)
article_order = models.IntegerField(
'排序,数字越大越靠前', blank=False, null=False, default=0)
show_toc = models.BooleanField("是否显示toc目录", blank=False, null=False, default=False)
category = models.ForeignKey(
'Category',
verbose_name='分类',

@ -2479,17 +2479,26 @@ li #reply-title {
}
.breadcrumb {
margin-bottom: 20px;
list-style: none;
border-radius: 4px;
margin-bottom: 20px;
list-style: none;
border-radius: 4px;
}
.breadcrumb > li {
display: inline-block;
display: inline-block;
}
.breadcrumb > li + li:before {
color: #ccc;
content: "/\00a0";
color: #ccc;
content: "/\00a0";
}
.breadcrumb > .active {
color: #777;
color: #777;
}
.break_line {
height: 1px;
border: none;
/*border-top: 1px dashed #f5d6d6;*/
}

@ -1,59 +1,293 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #ffffff; }
.highlight .c { color: #177500 } /* Comment */
.highlight .err { color: #000000 } /* Error */
.highlight .k { color: #A90D91 } /* Keyword */
.highlight .l { color: #1C01CE } /* Literal */
.highlight .n { color: #000000 } /* Name */
.highlight .o { color: #000000 } /* Operator */
.highlight .ch { color: #177500 } /* Comment.Hashbang */
.highlight .cm { color: #177500 } /* Comment.Multiline */
.highlight .cp { color: #633820 } /* Comment.Preproc */
.highlight .cpf { color: #177500 } /* Comment.PreprocFile */
.highlight .c1 { color: #177500 } /* Comment.Single */
.highlight .cs { color: #177500 } /* Comment.Special */
.highlight .kc { color: #A90D91 } /* Keyword.Constant */
.highlight .kd { color: #A90D91 } /* Keyword.Declaration */
.highlight .kn { color: #A90D91 } /* Keyword.Namespace */
.highlight .kp { color: #A90D91 } /* Keyword.Pseudo */
.highlight .kr { color: #A90D91 } /* Keyword.Reserved */
.highlight .kt { color: #A90D91 } /* Keyword.Type */
.highlight .ld { color: #1C01CE } /* Literal.Date */
.highlight .m { color: #1C01CE } /* Literal.Number */
.highlight .s { color: #C41A16 } /* Literal.String */
.highlight .na { color: #836C28 } /* Name.Attribute */
.highlight .nb { color: #A90D91 } /* Name.Builtin */
.highlight .nc { color: #3F6E75 } /* Name.Class */
.highlight .no { color: #000000 } /* Name.Constant */
.highlight .nd { color: #000000 } /* Name.Decorator */
.highlight .ni { color: #000000 } /* Name.Entity */
.highlight .ne { color: #000000 } /* Name.Exception */
.highlight .nf { color: #000000 } /* Name.Function */
.highlight .nl { color: #000000 } /* Name.Label */
.highlight .nn { color: #000000 } /* Name.Namespace */
.highlight .nx { color: #000000 } /* Name.Other */
.highlight .py { color: #000000 } /* Name.Property */
.highlight .nt { color: #000000 } /* Name.Tag */
.highlight .nv { color: #000000 } /* Name.Variable */
.highlight .ow { color: #000000 } /* Operator.Word */
.highlight .mb { color: #1C01CE } /* Literal.Number.Bin */
.highlight .mf { color: #1C01CE } /* Literal.Number.Float */
.highlight .mh { color: #1C01CE } /* Literal.Number.Hex */
.highlight .mi { color: #1C01CE } /* Literal.Number.Integer */
.highlight .mo { color: #1C01CE } /* Literal.Number.Oct */
.highlight .sb { color: #C41A16 } /* Literal.String.Backtick */
.highlight .sc { color: #2300CE } /* Literal.String.Char */
.highlight .sd { color: #C41A16 } /* Literal.String.Doc */
.highlight .s2 { color: #C41A16 } /* Literal.String.Double */
.highlight .se { color: #C41A16 } /* Literal.String.Escape */
.highlight .sh { color: #C41A16 } /* Literal.String.Heredoc */
.highlight .si { color: #C41A16 } /* Literal.String.Interpol */
.highlight .sx { color: #C41A16 } /* Literal.String.Other */
.highlight .sr { color: #C41A16 } /* Literal.String.Regex */
.highlight .s1 { color: #C41A16 } /* Literal.String.Single */
.highlight .ss { color: #C41A16 } /* Literal.String.Symbol */
.highlight .bp { color: #5B269A } /* Name.Builtin.Pseudo */
.highlight .vc { color: #000000 } /* Name.Variable.Class */
.highlight .vg { color: #000000 } /* Name.Variable.Global */
.highlight .vi { color: #000000 } /* Name.Variable.Instance */
.highlight .il { color: #1C01CE } /* Literal.Number.Integer.Long */
.codehilite .hll {
background-color: #ffffcc
}
.codehilite {
background: #ffffff;
}
.codehilite .c {
color: #177500
}
/* Comment */
.codehilite .err {
color: #000000
}
/* Error */
.codehilite .k {
color: #A90D91
}
/* Keyword */
.codehilite .l {
color: #1C01CE
}
/* Literal */
.codehilite .n {
color: #000000
}
/* Name */
.codehilite .o {
color: #000000
}
/* Operator */
.codehilite .ch {
color: #177500
}
/* Comment.Hashbang */
.codehilite .cm {
color: #177500
}
/* Comment.Multiline */
.codehilite .cp {
color: #633820
}
/* Comment.Preproc */
.codehilite .cpf {
color: #177500
}
/* Comment.PreprocFile */
.codehilite .c1 {
color: #177500
}
/* Comment.Single */
.codehilite .cs {
color: #177500
}
/* Comment.Special */
.codehilite .kc {
color: #A90D91
}
/* Keyword.Constant */
.codehilite .kd {
color: #A90D91
}
/* Keyword.Declaration */
.codehilite .kn {
color: #A90D91
}
/* Keyword.Namespace */
.codehilite .kp {
color: #A90D91
}
/* Keyword.Pseudo */
.codehilite .kr {
color: #A90D91
}
/* Keyword.Reserved */
.codehilite .kt {
color: #A90D91
}
/* Keyword.Type */
.codehilite .ld {
color: #1C01CE
}
/* Literal.Date */
.codehilite .m {
color: #1C01CE
}
/* Literal.Number */
.codehilite .s {
color: #C41A16
}
/* Literal.String */
.codehilite .na {
color: #836C28
}
/* Name.Attribute */
.codehilite .nb {
color: #A90D91
}
/* Name.Builtin */
.codehilite .nc {
color: #3F6E75
}
/* Name.Class */
.codehilite .no {
color: #000000
}
/* Name.Constant */
.codehilite .nd {
color: #000000
}
/* Name.Decorator */
.codehilite .ni {
color: #000000
}
/* Name.Entity */
.codehilite .ne {
color: #000000
}
/* Name.Exception */
.codehilite .nf {
color: #000000
}
/* Name.Function */
.codehilite .nl {
color: #000000
}
/* Name.Label */
.codehilite .nn {
color: #000000
}
/* Name.Namespace */
.codehilite .nx {
color: #000000
}
/* Name.Other */
.codehilite .py {
color: #000000
}
/* Name.Property */
.codehilite .nt {
color: #000000
}
/* Name.Tag */
.codehilite .nv {
color: #000000
}
/* Name.Variable */
.codehilite .ow {
color: #000000
}
/* Operator.Word */
.codehilite .mb {
color: #1C01CE
}
/* Literal.Number.Bin */
.codehilite .mf {
color: #1C01CE
}
/* Literal.Number.Float */
.codehilite .mh {
color: #1C01CE
}
/* Literal.Number.Hex */
.codehilite .mi {
color: #1C01CE
}
/* Literal.Number.Integer */
.codehilite .mo {
color: #1C01CE
}
/* Literal.Number.Oct */
.codehilite .sb {
color: #C41A16
}
/* Literal.String.Backtick */
.codehilite .sc {
color: #2300CE
}
/* Literal.String.Char */
.codehilite .sd {
color: #C41A16
}
/* Literal.String.Doc */
.codehilite .s2 {
color: #C41A16
}
/* Literal.String.Double */
.codehilite .se {
color: #C41A16
}
/* Literal.String.Escape */
.codehilite .sh {
color: #C41A16
}
/* Literal.String.Heredoc */
.codehilite .si {
color: #C41A16
}
/* Literal.String.Interpol */
.codehilite .sx {
color: #C41A16
}
/* Literal.String.Other */
.codehilite .sr {
color: #C41A16
}
/* Literal.String.Regex */
.codehilite .s1 {
color: #C41A16
}
/* Literal.String.Single */
.codehilite .ss {
color: #C41A16
}
/* Literal.String.Symbol */
.codehilite .bp {
color: #5B269A
}
/* Name.Builtin.Pseudo */
.codehilite .vc {
color: #000000
}
/* Name.Variable.Class */
.codehilite .vg {
color: #000000
}
/* Name.Variable.Global */
.codehilite .vi {
color: #000000
}
/* Name.Variable.Instance */
.codehilite .il {
color: #1C01CE
}
/* Literal.Number.Integer.Long */

@ -13,24 +13,24 @@
@time: 2016/11/2 下午11:10
"""
import hashlib
import logging
import random
import urllib
from django import template
from django.db.models import Q
from django.conf import settings
from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.template.defaultfilters import stringfilter
from django.utils.safestring import mark_safe
import random
from django.urls import reverse
from django.utils.safestring import mark_safe
from DjangoBlog.utils import cache
from DjangoBlog.utils import get_current_site
from blog.models import Article, Category, Tag, Links, SideBar, LinkShowType
from django.utils.encoding import force_text
from django.shortcuts import get_object_or_404
import hashlib
import urllib
from comments.models import Comment
from DjangoBlog.utils import cache_decorator, cache
from django.contrib.auth import get_user_model
from oauth.models import OAuthUser
from DjangoBlog.utils import get_current_site
import logging
logger = logging.getLogger(__name__)
@ -64,6 +64,13 @@ def custom_markdown(content):
return mark_safe(CommonMarkdown.get_markdown(content))
@register.simple_tag
def get_markdown_toc(content):
from DjangoBlog.utils import CommonMarkdown
body, toc = CommonMarkdown.get_markdown_with_toc(content)
return mark_safe(toc), mark_safe(body)
@register.filter(is_safe=True)
@stringfilter
def truncatechars_content(content):

@ -1,17 +1,18 @@
import os
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
from django.core.paginator import Paginator
from django.test import Client, RequestFactory, TestCase
from blog.models import Article, Category, Tag, SideBar, Links
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils import timezone
from DjangoBlog.utils import get_current_site, get_sha256
from accounts.models import BlogUser
from blog.forms import BlogSearchForm
from django.core.paginator import Paginator
from blog.models import Article, Category, Tag, SideBar, Links
from blog.templatetags.blog_tags import load_pagination_info, load_articletags
from accounts.models import BlogUser
from django.core.files.uploadedfile import SimpleUploadedFile
from django.conf import settings
from django.urls import reverse
from django.utils import timezone
import os
from django.core.management import call_command
# Create your tests here.
@ -147,8 +148,7 @@ class ArticleTest(TestCase):
response = self.client.get('/sitemap.xml')
self.assertEqual(response.status_code, 200)
from DjangoBlog.utils import block_code
block = block_code("`python`", 'python')
self.client.get("/admin/blog/article/1/delete/")
self.client.get('/admin/servermanager/emailsendlog/')
self.client.get('admin/admin/logentry/')

Binary file not shown.

@ -51,7 +51,17 @@
<p class='read-more'><a
href=' {{ article.get_absolute_url }}'>Read more</a></p>
{% else %}
{{ article.body|custom_markdown }}
{% get_markdown_toc article.body as markdown %}
{% if article.show_toc %}
<b>目录:</b>
{{ markdown.0|safe }}
<hr class="break_line"/>
{% endif %}
<div class="article">
{{ markdown.1|safe }}
</div>
{% endif %}
</div><!-- .entry-content -->

Loading…
Cancel
Save