Browse Source

Merge pull request #762 from leotrs/glossary

Add Glossary plugin for definition lists found in articles and pages
Justin Mayer 7 years ago
parent
commit
bf710c50a5
4 changed files with 142 additions and 0 deletions
  1. 2 0
      Readme.rst
  2. 1 0
      glossary/__init__.py
  3. 64 0
      glossary/glossary.py
  4. 75 0
      glossary/readme.md

+ 2 - 0
Readme.rst

@@ -100,6 +100,8 @@ GitHub activity           On the template side, you just have to iterate over th
 
 Global license            Allows you to define a ``LICENSE`` setting and adds the contents of that license variable to the article's context
 
+Glossary                  Adds a variable containing definitions extracted from definition lists in articles and pages. This variable is visible to all page templates.
+
 Goodreads activity        Lists books from your Goodreads shelves
 
 GooglePlus comments       Adds GooglePlus comments to Pelican

+ 1 - 0
glossary/__init__.py

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

+ 64 - 0
glossary/glossary.py

@@ -0,0 +1,64 @@
+"""
+Builds a glossary page containing definition lists found in articles
+and pages, and adds a `definitions` variable visible to all page templates.
+
+"""
+
+from pelican import signals, contents
+from bs4 import BeautifulSoup
+
+
+class Definitions():
+    definitions = []
+    exclude = ['Hint']
+
+
+def extract_definitions(content):
+    soup = BeautifulSoup(content.content, 'html.parser')
+
+    for def_list in soup.find_all('dl'):
+        defns = []
+        for def_title in def_list.find_all('dt'):
+            if def_title.text not in Definitions.exclude:
+                defns.append(
+                    {'title': get_title(def_title),
+                     'link': get_link(def_title, content.url),
+                     'definition': get_def(def_title),
+                     'source': content})
+
+        for defn in defns:
+            defn['see_also'] = [also for also in defns if also is not defn]
+
+        Definitions.definitions += defns
+
+
+def get_title(def_title):
+    return def_title.text
+
+
+def get_link(def_title, url):
+    a_tag = def_title.findChild('a')
+    if a_tag and a_tag['href']:
+        return url + a_tag['href']
+    else:
+        return None
+
+
+def get_def(def_title):
+    return ''.join(str(t) for t in def_title.find_next('dd').contents)
+
+
+def parse_content(content):
+    if isinstance(content, contents.Static) or not content.content:
+        return
+    else:
+        return extract_definitions(content)
+
+
+def set_definitions(generator, metadata):
+    generator.context['definitions'] = Definitions.definitions
+
+
+def register():
+    signals.content_object_init.connect(parse_content)
+    signals.page_generator_context.connect(set_definitions)

+ 75 - 0
glossary/readme.md

@@ -0,0 +1,75 @@
+# Glossary
+
+Builds a glossary page containing definition lists found in articles and
+pages.
+
+If you have an article or page that generates the following:
+
+file `defns.html` titled "My definitions"
+```
+<dl>
+  <dt><a href="some-link.html">My Term</a></dt>
+  <dd>This is definition for My Term.</dd>
+  <dt>Another Term</dt>
+  <dd>And another definition.</dd>
+</dl>
+```
+
+This plugin will extract all such definitions and put them inside the
+`definitions` variable in the pelican context. It will be seen by all page
+templates.
+
+The `definitions` variable will have the following attributes:
++ `title`, the definition title, inside <dt> tags,
++ `definition`, the definition, inside <dd> tags,
++ `link`, if the <dt> tags enclose a <a> tag, it will be stored here, or
+  None,
++ `source`, the article or page that contains this definition list,
++ `see_also`, containing a list of dicts just like this, made from other
+  definitions in the same list.
+
+For example, for the above html code, the `definitions` variable would look
+like the following:
+
+```
+definitions = [dict1, dict2]
+dict1.title = "My Term"
+dict1.definition = "This is definition for My Term."
+dict1.link = 'some-link.html'
+dict1.source = <content Object referring to "My definitions">
+dict1.see_also = [dict2]
+
+dict2.title = "Another Term"
+dict2.definition = "And another definition."
+dict2.link = None
+dict2.source = <content Object referring to "My definitions">
+dict2.see_also = [dict1]
+```
+
+Note the `link` attribute does not necessarily point to `source.url`.
+
+Next is an example usage of the `definitions` variable.
+
+```
+{% for def in definitions | sort(attribute='title') %}
+<dl>
+  <dt>{{ def.title }}</dt>
+  <dd>
+    <p>{{ def.definition }}</p>
+    <p>
+    Defined in:
+    {% if def.link %}<a href="{{ def.link }}">{% endif %}
+    {{ def.source.title }}
+    {% if def.link %}</a>{% endif %}.
+
+    {% if def.see_also %}
+    See also:
+    {% for also in def.see_also %}
+    <a href="{{ also.link }}">{{ also.title }}</a>
+    {% endfor%}
+    {% endif %}
+    </p>
+  </dd>
+</dl>
+{% endfor %}
+```