Начало
This commit is contained in:
100
tag_cloud/README.rst
Normal file
100
tag_cloud/README.rst
Normal file
@@ -0,0 +1,100 @@
|
||||
tag_cloud
|
||||
=========
|
||||
|
||||
**NOTE:** `This plugin has been moved to its own repository <https://github.com/pelican-plugins/tag-cloud>`_. Please file any issues/PRs there. Once all plugins have been migrated to the `new Pelican Plugins organization <https://github.com/pelican-plugins>`_, this monolithic repository will be archived.
|
||||
|
||||
This plugin generates a tag-cloud.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
In order to use to use this plugin, you have to edit(*) or create(+) the following files::
|
||||
|
||||
blog/
|
||||
├── pelicanconf.py *
|
||||
├── content
|
||||
├── plugins +
|
||||
│ └── tag_cloud.py +
|
||||
└── themes
|
||||
└── mytheme
|
||||
├── templates
|
||||
│ └── base.html *
|
||||
└── static
|
||||
└── css
|
||||
└── style.css *
|
||||
|
||||
In **pelicanconf.py** you have to activate the plugin::
|
||||
|
||||
PLUGIN_PATHS = ["plugins"]
|
||||
PLUGINS = ["tag_cloud"]
|
||||
|
||||
Into your **plugins** folder, you should add tag_cloud.py (from this repository).
|
||||
|
||||
In your theme files, you should change **base.html** to apply formats (and sizes) defined in **style.css**, as specified in "Settings", below.
|
||||
|
||||
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
|
||||
``TAG_CLOUD_BADGE = True`` Optionnal setting : can bring **badges**, which mean
|
||||
say : display the number of each tags present
|
||||
on all articles.
|
||||
================================================ =====================================================
|
||||
|
||||
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 }}
|
||||
{% if TAG_CLOUD_BADGE %}
|
||||
<span class="badge">{{ tag.2 }}</span>
|
||||
{% endif %}
|
||||
</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.
|
||||
You should copy/paste this **badge** CSS rule ``ul.tagcloud .list-group-item <span>.badge``
|
||||
if you're using ``TAG_CLOUD_BADGE`` setting. (this rule, potentially long , is suggested to avoid
|
||||
conflicts with CSS libs as twitter Bootstrap)
|
||||
|
||||
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%;
|
||||
}
|
||||
|
||||
/* ... add li.tag-3 etc, as much as needed */
|
||||
|
||||
ul.tagcloud .list-group-item span.badge {
|
||||
background-color: grey;
|
||||
color: white;
|
||||
}
|
||||
|
||||
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
tag_cloud/__init__.py
Normal file
2
tag_cloud/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .tag_cloud import *
|
||||
|
90
tag_cloud/tag_cloud.py
Normal file
90
tag_cloud/tag_cloud.py
Normal file
@@ -0,0 +1,90 @@
|
||||
'''
|
||||
tag_cloud
|
||||
===================================
|
||||
|
||||
This plugin generates a tag cloud from available tags
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collections import defaultdict
|
||||
from operator import itemgetter
|
||||
|
||||
import logging
|
||||
import math
|
||||
import random
|
||||
|
||||
from pelican import signals
|
||||
|
||||
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')
|
||||
settings.setdefault('TAG_CLOUD_BADGE', False)
|
||||
|
||||
|
||||
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 = tags[0]
|
||||
min_count = tags[-1]
|
||||
steps = generator.settings.get('TAG_CLOUD_STEPS')
|
||||
|
||||
# calculate word sizes
|
||||
def generate_tag(tag, count):
|
||||
tag = (
|
||||
tag,
|
||||
int(math.floor(steps - (steps - 1) * math.log(count - min_count + 1)
|
||||
/ (math.log(max_count - min_count + 1) or 1)))
|
||||
)
|
||||
if generator.settings.get('TAG_CLOUD_BADGE'):
|
||||
tag += (count,)
|
||||
return tag
|
||||
|
||||
tag_cloud = [
|
||||
generate_tag(tag, count)
|
||||
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
tag_cloud/test_data/article_1.md
Normal file
4
tag_cloud/test_data/article_1.md
Normal file
@@ -0,0 +1,4 @@
|
||||
Title: Article1
|
||||
tags: fun, pelican, plugins
|
||||
|
||||
content, yeah!
|
5
tag_cloud/test_data/article_2.md
Normal file
5
tag_cloud/test_data/article_2.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Title: Article2
|
||||
tags: pelican, plugins, python
|
||||
|
||||
content2, yeah!
|
||||
|
5
tag_cloud/test_data/article_3.md
Normal file
5
tag_cloud/test_data/article_3.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Title: Article3
|
||||
tags: pelican, plugins
|
||||
|
||||
content3, yeah!
|
||||
|
5
tag_cloud/test_data/article_4.md
Normal file
5
tag_cloud/test_data/article_4.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Title: Article4
|
||||
tags: pelican, fun
|
||||
|
||||
content4, yeah!
|
||||
|
5
tag_cloud/test_data/article_5.md
Normal file
5
tag_cloud/test_data/article_5.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Title: Article5
|
||||
tags: plugins, pelican, fun
|
||||
|
||||
content5, yeah!
|
||||
|
114
tag_cloud/test_tag_cloud.py
Normal file
114
tag_cloud/test_tag_cloud.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import unittest
|
||||
import os
|
||||
import six
|
||||
import tag_cloud
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp
|
||||
|
||||
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.temp_path = mkdtemp(prefix='pelicantests.')
|
||||
|
||||
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)
|
||||
|
||||
context = cls._settings.copy()
|
||||
context['generated_content'] = dict()
|
||||
context['static_links'] = set()
|
||||
cls.generator = ArticlesGenerator(
|
||||
context=context, settings=cls._settings,
|
||||
path=CONTENT_DIR, theme=cls._settings['THEME'], output_path=cls.temp_path)
|
||||
cls.generator.generate_context()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
rmtree(cls.temp_path)
|
||||
|
||||
def test_tag_cloud_random(self):
|
||||
self.generator.settings['TAG_CLOUD_STEPS'] = 10
|
||||
self.generator.settings['TAG_CLOUD_BADGE'] = False
|
||||
tag_cloud.generate_tag_cloud(self.generator)
|
||||
expected = [
|
||||
(Tag('pelican', self._settings), 1),
|
||||
(Tag('plugins', self._settings), 2),
|
||||
(Tag('fun', self._settings), 3),
|
||||
(Tag('python', self._settings), 10)
|
||||
]
|
||||
six.assertCountEqual(self, self.generator.tag_cloud, expected)
|
||||
|
||||
def test_tag_cloud_badge(self):
|
||||
self.generator.settings['TAG_CLOUD_STEPS'] = 10
|
||||
self.generator.settings['TAG_CLOUD_BADGE'] = True
|
||||
tag_cloud.generate_tag_cloud(self.generator)
|
||||
expected = [
|
||||
(Tag('pelican', self._settings), 1, 5),
|
||||
(Tag('plugins', self._settings), 2, 4),
|
||||
(Tag('fun', self._settings), 3, 3),
|
||||
(Tag('python', self._settings), 10, 1)
|
||||
]
|
||||
six.assertCountEqual(self, self.generator.tag_cloud, expected)
|
||||
|
||||
def test_tag_cloud_alphabetical(self):
|
||||
self.generator.settings['TAG_CLOUD_STEPS'] = 10
|
||||
self.generator.settings['TAG_CLOUD_SORTING'] = 'alphabetically'
|
||||
tag_cloud.generate_tag_cloud(self.generator)
|
||||
expected = [
|
||||
(Tag('fun', self._settings), 3),
|
||||
(Tag('pelican', self._settings), 1),
|
||||
(Tag('plugins', self._settings), 2),
|
||||
(Tag('python', self._settings), 10)
|
||||
]
|
||||
self.assertEqual(self.generator.tag_cloud, expected)
|
||||
|
||||
def test_tag_cloud_alphabetical_rev(self):
|
||||
self.generator.settings['TAG_CLOUD_STEPS'] = 10
|
||||
self.generator.settings['TAG_CLOUD_SORTING'] = 'alphabetically-rev'
|
||||
tag_cloud.generate_tag_cloud(self.generator)
|
||||
expected = [
|
||||
(Tag('python', self._settings), 10),
|
||||
(Tag('plugins', self._settings), 2),
|
||||
(Tag('pelican', self._settings), 1),
|
||||
(Tag('fun', self._settings), 3)
|
||||
]
|
||||
self.assertEqual(self.generator.tag_cloud, expected)
|
||||
|
||||
def test_tag_cloud_size(self):
|
||||
self.generator.settings['TAG_CLOUD_STEPS'] = 10
|
||||
self.generator.settings['TAG_CLOUD_SORTING'] = 'size'
|
||||
tag_cloud.generate_tag_cloud(self.generator)
|
||||
expected = [
|
||||
(Tag('pelican', self._settings), 1),
|
||||
(Tag('plugins', self._settings), 2),
|
||||
(Tag('fun', self._settings), 3),
|
||||
(Tag('python', self._settings), 10)
|
||||
]
|
||||
self.assertEqual(self.generator.tag_cloud, expected)
|
||||
|
||||
def test_tag_cloud_size_rev(self):
|
||||
self.generator.settings['TAG_CLOUD_STEPS'] = 10
|
||||
self.generator.settings['TAG_CLOUD_SORTING'] = 'size-rev'
|
||||
tag_cloud.generate_tag_cloud(self.generator)
|
||||
expected = [
|
||||
(Tag('python', self._settings), 10),
|
||||
(Tag('fun', self._settings), 3),
|
||||
(Tag('plugins', self._settings), 2),
|
||||
(Tag('pelican', self._settings), 1)
|
||||
]
|
||||
self.assertEqual(self.generator.tag_cloud, expected)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Reference in New Issue
Block a user