def renderTemperature(latest, _class='temperatures'): degC = latest.get('average') if degC is None: return "No data" degF = units.degCtoF(degC) return tag('div', _class=_class)[ tag('span', _class='mainTemperature')[ "%.01f" % degF, xml("°"), "F" ], tag('span', _class='temperatureSeparator')[ " / " ], tag('span', _class='altTemperature')[ "%.01f" % degC, xml("°"), "C" ], ]
def render_tabs(self, context): """The page's tabs show all named components""" tabs = [] for component in context['request'].site.components: if component.name: tabs.append( tag('li')[xml('» '), tag('a', href=component.url)[component.name], ]) return tag('ul', _class='heading')[tabs]
def render_tabs(self, context): """The page's tabs show all named components""" tabs = [] for component in context['request'].site.components: if component.name: tabs.append(tag('li')[ xml('» '), tag('a', href=component.url)[ component.name ], ]) return tag('ul', _class='heading')[ tabs ]
def __init__(self, data, feed): self.feed = feed try: self.title = data.title except AttributeError: self.title = "Untitled" self.content = xml(unicode(data.summary).encode("utf-8")) self.date = data.modified_parsed # Create a globally unique ID for this post # FIXME self.guid = str(hash(self.content))
def render_breadcrumbs(self, context): places = [self.render_mainTitle(context)] node = self.parent() # If we don't at least have a parent node, breadcrumbs # are going to be pretty useless. Just stick in a # non-breaking space as a placeholder. if not node: return xml(" ") while node: places.insert(0, breadcrumbSeparator) places.insert(0, node.render_link(context)) node = node.parent() return places
def listRenderCallback(self, obj, context, result): results = [] if result.called: return obj for success, item in obj: if success: results.append(str(item)) else: # If we had any failures, our listRenderErrback # should have already been called. Ignore this. return result.callback(xml(''.join(results))) return obj
def render_list(self, obj, context): """A new version of render_list that returns a Deferred if any item in the list is a Deferred. """ # Render each item in the list, noting whether we have any Deferreds renderedItems = [] hasDeferreds = False for item in obj: rendered = self.render(item, context) renderedItems.append(rendered) if isinstance(rendered, defer.Deferred): hasDeferreds = True # If we had any deferred items, we need to create a DeferredList # so we get notified once all of our content is rendered. Otherwise # we can join them now. if hasDeferreds: result = defer.Deferred() # Convert every result to a Deferred, wrapping non-deferred # objects in deferreds that are already completed. deferreds = [] for item in renderedItems: if not isinstance(item, defer.Deferred): d = defer.Deferred() d.callback(item) item = d deferreds.append(item) # Propagate errors to our parent. This is necessary # even with an errback in our DeferredList, as the # DeferredList doesn't absorb errors, it only detects them. item.addErrback(self.listRenderErrback, result) # Wait until all deferreds are completed dl = defer.DeferredList(deferreds) dl.addCallbacks(self.listRenderCallback, self.listRenderErrback, callbackArgs = (context, result), errbackArgs = (result,), ) return result else: return xml(''.join(renderedItems))
def formatItem(self, content): # Convert the root node, not the document- we don't want to # be outputting another XML declaration inside our larger document. return xml(XML.toString(content.childNodes[0]).encode('utf8'))
def format_unquoted(self, m): """Our 'unquoted' medium is plaintext inside an xml() marker to prevent quoting""" return xml(self.formatMessage(m, 'plaintext'))
class Page(Nouvelle.Twisted.Page): """A template for pages using our CSS- all pages have a heading with title, subtitle, and site name. The content of each page is in columns holding sections, while each page shares certain navigation features- section tabs at the top, and a 'breadcrumbs' display linking to and showing a page's parent pages. """ siteName = "CIA.vc" mainTitle = None subTitle = [] leftColumn = [] mainColumn = [] extraHeaders = [] # Placeholders for site-specific customization site_belowLeftColumn = [] site_bottomOfFooter = [] titleElements = [ tag('div', _class="mainTitle")[place("mainTitle")], tag('div', _class="subTitle")[place("subTitle")], ] logoElements = [ tag('a', _class="sitename", href="/")[tag('img', src='/media/img/nameplate-24.png', width=87, height=24, alt='CIA.vc'), ], ] document = [ xml('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n'), tag('html', xmlns="http://www.w3.org/1999/xhtml") [tag('head') [tag('title')[place("pageTitle")], place('baseTag'), xml('<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />' ), tag('link', rel='stylesheet', href='/media/css/old-site.css', type='text/css'), tag('link', rel='shortcut icon', href='/favicon.ico', type='image/png'), tag('script', type='text/javascript', src='/media/js/base.js')[" "], place('extraHeaders'), ], tag('body') [tag('div', _class="heading" )[tag('div', _class="topRight")[ tag('input', type='text', id='search'), place("tabs"), place('logoElements'), ], tag('div', _class="topLeft")[ place('titleElements'), ], tag('div', _class="tabBar")[place("breadcrumbs")], ], # The page body. We really shouldn't still be using a table for this... tag('table', _class="columns")[tag('tr')[ tag('td', _class="left")[place("templateLeftColumn"), ], tag('td', _class="main")[place("mainColumn")], ]], tag('div', _class="footer")[ # Legal goop tag('p', _class='smallprint') [xml("The CIA.vc server is Copyright © 2003-2007 "), EmailLink('mailto:[email protected]')["Micah Dowty"], ", and released under the ", tag('a', _href='/doc/COPYING')["GNU GPL"], ".", tag('br' ), "All hosted messages and metadata are owned by their respective authors.", ], # More optional text place("site_bottomOfFooter"), ], xml('<script type="text/javascript">' 'CIASearch.init("/api/search/", "search", "Search CIA.vc");' '</script>'), ], ], ] def render_pageTitle(self, context): # Wait for the title and site name to resolve into strings so we can mess with them a bit more result = defer.Deferred() defer.gatherResults([ defer.maybeDeferred(self.render_mainTitle, context), defer.maybeDeferred(self.render_siteName, context), ]).addCallback(self._render_pageTitle, context, result).addErrback(result.errback) return result def _render_pageTitle(self, titleAndSite, context, result): # Now that the title and site name have fully resolved, we can apply some heuristics... title, siteName = titleAndSite if title is None: result.callback(siteName) return if type(title) in types.StringTypes and type( siteName) in types.StringTypes: # The title and site are plain strings. If it starts with or ends with the site name, # just use it as-is to avoid being overly redundant. if title == siteName or title.startswith( siteName + " ") or title.endswith(" " + siteName): result.callback(title) return # Otherwise, stick the title and site name together result.callback([title, ' - ', siteName]) def render_templateLeftColumn(self, context): """A sneaky little rendering function that runs render_leftColumn, but then sticks in the site_* modifiers where possible. Note that this won't work if render_leftColumn returns a Deferred, but nothing in the CIA server does this yet. """ return self.render_leftColumn(context) + self.site_belowLeftColumn def render_siteName(self, context): return self.siteName def render_mainTitle(self, context): return self.mainTitle def render_subTitle(self, context): return self.subTitle def render_leftColumn(self, context): return self.leftColumn def render_mainColumn(self, context): return self.mainColumn def render_breadcrumbs(self, context): places = [self.render_mainTitle(context)] node = self.parent() # If we don't at least have a parent node, breadcrumbs # are going to be pretty useless. Just stick in a # non-breaking space as a placeholder. if not node: return xml(" ") while node: places.insert(0, breadcrumbSeparator) places.insert(0, node.render_link(context)) node = node.parent() return places def render_baseTag(self, context): """Return an HTML <base> tag pointing at this page's original URL. This keeps the page from breaking if it's saved to disk or copied elsewhere. """ return tag('base', href=context['request'].prePathURL()) def render_link(self, context): """Return a serializable object that should be used to link to this page. By default, this returns a plain link with the page's title, pointing to the page's URL. """ return tag('a', href=self.getURL(context))[self.render_mainTitle(context)] def parent(self): """Pages must implement this to return their parent page. This is used for the default implementation of breadcrumbs. """ pass def render_tabs(self, context): """The page's tabs show all named components""" tabs = [] for component in context['request'].site.components: if component.name: tabs.append( tag('li')[xml('» '), tag('a', href=component.url)[component.name], ]) return tag('ul', _class='heading')[tabs] def getURL(self, context): """Retrieve a URL suitable for linking to this page.""" pass
from twisted.internet import defer from Nouvelle import tag, place, xml, subcontext import types, random # Verify we have a new enough Nouvelle if (not hasattr(Nouvelle, "version_info")) or Nouvelle.version_info < (0, 92, 1): raise Exception("The installed copy of Nouvelle is too old") # Tag templates catalogList = tag('ul', _class="catalog") value = tag('strong') error = tag('span', _class="error") longError = tag('p', _class="error") unableToFormat = error["Unable to format data"] breadcrumbSeparator = xml(" » ") pageBody = tag('div', _class="pageBody") # Stock images fileIcon = tag('img', src="/images/bullet.png", _class="left-icon", width=9, height=9, alt="file") dirIcon = tag('img', src="/images/folder.png", _class="left-icon", width=14, height=12, alt="directory")
padding: 0em 0em 0em 0.25em; } span.timestamp { color: #888; } span.serverMessage { color: #800; } """ if __name__ == '__main__': print Serializer().render([ xml('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n'), tag('html', xmlns="http://www.w3.org/1999/xhtml")[ tag('head')[ tag('title')[ " ".join(sys.argv[1:]) ], tag('style', _type='text/css')[ stylesheet ], tag('meta', **{'http-equiv': 'refresh', 'content': 15}), ], tag('body')[ LogFormatter().format(sys.stdin), ], ], ]) ### The End ###
import Nouvelle.Twisted from twisted.internet import defer from Nouvelle import tag, place, xml, subcontext import types, random # Verify we have a new enough Nouvelle if (not hasattr(Nouvelle, "version_info")) or Nouvelle.version_info < (0, 92, 1): raise Exception("The installed copy of Nouvelle is too old") # Tag templates catalogList = tag('ul', _class="catalog") value = tag('strong') error = tag('span', _class="error") longError = tag('p', _class="error") unableToFormat = error[ "Unable to format data" ] breadcrumbSeparator = xml(" » ") pageBody = tag('div', _class="pageBody") # Stock images fileIcon = tag('img', src="/images/bullet.png", _class="left-icon", width=9, height=9, alt="file") dirIcon = tag('img', src="/images/folder.png", _class="left-icon", width=14, height=12, alt="directory") def Photo(url, **attrs): """A factory for images presented as a photo""" return tag('div', _class='photo')[ tag('img', _class='photo', src=url, alt="Photo", **attrs) ] def Bargraph(value, width=4, padding=0.2): """A factory for tags that use their size to express a value between 0 and 1""" return tag('span', _class='bargraph',