Browse Source

Summary: Show Source plugin complete.

Chris Ramsay 7 years ago
parent
commit
1d0960896b
4 changed files with 216 additions and 0 deletions
  1. 2 0
      Readme.rst
  2. 127 0
      show_source/ReadMe.rst
  3. 1 0
      show_source/__init__.py
  4. 86 0
      show_source/show_source.py

+ 2 - 0
Readme.rst

@@ -232,6 +232,8 @@ Series                    Groups related articles into a series
 
 Share post                Creates share URLs of article
 
+Show Source               Place a link to the source text of your posts.
+
 Simple footnotes          Adds footnotes to blog posts
 
 Sitemap                   Generates plain-text or XML sitemaps

+ 127 - 0
show_source/ReadMe.rst

@@ -0,0 +1,127 @@
+Show Source plugin
+------------------
+
+The plugin allows you to place a link to the source text of your posts in the
+same way that `Sphinx`_ does. It works for both pages and articles.
+
+Plugin Activation
+~~~~~~~~~~~~~~~~~
+
+To activate the plugin ensure that you have ``SHOW_SOURCE_ON_SIDEBAR = True`` or
+``SHOW_SOURCE_IN_SECTION = True`` your settings file.
+
+Making Source Available for Posts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to mark posts so that their source may be seen use the following
+metadata values (unless overridden)- for reStructuredText documents:
+
+.. code-block:: reStructuredText
+
+    :show_source: True
+
+or, in Markdown syntax
+
+.. code-block:: Markdown
+
+    Show_source: True
+
+The plugin will render your source document URL to a corresponding
+``article.show_source_url`` (or ``page.show_source_url``) attribute which is
+then accessible in the site templates.
+
+Show Source in the Templates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To get the show source links on the article or page you will have to modify your
+theme, either as a sidebar display or at the foot of an article.
+
+Article or Page Sidebar Display
+*******************************
+
+How to get the source link to appear in the sidebar using the
+`pelican-bootstrap3`_ theme:
+
+.. code-block:: HTML
+
+    {% if SHOW_SOURCE_ON_SIDEBAR %}
+        {% if (article and article.show_source_url) or (page and page.show_source_url) %}
+            <li class="list-group-item"><h4><i class="fa fa-tags fa-file-text"></i><span class="icon-label">This Page</span></h4>
+                <ul class="list-group">
+                    <li class="list-group-item">
+                        {% if article %}
+                        <a href="{{ SITEURL }}/{{ article.show_source_url }}">Show source</a>
+                        {% elif page %}
+                        <a href="{{ SITEURL }}/{{ page.show_source_url }}">Show source</a>
+                        {% endif %}
+                    </li>
+                </ul>
+            </li>
+        {% endif %}
+    {% endif %}
+
+Article Footer Display
+**********************
+
+Here's some code (yes, `pelican-bootstrap3`_ again) to enable a souce link at
+the bottom of an article:
+
+.. code-block:: HTML
+
+    {% if SHOW_SOURCE_IN_SECTION %}
+        {% if article and article.show_source_url %}
+        <section class="well" id="show-source">
+            <h4>This Page</h4>
+            <ul>
+                <a href="{{ SITEURL }}/{{ article.show_source_url }}">Show source</a>
+            </ul>
+        </section>
+        {% endif %}
+    {% endif %}
+
+
+Overriding Default Plugin Behaviour
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default behaviour of the plugin is that revealing source is enabled on a
+case by case basis. This can be changed by the use of
+:py:`SHOW_SOURCE_ALL_POSTS = True` in the settings file. This does mean that the
+plugin will publish all source documents no matter whether ``show_source`` is
+set in the metadata or not.
+
+Unless overridden, each document is saved as the article or page slug attribute
+with a ``.txt`` extension.
+
+So for example, if your configuration had ``ARTICLE_SAVE_AS`` configured like
+so:
+
+.. code-block:: python
+
+    ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%m}/{slug}/index.html'
+
+Your static HTML post and source text document will be like the following:
+
+.. code-block:: Text
+
+    posts/2016/10/welcome-to-my article/index.html
+    posts/2016/10/welcome-to-my article/welcome-to-my article.txt
+
+You can add the ``SHOW_SOURCE_FILENAME`` variable in your settings file to
+override the source file name, so you could set the following:
+
+.. code-block:: python
+
+    SHOW_SOURCE_FILENAME = 'my_source_file.txt'
+
+So with the ``ARTICLE_SAVE_AS`` configured as above, the files would be saved
+thus:
+
+.. code-block:: Text
+
+    posts/2016/10/welcome-to-my article/index.html
+    posts/2016/10/welcome-to-my article/my_source_file.txt
+
+This is the same behaviour for pages also.
+
+.. _`Sphinx`: http://www.sphinx-doc.org/
+.. _`pelican-bootstrap3`: https://github.com/getpelican/pelican-themes/tree/master/pelican-bootstrap3

+ 1 - 0
show_source/__init__.py

@@ -0,0 +1 @@
+from .show_source import *

+ 86 - 0
show_source/show_source.py

@@ -0,0 +1,86 @@
+import os
+import logging
+from urlparse import urljoin
+import six
+from pelican import signals
+from pelican.utils import pelican_open
+
+if not six.PY3:
+    from codecs import open
+
+logger = logging.getLogger(__name__)
+source_files = []
+PROCESS = ['articles', 'pages', 'drafts']
+
+def link_source_files(generator):
+    """
+    Processes each article/page object and formulates copy from and copy
+    to destinations, as well as adding a source file URL as an attribute.
+    """
+    # Get all attributes from the generator that are articles or pages
+    posts = [
+        getattr(generator, attr, None) for attr in PROCESS
+        if getattr(generator, attr, None) is not None]
+    # Work on each item
+    for post in posts[0]:
+        if not 'SHOW_SOURCE_ON_SIDEBAR' in generator.settings and \
+            not 'SHOW_SOURCE_IN_SECTION' in generator.settings:
+            return
+        # Only try this when specified in metadata or SHOW_SOURCE_ALL_POSTS
+        # override is present in settings
+        if 'SHOW_SOURCE_ALL_POSTS' in generator.settings or \
+            'show_source' in post.metadata:
+            # Source file name can be optionally set in config
+            show_source_filename = generator.settings.get(
+                'SHOW_SOURCE_FILENAME', '{}.txt'.format(post.slug)
+                )
+            try:
+                # Get the full path to the original source file
+                source_out = os.path.join(
+                    post.settings['OUTPUT_PATH'], post.save_as
+                    )
+                # Get the path to the original source file
+                source_out_path = os.path.split(source_out)[0]
+                # Create 'copy to' destination for writing later
+                copy_to = os.path.join(
+                    source_out_path, show_source_filename
+                    )
+                # Add file to published path
+                source_url = urljoin(
+                    post.save_as, show_source_filename
+                    )
+            except Exception:
+                return
+            # Format post source dict & populate
+            out = dict()
+            out['copy_raw_from'] = post.source_path
+            out['copy_raw_to'] = copy_to
+            logger.debug('Linked %s to %s', post.source_path, copy_to)
+            source_files.append(out)
+            # Also add the source path to the post as an attribute for tpls
+            post.show_source_url = source_url
+
+def _copy_from_to(from_file, to_file):
+    """
+    A very rough and ready copy from / to function.
+    """
+    with pelican_open(from_file) as text_in:
+        encoding = 'utf-8'
+        with open(to_file, 'w', encoding=encoding) as text_out:
+            text_out.write(text_in)
+            logger.info('Writing %s', to_file)
+
+def write_source_files(*args, **kwargs):
+    """
+    Called by the `page_writer_finalized` signal to process source files.
+    """
+    for source in source_files:
+        _copy_from_to(source['copy_raw_from'], source['copy_raw_to'])
+
+def register():
+    """
+    Calls the shots, based on signals
+    """
+    signals.article_generator_finalized.connect(link_source_files)
+    signals.page_generator_finalized.connect(link_source_files)
+    signals.page_writer_finalized.connect(write_source_files)