constance

Scripts for generating (an earlier obsolete version of) my personal web site
git clone https://code.djc.id.au/git/constance/
commit fe28aedca6a4a836553dbf1d27080ee2c2723d11
parent c25d9f114404f5298bdbde69ae9b527ace70b3ea
Author: Dan Callaghan <djc@djc.id.au>
Date:   Fri, 19 Sep 2008 01:46:40 +1000

functions for generating relative and absolute URLs (I should probably just
concede defeat and switch to Routes, or that other one I found on wsgi.org
whose name I've forgotten ...)

Diffstat:
MTODO | 3+--
Mtemplates/_commonwrapper.xml | 5++---
Mtemplates/_entry.xml | 13++++++++-----
Atemplates/_fragments.xml | 16++++++++++++++++
Mtemplates/multiple_atom.xml | 10++++++----
Mtemplates/tag_cloud.xml | 4++--
Mviewutils.py | 3++-
7 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/TODO b/TODO
@@ -15,8 +15,7 @@
   - perhaps as interim step could export from Nokia and embed gmaps directly in constance?
 - document on-disk format for the entry types
 - tests!!!!!!!!
-- escape high bytes in URLs (should work properly since pages are served in the same encoding as what we expect URLs to be in, but it seems to confuse at least MSN-Bot (and probably IE) sigh)
-  - better means of generating URLs?
+- something better for viewutils.tag_list (at least fix URL quoting)
 - have almost completely ditched colubrid, just need to replace StaticExports for testing then rm it
 - use encoding from config for blog.py instead of hard-coding utf8
 - invalid offsets (displays every entry at max and 500's on invalid such as alpha)
diff --git a/templates/_commonwrapper.xml b/templates/_commonwrapper.xml
@@ -4,8 +4,7 @@
      xmlns:xi="http://www.w3.org/2001/XInclude"
      py:strip="True">
 
-<span py:def="inline_sep()" class="inlinesep">·</span>
-<div py:def="block_sep()" class="blocksep">~</div>
+<xi:include href="_fragments.xml" />
 
 <py:match path="head">
 	<head profile="http://gmpg.org/xfn/11" py:attrs="select('@*')" py:with="title = unicode(select('title[1]/text()'))">
@@ -14,7 +13,7 @@
 		<title py:if="not title">${config.getunicode('global', 'name')}</title>
         <meta http-equiv="content-type" content="text/html; charset=utf-8" />
 		<meta name="generator" content="constance" />
-        <link rel="stylesheet" type="text/css" href="${environ.get('SCRIPT_NAME', '')}/static/css/common.css" />
+        <link rel="stylesheet" type="text/css" href="${uri('static', 'css', 'common.css')}" />
 	</head>
 </py:match>
 
diff --git a/templates/_entry.xml b/templates/_entry.xml
@@ -1,8 +1,11 @@
 <div xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://genshi.edgewall.org/"
+     xmlns:xi="http://www.w3.org/2001/XInclude"
 	 py:strip="True"
 	 py:def="show_entry(entry, show_comments=True)">
 
+<xi:include href="_fragments.xml" />
+
 <?python
 import blog
 from viewutils import mini_markdown, tag_list
@@ -15,7 +18,7 @@ from recaptcha.client import captcha
 
 	<div class="entrydate">
 		${entry.publication_date.strftime(str('%-1d %b %Y'))}
-	    <a href="${environ.get('SCRIPT_NAME', '')}/${entry.id}" rel="bookmark" class="permalink" title="permalink">#</a>
+	    <a href="${uri(entry.id)}" rel="bookmark" class="permalink" title="permalink">#</a>
 	</div>
 
     <div py:if="entry.tags" class="entrytags">
@@ -27,7 +30,7 @@ from recaptcha.client import captcha
     </div>
 
     <div class="entrycommentslink" py:if="not show_comments and entry.has_comments()">
-        <a href="${environ.get('SCRIPT_NAME', '')}/${entry.id}#comments" py:choose="len(entry.comments())">
+        <a href="${uri(entry.id)}#comments" py:choose="len(entry.comments())">
             <py:when test="0">no comments »</py:when>
             <py:when test="1">1 comment »</py:when>
             <py:otherwise>${len(entry.comments())} comments »</py:otherwise>
@@ -50,7 +53,7 @@ from recaptcha.client import captcha
             </p>
             ${block_sep()}
         </div>
-        <div class="commentform"><form method="post" action="${environ.get('SCRIPT_NAME', '')}/${entry.id}/comments/+new">
+        <div class="commentform"><form method="post" action="${uri(entry.id, 'comments', '+new')}">
             <p>
                 <label for="commentform-from">Name</label>
                 <input type="text" id="commentform-from" name="from" />
@@ -80,7 +83,7 @@ from recaptcha.client import captcha
 </div>
 
 <span py:def="stars(rating)" py:strip="True">
-<img src="${environ.get('SCRIPT_NAME', '')}/static/images/star.png" alt="[star]" py:for="_ in range(int(rating))" /><img src="${environ.get('SCRIPT_NAME', '')}/static/images/star-half.png" alt="[half-star]" py:if="rating > int(rating)" /><img src="${environ.get('SCRIPT_NAME', '')}/static/images/star-off.png" alt="" py:for="_ in range(int(5 - rating))" />
+<img src="${uri('static', 'images', 'star.png')}" alt="[star]" py:for="_ in range(int(rating))" /><img src="${uri('static', 'images', 'star-half.png')}" alt="[half-star]" py:if="rating > int(rating)" /><img src="${uri('static', 'images', 'star-off.png')}" alt="" py:for="_ in range(int(5 - rating))" />
 </span>
 
 <div class="entry readinglog" py:if="isinstance(entry, blog.ReadingLogEntry)">
@@ -98,7 +101,7 @@ from recaptcha.client import captcha
 
     <div class="entrydate">
         ${entry.publication_date.strftime(str('%-1d %b %Y'))}
-	    <a href="${environ.get('SCRIPT_NAME', '')}/+reading/#entry-${entry.id}" rel="bookmark" class="permalink" title="permalink">#</a>
+	    <a href="${uri('+reading', '')}#entry-${entry.id}" rel="bookmark" class="permalink" title="permalink">#</a>
     </div>
 
     <div py:if="entry.rating" class="rating">
diff --git a/templates/_fragments.xml b/templates/_fragments.xml
@@ -0,0 +1,16 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:py="http://genshi.edgewall.org/"
+     xmlns:xi="http://www.w3.org/2001/XInclude"
+     py:strip="True">
+
+<?python
+import urllib
+?>
+
+<span py:def="inline_sep()" class="inlinesep">·</span>
+<div py:def="block_sep()" class="blocksep">~</div>
+
+<span py:def="uri(*components)" py:strip="True">${'/'.join([environ.get('SCRIPT_NAME', '')] + [urllib.quote(component.encode(config.get('global', 'encoding')), '+') for component in components])}</span>
+<span py:def="abs_uri(*components)" py:strip="True">${environ['APP_URI']}/${'/'.join(urllib.quote(component.encode(config.get('global', 'encoding')), '+') for component in components)}</span>
+
+</div>
diff --git a/templates/multiple_atom.xml b/templates/multiple_atom.xml
@@ -3,6 +3,8 @@
       xmlns:py="http://genshi.edgewall.org/"
 	  xmlns:xi="http://www.w3.org/2001/XInclude">
 
+<xi:include href="_fragments.xml" />
+
 <?python
 import blog
 from viewutils import tag_list
@@ -24,17 +26,17 @@ ATOM_TIME_FORMAT = str('%Y-%m-%dT%H:%M:%S+10:00')
 		<name>${config.getunicode('global', 'author')}</name>
 		<email py:if="email">${email}</email>
 	</author>
-	<category py:for="tag in entry.tags" scheme="${environ['APP_URI']}/+tags/" term="${tag}" />
+	<category py:for="tag in entry.tags" scheme="${abs_uri('+tags', '')}" term="${tag}" />
 	<py:if test="isinstance(entry, blog.BlogEntry)">
-		<link rel="alternate" href="${environ['APP_URI']}/${entry.id}" />
+		<link rel="alternate" href="${abs_uri(entry.id)}" />
 		<title type="text">${entry.title}</title>
-		<content type="xhtml" xml:base="${environ['APP_URI']}/${entry.id}"><xhtml:div>
+		<content type="xhtml" xml:base="${abs_uri(entry.id)}"><xhtml:div>
 			<p py:if="entry.tags">Tagged: ${tag_list(environ.get('SCRIPT_NAME', ''), entry.tags)}</p>
 			${entry.body}
 		</xhtml:div></content>
 	</py:if>
 	<py:if test="isinstance(entry, blog.ReadingLogEntry)">
-		<link rel="alternate" href="${environ['APP_URI']}/+reading/#entry-${entry.id}" />
+		<link rel="alternate" href="${abs_uri('+reading', '')}#entry-${entry.id}" />
 		<title type="text">${entry.title} by ${entry.author}</title>
 		<summary py:if="entry.rating" type="text">${entry.rating} stars</summary>
 		<content type="xhtml"><xhtml:div>
diff --git a/templates/tag_cloud.xml b/templates/tag_cloud.xml
@@ -7,7 +7,7 @@
 
 <head>
     <title>Tag cloud</title>
-    <link rel="stylesheet" type="text/css" href="${environ.get('SCRIPT_NAME', '')}/static/css/tag_cloud.css" />
+    <link rel="stylesheet" type="text/css" href="${uri('static', 'css', 'tag_cloud.css')}" />
 </head>
 <body>
 
@@ -15,7 +15,7 @@
 
 <ol id="tagcloud">
     <li py:for="tag, freq in sorted(tag_freqs.iteritems(), key=lambda (t, f): t.lower())">
-        <a rel="tag" href="${environ.get('SCRIPT_NAME', '')}/+tags/${tag}" style="font-size: ${0.8 + (freq / 10.)}em;">${tag}</a>
+        <a rel="tag" href="${uri('+tags', tag)}" style="font-size: ${0.8 + (freq / 10.)}em;">${tag}</a>
         <span class="frequency">(used ${freq} times)</span>
     </li>
 </ol>
diff --git a/viewutils.py b/viewutils.py
@@ -1,4 +1,4 @@
-import re
+import re, urllib
 from markdown2 import Markdown
 import genshi
 
@@ -10,6 +10,7 @@ def mini_markdown(s):
     return genshi.Markup(match.group(1))
 
 def tag_list(script_name, tags):
+    # XXX urllib.quote
     return genshi.Markup(u', ').join(
             genshi.Markup(u'<a rel="tag" href="%s/+tags/%s">%s</a>' % (script_name, tag, tag)) 
             for tag in tags)