diff --git a/ChangeLog b/ChangeLog index 750a91d..f40cdc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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) diff --git a/README b/README index f68d2ef..2316919 100644 --- a/README +++ b/README @@ -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 diff --git a/dynastie/generators/generator.py b/dynastie/generators/generator.py index 03b2dff..2bb18b5 100755 --- a/dynastie/generators/generator.py +++ b/dynastie/generators/generator.py @@ -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 diff --git a/dynastie/generators/index.py b/dynastie/generators/index.py index 5dde0ae..5f342fa 100755 --- a/dynastie/generators/index.py +++ b/dynastie/generators/index.py @@ -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 > ' nav = nav + href + str(self.nb_pages-1) + '.html">Last >>' - new_dom = parseString('') + s = '' + 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('') + + if end < start: + self.addError('Invalid 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 diff --git a/dynastie/generators/post.py b/dynastie/generators/post.py index 5c48f80..5627b93 100755 --- a/dynastie/generators/post.py +++ b/dynastie/generators/post.py @@ -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'
' + post_content + u'
' + 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') diff --git a/dynastie/models.py b/dynastie/models.py index ffab2a6..7d76ed2 100755 --- a/dynastie/models.py +++ b/dynastie/models.py @@ -171,8 +171,9 @@ class Blog(models.Model): if errors: raise Exception(errors) - def generate(self): - self.report = '

Generation of ' + datetime.now().strftime("%d/%m/%Y at %H:%M:%S") + '
\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 + '
\n' + r - return self.report + duration = datetime.now() - start_time + t = '

Generation of ' + start_time.strftime("%d/%m/%Y at %H:%M:%S") + '
\n' + t = t + 'Duration ' + str(duration) + '

\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 = '

Generation of ' + start_time.strftime("%d/%m/%Y at %H:%M:%S") + ' post ' + str(post.id) + '
\n' + t = t + 'Duration ' + str(duration) + '

\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'] diff --git a/dynastie/sites/blog.soutade.fr/_base.html b/dynastie/sites/blog.soutade.fr/_base.html index 9da6c73..89a077b 100755 --- a/dynastie/sites/blog.soutade.fr/_base.html +++ b/dynastie/sites/blog.soutade.fr/_base.html @@ -77,6 +77,7 @@
diff --git a/dynastie/sites/blog.soutade.fr/_base_post.html b/dynastie/sites/blog.soutade.fr/_base_post.html index 3110b9c..f01e26e 100644 --- a/dynastie/sites/blog.soutade.fr/_base_post.html +++ b/dynastie/sites/blog.soutade.fr/_base_post.html @@ -78,6 +78,7 @@
diff --git a/dynastie/sites/blog.soutade.fr/css/blog.css b/dynastie/sites/blog.soutade.fr/css/blog.css index 0d2dbd9..7889e30 100755 --- a/dynastie/sites/blog.soutade.fr/css/blog.css +++ b/dynastie/sites/blog.soutade.fr/css/blog.css @@ -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 { diff --git a/dynastie/static/js/dynastie.js b/dynastie/static/js/dynastie.js index e1d6017..aeeeaa4 100755 --- a/dynastie/static/js/dynastie.js +++ b/dynastie/static/js/dynastie.js @@ -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'); } -} \ No newline at end of file +} diff --git a/dynastie/static/js/tinymce/jscripts/tiny_mce/plugins/dynastiecolor/editor_plugin.js b/dynastie/static/js/tinymce/jscripts/tiny_mce/plugins/dynastiecolor/editor_plugin.js deleted file mode 100755 index 40ac9fb..0000000 --- a/dynastie/static/js/tinymce/jscripts/tiny_mce/plugins/dynastiecolor/editor_plugin.js +++ /dev/null @@ -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); -})(); \ No newline at end of file diff --git a/dynastie/static/js/tinymce/jscripts/tiny_mce/plugins/dynastiecolor/editor_plugin.js b/dynastie/static/js/tinymce/jscripts/tiny_mce/plugins/dynastiecolor/editor_plugin.js new file mode 120000 index 0000000..3a96ace --- /dev/null +++ b/dynastie/static/js/tinymce/jscripts/tiny_mce/plugins/dynastiecolor/editor_plugin.js @@ -0,0 +1 @@ +editor_plugin_src.js \ No newline at end of file diff --git a/dynastie/templates/view_blog.html b/dynastie/templates/view_blog.html index 84f1e2b..c20939a 100755 --- a/dynastie/templates/view_blog.html +++ b/dynastie/templates/view_blog.html @@ -23,7 +23,7 @@ Drafts {% for draft in drafts %} - + {% endfor %}
{{ draft.id }}{{ draft.title }}{{ draft.creation_date }}{{ draft.modification_date }}Delete
{{ draft.id }}{{ draft.title }}{{ draft.category.name }}{{ draft.creation_date }}{{ draft.modification_date }}Delete

{% endif %} diff --git a/dynastie/urls.py b/dynastie/urls.py index d70ec25..1e2203f 100755 --- a/dynastie/urls.py +++ b/dynastie/urls.py @@ -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'), diff --git a/dynastie/views.py b/dynastie/views.py index 3215659..c83d8c5 100755 --- a/dynastie/views.py +++ b/dynastie/views.py @@ -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