Fix HTML article inclusion

Fix draft inclusion in preview
Enhance cache post content (avoid recomputing md5sum if present)
Add generation duration time
Add post only generation (for Dev)
Remove Draft when it becomes Post
Update blog Copyright
Update TinyMCE plugins for inclusion
Sort tags by name
This commit is contained in:
Gregory Soutade 2016-01-09 20:10:27 +01:00
parent 9b49bf9114
commit e0b8f544ff
14 changed files with 213 additions and 181 deletions

View File

@ -1,14 +1,21 @@
v0.4 (08/11/2015)
v0.4 (09/01/2016)
** User **
Redirect user to comment when it's added and not to begining of page
Enable code coloration support with Markdown syntax
Add article inclusion
Add autofocus to login page
Sort tags by name
Add generation duration time
** Dev **
Support Django 1.8
Enhance cache post content (avoid recomputing md5sum if present)
Add post only generation (for Dev)
** Bugs **
Always update modification date when post/draft is saved
Support Django 1.8
Draft were not remove from _draft directory when moving to Post
v0.3 (13/11/2014)

4
README
View File

@ -1,6 +1,6 @@
Dynastie is static blog generator delivered under GPL v3 licence terms.
Current version is 0.5
Current version is 0.4
Requirements :
Django >= 1.8, libapache2-mod-wsgi if you want to use Dynastie with Apache. PyGments (Optional).
@ -10,7 +10,7 @@ Installation :
* Update dynastie/wsgy.py (with $PWD/../) don't forget the final slash !
* Update dynastie/settings.py (SECRET_KEY...)
* Run ./manage.sh syncdb and create a superuser
* Run ./manage.sh runserver
* Run ./manage.sh runserver 0.0.0.0:8080
or
* Copy (and edit) apache_dynastie.conf in /etc/apache2/sites-available, and create a symbolic link from /etc/apache2/sites-enabled to /etc/apache2/sites-available

View File

@ -57,11 +57,13 @@ class DynastieGenerator:
URI = "http://indefero.soutade.fr/p/dynastie"
def __init__(self, hash_posts={}, hash_posts_content={}):
def __init__(self, request, hash_posts={}, hash_posts_content={}):
self.report = ''
self.somethingWrote = False
self.request = request
self.hash_posts = hash_posts
self.hash_posts_content = hash_posts_content
self.user = request and request.user or None
def addReport(self, string, color=''):
if string in self.report: return

View File

@ -31,8 +31,8 @@ from dynastie.generators import markdown2
class Index(DynastieGenerator):
def __init__(self, hash_posts={}, hash_posts_content={}):
DynastieGenerator.__init__(self, hash_posts, hash_posts_content)
def __init__(self, request=None, hash_posts={}, hash_posts_content={}):
DynastieGenerator.__init__(self, request, hash_posts, hash_posts_content)
self.hooks = {'posts' : self.createPosts,
'title' : self.createTitle,
@ -53,6 +53,7 @@ class Index(DynastieGenerator):
self.filename = 'index'
self.dirname = ''
self.blog = None
self.parent_posts = []
self.resetCounters()
@ -143,7 +144,8 @@ class Index(DynastieGenerator):
nav = nav + href + str(self.cur_page+1) + '.html">Next &gt;</a> '
nav = nav + href + str(self.nb_pages-1) + '.html">Last &gt;&gt;</a>'
new_dom = parseString('<div class="navigation">' + nav + '</div>')
s = '<div class="navigation">' + nav + '</div>'
new_dom = parseString(s.encode('utf-8'))
new_node = new_dom.getElementsByTagName('div')[0]
res = new_node.cloneNode(True)
root.replaceChild(res, node)
@ -230,23 +232,45 @@ class Index(DynastieGenerator):
return (b, p)
def _manageInternalPosts(self, post, text, parent_posts, user=None):
def _manageInternalPosts(self, post, text, user=None):
from dynastie.models import Post
if not user: user = post.author
if post and post.content_format != Post.CONTENT_TEXT: return text
internal_posts = re.search('\[\[([0-9]+)\]\]', text)
if not internal_posts: return text
for post_id in internal_posts.groups():
post_id = int(post_id)
if post_id in parent_posts: continue
_,post = self._have_I_right(user, post_id)
if not post: continue
new_content = self._loadPostContent(post, parent_posts)
if new_content:
text = text.replace('[[' + str(post_id) + ']]', new_content)
# Markdown replace
if not post or (post and post.content_format == Post.CONTENT_TEXT):
internal_posts = re.search('\[\[([0-9]+)\]\]', text)
if internal_posts:
for post_id in internal_posts.groups():
post_id = int(post_id)
if post_id in self.parent_posts: continue
_,post = self._have_I_right(user, post_id)
if not post: continue
new_content = self._loadPostContent(post)
if new_content:
text = text.replace('[[' + str(post_id) + ']]', new_content)
if internal_posts: return text
# HTML replace
if not post or (post and post.content_format == Post.CONTENT_HTML):
while True:
start = text.find('<dyn:postinclude')
if start == -1: break
end = text.find('</dyn:postinclude>')
if end < start:
self.addError('Invalid <dyn:postinclude> tags in ' + self.filename)
break
internal_posts = re.search('post_id="([0-9]+)"', text[start:])
if not internal_posts: break
for post_id in internal_posts.groups():
_,post = self._have_I_right(user, post_id)
if not post: break
new_content = self._loadPostContent(post)
if new_content:
text = text.replace(text[start:end+18], new_content.encode('utf-8'))
return text
def _loadPostContent(self, post, parent_posts):
def _loadPostContent(self, post):
from dynastie.models import Post
blog = post.blog
@ -255,29 +279,33 @@ class Index(DynastieGenerator):
filename = blog.src_path + '/_post/' + str(post.id)
if not os.path.exists(filename):
self.addError('File does not exists ' + filename)
return None
filename2 = blog.src_path + '/_draft/' + str(post.id)
if not os.path.exists(filename2):
self.addError('File does not exists ' + filename)
return None
else:
filename = filename2
if not filename in self.hash_posts_content:
f = open(filename, 'rb')
post_content = f.read()
f.close()
self.parent_posts.append(post.id)
post_content = self._manageInternalPosts(post, post_content)
if post.content_format == Post.CONTENT_TEXT:
parent_posts.append(post.id)
post_content = self._manageInternalPosts(post, post_content, parent_posts)
post_content = markdown2.markdown(post_content, extras=['fenced-code-blocks'])
self.hash_posts_content[filename] = post_content
else:
post_content = self.hash_posts_content[filename]
return post_content
def createPost(self, posts, dom, post_elem, root):
from dynastie.models import Post
post = self.cur_post_obj
if post.id in self.hash_posts and not self.first_try:
node = self.hash_posts[post.id]
node,_ = self.hash_posts[post.id]
return node.cloneNode(0)
values = {'post_content': '', 'author': 'Unknown'}
@ -286,7 +314,8 @@ class Index(DynastieGenerator):
except:
pass
post_content = _loadPostContent(post, [])
self.parent_posts = []
post_content = self._loadPostContent(post)
if not post_content: return None
post_content = self.pygmentCode(post_content)
@ -302,32 +331,26 @@ class Index(DynastieGenerator):
new_node = dom.createTextNode(post_content)
content_node.appendChild(new_node)
writer = StrictUTF8Writer()
post_elem.writexml(writer)
content = writer.getvalue().encode('utf-8')
md5 = hashlib.md5()
md5.update(content)
if post.id in self.hash_posts:
# Here, we are in first_try, check that computed
# post has the same result than the one in cache
self.first_try = False
writer = StrictUTF8Writer()
node = self.hash_posts[post.id]
node.writexml(writer)
content1 = writer.getvalue().encode('utf-8')
writer = StrictUTF8Writer()
post_elem.writexml(writer)
content2 = writer.getvalue().encode('utf-8')
_,md5_2 = self.hash_posts[post.id]
md5_1 = hashlib.md5()
md5_1.update(content1)
md5_2 = hashlib.md5()
md5_2.update(content2)
# If not, clear cache
if md5_1.digest() != md5_2.digest():
if md5.digest() != md5_2:
self.hash_posts = {}
self.hash_posts[post.id] = post_elem.cloneNode(0)
self.hash_posts[post.id] = (post_elem.cloneNode(0), md5.digest())
else:
self.hash_posts[post.id] = post_elem.cloneNode(0)
self.hash_posts[post.id] = (post_elem.cloneNode(0), md5.digest())
return post_elem
@ -544,6 +567,7 @@ class Index(DynastieGenerator):
from dynastie.models import Post, Blog
self.blog = blog
self.parent_posts = []
dom = self.parseTemplate(blog, src, output, 'index')
if dom is None: return self.report

View File

@ -217,6 +217,7 @@ class Post(Index):
self.blog = blog
self.parent_posts = []
posts = Post.objects.all()
return self._generate(blog, src, output, posts)
@ -230,26 +231,30 @@ class Post(Index):
v['date'] = now.strftime("%A, %d %B %Y %H:%m")
v['post_content'] = ''
post_content = self._manageInternalPosts(None, values['content'], [], self.user)
post_content = self._manageInternalPosts(None, values['content'], self.user)
post_content = self.pygmentCode(post_content)
self.simpleTransform(v, dom, root, node)
content_nodes = root.getElementsByTagName("div")
post_transform = ('post_content')
content_node = None
for content_node in content_nodes:
the_class = content_node.getAttribute('class')
if not the_class in post_transform:
continue
if the_class == 'post_content':
new_node = dom.createTextNode(post_content)
content_node.appendChild(new_node)
s = u'<div>' + post_content + u'</div>'
new_node = parseString(s.encode('utf-8'))
for n in new_node.childNodes[0].childNodes:
content_node.appendChild(n)
break
post_nodes = dom.getElementsByTagNameNS(self.URI, "post")
post_elem = post_nodes[0]
post_elem.parentNode.removeChild(post_elem)
return post_elem
return content_node
def preview(self, request, src, values):
from dynastie.models import Blog
@ -258,7 +263,8 @@ class Post(Index):
# Override all hooks
self.hooks = {'post' : self.createPreview,
'tags' : self.createTags}
'tags' : self.createTags,
}
if not os.path.exists(src + '/_post.html'):
self.addError('No _post.html found, exiting')

View File

@ -171,8 +171,9 @@ class Blog(models.Model):
if errors:
raise Exception(errors)
def generate(self):
self.report = '<br/><br/>Generation of ' + datetime.now().strftime("%d/%m/%Y at %H:%M:%S") + '<br/>\n'
def generate(self, request):
start_time = datetime.now()
self.report = ''
self.load_generators()
self.copytree(self.src_path, self.output_path)
generated = []
@ -190,7 +191,33 @@ class Blog(models.Model):
if not r is None:
self.report = self.report + '<br/>\n' + r
return self.report
duration = datetime.now() - start_time
t = '<br/><br/>Generation of ' + start_time.strftime("%d/%m/%Y at %H:%M:%S") + '<br/>\n'
t = t + 'Duration ' + str(duration) + '<br/><br/>\n'
return t + self.report
def generate_post(self, request, post):
from dynastie.generators import post as PostGenerator
start_time = datetime.now()
self.report = ''
self.load_generators()
self.copytree(self.src_path, self.output_path)
post_list = [post]
hash_posts = {}
hash_posts_content = {}
engine = globals()['post']
for name, obj in inspect.getmembers(engine):
if inspect.isclass(obj) and obj.__module__.startswith("dynastie.generators") \
and obj.__module__.endswith("post"):
e = obj(request, hash_posts, hash_posts_content)
self.report = e._generate(self, self.src_path, self.output_path, post_list)
break
# report = PostGenerator()._generate(self, self.src_path, self.output_path, post_list)
duration = datetime.now() - start_time
t = '<br/><br/>Generation of ' + start_time.strftime("%d/%m/%Y at %H:%M:%S") + ' post ' + str(post.id) + '<br/>\n'
t = t + 'Duration ' + str(duration) + '<br/><br/>\n'
return t + self.report
class Editor(models.Model):
name = models.CharField(max_length=255, unique=True)
@ -443,6 +470,10 @@ def delete_tag_signal(sender, **kwargs):
def delete_post_signal(sender, **kwargs):
kwargs['instance'].remove()
@receiver(post_delete, sender=Draft)
def delete_draft_signal(sender, **kwargs):
kwargs['instance'].remove()
@receiver(pre_delete, sender=Post)
def pre_delete_post_signal(sender, **kwargs):
post = kwargs['instance']

View File

@ -77,6 +77,7 @@
<div class="menu_content_header">Archives</div>
<div class="menu_content_content">
<ul>
<li><a href="/archive/2015">2015</a></li>
<li><a href="/archive/2014">2014</a></li>
<li><a href="/archive/2013">2013</a></li>
<li><a href="/archive/2012">2012</a></li>
@ -94,7 +95,7 @@
</div>
<footer>
<div class="footer">
Copyright © 2010-2015 Grégory Soutadé.<br/>
Copyright © 2010-2016 Grégory Soutadé.<br/>
Tous droits réservés.
</div>
</footer>

View File

@ -78,6 +78,7 @@
<div class="menu_content_header">Archives</div>
<div class="menu_content_content">
<ul>
<li><a href="/archive/2015">2015</a></li>
<li><a href="/archive/2014">2014</a></li>
<li><a href="/archive/2013">2013</a></li>
<li><a href="/archive/2012">2012</a></li>
@ -95,7 +96,7 @@
</div>
<footer>
<div class="footer">
Copyright © 2010-2015 Grégory Soutadé.<br/>
Copyright © 2010-2016 Grégory Soutadé.<br/>
Tous droits réservés.
</div>
</footer>

View File

@ -341,13 +341,13 @@ a img
.inlineimage
{
display:inline;
margin-right: 50px;
margin-right: 20px;
}
a .inlineimage
{
display:inline;
margin-right: 50px;
margin-right: 20px;
}
h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited
@ -463,68 +463,68 @@ ul li
}
/* Pygments */
.highlight { background-color: #e8e8e8; }
.color_emacs_hll { background-color: #ffffcc }
.color_emacs_c { color: #008800; font-style: italic } /* Comment */
.color_emacs_err { border: 1px solid #FF0000 } /* Error */
.color_emacs_k { color: #AA22FF; font-weight: bold } /* Keyword */
.color_emacs_o { color: #666666 } /* Operator */
.color_emacs_cm { color: #008800; font-style: italic } /* Comment.Multiline */
.color_emacs_cp { color: #008800 } /* Comment.Preproc */
.color_emacs_c1 { color: #008800; font-style: italic } /* Comment.Single */
.color_emacs_cs { color: #008800; font-weight: bold } /* Comment.Special */
.color_emacs_gd { color: #A00000 } /* Generic.Deleted */
.color_emacs_ge { font-style: italic } /* Generic.Emph */
.color_emacs_gr { color: #FF0000 } /* Generic.Error */
.color_emacs_gh { color: #000080; font-weight: bold } /* Generic.Heading */
.color_emacs_gi { color: #00A000 } /* Generic.Inserted */
.color_emacs_go { color: #808080 } /* Generic.Output */
.color_emacs_gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.color_emacs_gs { font-weight: bold } /* Generic.Strong */
.color_emacs_gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.color_emacs_gt { color: #0040D0 } /* Generic.Traceback */
.color_emacs_kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */
.color_emacs_kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */
.color_emacs_kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */
.color_emacs_kp { color: #AA22FF } /* Keyword.Pseudo */
.color_emacs_kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */
.color_emacs_kt { color: #00BB00; font-weight: bold } /* Keyword.Type */
.color_emacs_m { color: #666666 } /* Literal.Number */
.color_emacs_s { color: #BB4444 } /* Literal.String */
.color_emacs_na { color: #BB4444 } /* Name.Attribute */
.color_emacs_nb { color: #AA22FF } /* Name.Builtin */
.color_emacs_nc { color: #0000FF } /* Name.Class */
.color_emacs_no { color: #880000 } /* Name.Constant */
.color_emacs_nd { color: #AA22FF } /* Name.Decorator */
.color_emacs_ni { color: #999999; font-weight: bold } /* Name.Entity */
.color_emacs_ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.color_emacs_nf { color: #00A000 } /* Name.Function */
.color_emacs_nl { color: #A0A000 } /* Name.Label */
.color_emacs_nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.color_emacs_nt { color: #008000; font-weight: bold } /* Name.Tag */
.color_emacs_nv { color: #B8860B } /* Name.Variable */
.color_emacs_ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.color_emacs_w { color: #bbbbbb } /* Text.Whitespace */
.color_emacs_mf { color: #666666 } /* Literal.Number.Float */
.color_emacs_mh { color: #666666 } /* Literal.Number.Hex */
.color_emacs_mi { color: #666666 } /* Literal.Number.Integer */
.color_emacs_mo { color: #666666 } /* Literal.Number.Oct */
.color_emacs_sb { color: #BB4444 } /* Literal.String.Backtick */
.color_emacs_sc { color: #BB4444 } /* Literal.String.Char */
.color_emacs_sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */
.color_emacs_s2 { color: #BB4444 } /* Literal.String.Double */
.color_emacs_se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.color_emacs_sh { color: #BB4444 } /* Literal.String.Heredoc */
.color_emacs_si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.color_emacs_sx { color: #008000 } /* Literal.String.Other */
.color_emacs_sr { color: #BB6688 } /* Literal.String.Regex */
.color_emacs_s1 { color: #BB4444 } /* Literal.String.Single */
.color_emacs_ss { color: #B8860B } /* Literal.String.Symbol */
.color_emacs_bp { color: #AA22FF } /* Name.Builtin.Pseudo */
.color_emacs_vc { color: #B8860B } /* Name.Variable.Class */
.color_emacs_vg { color: #B8860B } /* Name.Variable.Global */
.color_emacs_vi { color: #B8860B } /* Name.Variable.Instance */
.color_emacs_il { color: #666666 } /* Literal.Number.Integer.Long */
.codehilite, .highlight { background-color: #e8e8e8; }
.hl, .color_emacs_hll { background-color: #ffffcc }
.c, .color_emacs_c { color: #008800; font-style: italic } /* Comment */
.er, .color_emacs_err { border: 1px solid #FF0000 } /* Error */
.k, .color_emacs_k { color: #AA22FF; font-weight: bold } /* Keyword */
.o, .color_emacs_o { color: #666666 } /* Operator */
.cm, .color_emacs_cm { color: #008800; font-style: italic } /* Comment.Multiline */
.cp, .color_emacs_cp { color: #008800 } /* Comment.Preproc */
.c1, .color_emacs_c1 { color: #008800; font-style: italic } /* Comment.Single */
.cs, .color_emacs_cs { color: #008800; font-weight: bold } /* Comment.Special */
.gd, .color_emacs_gd { color: #A00000 } /* Generic.Deleted */
.ge, .color_emacs_ge { font-style: italic } /* Generic.Emph */
.gr, .color_emacs_gr { color: #FF0000 } /* Generic.Error */
.gh, .color_emacs_gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi, .color_emacs_gi { color: #00A000 } /* Generic.Inserted */
.go, .color_emacs_go { color: #808080 } /* Generic.Output */
.gp, .color_emacs_gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.gs, .color_emacs_gs { font-weight: bold } /* Generic.Strong */
.gu, .color_emacs_gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt, .color_emacs_gt { color: #0040D0 } /* Generic.Traceback */
.kc, .color_emacs_kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */
.kd, .color_emacs_kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */
.kn, .color_emacs_kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */
.kp, .color_emacs_kp { color: #AA22FF } /* Keyword.Pseudo */
.kr, .color_emacs_kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */
.kt, .color_emacs_kt { color: #00BB00; font-weight: bold } /* Keyword.Type */
.m, .color_emacs_m { color: #666666 } /* Literal.Number */
.s, .color_emacs_s { color: #BB4444 } /* Literal.String */
.na, .color_emacs_na { color: #BB4444 } /* Name.Attribute */
.nb, .color_emacs_nb { color: #AA22FF } /* Name.Builtin */
.nc, .color_emacs_nc { color: #0000FF } /* Name.Class */
.no, .color_emacs_no { color: #880000 } /* Name.Constant */
.nd, .color_emacs_nd { color: #AA22FF } /* Name.Decorator */
.ni, .color_emacs_ni { color: #999999; font-weight: bold } /* Name.Entity */
.ne, .color_emacs_ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.nf, .color_emacs_nf { color: #00A000 } /* Name.Function */
.nl, .color_emacs_nl { color: #A0A000 } /* Name.Label */
.nn, .color_emacs_nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.nt, .color_emacs_nt { color: #008000; font-weight: bold } /* Name.Tag */
.nv, .color_emacs_nv { color: #B8860B } /* Name.Variable */
.ow, .color_emacs_ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.w, .color_emacs_w { color: #bbbbbb } /* Text.Whitespace */
.mf, .color_emacs_mf { color: #666666 } /* Literal.Number.Float */
.mh, .color_emacs_mh { color: #666666 } /* Literal.Number.Hex */
.mi, .color_emacs_mi { color: #666666 } /* Literal.Number.Integer */
.mo, .color_emacs_mo { color: #666666 } /* Literal.Number.Oct */
.sb, .color_emacs_sb { color: #BB4444 } /* Literal.String.Backtick */
.sc, .color_emacs_sc { color: #BB4444 } /* Literal.String.Char */
.sd, .color_emacs_sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */
.s2, .color_emacs_s2 { color: #BB4444 } /* Literal.String.Double */
.se, .color_emacs_se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.sh, .color_emacs_sh { color: #BB4444 } /* Literal.String.Heredoc */
.si, .color_emacs_si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.sx, .color_emacs_sx { color: #008000 } /* Literal.String.Other */
.sr, .color_emacs_sr { color: #BB6688 } /* Literal.String.Regex */
.s1, .color_emacs_s1 { color: #BB4444 } /* Literal.String.Single */
.ss, .color_emacs_ss { color: #B8860B } /* Literal.String.Symbol */
.bp, .color_emacs_bp { color: #AA22FF } /* Name.Builtin.Pseudo */
.vc, .color_emacs_vc { color: #B8860B } /* Name.Variable.Class */
.vg, .color_emacs_vg { color: #B8860B } /* Name.Variable.Global */
.vi, .color_emacs_vi { color: #B8860B } /* Name.Variable.Instance */
.il, .color_emacs_il { color: #666666 } /* Literal.Number.Integer.Long */
#search_form
{

View File

@ -3,7 +3,7 @@ tinyMCE.init({
// General options
mode : "textareas",
theme : "advanced",
plugins : "autolink,lists,spellchecker,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template,dynastiecolor",
plugins : "autolink,lists,spellchecker,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template,dynastiecolor,dynastieinclude",
editor_selector : "mceAdvanced",
encoding : "raw",
entities : "",
@ -14,7 +14,7 @@ tinyMCE.init({
// Theme options
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,charmap,emotions,iespell,media,advhr,dynastiecolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,charmap,emotions,iespell,media,advhr,dynastiecolor,dynastieinclude",
// theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,spellchecker,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,blockquote,pagebreak,|,insertfile,insertimage",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
@ -85,4 +85,4 @@ function switchEditor()
help.style.display="block";
// tinymce.execCommand('mceToggleEditor',false,'content');
}
}
}

View File

@ -1,50 +0,0 @@
/**
* editor_plugin_src.js
*
* Copyright 2012, Grégory Soutadé
* Released under LGPL License.
*
*/
(function() {
tinymce.create('tinymce.plugins.DynastieColor', {
init : function(ed, url) {
var t = this, css = tinymce.explode(ed.settings.content_css);
t.editor = ed;
// Force absolute CSS urls
tinymce.each(css, function(u, k) {
css[k] = ed.documentBaseURI.toAbsolute(u);
});
ed.addCommand('mceDynastieColor', function() {
ed.windowManager.open({
file : ed.getParam("plugin_dynastiecolor_pageurl", url + "/dynastiecolor.html"),
width : parseInt(ed.getParam("plugin_dynastiecolor_width", "700")),
height : parseInt(ed.getParam("plugin_dynastiecolor_height", "800")),
resizable : "yes",
scrollbars : "yes",
popup_css : css ? css.join(',') : ed.baseURI.toAbsolute("themes/" + ed.settings.theme + "/skins/" + ed.settings.skin + "/content.css"),
}, {
base : ed.documentBaseURI.getURI()
});
});
ed.addButton('dynastiecolor', {title : 'Insert code', cmd : 'mceDynastieColor', image : url + "/img/dynastiecolor.png"});
},
getInfo : function() {
return {
longname : 'DynastieColor',
author : 'Grégory Soutadé',
authorurl : 'http://soutade.fr',
infourl : 'http://indefero.soutade.fr/p/dynastie',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
}
});
// Register plugin
tinymce.PluginManager.add('dynastiecolor', tinymce.plugins.DynastieColor);
})();

View File

@ -0,0 +1 @@
editor_plugin_src.js

View File

@ -23,7 +23,7 @@
<b>Drafts</b>
<table>
{% for draft in drafts %}
<tr><td><a href="/draft/edit/{{ draft.id }}">{{ draft.id }}</a></td><td>{{ draft.title }}</td><td>{{ draft.creation_date }}</td><td>{{ draft.modification_date }}</td><td><a href="/draft/delete/{{ draft.id }}" onclick="return confirm('Do you really want to delete this item ?')">Delete</a></td></tr>
<tr><td><a href="/draft/edit/{{ draft.id }}">{{ draft.id }}</a></td><td>{{ draft.title }}</td><td>{{ draft.category.name }}</td><td>{{ draft.creation_date }}</td><td>{{ draft.modification_date }}</td><td><a href="/draft/delete/{{ draft.id }}" onclick="return confirm('Do you really want to delete this item ?')">Delete</a></td></tr>
{% endfor %}
</table><br/>
{% endif %}

View File

@ -47,6 +47,7 @@ urlpatterns = patterns('',
url(r'^draft/edit/(\d+)$', 'dynastie.views.edit_draft', name='edit_draft'),
url(r'^draft/delete/(\d+)$', 'dynastie.views.delete_draft', name='delete_draft'),
url(r'^generate/(\d+)$', 'dynastie.views.generate', name='generate'),
url(r'^generate/(\d+)/(\d+)$','dynastie.views.generate_post',name='generate_post'),
url(r'^preview/(\d+)$', 'dynastie.views.preview', name='preview'),
url(r'^tinyMCEExternalList/post/add/(\d+)$', 'dynastie.views.tinymcelist_add', name='tinymce'),
url(r'^tinyMCEExternalList/post/edit/(\d+)$', 'dynastie.views.tinymcelist_edit', name='tinymce'),

View File

@ -498,7 +498,7 @@ def add_post(request, blog_id):
return render(request, 'add_post.html', {
'form': form, 'blog_id' : blog_id,
'all_tags' : Tag.objects.all(),
'all_tags' : Tag.objects.all().order_by('name'),
'editor' : 'html'
})
@ -528,7 +528,7 @@ def edit_post(request, post_id):
if 'cancel' in request.POST:
return HttpResponseRedirect('/blog/' + str(blog_id))
else:
form = PostForm(instance=post, initial={'text_tags':', '.join((tag.name) for tag in post.tags.all())})
form = PostForm(instance=post, initial={'text_tags':', '.join((tag.name) for tag in post.tags.all().order_by('name'))})
filename = b.src_path + '/_post/' + str(post.pk)
if os.path.exists(filename):
@ -544,7 +544,7 @@ def edit_post(request, post_id):
return render(request, 'edit_post.html', {
'form': form, 'post_id' : post_id, 'content' : content,
'blog_id' : blog_id, 'comments' : comment_list,
'all_tags' : Tag.objects.all(),
'all_tags' : Tag.objects.all().order_by('name'),
'editor' : post.get_editor()
})
@ -588,7 +588,7 @@ def edit_draft(request, draft_id):
if 'cancel' in request.POST:
return HttpResponseRedirect('/blog/' + str(blog_id))
else:
form = PostForm(instance=draft, initial={'text_tags':', '.join((tag.name) for tag in draft.tags.all())})
form = PostForm(instance=draft, initial={'text_tags':', '.join((tag.name) for tag in draft.tags.all().order_by('name'))})
filename = b.src_path + '/_draft/' + str(draft.pk)
if os.path.exists(filename):
@ -601,7 +601,7 @@ def edit_draft(request, draft_id):
return render(request, 'edit_draft.html', {
'form': form, 'draft_id' : draft_id, 'content' : content,
'blog_id' : blog_id,
'all_tags' : Tag.objects.all(),
'all_tags' : Tag.objects.all().order_by('name'),
'editor' : draft.get_editor()
})
@ -649,7 +649,15 @@ def _generate(request, blog_id, report):
def generate(request, blog_id):
b,_ = have_I_right(request, blog_id)
report = b.generate()
report = b.generate(request)
return _generate(request, blog_id, report)
@login_required
def generate_post(request, blog_id, post_id):
b,post = have_I_right(request, blog_id, post_id)
report = b.generate_post(request, post)
return _generate(request, blog_id, report)
@ -708,7 +716,7 @@ def preview(request, blog_id):
content = request.POST['content']
if request.POST['editor'] == 'text':
from dynastie.generators import markdown2
content = markdown2.markdown(content)
content = markdown2.markdown(content, extras=['fenced-code-blocks'])
values = {'title' : request.POST['title'], \
'author' : request.user.first_name + ' ' + request.user.last_name, \
@ -721,7 +729,7 @@ def preview(request, blog_id):
if inspect.isclass(obj) and obj.__module__.startswith("dynastie.generators") \
and obj.__module__.endswith("post"):
e = obj()
content = e.preview(b.src_path, values)
content = e.preview(request, b.src_path, values)
break
output = b.output_path