--- a/svv/controllers.py Tue Jan 11 01:12:50 2011 +0200
+++ b/svv/controllers.py Thu Jan 20 23:14:07 2011 +0200
@@ -8,8 +8,10 @@
import werkzeug
from werkzeug import Response
-from svv import html, pdf
-from svv.html import tags
+from svv.html import tags as html
+from svv import pdf, utils
+
+import datetime
class AppHandler (object):
"""
@@ -92,6 +94,93 @@
Renders the layout template and HTML.
"""
+
+ # XXX: how to handle site title vs page title?
+ def format_title (self) :
+ """
+ Render site/page title as plain text.
+ """
+
+ return u"SpeksiVVuokraus"
+
+ def build_breadcrumb (self) :
+ """
+ Return an optional list of (title, target, args) segments leading up to and including this page.
+ """
+
+ return None
+
+ def render_header (self) :
+ """
+ Page header.
+ """
+
+ from svv import urls
+
+ # link to main page
+ return html.a(href=self.url_for(urls.Index))(
+ self.format_title()
+ )
+
+ def render_menu (self) :
+ """
+ Site navigation menu (vertical menu next to content)
+ """
+
+ # XXX: circular-import hack for urls
+ # it's not sustainable for a base class to referr to its subclasses at define time
+ from svv import urls
+
+ # XXX: menu def, should be somewhere elsewhere..
+ menu = [
+ ("Kalenteri", urls.CalendarView),
+ ("Uusi tilaus", urls.NewOrderView),
+ ("Tilaukset", urls.OrdersView),
+ ("Tilaajat", urls.CustomersView),
+ ("Inventaari", urls.InventoryView),
+ ]
+
+ # render
+ return html.ul(
+ html.li(
+ html.a(href=self.url_for(target))(title)
+
+ ) for title, target in menu
+ )
+
+ def render_navigation (self) :
+ """
+ Page navigation menu (compact horizontal above content), used for breadcrumb
+ """
+
+ breadcrumb = self.build_breadcrumb()
+
+ if not breadcrumb :
+ # optional
+ return None
+
+ return html.ul(
+ html.li(
+ html.a(href=self.url_for(target, **args))(
+ title
+ )
+ ) for title, target, args in breadcrumb
+ )
+
+ def render_footer (self) :
+ """
+ Page footer.
+ """
+
+ # current tz-aware time
+ now = datetime.datetime.now(utils.LocalTimezone())
+
+ return (
+ html.div(class_='right')(
+ # timestamp with timezone offset
+ now.strftime('%Y/%m/%d %H:%M:%S %Z (GMT%z)')
+ )
+ )
def render_content (self, **args) :
"""
@@ -108,7 +197,7 @@
"""
# XXX: layout template, should be somewhere far away
- title = "Index"
+
css = [
"/static/layout.css",
"/static/style.css",
@@ -133,41 +222,49 @@
#"/static/js/treelist.js"
]
- head = (
- tags.title(title),
- (tags.link(rel='Stylesheet', type="text/css", href=src) for src in css),
- # XXX: script can't self-close >_<
- (tags.script(src=src)(" ") for src in scripts),
+ return html.document(
+ head=(
+ html.title(
+ # plaintext title
+ self.format_title()
+ ),
+
+ (
+ html.link(rel='Stylesheet', type="text/css", href=src) for src in css
+ ),
+
+ # XXX: script can't self-close?
+ (
+ html.script(src=src, _selfclosing=False) for src in scripts
+ ),
+ ),
+
+ body=(
+ html.div(id='header')(
+ self.render_header()
+ ),
+
+ html.div(id='container')(
+ html.div(id='menu')(
+ self.render_menu()
+ ),
+
+ # XXX: breadcrumb etc.
+ # html.div(id='nav')(
+ # self.render_navgation()
+ #),
+
+ # the actual page content (pre-rendered)
+ html.div(id='content')(
+ content
+ ),
+ ),
+ html.div(id='footer')(
+ self.render_footer()
+ ),
+ ),
)
- # XXX: silly circular-import hack for urls
- # it's not sustainable for a base class to referr to its subclasses at define time
- from svv import urls
-
- header = ("Foo List")
- nav = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Nav A', 'Nav B', 'Nav C'])]
- menu = [tags.ul(tags.li(tags.a(href=url)(name)) for name, url in [
- ("Kalenteri", self.url_for(urls.CalendarView)),
- ("Uusi tilaus", self.url_for(urls.NewOrderView)),
- ("Tilaukset", self.url_for(urls.OrdersView)),
- ("Tilaajat", self.url_for(urls.CustomersView)),
- ("Inventaari", self.url_for(urls.InventoryView)),
- ])]
- footer = ("Copyright?")
-
- layout = (
- tags.div(id='header')(header),
- tags.div(id='container')(
- tags.div(id='menu')(menu),
- # tags.div(id='nav')(nav),
- tags.div(id='content')(content),
- ),
- tags.div(id='footer')(footer),
- )
-
- # perform the actual rendering (run generators etc.)
- return unicode(html.document(head, layout))
-
def render (self, **url_values) :
"""
Render full page HTML
@@ -194,11 +291,11 @@
response = super(PageHandler, self).respond(**url_values)
if not response :
- # render page HTML
- html = self.render(**url_values)
+ # render page HTML as unicode
+ html = unicode(self.render(**url_values))
# response object
- # XXX: unicode?
+ # XXX: charset?
return Response(html, mimetype='text/html')
# ok
@@ -272,30 +369,30 @@
data = self.DATA
def render_item (id, text, children) :
- return tags.li(
- tags.div(class_='item')(
+ return html.li(
+ html.div(class_='item')(
# item text
- tags.a(tags.input(type='checkbox', name_=id, checked=(
+ html.a(html.input(type='checkbox', name_=id, checked=(
'checked' if self.request.form.get(str(id)) else None
)), text, class_='text'),
),
# children
- tags.ul(render_item(*item) for item in children if item) if children else None,
+ html.ul(render_item(*item) for item in children if item) if children else None,
#
class_=('more open' if children else None),
)
# XXX: nothing much to see here
- return tags.h1("Mui.")
+ return html.h1("Mui.")
# render it
return (
- tags.h3("Item list"),
- tags.form(action='.', method='post')(
- tags.ul(class_='treelist')(render_item(*item) for item in data),
- tags.input(type='submit'),
+ html.h3("Item list"),
+ html.form(action='.', method='post')(
+ html.ul(class_='treelist')(render_item(*item) for item in data),
+ html.input(type='submit'),
),
)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/svv/utils.py Thu Jan 20 23:14:07 2011 +0200
@@ -0,0 +1,55 @@
+"""
+ Miscellanous bucket of everything
+"""
+
+import datetime
+import time
+
+class LocalTimezone (datetime.tzinfo) :
+ """
+ Our platform's (the 'time' module) idea of our local timezone.
+ """
+
+ ZERO = datetime.timedelta(0)
+
+ STDOFFSET = datetime.timedelta(seconds = -time.timezone)
+
+ if time.daylight:
+ DSTOFFSET = datetime.timedelta(seconds = -time.altzone)
+ else:
+ DSTOFFSET = STDOFFSET
+
+ DSTDIFF = DSTOFFSET - STDOFFSET
+
+ def _isdst (self, dt) :
+ # time tuple in local time
+ tt = (dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second,
+ dt.weekday(), 0, -1)
+
+ # to UTC timestamp
+ stamp = time.mktime(tt)
+
+ # roundtrip..
+ tt = time.localtime(stamp)
+
+ # to figure out DST flag
+ return tt.tm_isdst > 0
+
+ def utcoffset (self, dt) :
+ if self._isdst(dt) :
+ return self.DSTOFFSET
+ else:
+ return self.STDOFFSET
+
+ def dst (self, dt) :
+ if self._isdst(dt) :
+ return self.DSTDIFF
+ else:
+ return self.ZERO
+
+ def tzname (self, dt) :
+ # varies by DST
+ return time.tzname[self._isdst(dt)]
+
+