Remove unused imports, fix too long lines and indentions.
[Melange.git] / app / soc / views / helper / html_menu.py
blob681e8b58447793e01ae931a613f9abe7b6c02d23
1 #!/usr/bin/python2.5
3 # Copyright 2008 the Melange authors.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """Helpers for displaying arbitrarily nested menus as HTML lists.
18 """
20 __authors__ = [
21 '"Todd Larsen" <tlarsen@google.com>',
25 class HtmlMenu:
26 """Ordered collection of MenuItem objects as <p>...</p> paragraphs.
27 """
28 ITEM_PREFIX_FMT = '%(indent)s<p>'
29 ITEM_SUFFIX_FMT = '%(indent)s</p>'
31 def __init__(self, menu, item_class=None):
32 """Wraps an soc.logic.menu.Menu in order to render it as HTML.
34 Args:
35 menu: an soc.logic.menu.Menu object
36 item_class: style used to render the MenuItems contained in menu;
37 default is None, which causes AHrefMenuItem to be used
38 """
39 self._menu = menu
41 # workaround for circular dependency between AHrefMenuItem and this class
42 if not item_class:
43 item_class = AHrefMenuItem
45 self._item_class = item_class
47 def getHtmlTags(self, indent):
48 """Returns list of HTML tags for arbitrarily nested items in the menu.
50 Args:
51 indent: string prepended to the beginning of each line of output
52 (usually consists entirely of spaces)
54 Returns:
55 a list of strings that can be joined with '\n' into a single string
56 to produce an entire <ul>...</ul> list in HTML
57 """
58 tags = []
60 if self._menu.items:
61 tags.append(self.ITEM_PREFIX_FMT % {'indent': indent})
63 for item in self._menu.items:
64 tags.extend(self._item_class(
65 item, menu_class=self.__class__).getHtmlTags(indent + ' '))
67 tags.append(self.ITEM_SUFFIX_FMT % {'indent': indent})
69 return tags
71 def __str__(self):
72 return '\n'.join(self.getHtmlTags(''))
75 class UlMenu(HtmlMenu):
76 """Ordered collection of MenuItem objects as a <ul> list.
77 """
78 ITEM_PREFIX_FMT = '%(indent)s<ul>'
79 ITEM_SUFFIX_FMT = '%(indent)s</ul>'
81 def __init__(self, menu, item_class=None):
82 """Wraps an soc.logic.menu.Menu in order to render it as HTML.
84 Args:
85 menu: an soc.logic.menu.Menu object
86 item_class: style used to render the MenuItems contained in menu;
87 default is None, which causes LiMenuItem to be used
88 """
89 # workaround for circular dependency between LiMenuItem and this class
90 if not item_class:
91 item_class = LiMenuItem
93 HtmlMenu.__init__(self, menu, item_class=item_class)
96 class HtmlMenuItem:
97 """Base class for specific MenuItem wrappers used by HtmlMenu sub-classes.
98 """
100 def __init__(self, item, menu_class=HtmlMenu):
101 """Wraps an soc.logic.menu.MenuItem in order to render it as HTML.
103 Args:
104 item: an soc.logic.menu.MenuItem object to wrap, in order to produce
105 a representation of it as HTML tags later
106 menu_class: a class derived from HtmlMenu, used to style any sub-menu
107 of the MenuItem; default is HtmlMenu
109 self._item = self.escapeItem(item)
110 self._menu_class = menu_class
112 def getItemHtmlTags(self, indent):
113 """Returns list of HTML tags for the menu item itself.
115 This method is intended to be overridden by sub-classes.
117 Args:
118 indent: string prepended to the beginning of each line of output
119 (usually consists entirely of spaces)
121 Returns:
122 a list of strings that can be joined with '\n' into a single string
123 to produce:
124 <b>name</b> value <i>(annotation)</i>
125 with value and/or <i>(annotation)</i> omitted if either is missing
127 # TODO(tlarsen): implement "selected" style
129 tags = ['%s<b>%s</b>' % (indent, self._item.name)]
131 if self._item.value:
132 tags.append('%s%s' % (indent, self._item.value))
134 if self._item.annotation:
135 tags.append('%s<i>(%s)</i>' % (indent, self._item.annotation))
137 return tags
139 def getSubMenuHtmlTags(self, indent):
140 """Returns list of HTML tags for any sub-menu, if one exists.
142 Args:
143 indent: string prepended to the beginning of each line of output
144 (usually consists entirely of spaces)
146 Returns:
147 an empty list if there is no sub-menu
148 -OR-
149 the list of HTML tags that render the entire sub-menu (depends on the
150 menu_class that was provided to __init__()
152 if not self._item.sub_menu:
153 return []
155 return self._menu_class(self._item.sub_menu,
156 item_class=self.__class__).getHtmlTags(indent)
158 def getHtmlTags(self, indent):
159 """Returns list of HTML tags for a menu item (and possibly its sub-menus).
161 Args:
162 indent: string prepended to the beginning of each line of output
163 (usually consists entirely of spaces)
165 Returns:
166 a list of strings that can be joined with '\n' into a single string
167 to produce an HTML representation of the wrapped MenuItem, with
168 arbitrarily nested sub-menus possibly appended
170 return self.getItemHtmlTags(indent) + self.getSubMenuHtmlTags(indent)
172 def escapeItem(self, item):
173 """HTML-escapes possibly user-supplied fields to prevent XSS.
175 Args:
176 item: an soc.logic.menu.MenuItem that is altered in-place; the
177 fields that are potentially user-provided (name, value, annotation)
178 are escaped using self.escapeText()
180 Returns:
181 the originally supplied item, for convenience, so that this method can
182 be combined with an assignment
184 item.name = self.escapeText(item.name)
185 item.value = self.escapeText(item.value)
186 item.annotation = self.escapeText(item.annotation)
187 return item
189 def escapeText(self, text):
192 # TODO(tlarsen): user-supplied content *must* be escaped to prevent XSS
193 return text
195 def __str__(self):
196 return '\n'.join(self.getHtmlTags(''))
199 class AHrefMenuItem(HtmlMenuItem):
200 """Provides HTML menu item properties as attributes as an <a href> link.
203 def getItemHtmlTags(self, indent):
204 """Returns list of HTML tags for the menu item itself.
206 Args:
207 indent: string prepended to the beginning of each line of output
208 (usually consists entirely of spaces)
210 Returns:
211 a list of strings that can be joined with '\n' into a single string
212 to produce an <a href="...">...</a> link, or just the MenuItem.name
213 as plain text if there was no AHrefMenuItem.value URL
215 # TODO(tlarsen): implement "selected" style
217 if not self._item.value:
218 # if no URL, then not a link, so just display item.name as text
219 return [self._item.name]
221 # URL supplied, so make an <a href="item.value">item.name</a> link
222 return ['%s<a href=' % indent,
223 '%s "%s"' % (indent, self._item.value),
224 '%s>%s</a>' % (indent, self._item.name)]
227 class LiMenuItem(AHrefMenuItem):
228 """Provides HTML menu item properties as attributes as an <li> list item.
231 def __init__(self, item, menu_class=UlMenu):
232 """Wraps an soc.logic.menu.MenuItem in order to render it as HTML.
234 Args:
235 item: an soc.logic.menu.MenuItem object to wrap, in order to produce
236 a representation of it as HTML tags later
237 menu_class: a class derived from HtmlMenu, used to style any sub-menu
238 of the MenuItem; default is UlMenu
240 AHrefMenuItem.__init__(self, item, menu_class=menu_class)
242 def getHtmlTags(self, indent):
243 """Returns <a href> link wrapped as an <li> list item.
245 See also AHrefMenuItem.getHtmlTags().
247 return (['%s<li>' % indent]
248 + AHrefMenuItem.getHtmlTags(self, indent + ' ')
249 + ['%s</li>' % indent])