def unknownElement(self, element): # Format the element name and attributes elementName = tag("span", _class="xml-element-name")[element.nodeName] elementContent = [elementName] for attr in element.attributes.values(): elementContent.extend( [ " ", tag("span", _class="xml-attribute-name")[attr.name], '="', tag("span", _class="xml-attribute-value")[attr.value], '"', ] ) # Now the contents... if element.hasChildNodes(): completeElement = [ "<", elementContent, ">", tag("blockquote", _class="xml-element-content")[[self.parse(e) for e in element.childNodes],], "</", elementName, ">", ] else: completeElement = ["<", elementContent, "/>"] return tag("div", _class="xml-element")[completeElement]
def render_intervals(self, context): return [[ tag('a', _name=anchor, id=anchor)[ tag('h2')[ name ], ], tag('div', _class='sensorInterval')[ ' ', self.renderInterval(length, context) ], ] for name, length, anchor in self.intervals]
def unknownElement(self, element): # Format the element name and attributes elementName = tag('span', _class="xml-element-name")[ element.nodeName ] elementContent = [ elementName ] for attr in element.attributes.values(): elementContent.extend([ ' ', tag('span', _class='xml-attribute-name')[ attr.name ], '="', tag('span', _class='xml-attribute-value')[ attr.value ], '"', ]) # Now the contents... if element.hasChildNodes(): completeElement = [ "<", elementContent, ">", tag('blockquote', _class='xml-element-content')[ [self.parse(e) for e in element.childNodes], ], "</", elementName, ">", ] else: completeElement = ["<", elementContent, "/>"] return tag('div', _class='xml-element')[ completeElement ]
def renderEntry(self, entry): return [ tag('hr'), tag('a', href="feeds.py/entry?id=%s" % entry.guid)[ entry.title ], tag('br'), tag('i')[ entry.feed.name ], " (", formatDate(entry.date), ") ", ]
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 _render_rows(self, metadata, context, result): url, description, photo_results, owner_results = metadata rows = [] if url: rows.append(tag("a", href=url)[url]) if photo_results and photo_results[0][0]: path, width, height = photo_results[0] rows.append(Template.Photo("/images/db/" + path, width=width, height=height)) if description: rows.append(description) # XXX: This is kind of a hack, but it should improve usability # between the old and new sites. Show 'edit' links if # this is something users can edit (projects or authors) # and if it isn't claimed exclusively already. if ( not owner_results and len(self.target.pathSegments) >= 2 and self.target.pathSegments[0] in ("project", "author") ): rows.append( tag( "a", href="/account/%ss/add/%s/" % (self.target.pathSegments[0], "/".join(self.target.pathSegments[1:])), )["Edit..."] ) result.callback(rows)
def formatLine(self, line): """Format one line from the IRC log, returning a (timestamp, nick, content) tuple""" timestamp, message = line.split(" ", 1) timestamp = self.formatTimestamp(int(timestamp[1:])) nick = () # Strip colors message = re.sub("(\x03..|\x0F|\x02)", "", message) if message[0] == '<': # Normal conversation sender, content = message[1:].split("> ", 1) nick = [" <", self.formatNick(sender), "> "] elif message[0] == '-': # A system message of some sort content = tag('span', _class="serverMessage")[ message[1:].split("- ", 1)[1] ] elif message[0] == '[': # A CTCP message sender, ctcp = message[1:].split("] ", 1) msgType, content = ctcp.split(" ", 1) if msgType == "ACTION": content = [self.formatNick(sender), " ", content] else: content = ["CTCP ", msgType, " ", content] else: content = message return [tag('td', _class="timestamp")[ timestamp ], tag('td', _class="nick")[ nick ], tag('td', _class="content")[ content ]]
def renderMetadataItem(self, name, value, mimeType, context): """Render a single metadata item. If the content is short and in a text format, we include it directly. Otherwise, just link to it. XXX: These links don't really make sense any more, since the metadata format changed. """ valueTag = tag('value', _type=mimeType)[ str(value) ] return tag('item', _name=name)[ valueTag ]
def SubscriptionLink(url, content, icon="/images/rss.png", iconSize=(36,14)): """An anchor tag that can be used to link to RSS feeds. """ return tag('a', href = url)[ tag('img', src=icon, _class="left-icon", alt="RSS", width=iconSize[0], height=iconSize[1]), content, ]
def _render_photo(self, query_results, context, result): if query_results and query_results[0][0]: result.callback(tag('image')[ tag('url')[ '/images/db/' + query_results[0][0] ], tag('title')[ place('title') ], tag('link')[ place('link') ], ]) else: result.callback([])
def MessageHeaders(d): """A factory for displaying message headers from a dictionary-like object. If order is important (it probably is) use twisted.python.util.OrderedDict. """ return tag('table', _class="messageHeaders")[[ tag('tr')[tag('td', _class='name')[name, ":"], tag('td', _class='value')[value], ] for name, value in d.iteritems() ]]
def SectionGrid(*rows): """Create a grid of sections, for layouts showing a lot of small boxes in a regular pattern. """ return tag('table', _class="sectionGrid")[[ tag('tr', _class="sectionGrid")[[ tag('td', _class="sectionGrid")[cell] for cell in row ]] for row in rows ]]
def render_content(self, context): e = self.entries[context['args']['id']] return [ tag('b')[ place('title') ], tag('br'), tag('i')[ e.feed.name ], " (", formatDate(e.date), ") ", tag('hr'), tag('p')[ e.content ], ]
def SubscriptionLink(url, content, icon="/images/rss.png", iconSize=(36, 14)): """An anchor tag that can be used to link to RSS feeds. """ return tag('a', href=url)[tag('img', src=icon, _class="left-icon", alt="RSS", width=iconSize[0], height=iconSize[1]), content, ]
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 format(self, f): """Read an IRC log from the given file-like object, returning the corresponding formatted Nouvelle tree. """ return tag('table')[[ tag('tr')[ self.formatLine(line), ] for line in f.xreadlines() ]]
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 renderBargraph(alpha, numBars=16): alpha = max(0, min(1, alpha)) filledBars = int(alpha * numBars + 0.5) bars = [] for i in xrange(numBars): if i < filledBars: bars.append(tag('span', _class="filledBar")[ " " ]) else: bars.append(tag('span', _class="emptyBar")[ " " ]) return tag('span', _class="bargraph")[ bars ]
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 SectionGrid(*rows): """Create a grid of sections, for layouts showing a lot of small boxes in a regular pattern. """ return tag('table', _class="sectionGrid")[[ tag('tr', _class="sectionGrid")[[ tag('td', _class="sectionGrid")[ cell ] for cell in row ]] for row in rows ]]
def _render(self, rows, result): """The backend for render(), called once our rows list is known""" if rows: result.callback( subcontext(owner=self)[ tag('span', _class="section")[place("title")], tag('div', _class="section")[ tag('div', _class="sectionTop")[" "], [tag('div', _class="row")[r] for r in rows], ], ]) else: result.callback([])
def MessageHeaders(d): """A factory for displaying message headers from a dictionary-like object. If order is important (it probably is) use twisted.python.util.OrderedDict. """ return tag('table', _class="messageHeaders")[[ tag('tr')[ tag('td', _class='name')[ name, ":" ], tag('td', _class='value')[ value ], ] for name, value in d.iteritems() ]]
def render_description(self, context): details = [] if self.source.sensor_type: details.append("%s sensor" % self.source.sensor_type) if self.source.micro_type: details.append("%s microcontroller" % self.source.micro_type) return tag('div', _class='description')[ self.source.description, tag('p')[ ", ".join(details) ], ]
def _render(self, rows, result): """The backend for render(), called once our rows list is known""" if rows: result.callback(subcontext(owner=self)[ tag('span', _class="section")[ place("title") ], tag('div', _class="section")[ tag('div', _class="sectionTop")[" "], [tag('div', _class="row")[r] for r in rows], ], ]) else: result.callback([])
def render_navigation(self, context): if self.showDetails(context): detailSwitch = tag('a', _class='navigation', href="?details=0")["Hide details"] else: detailSwitch = tag('a', _class='navigation', href="?details=1")["Show details"] return tag('div', _class='navigation')[ tag('a', _class='navigation', href='../../')[ "All Sensors..." ], [tag('a', _class='navigation', href="#%s" % anchor or 'top')[ name ] for name, length, anchor in self.intervals], detailSwitch, ]
class Table(Nouvelle.ResortableTable): """Add sorting indicators to Nouvelle's normal ResortableTable""" reversedSortIndicator = tag('img', _class='sortIndicator', width=11, height=7, src="/images/sort_up.png", alt="Reversed sort column") sortIndicator = tag('img', _class='sortIndicator', width=11, height=7, src="/images/sort_down.png", alt="Sort column")
def render_sources(self, context): return tag('table')[ tag('tr')[ tag('th')[ "Name" ], tag('th')[ "Current Temperature" ], tag('th')[ "Last 24 Hours" ], tag('th')[ "Last Updated" ], tag('th')[ "Battery" ], ], tag('tr')[ tag('td')[" "] ], [self.renderSource(source, context) for source in self.db.iterSources()], ]
def render_message(self, context): if not self.message: context["request"].setResponseCode(404) return self.notFoundMessage # Try to format it using several media, in order of decreasing preference. # The 'xhtml-long' formatter lets messages define a special formatter to # use when an entire page is devoted to their one message, possibly showing # it in greater detail. 'xhtml' is the formatter most messages should have. # 'plaintext' is a nice fallback. # # This default list of media to try can be overridden with an argument in our URL. if "media" in context["args"]: mediaList = context["args"]["media"][0].split() else: mediaList = ("xhtml-long", "xhtml", "plaintext") for medium in mediaList: try: formatted = Formatters.getFactory().findMedium(medium, self.message).formatMessage(self.message) except Message.NoFormatterError: continue return formatted # Still no luck? Display a warning message and a pretty-printed XML tree return [tag("h1")["No formatter available"], XML.htmlPrettyPrint(self.message.xml)]
def render_message(self, context): if not self.message: context['request'].setResponseCode(404) return self.notFoundMessage # Try to format it using several media, in order of decreasing preference. # The 'xhtml-long' formatter lets messages define a special formatter to # use when an entire page is devoted to their one message, possibly showing # it in greater detail. 'xhtml' is the formatter most messages should have. # 'plaintext' is a nice fallback. # # This default list of media to try can be overridden with an argument in our URL. if 'media' in context['args']: mediaList = context['args']['media'][0].split() else: mediaList = ('xhtml-long', 'xhtml', 'plaintext') for medium in mediaList: try: formatted = Formatters.getFactory().findMedium( medium, self.message).formatMessage(self.message) except Message.NoFormatterError: continue return formatted # Still no luck? Display a warning message and a pretty-printed XML tree return [ tag('h1')[ "No formatter available" ], XML.htmlPrettyPrint(self.message.xml), ]
def component_headers(self, element, args): """Format all relevant commit metadata in an email-style header box""" message = args.message commit = XML.dig(message.xml, "message", "body", "commit") source = XML.dig(message.xml, "message", "source") author = XML.dig(commit, "author") version = XML.dig(commit, "version") revision = XML.dig(commit, "revision") diffLines = XML.dig(commit, "diffLines") url = XML.dig(commit, "url") log = XML.dig(commit, "log") project = XML.dig(source, "project") module = XML.dig(source, "module") branch = XML.dig(source, "branch") headers = OrderedDict() if author: headers['Author'] = XML.shallowText(author) if project: headers['Project'] = XML.shallowText(project) if module: headers['Module'] = XML.shallowText(module) if branch: headers['Branch'] = XML.shallowText(branch) if version: headers['Version'] = XML.shallowText(version) if revision: headers['Revision'] = XML.shallowText(revision) if diffLines: headers['Changed Lines'] = XML.shallowText(diffLines) if url: headers['URL'] = tag('a', href=XML.shallowText(url))[ Util.extractSummary(url) ] return [Template.MessageHeaders(headers)]
def render_item(self, context, id, content): url = Link.MessageLink(self.target, id).getURL(context) m = Message.Message(content) tags = [ tag('link')[ url ], tag('dc:date')[ TimeUtil.formatDateISO8601(XML.digValue(m.xml, int, "message", "timestamp")) ], tag('description')[ quote(self.formatMessage(m)) ], ] # Generate a title if we can, but if we can't don't worry too much try: tags.append(tag('title')[ Formatters.getFactory().findMedium('title', m).formatMessage(m) ]) except Message.NoFormatterError: pass return tag('item', **{'rdf:about': url})[tags]
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 render_pyInfo(self, context): result = [] for line in ('Python %s on %s' % (sys.version, sys.platform)).split("\n"): if result: result.append(tag('br')) result.append(line) return result
def render_data(self, context, file): """We hyperlink the file name, and give it an icon to indicate directory vs file""" if file.isdir(): icon = Template.dirIcon else: icon = Template.fileIcon name = file.basename() return [icon, tag("a", href=name)[name]]
def messageToItemContent(self, context, m, id): """Render an XML message as the content of an RSS <item>""" url = Link.MessageLink(self.target, id).getURL(context) tags = [ tag('pubDate')[ TimeUtil.formatDateRFC822(XML.digValue(m.xml, int, "message", "timestamp")) ], tag('guid')[url], tag('link')[url], tag('description')[ quote(self.formatMessage(m)) ], ] # Generate a title if we can, but if we can't don't worry too much try: tags.append(tag('title')[ Formatters.getFactory().findMedium('title', m).formatMessage(m) ]) except Message.NoFormatterError: pass return tags
def __init__(self, target, key=None, tagFactory=tag('a'), text=None): segments = ['.metadata'] if key: segments.append(key) TargetRelativeLink.__init__(self, target, segments) self.tagFactory = tagFactory self.key = key self.text = text
def render_extraHeaders(self, context): # Add a <link> tag pointing at our RSS feed. Some RSS # aggregators can use this to automatically detect feeds. return tag('link', rel = 'alternate', type = 'application/rss+xml', title = 'RSS', href = Link.RSSLink(self.target).getURL(context), )
def renderLatest(self): self.latest = self.source.getLatestPacket() if self.latest: info = [] if self.latest.get('average'): info.append(renderTemperature(self.latest)) if self.latest.get('voltage'): info.append(tag('p')[ "Battery: ", renderBatteryBargraph(self.latest) ]) if self.latest.get('time'): info.append(tag('p')[ "Last reading received ", tag('strong')[ renderTimestamp(self.latest) ]]) else: info = ["No data"] return tag('div', _class='currentData')[info]
def render_extraHeaders(self, context): # Add a <link> tag pointing at our RSS feed. Some RSS # aggregators can use this to automatically detect feeds. return tag( 'link', rel='alternate', type='application/rss+xml', title='RSS', href=Link.RSSLink(self.target).getURL(context), )
def __init__(self, target, id, extraSegments=(), tagFactory=tag('a'), text=None): TargetRelativeLink.__init__(self, target, ('.message', "%x" % id) + extraSegments) self.tagFactory = tagFactory self.text = text
def _render_counters(self, counterdict, context, result): tags = [] for name, valueDict in counterdict.iteritems(): eventCount = valueDict.get('eventCount', 0) try: del valueDict['eventCount'] except KeyError: pass tags.append(tag('counter', _name = name, **valueDict)[ eventCount ]) result.callback(tags)
def formatItems(self, messages, context): items = [] for id, content in messages: try: items.append(tag('item')[self.messageToItemContent(context, Message.Message(content), id)]) except: log.msg("Exception occurred in %s.formatItems\n%s" % ( self.__class__.__name__, "".join(traceback.format_exception(*sys.exc_info())))) return items
def render_data(self, context, file): """We hyperlink the file name, and give it an icon to indicate directory vs file""" if file.isdir(): icon = Template.dirIcon else: icon = Template.fileIcon name = file.basename() return [ icon, tag('a', href=name)[name], ]
def render_section(self, section, rows): """Given a heading renderable and a list of rows for that heading, render one section of the 'related' box. """ # Truncate the rows if we need to if len(rows) > self.sectionLimit: footer = tag( 'div', _class='relatedFooter')['(%d others)' % (len(rows) - self.sectionLimit)] rows = rows[:self.sectionLimit] else: footer = () parentTitle = rows[0][1] return [ tag('div', _class='relatedHeading')[self.makeLink(section, parentTitle)], RelatedTable(rows, self.columns, showHeading=False), footer, ]
def FileTree(tree): """A factory for rendering file trees from a tree of nested dictionaries. Dictionaries with no children are treated as files, dictionaries with children are treated as directories. """ keys = tree.keys() keys.sort() items = [] for key in keys: if not key: # This can happen when there's a trailing slash, for example because a new directory # was added. (in clients that are smart enough to detect that) Ignore it here for now. continue if tree[key]: items.append( tag('li', _class='directory')[key, FileTree(tree[key])]) else: items.append(tag('li', _class='file')[key]) return tag('ul', _class='fileTree')[items]
def format_generator(self, gen): """Format the information contained in this message's <generator> tag""" name = XML.digValue(gen, str, "name") url = XML.digValue(gen, str, "url") version = XML.digValue(gen, str, "version") if url: name = tag('a', href=url)[ name ] items = ["Generated by ", Template.value[ name ]] if version: items.extend([" version ", version]) return items
def evalComponent(self, node, args): """Here we convert all components starting with 'n:' into Novuelle tags. FIXME: This should really be using proper DOM namespace manipulation and such """ if node.nodeType == node.ELEMENT_NODE and node.nodeName.startswith( "n:"): attrs = {} for attr in node.attributes.values(): attrs[str(attr.name)] = attr.value return [ tag(node.nodeName[2:], **attrs)[self.walkComponents(node.childNodes, args)] ] return CommitFormatter.evalComponent(self, node, args)
def render(self, context): # Obfuscate the content content = treeReplace(self.content, "@", " at ") content = treeReplace(content, ".", " dot ") # Create an 'onmouseover' script that will replace our link's # href with the correct one. We start by randomly dividing the # email address into small chunks. parts = randomlySubdivide(self.href, 1, 5) script = "this.href=" + "+".join(["'%s'" % part for part in parts]) # Assemble and render the final link return tag('a', href="/doc/mail", onmouseover=script)[content].render(context)
def _render_rows(self, metadata, context, result): url, description, photo_results, owner_results = metadata rows = [] if url: rows.append(tag('a', href=url)[url]) if photo_results and photo_results[0][0]: path, width, height = photo_results[0] rows.append(Template.Photo('/images/db/' + path, width=width, height=height)) if description: rows.append(description) # XXX: This is kind of a hack, but it should improve usability # between the old and new sites. Show 'edit' links if # this is something users can edit (projects or authors) # and if it isn't claimed exclusively already. if (not owner_results and len(self.target.pathSegments) >= 2 and self.target.pathSegments[0] in ('project', 'author')): rows.append(tag('a', href='/account/%ss/add/%s/' % ( self.target.pathSegments[0], '/'.join(self.target.pathSegments[1:]))) ["Edit..."]) result.callback(rows)
def format_file(self, name, fileTag=None): """Given the short name of a file, and optionally its XML tag, return a Nouvelle-serializable representation. """ if fileTag: # If we have a 'uri' attribute, make this file a hyperlink uri = fileTag.getAttribute('uri') if uri: name = tag('a', href=uri)[name] # If we have an 'action' attribute, represent it with an icon actionIcon = self.actionIcons.get(fileTag.getAttribute('action')) if actionIcon: name = (name, actionIcon) return name
def render_rows(self, context): """Assemble our file tree in the form of nested dictionaries, then let Template.FileTree render it. """ request = context['request'] tree = {} node = tree urlSegments = [''] # Walk down the tree putting in our ancestor directories # (not counting the root directory, since navigating to # it is better done using our tabs or site name link) for path in request.prepath: if path: urlSegments.append(path) link = tag('a', href="/".join(urlSegments))[path] node = node.setdefault(link, {}) return [Template.FileTree(tree)]
def _loadSidebar(self, path): """Load sidebar links from a simple text file format. Lines beginning with a dash specify a new section heading, links are made by lines of the form 'title :: URL'. Other lines are ignored. """ sections = [] for line in open(path).xreadlines(): line = line.strip() if not line: continue if line[0] == '-': sections.append(Template.StaticSection(line[1:].strip())) continue pieces = line.split("::", 1) if len(pieces) > 1: title, url = pieces sections[-1].rows.append( tag('a', href=url.strip())[title.strip()]) return sections
def component_headers(self, element, args): """Format all relevant commit metadata in an email-style header box""" from LibCIA.Web import Template message = args.message commit = XML.dig(message.xml, "message", "body", "commit") source = XML.dig(message.xml, "message", "source") author = XML.dig(commit, "author") version = XML.dig(commit, "version") revision = XML.dig(commit, "revision") diffLines = XML.dig(commit, "diffLines") url = XML.dig(commit, "url") log = XML.dig(commit, "log") project = XML.dig(source, "project") module = XML.dig(source, "module") branch = XML.dig(source, "branch") headers = OrderedDict() if author: headers['Author'] = XML.shallowText(author) if project: headers['Project'] = XML.shallowText(project) if module: headers['Module'] = XML.shallowText(module) if branch: headers['Branch'] = XML.shallowText(branch) if version: headers['Version'] = XML.shallowText(version) if revision: headers['Revision'] = XML.shallowText(revision) if diffLines: headers['Changed Lines'] = XML.shallowText(diffLines) if url: headers['URL'] = tag( 'a', href=XML.shallowText(url))[Util.extractSummary(url)] return [Template.MessageHeaders(headers)]
class Hello(Twisted.Page): isLeaf = 1 document = tag('html')[tag('head')[tag('title')["Hi"], ], tag('body')[tag('h3')["Hello World!"], tag('p')[place("dataTable")]], ] def render_dataTable(self, context): data = [] for id in BZFlag.Players.keys(): player = BZFlag.Players[id] data.append([ id, player.callsign, player.wins - player.losses, player.team ]) return MyTable(data, [ Nouvelle.IndexedColumn('id', 0), Nouvelle.IndexedColumn('callsign', 1), Nouvelle.IndexedColumn('score', 2), Nouvelle.IndexedColumn('team', 3), ], id='players')
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 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', style="padding: 0em %.4fem" % (value * width + padding))
class MessagePage(Template.Page): """A page that views one message from the stats database""" mainTitle = 'Archived Message' def __init__(self, statsPage, id): self.statsPage = statsPage self.id = id Template.Page.__init__(self) self.putChild('xml', UnformattedMessagePage(self.statsPage.target, self.id)) def parent(self): return self.statsPage def preRender(self, context): # Load the message once, so multiple components can share it xml = self.statsPage.target.messages.getMessageById(self.id) if xml: self.message = Message.Message(xml) else: self.message = None context['component'] = self.statsPage.component def render_subTitle(self, context): return ["for ", self.statsPage.render_mainTitle(context)] def render_message(self, context): if not self.message: context['request'].setResponseCode(404) return self.notFoundMessage # Try to format it using several media, in order of decreasing preference. # The 'xhtml-long' formatter lets messages define a special formatter to # use when an entire page is devoted to their one message, possibly showing # it in greater detail. 'xhtml' is the formatter most messages should have. # 'plaintext' is a nice fallback. # # This default list of media to try can be overridden with an argument in our URL. if 'media' in context['args']: mediaList = context['args']['media'][0].split() else: mediaList = ('xhtml-long', 'xhtml', 'plaintext') for medium in mediaList: try: formatted = Formatters.getFactory().findMedium( medium, self.message).formatMessage(self.message) except Message.NoFormatterError: continue return formatted # Still no luck? Display a warning message and a pretty-printed XML tree return [ tag('h1')[ "No formatter available" ], XML.htmlPrettyPrint(self.message.xml), ] def render_leftColumn(self, context): return [ EnvelopeSection(self.statsPage.target, self.message), LinksSection(self.statsPage.target, self.id), Info.Clock(), ] notFoundMessage = [ tag('h1')[ "Not Found" ], tag('p')[ "This message was not found in our database. The number could be " "incorrect, or the message may be old enough that it was deleted " "from the database. Each stats target archives a fixed number of messages, " "so you might be able to find another copy of it on a different stats " "target with less traffic." ] ] mainColumn = [ Template.pageBody[ place('message') ], ]
def parseString(self, s): s = s.strip() if s: return tag('p', _class='xml-text')[ s ] else: return ()
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