123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- from hashlib import sha1
- from dominate import tags
- from visitor import Visitor
- class BootstrapRenderer(Visitor):
- def __init__(self, html5=True, id=None):
- self.html5 = html5
- self._in_dropdown = False
- self.id = id
- def visit_Navbar(self, node):
- # create a navbar id that is somewhat fixed, but do not leak any
- # information about memory contents to the outside
- node_id = self.id or sha1(str(id(node)).encode()).hexdigest()
- root = tags.nav() if self.html5 else tags.div(role='navigation')
- root['class'] = 'navbar navbar-default'
- cont = root.add(tags.div(_class='container-fluid'))
- # collapse button
- header = cont.add(tags.div(_class='navbar-header'))
- btn = header.add(tags.button())
- btn['type'] = 'button'
- btn['class'] = 'navbar-toggle collapsed'
- btn['data-toggle'] = 'collapse'
- btn['data-target'] = '#' + node_id
- btn['aria-expanded'] = 'false'
- btn['aria-controls'] = 'navbar'
- btn.add(tags.span('Toggle navigation', _class='sr-only'))
- btn.add(tags.span(_class='icon-bar'))
- btn.add(tags.span(_class='icon-bar'))
- btn.add(tags.span(_class='icon-bar'))
- # title may also have a 'get_url()' method, in which case we render
- # a brand-link
- if node.title is not None:
- if hasattr(node.title, 'get_url'):
- header.add(tags.a(node.title.text, _class='navbar-brand',
- href=node.title.get_url()))
- else:
- header.add(tags.span(node.title, _class='navbar-brand'))
- bar = cont.add(tags.div(
- _class='navbar-collapse collapse',
- id=node_id,
- ))
- bar_list = bar.add(tags.ul(_class='nav navbar-nav'))
- for item in node.items:
- bar_list.add(self.visit(item))
- return root
- def visit_Text(self, node):
- if not self._in_dropdown:
- return tags.p(node.text, _class='navbar-text')
- return tags.li(node.text, _class='dropdown-header')
- def visit_Link(self, node):
- item = tags.li()
- item.add(tags.a(node.text, href=node.get_url()))
- return item
- def visit_Separator(self, node):
- if not self._in_dropdown:
- raise RuntimeError('Cannot render separator outside Subgroup.')
- return tags.li(role='separator', _class='divider')
- def visit_Subgroup(self, node):
- if not self._in_dropdown:
- li = tags.li(_class='dropdown')
- if node.active:
- li['class'] = 'active'
- a = li.add(tags.a(node.title, href='#', _class='dropdown-toggle'))
- a['data-toggle'] = 'dropdown'
- a['role'] = 'button'
- a['aria-haspopup'] = 'true'
- a['aria-expanded'] = 'false'
- a.add(tags.span(_class='caret'))
- ul = li.add(tags.ul(_class='dropdown-menu'))
- self._in_dropdown = True
- for item in node.items:
- ul.add(self.visit(item))
- self._in_dropdown = False
- return li
- else:
- raise RuntimeError('Cannot render nested Subgroups')
- def visit_View(self, node):
- item = tags.li()
- item.add(tags.a(node.text, href=node.get_url(), title=node.text))
- if node.active:
- item['class'] = 'active'
- return item
|