Get htmltmpl mostly working

This commit is contained in:
Sam Ruby 2006-08-29 15:19:35 -04:00
parent d17d509adc
commit 92eab64934
30 changed files with 544 additions and 46 deletions

View File

@ -64,17 +64,19 @@ def __init__():
# planet wide options # planet wide options
define_planet('name', "Unconfigured Planet") define_planet('name', "Unconfigured Planet")
define_planet('link', "Unconfigured Planet") define_planet('link', '')
define_planet('cache_directory', "cache") define_planet('cache_directory', "cache")
define_planet('log_level', "WARNING") define_planet('log_level', "WARNING")
define_planet('feed_timeout', 20) define_planet('feed_timeout', 20)
define_planet('date_format', "%B %d, %Y %I:%M %p") define_planet('date_format', "%B %d, %Y %I:%M %p")
define_planet('new_date_format', "%B %d, %Y")
define_planet('generator', 'Venus') define_planet('generator', 'Venus')
define_planet('generator_uri', 'http://intertwingly.net/code/venus/') define_planet('generator_uri', 'http://intertwingly.net/code/venus/')
define_planet('owner_name', 'Anonymous Coward') define_planet('owner_name', 'Anonymous Coward')
define_planet('owner_email', '') define_planet('owner_email', '')
define_planet('output_theme', '') define_planet('output_theme', '')
define_planet('output_dir', 'output') define_planet('output_dir', 'output')
define_planet('feed', None)
define_planet_list('template_files') define_planet_list('template_files')
define_planet_list('bill_of_materials') define_planet_list('bill_of_materials')
@ -160,8 +162,25 @@ def cache_lists_directory():
else: else:
return os.path.join(cache_directory(), 'lists') return os.path.join(cache_directory(), 'lists')
def feeds(): def feed():
""" list the feeds defined """ if parser.has_option('Planet', 'feed'):
parser.get('Planet', 'feed')
elif link():
for template_file in template_files:
name = os.path.splitext(os.path.basename(template_file))[0]
if name.find('atom')>=0 or name.find('rss')>=0:
return urlparse.urljoin(link(), name)
def feedtype():
if parser.has_option('Planet', 'feedtype'):
parser.get('Planet', 'feedtype')
elif feed() and feed().find('atom')>=0:
return 'atom'
elif feed() and feed().find('rss')>=0:
return 'rss'
def subscriptions():
""" list the feed subscriptions """
return filter(lambda feed: feed!='Planet' and feed not in template_files(), return filter(lambda feed: feed!='Planet' and feed not in template_files(),
parser.sections()) parser.sections())

View File

@ -1,5 +1,5 @@
from xml.sax.saxutils import escape from xml.sax.saxutils import escape
import sgmllib, time, os, sys import sgmllib, time, os, sys, new, urlparse
from planet import config, feedparser, htmltmpl from planet import config, feedparser, htmltmpl
class stripHtml(sgmllib.SGMLParser): class stripHtml(sgmllib.SGMLParser):
@ -54,6 +54,9 @@ def Plain(value):
def PlanetDate(value): def PlanetDate(value):
return time.strftime(config.date_format(), value) return time.strftime(config.date_format(), value)
def NewDate(value):
return time.strftime(config.new_date_format(), value)
def Rfc822(value): def Rfc822(value):
return time.strftime("%a, %d %b %Y %H:%M:%S +0000", value) return time.strftime("%a, %d %b %Y %H:%M:%S +0000", value)
@ -64,7 +67,6 @@ def Rfc3399(value):
Base = [ Base = [
['author', String, 'author'], ['author', String, 'author'],
['author_name', String, 'author_detail', 'name'], ['author_name', String, 'author_detail', 'name'],
['feed', String, 'links', {'rel':'self'}, 'href'],
['generator', String, 'generator'], ['generator', String, 'generator'],
['id', String, 'id'], ['id', String, 'id'],
['icon', String, 'icon'], ['icon', String, 'icon'],
@ -76,9 +78,9 @@ Base = [
['subtitle', String, 'subtitle_detail', 'value'], ['subtitle', String, 'subtitle_detail', 'value'],
['title', String, 'title_detail', 'value'], ['title', String, 'title_detail', 'value'],
['title_plain', Plain, 'title_detail', 'value'], ['title_plain', Plain, 'title_detail', 'value'],
['url', String, 'links', {'rel':'self'}, 'href'],
] ]
# ? new_date, new_channel
Items = [ Items = [
['author', String, 'author'], ['author', String, 'author'],
['author_email', String, 'author_detail', 'email'], ['author_email', String, 'author_detail', 'email'],
@ -95,6 +97,9 @@ Items = [
['date_iso', Rfc3399, 'updated_parsed'], ['date_iso', Rfc3399, 'updated_parsed'],
['id', String, 'id'], ['id', String, 'id'],
['link', String, 'links', {'rel': 'alternate'}, 'href'], ['link', String, 'links', {'rel': 'alternate'}, 'href'],
['new_channel', String, 'id'],
['new_date', NewDate, 'published_parsed'],
['new_date', NewDate, 'updated_parsed'],
['rights', String, 'rights_detail', 'value'], ['rights', String, 'rights_detail', 'value'],
['title_language', String, 'title_detail', 'language'], ['title_language', String, 'title_detail', 'language'],
['title_plain', Plain, 'title_detail', 'value'], ['title_plain', Plain, 'title_detail', 'value'],
@ -108,14 +113,6 @@ Items = [
['published_iso', Rfc3399, 'published_parsed'], ['published_iso', Rfc3399, 'published_parsed'],
] ]
Channels = [
['url', None],
['link', None],
['message', None],
['title_plain', None],
['name', None],
]
# Add additional rules for source information # Add additional rules for source information
for rule in Base: for rule in Base:
Items.append(['channel_'+rule[0], rule[1], 'source'] + rule[2:]) Items.append(['channel_'+rule[0], rule[1], 'source'] + rule[2:])
@ -161,13 +158,67 @@ def tmpl_mapper(source, rules):
return output return output
def _end_planet_source(self):
self._end_source()
context = self._getContext()
if not context.has_key('sources'): context['sources'] = []
context.sources.append(context.source)
del context['source']
def template_info(source): def template_info(source):
""" get template information from a feedparser output """ """ get template information from a feedparser output """
# wire in support for planet:source, call feedparser, unplug planet:source
mixin=feedparser._FeedParserMixin
mixin._start_planet_source = mixin._start_source
mixin._end_planet_source = \
new.instancemethod(_end_planet_source, None, mixin)
data=feedparser.parse(source) data=feedparser.parse(source)
del mixin._start_planet_source
del mixin._end_planet_source
# apply rules to convert feed parser output to htmltmpl input
output = {'Channels': [], 'Items': []} output = {'Channels': [], 'Items': []}
output['Channels'].append(tmpl_mapper(data.feed, Base)) output.update(tmpl_mapper(data.feed, Base))
sources = [(source.get('planet_name',None),source)
for source in data.feed.get('sources',[])]
sources.sort()
for name, feed in sources:
output['Channels'].append(tmpl_mapper(feed, Base))
for entry in data.entries: for entry in data.entries:
output['Items'].append(tmpl_mapper(entry, Items)) output['Items'].append(tmpl_mapper(entry, Items))
# feed level information
output['generator'] = config.generator_uri()
output['name'] = config.name()
output['link'] = config.link()
output['owner_name'] = config.owner_name()
output['owner_email'] = config.owner_email()
if config.feed():
output['feed'] = config.feed()
output['feedtype'] = config.feed().find('rss')>=0 and 'rss' or 'atom'
# date/time information
date = time.gmtime()
output['date'] = PlanetDate(date)
output['date_iso'] = Rfc3399(date)
output['date_822'] = Rfc822(date)
# remove new_dates and new_channels that aren't "new"
date = channel = None
for item in output['Items']:
if item.has_key('new_date'):
if item['new_date'] == date:
del item['new_date']
else:
date = item['new_date']
if item.has_key('new_channel'):
if item['new_channel'] == channel:
del item['new_channel']
else:
channel = item['new_channel']
return output return output
def run(script, doc, output_file=None): def run(script, doc, output_file=None):
@ -177,6 +228,10 @@ def run(script, doc, output_file=None):
tp = htmltmpl.TemplateProcessor(html_escape=0) tp = htmltmpl.TemplateProcessor(html_escape=0)
for key,value in template_info(doc).items(): for key,value in template_info(doc).items():
tp.set(key, value) tp.set(key, value)
reluri = os.path.splitext(os.path.basename(output_file))[0]
tp.set('url', urlparse.urljoin(config.link(),reluri))
output = open(output_file, "w") output = open(output_file, "w")
output.write(tp.process(template)) output.write(tp.process(template))
output.close() output.close()

View File

@ -147,5 +147,5 @@ def spiderPlanet(configFile):
log = planet.getLogger(config.log_level()) log = planet.getLogger(config.log_level())
planet.setTimeout(config.feed_timeout()) planet.setTimeout(config.feed_timeout())
for feed in config.feeds(): for feed in config.subscriptions():
spiderFeed(feed) spiderFeed(feed)

View File

@ -42,7 +42,7 @@ def splice(configFile):
# insert subscription information # insert subscription information
feed.setAttribute('xmlns:planet',planet.xmlns) feed.setAttribute('xmlns:planet',planet.xmlns)
sources = config.cache_sources_directory() sources = config.cache_sources_directory()
for sub in config.feeds(): for sub in config.subscriptions():
data=feedparser.parse(filename(sources,sub)) data=feedparser.parse(filename(sources,sub))
if not data.feed: continue if not data.feed: continue
xdoc=minidom.parseString('''<planet:source xmlns:planet="%s" xdoc=minidom.parseString('''<planet:source xmlns:planet="%s"

View File

@ -0,0 +1,7 @@
;
; Description: id
; Expect: feed == 'http://example.com/atom.xml' and feedtype == 'atom'
;
[Planet]
feed: http://example.com/atom.xml

View File

@ -0,0 +1,7 @@
;
; Description: id
; Expect: generator == 'http://example.com/planet'
;
[Planet]
generator_uri: http://example.com/planet

View File

@ -0,0 +1,7 @@
;
; Description: id
; Expect: link == 'http://example.com/planet'
;
[Planet]
link: http://example.com/planet

View File

@ -0,0 +1,7 @@
;
; Description: id
; Expect: name == 'My Planet'
;
[Planet]
name: My Planet

View File

@ -0,0 +1,7 @@
;
; Description: id
; Expect: owner_email == 'me@example.com'
;
[Planet]
owner_email: me@example.com

View File

@ -0,0 +1,7 @@
;
; Description: id
; Expect: owner_name == 'me'
;
[Planet]
owner_name: me

View File

@ -1,14 +1,16 @@
<!-- <!--
Description: id Description: id
Expect: Channels[0]['name'] == 'foo' Expect: Channels[0]['name'] == 'foo' and Items[0]['channel_name'] == 'foo'
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<planet:name>foo</planet:name>
<entry> <entry>
<source> <source>
<planet:name>foo</planet:name> <planet:name>foo</planet:name>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<planet:name>foo</planet:name>
</planet:source>
</feed> </feed>

View File

@ -4,9 +4,6 @@ Expect: Channels[0]['author'] == 'John Doe' and Channels[0]['author_name']
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<author>
<name>John Doe</name>
</author>
<entry> <entry>
<source> <source>
<author> <author>
@ -14,5 +11,10 @@ Expect: Channels[0]['author'] == 'John Doe' and Channels[0]['author_name']
</author> </author>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<author>
<name>John Doe</name>
</author>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['icon'] == 'http://www.example.com/favicon.ico' and It
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<icon>http://www.example.com/favicon.ico</icon>
<entry> <entry>
<source> <source>
<icon>http://www.example.com/favicon.ico</icon> <icon>http://www.example.com/favicon.ico</icon>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<icon>http://www.example.com/favicon.ico</icon>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['id'] == 'http://example.com/' and Items[0]['channel_i
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<id>http://example.com/</id>
<entry> <entry>
<source> <source>
<id>http://example.com/</id> <id>http://example.com/</id>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<id>http://example.com/</id>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['logo'] == 'http://www.example.com/logo.jpg' and Items
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<logo>http://www.example.com/logo.jpg</logo>
<entry> <entry>
<source> <source>
<logo>http://www.example.com/logo.jpg</logo> <logo>http://www.example.com/logo.jpg</logo>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<logo>http://www.example.com/logo.jpg</logo>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['name'] == 'foo' and Items[0]['channel_name'] == 'foo'
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<planet:name>foo</planet:name>
<entry> <entry>
<source> <source>
<planet:name>foo</planet:name> <planet:name>foo</planet:name>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<planet:name>foo</planet:name>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['rights'] == '&copy; 2006' and Items[0]['channel_right
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<rights type="html">&amp;copy; 2006</rights>
<entry> <entry>
<source> <source>
<rights type="html">&amp;copy; 2006</rights> <rights type="html">&amp;copy; 2006</rights>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<rights type="html">&amp;copy; 2006</rights>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['subtitle'] == 'snarky phrase' and Items[0]['channel_s
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<subtitle>snarky phrase</subtitle>
<entry> <entry>
<source> <source>
<subtitle>snarky phrase</subtitle> <subtitle>snarky phrase</subtitle>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<subtitle>snarky phrase</subtitle>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['title'] == 'visible name' and Channels[0]['title_plai
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<title>visible name</title>
<entry> <entry>
<source> <source>
<title>visible name</title> <title>visible name</title>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<title>visible name</title>
</planet:source>
</feed> </feed>

View File

@ -4,11 +4,13 @@ Expect: Channels[0]['last_updated_iso'] == '2004-02-29T02:14:55+00:00' and
--> -->
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<updated>2004-02-28T18:14:55-08:00</updated>
<entry> <entry>
<source> <source>
<updated>2004-02-28T18:14:55-08:00</updated> <updated>2004-02-28T18:14:55-08:00</updated>
</source> </source>
</entry> </entry>
<planet:source xmlns:planet='http://planet.intertwingly.net/'>
<updated>2004-02-28T18:14:55-08:00</updated>
</planet:source>
</feed> </feed>

View File

@ -14,7 +14,7 @@ class ConfigTest(unittest.TestCase):
config.template_files()) config.template_files())
def test_feeds(self): def test_feeds(self):
feeds = config.feeds() feeds = config.subscriptions()
feeds.sort() feeds.sort()
self.assertEqual(['feed1', 'feed2'], feeds) self.assertEqual(['feed1', 'feed2'], feeds)
@ -24,7 +24,7 @@ class ConfigTest(unittest.TestCase):
self.assertEqual('Test Configuration', config.name()) self.assertEqual('Test Configuration', config.name())
def test_link(self): def test_link(self):
self.assertEqual('Unconfigured Planet', config.link()) self.assertEqual('', config.link())
# per template configuration # per template configuration

View File

@ -1,20 +1,22 @@
#!/usr/bin/env python #!/usr/bin/env python
import unittest, os, sys, glob, new, re, StringIO, time import unittest, os, sys, glob, new, re, StringIO, time
from planet import config
from planet.shell import tmpl from planet.shell import tmpl
testfiles = 'tests/data/filter/tmpl/%s.xml' testfiles = 'tests/data/filter/tmpl/%s.%s'
class FilterTmplTest(unittest.TestCase): class FilterTmplTest(unittest.TestCase):
desc_re = re.compile("Description:\s*(.*?)\s*Expect:\s*(.*)\s*-->") desc_feed_re = re.compile("Description:\s*(.*?)\s*Expect:\s*(.*)\s*-->")
desc_config_re = re.compile(";\s*Description:\s*(.*?)\s*;\s*Expect:\s*(.*)")
simple_re = re.compile("^(\S+) == (u?'[^']*'|\([0-9, ]+\))$") simple_re = re.compile("^(\S+) == (u?'[^']*'|\([0-9, ]+\))$")
def eval(self, name): def eval_feed(self, name):
# read the test case # read the test case
try: try:
testcase = open(testfiles % name) testcase = open(testfiles % (name,'xml'))
data = testcase.read() data = testcase.read()
description, expect = self.desc_re.search(data).groups() description, expect = self.desc_feed_re.search(data).groups()
testcase.close() testcase.close()
except: except:
raise RuntimeError, "can't parse %s" % name raise RuntimeError, "can't parse %s" % name
@ -29,9 +31,37 @@ class FilterTmplTest(unittest.TestCase):
lhs, rhs = self.simple_re.match(expect).groups() lhs, rhs = self.simple_re.match(expect).groups()
self.assertEqual(eval(rhs), eval(lhs, results)) self.assertEqual(eval(rhs), eval(lhs, results))
# build a test method for each test file def eval_config(self, name):
for testcase in glob.glob(testfiles % '*'): # read the test case
try:
testcase = open(testfiles % (name,'ini'))
data = testcase.read()
description, expect = self.desc_config_re.search(data).groups()
testcase.close()
except:
raise RuntimeError, "can't parse %s" % name
# map to template info
config.load(testfiles % (name,'ini'))
results = tmpl.template_info("<feed/>")
# verify the results
if not self.simple_re.match(expect):
self.assertTrue(eval(expect, results), expect)
else:
lhs, rhs = self.simple_re.match(expect).groups()
self.assertEqual(eval(rhs), eval(lhs, results))
# build a test method for each xml test file
for testcase in glob.glob(testfiles % ('*','xml')):
root = os.path.splitext(os.path.basename(testcase))[0] root = os.path.splitext(os.path.basename(testcase))[0]
func = lambda self, name=root: self.eval(name) func = lambda self, name=root: self.eval_feed(name)
method = new.instancemethod(func, None, FilterTmplTest)
setattr(FilterTmplTest, "test_" + root, method)
# build a test method for each ini test file
for testcase in glob.glob(testfiles % ('*','ini')):
root = os.path.splitext(os.path.basename(testcase))[0]
func = lambda self, name=root: self.eval_config(name)
method = new.instancemethod(func, None, FilterTmplTest) method = new.instancemethod(func, None, FilterTmplTest)
setattr(FilterTmplTest, "test_" + root, method) setattr(FilterTmplTest, "test_" + root, method)

View File

@ -19,7 +19,7 @@ class ReadingListTest(unittest.TestCase):
# administrivia # administrivia
def test_feeds(self): def test_feeds(self):
feeds = [split(feed)[1] for feed in config.feeds()] feeds = [split(feed)[1] for feed in config.subscriptions()]
feeds.sort() feeds.sort()
self.assertEqual(['testfeed0.atom', 'testfeed1a.atom', self.assertEqual(['testfeed0.atom', 'testfeed1a.atom',
'testfeed2.atom', 'testfeed3.rss'], feeds) 'testfeed2.atom', 'testfeed3.rss'], feeds)
@ -27,7 +27,7 @@ class ReadingListTest(unittest.TestCase):
# dictionaries # dictionaries
def test_feed_options(self): def test_feed_options(self):
feeds = dict([(split(feed)[1],feed) for feed in config.feeds()]) feeds = dict([(split(feed)[1],feed) for feed in config.subscriptions()])
feed1 = feeds['testfeed1a.atom'] feed1 = feeds['testfeed1a.atom']
self.assertEqual('one', config.feed_options(feed1)['name']) self.assertEqual('one', config.feed_options(feed1)['name'])

View File

@ -20,7 +20,7 @@ class ConfigTest(unittest.TestCase):
self.assertTrue('index.html.xslt' in config.template_files()) self.assertTrue('index.html.xslt' in config.template_files())
def test_feeds(self): def test_feeds(self):
feeds = config.feeds() feeds = config.subscriptions()
feeds.sort() feeds.sort()
self.assertEqual(['feed1', 'feed2'], feeds) self.assertEqual(['feed1', 'feed2'], feeds)
@ -30,7 +30,7 @@ class ConfigTest(unittest.TestCase):
self.assertEqual('Test Configuration', config.name()) self.assertEqual('Test Configuration', config.name())
def test_link(self): def test_link(self):
self.assertEqual('Unconfigured Planet', config.link()) self.assertEqual('', config.link())
# per template configuration # per template configuration

View File

@ -1,10 +1,9 @@
# This template is based on the one originally developed by Stefano Mazzocci # This theme is based on the one originally developed by Stefano Mazzocci
# for planetapache.org, and modified by Sam Ruby for planet.intertwingly.net # for planetapache.org, and modified by Sam Ruby for planet.intertwingly.net
[Planet] [Planet]
template_files: template_files:
atom.xml.xslt atom.xml.xslt
rss20.xml.tmpl
foafroll.xml.xslt foafroll.xml.xslt
index.html.xslt index.html.xslt
opml.xml.xslt opml.xml.xslt

View File

@ -0,0 +1,20 @@
# This theme is based on the one contained in Planet V2.0. It demonstrates
# that one can mix the use of htmltmpl and xslt templates.
[Planet]
template_files:
atom.xml.xslt
foafroll.xml.xslt
index.html.tmpl
opml.xml.xslt
rss10.xml.tmpl
rss20.xml.tmpl
template_directories:
../common
bill_of_materials:
planet.css
images/feed-icon-10x10.png
images/logo.png
images/planet.png

View File

@ -0,0 +1,126 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
### Fancy Planet HTML template.
###
### When combined with the stylesheet and images in the output/ directory
### of the Planet source, this gives you a much prettier result than the
### default examples template and demonstrates how to use the config file
### to support things like faces
###
### For documentation on the more boring template elements, see
### examples/config.ini and examples/index.html.tmpl in the Planet source.
<head>
<title><TMPL_VAR name></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="generator" content="<TMPL_VAR generator ESCAPE="HTML">">
<link rel="stylesheet" href="planet.css" type="text/css">
<TMPL_IF feedtype>
<link rel="alternate" href="<TMPL_VAR feed ESCAPE="HTML">" title="<TMPL_VAR channel_title_plain ESCAPE="HTML">" type="application/<TMPL_VAR feedtype>+xml">
</TMPL_IF>
</head>
<body>
<h1><TMPL_VAR name></h1>
<TMPL_VAR admin>
<TMPL_LOOP Items>
<TMPL_IF new_date>
<TMPL_UNLESS __FIRST__>
### End <div class="channelgroup">
</div>
### End <div class="daygroup">
</div>
</TMPL_UNLESS>
<div class="daygroup">
<h2><TMPL_VAR new_date></h2>
</TMPL_IF>
<TMPL_IF new_channel>
<TMPL_UNLESS new_date>
### End <div class="channelgroup">
</div>
</TMPL_UNLESS>
<div class="channelgroup">
### Planet provides template variables for *all* configuration options for
### the channel (and defaults), even if it doesn't know about them. We
### exploit this here to add hackergotchi faces to our channels. Planet
### doesn't know about the "face", "facewidth" and "faceheight" configuration
### variables, but makes them available to us anyway.
<h3><a href="<TMPL_VAR channel_link ESCAPE="HTML">" title="<TMPL_VAR channel_title_plain ESCAPE="HTML">"><TMPL_VAR channel_name></a></h3>
<TMPL_IF channel_face>
<img class="face" src="images/<TMPL_VAR channel_face ESCAPE="HTML">" width="<TMPL_VAR channel_facewidth ESCAPE="HTML">" height="<TMPL_VAR channel_faceheight ESCAPE="HTML">" alt="">
</TMPL_IF>
</TMPL_IF>
<div class="entrygroup" id="<TMPL_VAR id>"<TMPL_IF channel_language> lang="<TMPL_VAR channel_language>"</TMPL_IF>>
<TMPL_IF title>
<h4<TMPL_IF title_language> lang="<TMPL_VAR title_language>"</TMPL_IF>><a href="<TMPL_VAR link ESCAPE="HTML">"><TMPL_VAR title></a></h4>
</TMPL_IF>
<div class="entry">
<div class="content"<TMPL_IF content_language> lang="<TMPL_VAR content_language>"</TMPL_IF>>
<TMPL_VAR content>
</div>
### Planet also makes available all of the information from the feed
### that it can. Use the 'planet-cache' tool on the cache file for
### a particular feed to find out what additional keys it supports.
### Comment extra fields are 'author' and 'category' which we
### demonstrate below.
<p class="date">
<a href="<TMPL_VAR link ESCAPE="HTML">"><TMPL_IF author>by <TMPL_VAR author ESCAPE="HTML"> at </TMPL_IF><TMPL_VAR date><TMPL_IF category> under <TMPL_VAR category></TMPL_IF></a>
</p>
</div>
</div>
<TMPL_IF __LAST__>
### End <div class="channelgroup">
</div>
### End <div class="daygroup">
</div>
</TMPL_IF>
</TMPL_LOOP>
<div class="sidebar">
<img src="images/logo.png" width="136" height="136" alt="">
<h2>Subscriptions</h2>
<ul>
<TMPL_LOOP Channels>
<li>
<a href="<TMPL_VAR url ESCAPE="HTML">" title="subscribe"><img src="images/feed-icon-10x10.png" alt="(feed)"></a> <a <TMPL_IF link>href="<TMPL_VAR link ESCAPE="HTML">" </TMPL_IF><TMPL_IF message>class="message" title="<TMPL_VAR message ESCAPE="HTML">"</TMPL_IF><TMPL_UNLESS message>title="<TMPL_VAR title_plain ESCAPE="HTML">"</TMPL_UNLESS>><TMPL_VAR name></a>
</li>
</TMPL_LOOP>
</ul>
<p>
<strong>Last updated:</strong><br>
<TMPL_VAR date><br>
<em>All times are UTC.</em><br>
<br>
Powered by:<br>
<a href="http://www.planetplanet.org/"><img src="images/planet.png" width="80" height="15" alt="Planet" border="0"></a>
</p>
<p>
<h2>Planetarium:</h2>
<ul>
<li><a href="http://www.planetapache.org/">Planet Apache</a></li>
<li><a href="http://planet.debian.net/">Planet Debian</a></li>
<li><a href="http://planet.freedesktop.org/">Planet freedesktop.org</a></li>
<li><a href="http://planet.gnome.org/">Planet GNOME</a></li>
<li><a href="http://planetsun.org/">Planet Sun</a></li>
<li><a href="http://fedora.linux.duke.edu/fedorapeople/">Fedora People</a></li>
<li><a href="http://www.planetplanet.org/">more...</a></li>
</ul>
</p>
</div>
</body>
</html>

View File

@ -0,0 +1,150 @@
body {
border-right: 1px solid black;
margin-right: 200px;
padding-left: 20px;
padding-right: 20px;
}
h1 {
margin-top: 0px;
padding-top: 20px;
font-family: "Bitstream Vera Sans", sans-serif;
font-weight: normal;
letter-spacing: -2px;
text-transform: lowercase;
text-align: right;
color: grey;
}
.admin {
text-align: right;
}
h2 {
font-family: "Bitstream Vera Sans", sans-serif;
font-weight: normal;
color: #200080;
margin-left: -20px;
}
h3 {
font-family: "Bitstream Vera Sans", sans-serif;
font-weight: normal;
background-color: #a0c0ff;
border: 1px solid #5080b0;
padding: 4px;
}
h3 a {
text-decoration: none;
color: inherit;
}
h4 {
font-family: "Bitstream Vera Sans", sans-serif;
font-weight: bold;
}
h4 a {
text-decoration: none;
color: inherit;
}
img.face {
float: right;
margin-top: -3em;
}
.entry {
margin-bottom: 2em;
}
.entry .date {
font-family: "Bitstream Vera Sans", sans-serif;
color: grey;
}
.entry .date a {
text-decoration: none;
color: inherit;
}
.sidebar {
position: absolute;
top: 0px;
right: 0px;
width: 200px;
margin-left: 0px;
margin-right: 0px;
padding-right: 0px;
padding-top: 20px;
padding-left: 0px;
font-family: "Bitstream Vera Sans", sans-serif;
font-size: 85%;
}
.sidebar h2 {
font-size: 110%;
font-weight: bold;
color: black;
padding-left: 5px;
margin-left: 0px;
}
.sidebar ul {
padding-left: 1em;
margin-left: 0px;
list-style-type: none;
}
.sidebar ul li:hover {
color: grey;
}
.sidebar ul li a {
text-decoration: none;
}
.sidebar ul li a:hover {
text-decoration: underline;
}
.sidebar ul li a img {
border: 0;
}
.sidebar p {
border-top: 1px solid grey;
margin-top: 30px;
padding-top: 10px;
padding-left: 5px;
}
.sidebar .message {
cursor: help;
border-bottom: 1px dashed red;
}
.sidebar a.message:hover {
cursor: help;
background-color: #ff0000;
color: #ffffff !important;
text-decoration: none !important;
}
a:hover {
text-decoration: underline !important;
color: blue !important;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns="http://purl.org/rss/1.0/"
>
<channel rdf:about="<TMPL_VAR link ESCAPE="HTML">">
<title><TMPL_VAR name ESCAPE="HTML"></title>
<link><TMPL_VAR link ESCAPE="HTML"></link>
<description><TMPL_VAR name ESCAPE="HTML"> - <TMPL_VAR link ESCAPE="HTML"></description>
<items>
<rdf:Seq>
<TMPL_LOOP Items>
<rdf:li rdf:resource="<TMPL_VAR id ESCAPE="HTML">" />
</TMPL_LOOP>
</rdf:Seq>
</items>
</channel>
<TMPL_LOOP Items>
<item rdf:about="<TMPL_VAR id ESCAPE="HTML">">
<title><TMPL_VAR channel_name ESCAPE="HTML"><TMPL_IF title>: <TMPL_VAR title_plain ESCAPE="HTML"></TMPL_IF></title>
<link><TMPL_VAR link ESCAPE="HTML"></link>
<TMPL_IF content>
<content:encoded><TMPL_VAR content ESCAPE="HTML"></content:encoded>
</TMPL_IF>
<dc:date><TMPL_VAR date_iso></dc:date>
<TMPL_IF author_name>
<dc:creator><TMPL_VAR author_name></dc:creator>
</TMPL_IF>
</item>
</TMPL_LOOP>
</rdf:RDF>