From e4f8a604cb87c43a60fa0ae1a567d68d9ab1cd33 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sat, 23 Mar 2013 16:05:56 -0500 Subject: [PATCH 01/23] Adding new plugin Code Include This plugin allows you to include other files as a code block with syntax highlighting in ReST articles. You'll need docutils>0.10, as there was a circular import bug in the 0.10 release. --- pelicanext/code_include/README.rst | 70 ++++++++++ pelicanext/code_include/__init__.py | 0 pelicanext/code_include/code_include.py | 167 ++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 pelicanext/code_include/README.rst create mode 100644 pelicanext/code_include/__init__.py create mode 100644 pelicanext/code_include/code_include.py diff --git a/pelicanext/code_include/README.rst b/pelicanext/code_include/README.rst new file mode 100644 index 0000000..0f3c0dc --- /dev/null +++ b/pelicanext/code_include/README.rst @@ -0,0 +1,70 @@ +Include Pygments highlighted code with reStructuredText +======================================================= + +:author: Colin Dunklau + +Use this plugin to make writing coding tutorials easier! You can +maintain the example source files separately from the actual article. + + +Based heavily on ``docutils.parsers.rst.directives.Include``. Include +a file and output as a code block formatted with pelican's Pygments +directive. + +Note that this is broken with the Docutils 0.10 release, there's a +circular import. It was fixed in trunk: +http://sourceforge.net/p/docutils/bugs/214/ + +Directives +---------- + +.. code:: rst + + .. code-include:: incfile.py + :lexer: string, name of the Pygments lexer to use, default 'text' + :encoding: string, encoding with which to open the file + :tab-width: integer, hard tabs are replaced with `tab-width` spaces + :start-line: integer, starting line to begin reading include file + :end-line: integer, last line from include file to display + +``start-line``, and ``end-line`` have the same meaning as in the +docutils ``include`` directive, that is, they index from zero. + +Example +------- + +./incfile.py: + +.. code:: python + + # These two comment lines will not + # be included in the output + import random + + insults = ['I fart in your general direction', + 'your mother was a hampster', + 'your father smelt of elderberries'] + + def insult(): + print random.choice(insults) + # This comment line will be included + # ...but this one won't + +./yourfile.rst: + +.. code:: rst + + How to Insult the English + ========================= + + :author: Pierre Devereaux + + A function to help insult those silly English knnnnnnniggets: + + .. code-include:: incfile.py + :lexer: python + :encoding: utf-8 + :tab-width: 4 + :start-line: 3 + :end-line: 11 + diff --git a/pelicanext/code_include/__init__.py b/pelicanext/code_include/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py new file mode 100644 index 0000000..b03a1c7 --- /dev/null +++ b/pelicanext/code_include/code_include.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +import os.path + +from docutils import io, nodes, statemachine, utils +from docutils.utils.error_reporting import SafeString, ErrorString +from docutils.parsers.rst import directives, Directive + +from pelican.rstdirectives import Pygments + +""" +Include Pygments highlighted code with reStructuredText +======================================================= + +:author: Colin Dunklau + +Use this plugin to make writing coding tutorials easier! You can +maintain the example source files separately from the actual article. + + +Based heavily on ``docutils.parsers.rst.directives.Include``. Include +a file and output as a code block formatted with pelican's Pygments +directive. + +Note that this is broken with the Docutils 0.10 release, there's a +circular import. It was fixed in trunk: +http://sourceforge.net/p/docutils/bugs/214/ + +Directives +---------- + +.. code:: rst + + .. code-include:: incfile.py + :lexer: string, name of the Pygments lexer to use, default 'text' + :encoding: string, encoding with which to open the file + :tab-width: integer, hard tabs are replaced with `tab-width` spaces + :start-line: integer, starting line to begin reading include file + :end-line: integer, last line from include file to display + +``start-line``, and ``end-line`` have the same meaning as in the +docutils ``include`` directive, that is, they index from zero. + +Example +------- + +./incfile.py: + +.. code:: python + + # These two comment lines will not + # be included in the output + import random + + insults = ['I fart in your general direction', + 'your mother was a hampster', + 'your father smelt of elderberries'] + + def insult(): + print random.choice(insults) + # This comment line will be included + # ...but this one won't + +./yourfile.rst: + +.. code:: rst + + How to Insult the English + ========================= + + :author: Pierre Devereaux + + A function to help insult those silly English knnnnnnniggets: + + .. code-include:: incfile.py + :lexer: python + :encoding: utf-8 + :tab-width: 4 + :start-line: 3 + :end-line: 11 + +""" + +class CodeInclude(Directive): + + """ + Include content read from a separate source file, and highlight + it with the given lexer (using pelican.rstdirectives.CodeBlock) + + The encoding of the included file can be specified. Only a part + of the given file argument may be included by specifying start + and end line. Hard tabs will be replaced with ``tab-width`` + spaces. + """ + + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + option_spec = {'lexer': directives.unchanged, + 'encoding': directives.encoding, + 'tab-width': int, + 'start-line': int, + 'end-line': int} + + def run(self): + """Include a file as part of the content of this reST file.""" + if not self.state.document.settings.file_insertion_enabled: + raise self.warning('"%s" directive disabled.' % self.name) + source = self.state_machine.input_lines.source( + self.lineno - self.state_machine.input_offset - 1) + source_dir = os.path.dirname(os.path.abspath(source)) + path = directives.path(self.arguments[0]) + path = os.path.normpath(os.path.join(source_dir, path)) + path = utils.relative_path(None, path) + path = nodes.reprunicode(path) + encoding = self.options.get( + 'encoding', self.state.document.settings.input_encoding) + e_handler=self.state.document.settings.input_encoding_error_handler + tab_width = self.options.get( + 'tab-width', self.state.document.settings.tab_width) + try: + self.state.document.settings.record_dependencies.add(path) + include_file = io.FileInput(source_path=path, + encoding=encoding, + error_handler=e_handler) + except UnicodeEncodeError, error: + raise self.severe(u'Problems with "%s" directive path:\n' + 'Cannot encode input file path "%s" ' + '(wrong locale?).' % + (self.name, SafeString(path))) + except IOError, error: + raise self.severe(u'Problems with "%s" directive path:\n%s.' % + (self.name, ErrorString(error))) + startline = self.options.get('start-line', None) + endline = self.options.get('end-line', None) + try: + if startline or (endline is not None): + lines = include_file.readlines() + rawtext = ''.join(lines[startline:endline]) + else: + rawtext = include_file.read() + except UnicodeError, error: + raise self.severe(u'Problem with "%s" directive:\n%s' % + (self.name, ErrorString(error))) + + include_lines = statemachine.string2lines(rawtext, tab_width, + convert_whitespace=True) + + # default lexer to 'text' + lexer = self.options.get('lexer', 'text') + + self.options['source'] = path + codeblock = Pygments(self.name, + [lexer], # arguments + {}, # no options for this directive + include_lines, # content + self.lineno, + self.content_offset, + self.block_text, + self.state, + self.state_machine) + return codeblock.run() + + +def register(): + directives.register_directive('code-include', CodeInclude) + From ccef5de59dacb58e2fbd81d95f7c15c64448ca1d Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sat, 23 Mar 2013 16:24:56 -0500 Subject: [PATCH 02/23] Some minor tweaks: documentation, py3 compliance Pulled most documentation out of code to avoid desync Fixed unicode literals Fixed except syntax for py3 compliance --- pelicanext/code_include/code_include.py | 74 ++----------------------- 1 file changed, 6 insertions(+), 68 deletions(-) diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py index b03a1c7..9d108c7 100644 --- a/pelicanext/code_include/code_include.py +++ b/pelicanext/code_include/code_include.py @@ -17,68 +17,6 @@ Include Pygments highlighted code with reStructuredText Use this plugin to make writing coding tutorials easier! You can maintain the example source files separately from the actual article. - -Based heavily on ``docutils.parsers.rst.directives.Include``. Include -a file and output as a code block formatted with pelican's Pygments -directive. - -Note that this is broken with the Docutils 0.10 release, there's a -circular import. It was fixed in trunk: -http://sourceforge.net/p/docutils/bugs/214/ - -Directives ----------- - -.. code:: rst - - .. code-include:: incfile.py - :lexer: string, name of the Pygments lexer to use, default 'text' - :encoding: string, encoding with which to open the file - :tab-width: integer, hard tabs are replaced with `tab-width` spaces - :start-line: integer, starting line to begin reading include file - :end-line: integer, last line from include file to display - -``start-line``, and ``end-line`` have the same meaning as in the -docutils ``include`` directive, that is, they index from zero. - -Example -------- - -./incfile.py: - -.. code:: python - - # These two comment lines will not - # be included in the output - import random - - insults = ['I fart in your general direction', - 'your mother was a hampster', - 'your father smelt of elderberries'] - - def insult(): - print random.choice(insults) - # This comment line will be included - # ...but this one won't - -./yourfile.rst: - -.. code:: rst - - How to Insult the English - ========================= - - :author: Pierre Devereaux - - A function to help insult those silly English knnnnnnniggets: - - .. code-include:: incfile.py - :lexer: python - :encoding: utf-8 - :tab-width: 4 - :start-line: 3 - :end-line: 11 - """ class CodeInclude(Directive): @@ -123,13 +61,13 @@ class CodeInclude(Directive): include_file = io.FileInput(source_path=path, encoding=encoding, error_handler=e_handler) - except UnicodeEncodeError, error: - raise self.severe(u'Problems with "%s" directive path:\n' + except UnicodeEncodeError as error: + raise self.severe('Problems with "%s" directive path:\n' 'Cannot encode input file path "%s" ' '(wrong locale?).' % (self.name, SafeString(path))) - except IOError, error: - raise self.severe(u'Problems with "%s" directive path:\n%s.' % + except IOError as error: + raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) startline = self.options.get('start-line', None) endline = self.options.get('end-line', None) @@ -139,8 +77,8 @@ class CodeInclude(Directive): rawtext = ''.join(lines[startline:endline]) else: rawtext = include_file.read() - except UnicodeError, error: - raise self.severe(u'Problem with "%s" directive:\n%s' % + except UnicodeError as error: + raise self.severe('Problem with "%s" directive:\n%s' % (self.name, ErrorString(error))) include_lines = statemachine.string2lines(rawtext, tab_width, From 23d426aed7e098f00e768e94f10c1584bc37bd13 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sat, 23 Mar 2013 17:12:22 -0500 Subject: [PATCH 03/23] PEP 8 fixes --- pelicanext/code_include/code_include.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py index 9d108c7..3edd94a 100644 --- a/pelicanext/code_include/code_include.py +++ b/pelicanext/code_include/code_include.py @@ -1,12 +1,5 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -import os.path - -from docutils import io, nodes, statemachine, utils -from docutils.utils.error_reporting import SafeString, ErrorString -from docutils.parsers.rst import directives, Directive - -from pelican.rstdirectives import Pygments """ Include Pygments highlighted code with reStructuredText @@ -19,6 +12,15 @@ maintain the example source files separately from the actual article. """ +import os.path + +from docutils import io, nodes, statemachine, utils +from docutils.utils.error_reporting import SafeString, ErrorString +from docutils.parsers.rst import directives, Directive + +from pelican.rstdirectives import Pygments + + class CodeInclude(Directive): """ @@ -53,7 +55,7 @@ class CodeInclude(Directive): path = nodes.reprunicode(path) encoding = self.options.get( 'encoding', self.state.document.settings.input_encoding) - e_handler=self.state.document.settings.input_encoding_error_handler + e_handler = self.state.document.settings.input_encoding_error_handler tab_width = self.options.get( 'tab-width', self.state.document.settings.tab_width) try: @@ -68,7 +70,7 @@ class CodeInclude(Directive): (self.name, SafeString(path))) except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % - (self.name, ErrorString(error))) + (self.name, ErrorString(error))) startline = self.options.get('start-line', None) endline = self.options.get('end-line', None) try: @@ -89,9 +91,9 @@ class CodeInclude(Directive): self.options['source'] = path codeblock = Pygments(self.name, - [lexer], # arguments + [lexer], # arguments {}, # no options for this directive - include_lines, # content + include_lines, # content self.lineno, self.content_offset, self.block_text, @@ -102,4 +104,3 @@ class CodeInclude(Directive): def register(): directives.register_directive('code-include', CodeInclude) - From 5b8ffde2a51636720f303d7753344c2c8a7d27c0 Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Sun, 24 Mar 2013 15:39:44 -0400 Subject: [PATCH 04/23] initial commit of disqus_static plugin, a plugin for allowing you to fetch disqus comments from their API and embed them into your templates at HTML generation time. --- pelicanext/disqus_static/README.rst | 61 +++++++++++++++++++++++ pelicanext/disqus_static/disqus_static.py | 41 +++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 pelicanext/disqus_static/README.rst create mode 100644 pelicanext/disqus_static/disqus_static.py diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst new file mode 100644 index 0000000..fac6c8d --- /dev/null +++ b/pelicanext/disqus_static/README.rst @@ -0,0 +1,61 @@ +Disqus static comment plugin for Pelican +==================================== + +This plugin adds a disqus_comments property to all articles. +Comments are fetched at generation time using disqus API. + +Installation +------------ +Because we use disqus API to retrieve the comments you need to create an application at +http://disqus.com/api/applications/ which will provide you with a secret and public keys for the API. + +Put ``disqus_static.py`` plugin in ``plugins`` folder in pelican installation +and use the following in your settings:: + + PLUGINS = [u"pelican.plugins.disqus_static"] + + DISQUS_SITENAME = u'YOUR_SITENAME' + DISQUS_SECRET_KEY = u'YOUR_SECRET_KEY' + DISQUS_PUBLIC_KEY = u'YOUR_PUBLIC_KEY' + +Usage +----- + +Example use of the comments in templates: +.. code-block:: html+jinja + + {% if article.disqus_comments %} +
+

{{ article.disqus_comments|length }} comments

+
    + {% for comment in article.disqus_comments %} +
  • +
    +
    + Avatar +
    +
    +
    + {{ comment.author.name }} + {{ comment.createdAt }} +
    +
    +
    +
    + {{ comment.message }} +
    +
    +
    +
    +
    +
  • + {% endfor %} +
+
+ {% endif %} + +TODO +----- + + - handle replies to comments properly and maintain parent-child relationships + - test for sites with over 100 comments (I think disqus API only returns 100 items per request) diff --git a/pelicanext/disqus_static/disqus_static.py b/pelicanext/disqus_static/disqus_static.py new file mode 100644 index 0000000..78b56e5 --- /dev/null +++ b/pelicanext/disqus_static/disqus_static.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +Disqus static comment plugin for Pelican +==================================== +This plugin adds a disqus_comments property to all articles. +Comments are fetched at generation time using disqus API. +""" + +from disqusapi import DisqusAPI +from pelican import signals + +def initialized(pelican): + from pelican.settings import _DEFAULT_CONFIG + _DEFAULT_CONFIG.setdefault('DISQUS_SECRET_KEY', '') + _DEFAULT_CONFIG.setdefault('DISQUS_PUBLIC_KEY', '') + if pelican: + pelican.settings.setdefault('DISQUS_SECRET_KEY', '') + pelican.settings.setdefault('DISQUS_PUBLIC_KEY', '') + +def disqus_static(generator): + disqus = DisqusAPI(generator.settings['DISQUS_SECRET_KEY'], + generator.settings['DISQUS_PUBLIC_KEY']) + threads = disqus.threads.list(forum=generator.settings['DISQUS_SITENAME']) + thread_dict = {} # disqus thread id => title + for thread in threads: + thread_dict[thread['id']] = thread['title'] + posts = disqus.posts.list(forum=generator.settings['DISQUS_SITENAME']) + post_dict = {} # title => [post1, post2, ...] + for post in posts: + if post['thread'] not in thread_dict.keys(): + continue + if thread_dict[post['thread']] not in post_dict.keys(): + post_dict[thread_dict[post['thread']]] = [] + post_dict[thread_dict[post['thread']]].append(post) + for article in generator.articles: + if article.title in post_dict: + article.disqus_comments = post_dict[article.title] + +def register(): + signals.initialized.connect(initialized) + signals.article_generator_finalized.connect(disqus_static) From c29e08209312ff35514ef219723e5098c9a0338c Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Sun, 24 Mar 2013 15:47:27 -0400 Subject: [PATCH 05/23] fix README markdown display --- pelicanext/disqus_static/README.rst | 57 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst index fac6c8d..05c68b6 100644 --- a/pelicanext/disqus_static/README.rst +++ b/pelicanext/disqus_static/README.rst @@ -21,38 +21,37 @@ and use the following in your settings:: Usage ----- -Example use of the comments in templates: .. code-block:: html+jinja - {% if article.disqus_comments %} -
-

{{ article.disqus_comments|length }} comments

-
    - {% for comment in article.disqus_comments %} -
  • -
    -
    - Avatar -
    -
    -
    - {{ comment.author.name }} - {{ comment.createdAt }} -
    -
    -
    -
    - {{ comment.message }} + {% if article.disqus_comments %} +
    +

    {{ article.disqus_comments|length }} comments

    +
      + {% for comment in article.disqus_comments %} +
    • +
      +
      + Avatar +
      +
      +
      + {{ comment.author.name }} + {{ comment.createdAt }} +
      +
      +
      +
      + {{ comment.message }} +
      +
      +
      +
      -
    -
    -
    -
    -
  • - {% endfor %} -
-
- {% endif %} + + {% endfor %} + + + {% endif %} TODO ----- From 4e7a4bd592d902b8ab3e625c5e99f55a33d60fa8 Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Sun, 24 Mar 2013 16:13:47 -0400 Subject: [PATCH 06/23] make the disqus_static plugin work for sites with over 25 comments --- pelicanext/disqus_static/README.rst | 4 +++- pelicanext/disqus_static/disqus_static.py | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst index 05c68b6..9bcc84f 100644 --- a/pelicanext/disqus_static/README.rst +++ b/pelicanext/disqus_static/README.rst @@ -9,6 +9,9 @@ Installation Because we use disqus API to retrieve the comments you need to create an application at http://disqus.com/api/applications/ which will provide you with a secret and public keys for the API. +We use disqus-python package for communication with disqus API: +``pip install disqus-python`` + Put ``disqus_static.py`` plugin in ``plugins`` folder in pelican installation and use the following in your settings:: @@ -57,4 +60,3 @@ TODO ----- - handle replies to comments properly and maintain parent-child relationships - - test for sites with over 100 comments (I think disqus API only returns 100 items per request) diff --git a/pelicanext/disqus_static/disqus_static.py b/pelicanext/disqus_static/disqus_static.py index 78b56e5..c775474 100644 --- a/pelicanext/disqus_static/disqus_static.py +++ b/pelicanext/disqus_static/disqus_static.py @@ -6,7 +6,7 @@ This plugin adds a disqus_comments property to all articles. Comments are fetched at generation time using disqus API. """ -from disqusapi import DisqusAPI +from disqusapi import DisqusAPI, Paginator from pelican import signals def initialized(pelican): @@ -20,11 +20,13 @@ def initialized(pelican): def disqus_static(generator): disqus = DisqusAPI(generator.settings['DISQUS_SECRET_KEY'], generator.settings['DISQUS_PUBLIC_KEY']) - threads = disqus.threads.list(forum=generator.settings['DISQUS_SITENAME']) + threads = Paginator(disqus.threads.list, + forum=generator.settings['DISQUS_SITENAME']) thread_dict = {} # disqus thread id => title for thread in threads: thread_dict[thread['id']] = thread['title'] - posts = disqus.posts.list(forum=generator.settings['DISQUS_SITENAME']) + + posts = Paginator(disqus.posts.list, forum=generator.settings['DISQUS_SITENAME']) post_dict = {} # title => [post1, post2, ...] for post in posts: if post['thread'] not in thread_dict.keys(): @@ -32,6 +34,7 @@ def disqus_static(generator): if thread_dict[post['thread']] not in post_dict.keys(): post_dict[thread_dict[post['thread']]] = [] post_dict[thread_dict[post['thread']]].append(post) + for article in generator.articles: if article.title in post_dict: article.disqus_comments = post_dict[article.title] From 1dc73cda430484dbc6ce0b40c5ff827e2dc5b505 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sun, 24 Mar 2013 16:34:03 -0500 Subject: [PATCH 07/23] Whitespace fixes --- pelicanext/code_include/code_include.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py index 3edd94a..728c411 100644 --- a/pelicanext/code_include/code_include.py +++ b/pelicanext/code_include/code_include.py @@ -22,7 +22,6 @@ from pelican.rstdirectives import Pygments class CodeInclude(Directive): - """ Include content read from a separate source file, and highlight it with the given lexer (using pelican.rstdirectives.CodeBlock) @@ -49,15 +48,18 @@ class CodeInclude(Directive): source = self.state_machine.input_lines.source( self.lineno - self.state_machine.input_offset - 1) source_dir = os.path.dirname(os.path.abspath(source)) + path = directives.path(self.arguments[0]) path = os.path.normpath(os.path.join(source_dir, path)) path = utils.relative_path(None, path) path = nodes.reprunicode(path) + encoding = self.options.get( 'encoding', self.state.document.settings.input_encoding) e_handler = self.state.document.settings.input_encoding_error_handler tab_width = self.options.get( 'tab-width', self.state.document.settings.tab_width) + try: self.state.document.settings.record_dependencies.add(path) include_file = io.FileInput(source_path=path, From 77c7de21c5ac7b2e345d1fe6d948fb98d1fb26d5 Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Thu, 28 Mar 2013 18:25:11 -0400 Subject: [PATCH 08/23] add support for child posts --- pelicanext/disqus_static/README.rst | 24 +++++------ pelicanext/disqus_static/disqus_static.py | 51 +++++++++++++++++++---- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst index 9bcc84f..4e96548 100644 --- a/pelicanext/disqus_static/README.rst +++ b/pelicanext/disqus_static/README.rst @@ -28,11 +28,11 @@ Usage {% if article.disqus_comments %}
-

{{ article.disqus_comments|length }} comments

+

{{ article.disqus_comment_count }} comments

    - {% for comment in article.disqus_comments %} + {% for comment in article.disqus_comments recursive %}
  • -
    +
    Avatar
    @@ -41,22 +41,20 @@ Usage {{ comment.author.name }} {{ comment.createdAt }} -
    -
    -
    - {{ comment.message }} -
    +
    +
    + {{ comment.message }}
    + {% if comment.children %} +
      + {{ loop(comment.children) }} +
    + {% endif %}
  • {% endfor %}
{% endif %} - -TODO ------ - - - handle replies to comments properly and maintain parent-child relationships diff --git a/pelicanext/disqus_static/disqus_static.py b/pelicanext/disqus_static/disqus_static.py index c775474..3cb4473 100644 --- a/pelicanext/disqus_static/disqus_static.py +++ b/pelicanext/disqus_static/disqus_static.py @@ -20,24 +20,59 @@ def initialized(pelican): def disqus_static(generator): disqus = DisqusAPI(generator.settings['DISQUS_SECRET_KEY'], generator.settings['DISQUS_PUBLIC_KEY']) + # first retrieve the threads threads = Paginator(disqus.threads.list, forum=generator.settings['DISQUS_SITENAME']) - thread_dict = {} # disqus thread id => title + # build a {thread_id: title} dict + thread_dict = {} for thread in threads: thread_dict[thread['id']] = thread['title'] - posts = Paginator(disqus.posts.list, forum=generator.settings['DISQUS_SITENAME']) - post_dict = {} # title => [post1, post2, ...] + # now retrieve the posts + posts = Paginator(disqus.posts.list, + forum=generator.settings['DISQUS_SITENAME']) + + # build a {post_id: [child_post1, child_post2, ...]} dict + child_dict = {} for post in posts: - if post['thread'] not in thread_dict.keys(): - continue - if thread_dict[post['thread']] not in post_dict.keys(): - post_dict[thread_dict[post['thread']]] = [] - post_dict[thread_dict[post['thread']]].append(post) + if post['id'] not in child_dict.keys(): + child_dict[post['id']] = [] + if post['parent'] is not None: + if str(post['parent']) not in child_dict.keys(): + child_dict[str(post['parent'])] = [] + child_dict[str(post['parent'])].append(post) + + # build a {title: [post1, post2, ...]} dict + post_dict = {} + for post in posts: + build_post_dict(post_dict, child_dict, thread_dict, post) for article in generator.articles: if article.title in post_dict: article.disqus_comments = post_dict[article.title] + article.disqus_comment_count = sum([ + postcounter(post) for post in post_dict[article.title]]) + +def postcounter(node): + return 1 + sum([postcounter(n) for n in node['children']]) + +def build_post_dict(post_dict, child_dict, thread_dict, post): + if post['thread'] not in thread_dict.keys(): + return # invalid thread, should never happen + + build_child_dict(child_dict, post) + + if post['parent'] is not None: + return # this is a child post, don't want to display it here + + if thread_dict[post['thread']] not in post_dict.keys(): + post_dict[thread_dict[post['thread']]] = [] + post_dict[thread_dict[post['thread']]].append(post) + +def build_child_dict(child_dict, post): + post['children'] = child_dict[post['id']] + for child in child_dict[post['id']]: + build_child_dict(child_dict, child) def register(): signals.initialized.connect(initialized) From 86c0725f24c969d88a79444cb638cef72cb2f44d Mon Sep 17 00:00:00 2001 From: Barry Steyn Date: Thu, 9 May 2013 21:20:21 -0400 Subject: [PATCH 09/23] Ability to add latex to pages --- latex/Readme.md | 3 +++ latex/latex.py | 1 + 2 files changed, 4 insertions(+) diff --git a/latex/Readme.md b/latex/Readme.md index 9a18cf5..dc4c1cd 100644 --- a/latex/Readme.md +++ b/latex/Readme.md @@ -30,6 +30,9 @@ between the `` parameters (for the NotMyIdea template, this file is base.h {% if article and article.latex %} {{ article.latex }} {% endif %} + {% if page and page.latex %} + {{ article.latex }} + {% endif %} Usage ----- diff --git a/latex/latex.py b/latex/latex.py index 2ebd1c7..ce16044 100644 --- a/latex/latex.py +++ b/latex/latex.py @@ -45,3 +45,4 @@ def register(): Plugin registration """ signals.article_generate_context.connect(addLatex) + signals.pages_generate_context.connect(addLatex) From 457604623f52a4c4c89a1b8ee569cb0e3a7b991d Mon Sep 17 00:00:00 2001 From: Barry Steyn Date: Thu, 9 May 2013 21:24:54 -0400 Subject: [PATCH 10/23] Correct error in documentation --- latex/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/latex/Readme.md b/latex/Readme.md index dc4c1cd..51424ce 100644 --- a/latex/Readme.md +++ b/latex/Readme.md @@ -31,7 +31,7 @@ between the `` parameters (for the NotMyIdea template, this file is base.h {{ article.latex }} {% endif %} {% if page and page.latex %} - {{ article.latex }} + {{ page.latex }} {% endif %} Usage From 850db33263e9dfcefb22377cbaf2c4b16d59f6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20M=C3=A9taireau?= Date: Fri, 17 May 2013 11:30:22 +1000 Subject: [PATCH 11/23] Don't enforce the licence to be AGPL. --- Contributing.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Contributing.rst b/Contributing.rst index 8e5b0e5..3f09c17 100644 --- a/Contributing.rst +++ b/Contributing.rst @@ -3,7 +3,7 @@ Contributing a plugin Details of how to write a plugin is explained in the official Pelican `docs`_. -If you want to contribute, please fork this repository and issue your pull +If you want to contribute, please fork this repository and issue your pull request. Make sure that your plugin follows the structure below:: my_plugin @@ -11,7 +11,7 @@ request. Make sure that your plugin follows the structure below:: ├── my_plugin.py ├── test_my_plugin.py └── Readme.rst / Readme.md - + ``my_plugin.py`` is the actual plugin implementation. Include a brief explanation of what the plugin does as a module docstring. Leave any further @@ -19,12 +19,13 @@ explanations and usage details to ``Readme`` file. ``__init__.py`` should contain a single line with ``from .my_plugin import *``. -Place tests for your plugin in the same folder with name ``test_my_plugin.py``. +Place tests for your plugin in the same folder with name ``test_my_plugin.py``. You can use ``test_data`` main folder, if you need content or templates in your tests. -**Note:** Plugins in the repository are licensed with *GNU AFFERO GENERAL PUBLIC LICENSE -Version 3*. By submitting a pull request, you accept to release your -contribution under same license. Please refer to the ``LICENSE`` file for -full text of the license. +**Note:** Each plugin can contain a LICENSE file stating the license it's +released under. If there is an absence of LICENSE then it defaults to the +*GNU AFFERO GENERAL PUBLIC LICENSE Version 3*. + +Please refer to the ``LICENSE`` file for the full text of the license. .. _docs: http://docs.getpelican.com/en/latest/plugins.html#how-to-create-plugins From b83ce37a2a438915e4b0c853f5aaf644f49d511f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20M=C3=A9taireau?= Date: Fri, 17 May 2013 11:33:16 +1000 Subject: [PATCH 12/23] Also update the LICENSE file --- LICENSE | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LICENSE b/LICENSE index dba13ed..ba67bd0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,7 @@ +Unless the folder itself contains a LICENSE stating otherwise, all the files +distributed here are released under the GNU AFFERO GENERAL PUBLIC LICENSE. + + GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 From 4ba1c5fd6b038880303a62f2a14a952e589a9be9 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Thu, 16 May 2013 20:59:44 -0500 Subject: [PATCH 13/23] Restructured to account for repo layout change --- {pelicanext/code_include => code_include}/README.rst | 1 - code_include/__init__.py | 1 + {pelicanext/code_include => code_include}/code_include.py | 0 pelicanext/code_include/__init__.py | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename {pelicanext/code_include => code_include}/README.rst (99%) create mode 100644 code_include/__init__.py rename {pelicanext/code_include => code_include}/code_include.py (100%) delete mode 100644 pelicanext/code_include/__init__.py diff --git a/pelicanext/code_include/README.rst b/code_include/README.rst similarity index 99% rename from pelicanext/code_include/README.rst rename to code_include/README.rst index 0f3c0dc..b7e08ec 100644 --- a/pelicanext/code_include/README.rst +++ b/code_include/README.rst @@ -6,7 +6,6 @@ Include Pygments highlighted code with reStructuredText Use this plugin to make writing coding tutorials easier! You can maintain the example source files separately from the actual article. - Based heavily on ``docutils.parsers.rst.directives.Include``. Include a file and output as a code block formatted with pelican's Pygments directive. diff --git a/code_include/__init__.py b/code_include/__init__.py new file mode 100644 index 0000000..019171c --- /dev/null +++ b/code_include/__init__.py @@ -0,0 +1 @@ +from code_include import * diff --git a/pelicanext/code_include/code_include.py b/code_include/code_include.py similarity index 100% rename from pelicanext/code_include/code_include.py rename to code_include/code_include.py diff --git a/pelicanext/code_include/__init__.py b/pelicanext/code_include/__init__.py deleted file mode 100644 index e69de29..0000000 From 95600f17b7638c230e50792a641ae8e2610ed69c Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Thu, 16 May 2013 22:41:13 -0500 Subject: [PATCH 14/23] Removed docstrings to avoid doc duplication. --- code_include/code_include.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/code_include/code_include.py b/code_include/code_include.py index 728c411..b87c8dd 100644 --- a/code_include/code_include.py +++ b/code_include/code_include.py @@ -1,17 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -""" -Include Pygments highlighted code with reStructuredText -======================================================= - -:author: Colin Dunklau - -Use this plugin to make writing coding tutorials easier! You can -maintain the example source files separately from the actual article. - -""" - import os.path from docutils import io, nodes, statemachine, utils @@ -22,16 +11,6 @@ from pelican.rstdirectives import Pygments class CodeInclude(Directive): - """ - Include content read from a separate source file, and highlight - it with the given lexer (using pelican.rstdirectives.CodeBlock) - - The encoding of the included file can be specified. Only a part - of the given file argument may be included by specifying start - and end line. Hard tabs will be replaced with ``tab-width`` - spaces. - """ - required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True From 749f499206412d55a2346dbab8d338940a371d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20M=C3=A9taireau?= Date: Fri, 17 May 2013 15:39:25 +1000 Subject: [PATCH 15/23] Move disqus_static out of pelicanext --- {pelicanext/disqus_static => disqus_static}/README.rst | 0 {pelicanext/disqus_static => disqus_static}/disqus_static.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {pelicanext/disqus_static => disqus_static}/README.rst (100%) rename {pelicanext/disqus_static => disqus_static}/disqus_static.py (100%) diff --git a/pelicanext/disqus_static/README.rst b/disqus_static/README.rst similarity index 100% rename from pelicanext/disqus_static/README.rst rename to disqus_static/README.rst diff --git a/pelicanext/disqus_static/disqus_static.py b/disqus_static/disqus_static.py similarity index 100% rename from pelicanext/disqus_static/disqus_static.py rename to disqus_static/disqus_static.py From e07dac87995d1a9745cef2c1476af313fbb3dd56 Mon Sep 17 00:00:00 2001 From: bas smit Date: Sat, 18 May 2013 20:07:37 +0200 Subject: [PATCH 16/23] Skip static content for toc extraction --- extract_toc/extract_toc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extract_toc/extract_toc.py b/extract_toc/extract_toc.py index b926eff..479970b 100644 --- a/extract_toc/extract_toc.py +++ b/extract_toc/extract_toc.py @@ -8,10 +8,12 @@ and place it in its own article.toc variable. from os import path from bs4 import BeautifulSoup -from pelican import signals, readers +from pelican import signals, readers, contents def extract_toc(content): + if isinstance(content, contents.Static): + return soup = BeautifulSoup(content._content) filename = content.source_path extension = path.splitext(filename)[1][1:] From f920f0ec9e7d290d78f7991cce1c3308d7223f96 Mon Sep 17 00:00:00 2001 From: bas smit Date: Sat, 18 May 2013 20:36:55 +0200 Subject: [PATCH 17/23] Update the extract_toc documentation with a md/rst toc example --- extract_toc/README.md | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/extract_toc/README.md b/extract_toc/README.md index 2cd826a..2dbc8bb 100644 --- a/extract_toc/README.md +++ b/extract_toc/README.md @@ -54,6 +54,50 @@ ToC generated by Markdown is enclosed in `
`. On the other hand ToC generated by reST is enclosed in `
`. `extract_toc` relies on this behavior to work. +reStructuredText Example +------------------------ + +To add a table of contents to your reStructuredText document you need to add a 'contents directive' at the place where you want the table of contents to appear. See the [documentation](http://docutils.sourceforge.net/docs/ref/rst/directives.html#table-of-contents) for more details. + +```rst +My super title +############## + +:date: 2010-10-03 +:tags: thats, awesome + +.. contents:: +.. + 1 Head 1 + 1.1 Head 2 + 2 Head 3 + 3 head 4 + +Heading 1 +--------- + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. +``` + +Markdown Example +---------------- + +To add a table of contents to your Markdown document you need to place the 'TOC marker' at the place where you would like the table of contents to appear. See the Python Markdown [documentation](http://pythonhosted.org/Markdown/extensions/toc.html) for more details. + +Important! To enable table of contents generation for the markdown reader you need to set `MD_EXTENSIONS = (['toc'])` in your pelican configuration file. + +```Markdown +title: My super title +date: 4-4-2013 +tags: thats, awesome + +[TOC] + +# Heading 1 # + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. +``` + Template Example ================ From 8d0e643637d349cc5407b3b12b796f0331398444 Mon Sep 17 00:00:00 2001 From: bas smit Date: Fri, 24 May 2013 11:12:51 +0200 Subject: [PATCH 18/23] Explicitly set the html parser to make sure no extra tags get added. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BeautifulSoup supports multiple html parsers. Some of those parsers try to make the html valid by adding/removing tags[1]. This can lead to useless html, head & body tags in the final document. By explicitly setting the parser to ’html.parser’ this behaviour can be avoided. [1] http://www.crummy.com/software/BeautifulSoup/bs4/doc/#differences-between-parsers --- extract_toc/extract_toc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extract_toc/extract_toc.py b/extract_toc/extract_toc.py index 479970b..a3a7e00 100644 --- a/extract_toc/extract_toc.py +++ b/extract_toc/extract_toc.py @@ -14,7 +14,7 @@ from pelican import signals, readers, contents def extract_toc(content): if isinstance(content, contents.Static): return - soup = BeautifulSoup(content._content) + soup = BeautifulSoup(content._content,'html.parser') filename = content.source_path extension = path.splitext(filename)[1][1:] toc = '' From 114c2bc14684c0affabeec125955d712d12f998d Mon Sep 17 00:00:00 2001 From: Irfan Ahmad Date: Mon, 27 May 2013 09:49:00 +0500 Subject: [PATCH 19/23] Added new plugin "Optimize Images" --- optimize_images/Readme.md | 26 +++++++++++++++ optimize_images/__init__.py | 0 optimize_images/optimize_images.py | 51 ++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 optimize_images/Readme.md create mode 100644 optimize_images/__init__.py create mode 100644 optimize_images/optimize_images.py diff --git a/optimize_images/Readme.md b/optimize_images/Readme.md new file mode 100644 index 0000000..d6fcc0f --- /dev/null +++ b/optimize_images/Readme.md @@ -0,0 +1,26 @@ +Optimize Images Plugin For Pelican +================================== + +This plugin applies lossless compression on JPEG and PNG images, with no +effect on image quality. It uses [jpegtran][1] and [OptiPNG][2]. It assumes +that both of these tools are installed on system path. + +[1]: http://jpegclub.org/jpegtran/ "jpegtran" +[2]: http://optipng.sourceforge.net/ "OptiPNG" + + +Installation +------------ + +To enable, ensure that `optimize_images.py` is put somewhere that is accessible. +Then use as follows by adding the following to your settings.py: + + PLUGIN_PATH = 'path/to/pelican-plugins' + PLUGINS = ["optimize_images"] + +`PLUGIN_PATH` can be a path relative to your settings file or an absolute path. + +Usage +----- +The plugin will activate and optimize images upon `finalized` signal of +pelican. \ No newline at end of file diff --git a/optimize_images/__init__.py b/optimize_images/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/optimize_images/optimize_images.py b/optimize_images/optimize_images.py new file mode 100644 index 0000000..b49f523 --- /dev/null +++ b/optimize_images/optimize_images.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +""" +Optimized images (jpg and png) +Assumes that jpegtran and optipng are isntalled on path. +http://jpegclub.org/jpegtran/ +http://optipng.sourceforge.net/ +Copyright (c) 2012 Irfan Ahmad (http://i.com.pk) +""" + +import logging +import os +from subprocess import call + +from pelican import signals + +logger = logging.getLogger(__name__) + +# A list of file types with their respective commands +COMMANDS = [ + ('.jpg', 'jpegtran -copy none -optimize "{filename}" "{filename}"'), + ('.png', 'optipng "{filename}"'), +] + +def optimize_images(pelican): + """ + Optimized jpg and png images + + :param pelican: The Pelican instance + """ + for dirpath, _, filenames in os.walk(pelican.settings['OUTPUT_PATH']): + for name in filenames: + optimize(dirpath, name) + +def optimize(dirpath, filename): + """ + Check if the name is a type of file that should be optimized. + And optimizes it if required. + + :param dirpath: Path of the file to be optimzed + :param name: A file name to be optimized + """ + for extension, command in COMMANDS: + if filename.endswith(extension): + filepath = os.path.join(dirpath, filename) + command = command.format(filename=filepath) + call(command, shell=True) + + +def register(): + signals.finalized.connect(optimize_images) From 65c4fe2db2b08cff0825a7fcdbb98221430f30fe Mon Sep 17 00:00:00 2001 From: Irfan Ahmad Date: Sat, 1 Jun 2013 11:24:05 +0500 Subject: [PATCH 20/23] FIXED: https://github.com/getpelican/pelican-plugins/pull/31#issuecomment-18748236 --- optimize_images/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/optimize_images/__init__.py b/optimize_images/__init__.py index e69de29..cbb056a 100644 --- a/optimize_images/__init__.py +++ b/optimize_images/__init__.py @@ -0,0 +1 @@ +from .optimize_images import * From d0a7eca70e4668e2921671a8d2c71ee343dc814b Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sun, 2 Jun 2013 20:06:47 -0400 Subject: [PATCH 21/23] summary: Adjust to the newly-public DEFAULT_CONFIG This keeps us up to date with the core commit e9dc1dd (settings: Make DEFAULT_CONFIG public, 2013-03-24). --- summary/summary.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/summary/summary.py b/summary/summary.py index 500e6ec..a3af2da 100644 --- a/summary/summary.py +++ b/summary/summary.py @@ -11,11 +11,11 @@ import types from pelican import signals def initialized(pelican): - from pelican.settings import _DEFAULT_CONFIG - _DEFAULT_CONFIG.setdefault('SUMMARY_BEGIN_MARKER', - '') - _DEFAULT_CONFIG.setdefault('SUMMARY_END_MARKER', - '') + from pelican.settings import DEFAULT_CONFIG + DEFAULT_CONFIG.setdefault('SUMMARY_BEGIN_MARKER', + '') + DEFAULT_CONFIG.setdefault('SUMMARY_END_MARKER', + '') if pelican: pelican.settings.setdefault('SUMMARY_BEGIN_MARKER', '') From 71db23cd9735e8b8bf0c99056e85dc671a1cd48e Mon Sep 17 00:00:00 2001 From: julien ortet Date: Tue, 4 Jun 2013 22:56:11 +0200 Subject: [PATCH 22/23] adding ical plugin --- ical/Readme.rst | 28 ++++++++++++++++++++++++++ ical/__init__.py | 1 + ical/ical.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 ical/Readme.rst create mode 100644 ical/__init__.py create mode 100644 ical/ical.py diff --git a/ical/Readme.rst b/ical/Readme.rst new file mode 100644 index 0000000..0260a72 --- /dev/null +++ b/ical/Readme.rst @@ -0,0 +1,28 @@ +ical +-------- + +This plugin read the calendar defined in the page metadata : calendar : + +with:: + + :calendar: /path/to/your/ics/file + +Example of code that can be added in page template :: + + + {% if page.calendar %} +
+ {% for vevent in events[page.slug] %} +
{{ vevent.summary }}
+
{{ vevent.description|replace('\n\n', '
') }}
+
{{ vevent.dtstart }}
+
{{ vevent.dtend }}
+ + {% endfor %} +
+ {% endif %} + +this plugins needs icalendar module installed:: + + pip install icalendar + diff --git a/ical/__init__.py b/ical/__init__.py new file mode 100644 index 0000000..8a1352a --- /dev/null +++ b/ical/__init__.py @@ -0,0 +1 @@ +from .ical import * diff --git a/ical/ical.py b/ical/ical.py new file mode 100644 index 0000000..26fdd12 --- /dev/null +++ b/ical/ical.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +""" +ical plugin for Pelican +=========================== + +This plugin parse the calendars defined in pages metadata :calendar: +One calendar per page + +""" + +from icalendar import Calendar, Event +from pelican import signals , utils +import pytz +import datetime +import os.path + +def init_cal(generator): + # initialisation of the dictionnary of calendar + # you can add one calendar per page + calDict = {} + generator.context['events'] = calDict + +def add_ical(generator, metadata): + # check if a calendar is here + if 'calendar' in metadata.keys(): + summ = [] + path = metadata['calendar'] + if not os.path.isabs(path): + path = os.path.abspath(metadata['calendar']) + cal = Calendar.from_ical(open(path,'rb').read()) + for element in cal.walk(): + eventdict = {} + if element.name == "VEVENT": + if element.get('summary') != None: + eventdict['summary'] = element.get('summary') + if element.get('description') != None: + eventdict['description'] = element.get('description') + if element.get('url') != None: + eventdict['url'] = element.get('url') + if element.get('dtstart') != None: + eventdict['dtstart'] = element.get('dtstart').dt + if element.get('dtend') != None: + eventdict['dtend'] = element.get('dtend').dt + summ.append(eventdict) + # the id of the calendar is the slugify name of the page + calId = utils.slugify(metadata['title']) + generator.context['events'][calId] = summ + + +def register(): + signals.pages_generator_init.connect(init_cal) + signals.pages_generate_context.connect(add_ical) From a3ddc43746ac2160d13309e2db2f4983bbae56c5 Mon Sep 17 00:00:00 2001 From: Justin Mayer Date: Wed, 5 Jun 2013 09:36:00 -0700 Subject: [PATCH 23/23] Improve ical plugin documentation --- ical/Readme.rst | 33 ++++++++++++++++++++++----------- ical/ical.py | 10 +++++----- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/ical/Readme.rst b/ical/Readme.rst index 0260a72..e8897d1 100644 --- a/ical/Readme.rst +++ b/ical/Readme.rst @@ -1,28 +1,39 @@ ical --------- +---- -This plugin read the calendar defined in the page metadata : calendar : +This plugin looks for and parses an ``.ics`` file if it is defined in a given +page's ``calendar`` metadata. One calendar can be defined per page. -with:: +Dependencies +------------ + +This plugin depends on the ``icalendar`` package, which can be installed via +pip:: + + pip install icalendar + +Usage +----- + +For a reST-formatted page, include the following line in the metadata:: :calendar: /path/to/your/ics/file -Example of code that can be added in page template :: +For Markdown, include the following line in the page metadata:: + Calendar: /path/to/your/ics/file + +Following is some example code that can be added to your theme's ``page.html`` +template in order to display the calendar:: {% if page.calendar %}
- {% for vevent in events[page.slug] %} + {% for vevent in events[page.slug] %}
{{ vevent.summary }}
{{ vevent.description|replace('\n\n', '
') }}
{{ vevent.dtstart }}
{{ vevent.dtend }}
- + {% endfor %}
{% endif %} - -this plugins needs icalendar module installed:: - - pip install icalendar - diff --git a/ical/ical.py b/ical/ical.py index 26fdd12..ccfefaa 100644 --- a/ical/ical.py +++ b/ical/ical.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- """ ical plugin for Pelican -=========================== +======================= -This plugin parse the calendars defined in pages metadata :calendar: -One calendar per page +This plugin looks for and parses an .ics file if it is defined in a given +page's :calendar: metadata. One calendar can be defined per page. """ @@ -15,7 +15,7 @@ import datetime import os.path def init_cal(generator): - # initialisation of the dictionnary of calendar + # initialisation of the calendar dictionary # you can add one calendar per page calDict = {} generator.context['events'] = calDict @@ -42,7 +42,7 @@ def add_ical(generator, metadata): if element.get('dtend') != None: eventdict['dtend'] = element.get('dtend').dt summ.append(eventdict) - # the id of the calendar is the slugify name of the page + # the id of the calendar is the slugified name of the page calId = utils.slugify(metadata['title']) generator.context['events'][calId] = summ