Browse Source

Merge pull request #143 from alistairmagee/subcategory

Sub-categories with same basename but different parents should be unique
Justin Mayer 11 years ago
parent
commit
d13465d1b2
2 changed files with 59 additions and 21 deletions
  1. 18 5
      subcategory/README.md
  2. 41 16
      subcategory/subcategory.py

+ 18 - 5
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:
     <nav class="breadcrumb">
     <ol>
         <li>
-            <a href="{{ SITEURL }}/{{ arcticle.categor.url }}">{{ article.category}}</a>
+            <a href="{{ SITEURL }}/{{ arcticle.category.url }}">{{ article.category}}</a>
         </li>
     {% for subcategory in article.subcategories %}
         <li>
-            <a href="{{ SITEURL }}/{{ category.url }}>{{ subcategory }}</a>
+            <a href="{{ SITEURL }}/{{ subcategory.url }}>{{ subcategory.shortname }}</a>
         </li>
     {% endfor %}
     </ol>
     </nav>
  
+##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##
 

+ 41 - 16
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)