Browse Source

break out tag_cloud from core into plugin

winlu 9 years ago
parent
commit
edfd3365af

+ 0 - 3
.gitmodules

@@ -46,9 +46,6 @@
 [submodule "pandoc_reader"]
 [submodule "pandoc_reader"]
 	path = pandoc_reader
 	path = pandoc_reader
 	url = https://github.com/liob/pandoc_reader.git
 	url = https://github.com/liob/pandoc_reader.git
-[submodule "sort_tags"]
-	path = sort_tags
-	url = https://github.com/ingwinlu/sort_tags.git
 [submodule "bootstrapify"]
 [submodule "bootstrapify"]
 	path = bootstrapify
 	path = bootstrapify
 	url = https://github.com/ingwinlu/pelican-bootstrapify.git
 	url = https://github.com/ingwinlu/pelican-bootstrapify.git

+ 2 - 2
Readme.rst

@@ -156,14 +156,14 @@ Simple footnotes          Adds footnotes to blog posts
 
 
 Sitemap                   Generates plain-text or XML sitemaps
 Sitemap                   Generates plain-text or XML sitemaps
 
 
-sort_tags                 Provides `tags_sorted_by_article_length` to templates, which contains all tags, sorted by how many articles it contains first, and alphabetically second.
-
 Static comments           Allows you to add static comments to an article
 Static comments           Allows you to add static comments to an article
 
 
 Subcategory               Adds support for subcategories
 Subcategory               Adds support for subcategories
 
 
 Summary                   Allows easy, variable length summaries directly embedded into the body of your articles
 Summary                   Allows easy, variable length summaries directly embedded into the body of your articles
 
 
+tag_cloud                 Provides a tag_cloud
+
 Thumbnailer               Creates thumbnails for all of the images found under a specific directory
 Thumbnailer               Creates thumbnails for all of the images found under a specific directory
 
 
 Tipue Search              Serializes generated HTML to JSON that can be used by jQuery plugin - Tipue Search
 Tipue Search              Serializes generated HTML to JSON that can be used by jQuery plugin - Tipue Search

+ 0 - 1
sort_tags

@@ -1 +0,0 @@
-Subproject commit a3413a417ede463a66e59c5ea1ea017ff7782b84

+ 52 - 0
tag_cloud/README.rst

@@ -0,0 +1,52 @@
+tag_cloud
+=========
+
+This plugin generates a tag-cloud.
+
+Settings
+--------
+
+================================================    =====================================================
+Setting name (followed by default value)            What does it do?
+================================================    =====================================================
+``TAG_CLOUD_STEPS = 4``                             Count of different font sizes in the tag
+                                                    cloud.
+``TAG_CLOUD_MAX_ITEMS = 100``                       Maximum number of tags in the cloud.
+``TAG_CLOUD_SORTING = 'random'``                    The tag cloud ordering scheme.  Valid values:
+                                                    random, alphabetically, alphabetically-rev, size and
+                                                    size-rev
+================================================    =====================================================
+
+The default theme does not include a tag cloud, but it is pretty easy to add one::
+
+    <ul class="tagcloud">
+        {% for tag in tag_cloud %}
+            <li class="tag-{{ tag.1 }}"><a href="{{ SITEURL }}/{{ tag.0.url }}">{{ tag.0 }}</a></li>
+        {% endfor %}
+    </ul>
+
+You should then also define CSS styles with appropriate classes (tag-1 to tag-N,
+where N matches ``TAG_CLOUD_STEPS``), tag-1 being the most frequent, and
+define a ``ul.tagcloud`` class with appropriate list-style to create the cloud.
+For example::
+
+    ul.tagcloud {
+      list-style: none;
+        padding: 0;
+    }
+
+    ul.tagcloud li {
+        display: inline-block;
+    }
+
+    li.tag-1 {
+        font-size: 150%;
+    }
+
+    li.tag-2 {
+        font-size: 120%;
+    }
+
+    ...
+
+By default the tags in the cloud are sorted randomly, but if you prefers to have it alphabetically use the `alphabetically` (ascending) and `alphabetically-rev` (descending). Also is possible to sort the tags by it's size (number of articles with this specific tag) using the values `size` (ascending) and `size-rev` (descending).

+ 2 - 0
tag_cloud/__init__.py

@@ -0,0 +1,2 @@
+from .tag_cloud import *
+

+ 78 - 0
tag_cloud/tag_cloud.py

@@ -0,0 +1,78 @@
+'''
+tag_cloud
+===================================
+
+This plugin generates a tag cloud from available tags
+'''
+from __future__ import unicode_literals
+
+from collections import defaultdict
+from operator import attrgetter, itemgetter
+
+import logging
+import math
+import random
+
+from pelican import signals, contents
+
+logger = logging.getLogger(__name__)
+
+def set_default_settings(settings):
+    settings.setdefault('TAG_CLOUD_STEPS', 4)
+    settings.setdefault('TAG_CLOUD_MAX_ITEMS', 100)
+    settings.setdefault('TAG_CLOUD_SORTING', 'random')
+
+def init_default_config(pelican):
+    from pelican.settings import DEFAULT_CONFIG
+    set_default_settings(DEFAULT_CONFIG)
+    if(pelican):
+           set_default_settings(pelican.settings)
+
+def generate_tag_cloud(generator):
+    tag_cloud = defaultdict(int)
+    for article in generator.articles:
+        for tag in getattr(article, 'tags', []):
+            tag_cloud[tag] += 1
+
+    tag_cloud = sorted(tag_cloud.items(), key=itemgetter(1), reverse=True)
+    tag_cloud = tag_cloud[:generator.settings.get('TAG_CLOUD_MAX_ITEMS')]
+
+    tags = list(map(itemgetter(1), tag_cloud))
+    if tags:
+        max_count = max(tags)
+    steps = generator.settings.get('TAG_CLOUD_STEPS')
+
+    # calculate word sizes
+    tag_cloud = [
+        (
+            tag,
+            int(math.floor(steps - (steps - 1) * math.log(count)
+                / (math.log(max_count)or 1)))
+        )
+        for tag, count in tag_cloud
+    ]
+
+    sorting = generator.settings.get('TAG_CLOUD_SORTING')
+
+    if sorting == 'alphabetically':
+        tag_cloud.sort(key=lambda elem: elem[0].name)
+    elif sorting == 'alphabetically-rev':
+        tag_cloud.sort(key=lambda elem: elem[0].name, reverse=True)
+    elif sorting == 'size':
+        tag_cloud.sort(key=lambda elem: elem[1])
+    elif sorting == 'size-rev':
+        tag_cloud.sort(key=lambda elem: elem[1], reverse=True)
+    elif sorting == 'random':
+        random.shuffle(tag_cloud)
+    else:
+        logger.warning("setting for TAG_CLOUD_SORTING not recognized: %s, "
+                       "falling back to 'random'", sorting)
+        random.shuffle(tag_cloud)
+
+    #make available in context
+    generator.tag_cloud = tag_cloud
+    generator._update_context(['tag_cloud'])
+
+def register():
+    signals.initialized.connect(init_default_config)
+    signals.article_generator_finalized.connect(generate_tag_cloud)

+ 4 - 0
tag_cloud/test_data/article_1.md

@@ -0,0 +1,4 @@
+Title: Article1
+tags: fun, pelican, plugins
+
+content, yeah!

+ 5 - 0
tag_cloud/test_data/article_2.md

@@ -0,0 +1,5 @@
+Title: Article2
+tags: pelican, plugins, python
+
+content2, yeah!
+

+ 84 - 0
tag_cloud/test_tag_cloud.py

@@ -0,0 +1,84 @@
+import unittest, os, sys
+import six
+import tag_cloud
+
+from pelican.generators import ArticlesGenerator
+from pelican.tests.support import get_settings
+from pelican.urlwrappers import Tag
+
+CUR_DIR = os.path.dirname(__file__)
+CONTENT_DIR = os.path.join(CUR_DIR, 'test_data')
+
+class TestTagCloudGeneration(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls._settings = get_settings(filenames={})
+        cls._settings['DEFAULT_CATEGORY'] = 'Default'
+        cls._settings['DEFAULT_DATE'] = (1970, 1, 1)
+        cls._settings['READERS'] = {'asc': None}
+        cls._settings['CACHE_CONTENT'] = False
+        tag_cloud.set_default_settings(cls._settings)
+
+        cls.generator = ArticlesGenerator(
+            context=cls._settings.copy(), settings=cls._settings,
+            path=CONTENT_DIR, theme=cls._settings['THEME'], output_path=None)
+        cls.generator.generate_context()
+
+
+    def test_tag_cloud_random(self):
+        tag_cloud.generate_tag_cloud(self.generator)
+        expected = [
+                (Tag('plugins', self._settings), 1),
+                (Tag('fun', self._settings), 4),
+                (Tag('python', self._settings), 4),
+                (Tag('pelican', self._settings), 1)
+            ]
+        six.assertCountEqual(self, self.generator.tag_cloud, expected)
+
+    def test_tag_cloud_alphabetical(self):
+        self.generator.settings['TAG_CLOUD_SORTING'] = 'alphabetically'
+        tag_cloud.generate_tag_cloud(self.generator)
+        expected = [
+                (Tag('fun', self._settings), 4),
+                (Tag('pelican', self._settings), 1),
+                (Tag('plugins', self._settings), 1),
+                (Tag('python', self._settings), 4)
+            ]
+        self.assertEqual(self.generator.tag_cloud, expected)
+    
+    def test_tag_cloud_alphabetical_rev(self):
+        self.generator.settings['TAG_CLOUD_SORTING'] = 'alphabetically-rev'
+        tag_cloud.generate_tag_cloud(self.generator)
+        expected = [
+                (Tag('python', self._settings), 4),
+                (Tag('plugins', self._settings), 1),
+                (Tag('pelican', self._settings), 1),
+                (Tag('fun', self._settings), 4)
+            ]
+        self.assertEqual(self.generator.tag_cloud, expected)
+
+    def test_tag_cloud_size(self):
+        self.generator.settings['TAG_CLOUD_SORTING'] = 'size'
+        tag_cloud.generate_tag_cloud(self.generator)
+        expected = [
+                (Tag('pelican', self._settings), 1),
+                (Tag('plugins', self._settings), 1),
+                (Tag('fun', self._settings), 4),
+                (Tag('python', self._settings), 4)
+            ]
+        self.assertEqual(self.generator.tag_cloud, expected)
+
+    def test_tag_cloud_size_rev(self):
+        self.generator.settings['TAG_CLOUD_SORTING'] = 'size-rev'
+        tag_cloud.generate_tag_cloud(self.generator)
+        expected = [
+                (Tag('fun', self._settings), 4),
+                (Tag('python', self._settings), 4),
+                (Tag('pelican', self._settings), 1),
+                (Tag('plugins', self._settings), 1)
+            ]
+        self.assertEqual(self.generator.tag_cloud, expected)
+
+if __name__ == "__main__":
+    unittest.main()