diff --git a/subcategory/README.md b/subcategory/README.md index f9a3f24..67993aa 100644 --- a/subcategory/README.md +++ b/subcategory/README.md @@ -3,9 +3,7 @@ Adds support for subcategories in addition to article categories. Subcategories are heirachial. Each subcategory has a parent, which is either a -regular category or another subcategory. Subcategories with the same name but -different parents are not the same. Their articles won't be grouped together -under that name. +regular category or another subcategory. Feeds can be generated for each subcategory just like categories and tags. @@ -27,16 +25,31 @@ breadcrumb style navigation you might try something like this: +##Subcategory Names## +Each subcategory's name is a `/` seperated list of it parents and itself. +This is neccesary to keep each subcategory unique. It means you can have +`Category 1/Foo` and `Category 2/Foo` and the won't intefere with each other. +Each subcategory has an attribute `shortname` which is just the name without +it's parents associated. For example if you had + + Category/Sub Category1/Sub Category2 + +the name for Sub Category 2 would be `Category/Sub Category1/Sub Category2` and +the shortname would be `Sub Category2` + +If you need to use the slug, it is generated from the short name, not the full +name. + ##Settings## diff --git a/subcategory/subcategory.py b/subcategory/subcategory.py index be37b81..e037f74 100644 --- a/subcategory/subcategory.py +++ b/subcategory/subcategory.py @@ -6,64 +6,89 @@ Adds support for subcategories on pelican articles """ import os from collections import defaultdict -from pelican import signals -from pelican.urlwrappers import URLWrapper, Category from operator import attrgetter from functools import partial +from pelican import signals +from pelican.urlwrappers import URLWrapper, Category +from pelican.utils import (slugify, python_2_unicode_compatible) + from six import text_type class SubCategory(URLWrapper): - def __init__(self, name, parent, *args, **kwargs): - super(SubCategory, self).__init__(name, *args, **kwargs) + def __init__(self, name, parent, settings): + super(SubCategory, self).__init__(name, settings) self.parent = parent + self.shortname = name.split('/') + self.shortname = self.shortname.pop() + self.slug = slugify(self.shortname, settings.get('SLUG_SUBSTITUIONS', ())) if isinstance(self.parent, SubCategory): self.savepath = os.path.join(self.parent.savepath, self.slug) self.fullurl = '{}/{}'.format(self.parent.fullurl, self.slug) else: #parent is a category self.savepath = os.path.join(self.parent.slug, self.slug) self.fullurl = '{}/{}'.format(self.parent.slug, self.slug) - + def as_dict(self): d = self.__dict__ - d['name'] = self.name + d['shortname'] = self.shortname d['savepath'] = self.savepath d['fullurl'] = self.fullurl d['parent'] = self.parent return d + def __hash__(self): + return hash(self.fullurl) + + def _key(self): + return self.fullurl + def get_subcategories(generator, metadata): if 'SUBCATEGORY_SAVE_AS' not in generator.settings: generator.settings['SUBCATEGORY_SAVE_AS'] = os.path.join( 'subcategory', '{savepath}.html') if 'SUBCATEGORY_URL' not in generator.settings: generator.settings['SUBCATEGORY_URL'] = 'subcategory/{fullurl}.html' + category_list = text_type(metadata.get('category')).split('/') category = (category_list.pop(0)).strip() category = Category(category, generator.settings) metadata['category'] = category #generate a list of subcategories with their parents sub_list = [] - parent = category + parent = category.name for subcategory in category_list: subcategory.strip() - subcategory = SubCategory(subcategory, parent, generator.settings) + subcategory = parent + '/' + subcategory sub_list.append(subcategory) parent = subcategory metadata['subcategories'] = sub_list -def organize_subcategories(generator): - generator.subcategories = defaultdict(list) +def create_subcategories(generator): + generator.subcategories = [] for article in generator.articles: - subcategories = article.metadata.get('subcategories') - for cat in subcategories: - generator.subcategories[cat].append(article) + parent = article.category + actual_subcategories = [] + for subcategory in article.subcategories: + #following line returns a list of items, tuples in this case + sub_cat = [item for item in generator.subcategories + if item[0].name == subcategory] + if sub_cat: + sub_cat[0][1].append(article) + parent = sub_cat[0][0] + actual_subcategories.append(parent) + else: + new_sub = SubCategory(subcategory, parent, generator.settings) + generator.subcategories.append((new_sub, [article,])) + parent = new_sub + actual_subcategories.append(parent) + article.subcategories = actual_subcategories def generate_subcategories(generator, writer): write = partial(writer.write_file, relative_urls=generator.settings['RELATIVE_URLS']) subcategory_template = generator.get_template('subcategory') - for subcat, articles in generator.subcategories.items(): + for subcat, articles in generator.subcategories: articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in generator.dates if article in articles] write(subcat.save_as, subcategory_template, generator.context, @@ -72,7 +97,7 @@ def generate_subcategories(generator, writer): page_name=subcat.page_name, all_articles=generator.articles) def generate_subcategory_feeds(generator, writer): - for subcat, articles in generator.subcategories.items(): + for subcat, articles in generator.subcategories: articles.sort(key=attrgetter('date'), reverse=True) if generator.settings.get('SUBCATEGORY_FEED_ATOM'): writer.write_feed(articles, generator.context, @@ -89,5 +114,5 @@ def generate(generator, writer): def register(): signals.article_generator_context.connect(get_subcategories) - signals.article_generator_finalized.connect(organize_subcategories) + signals.article_generator_finalized.connect(create_subcategories) signals.article_writer_finalized.connect(generate)