24
23
import genshi.template
26
25
from ivle.webapp.media import media_url
27
from ivle.webapp.core import Plugin as CorePlugin
28
26
from ivle.webapp.base.views import BaseView
29
from ivle.webapp.base.plugins import ViewPlugin, OverlayPlugin
30
from ivle.webapp.errors import HTTPError, Unauthorized
31
from ivle.webapp.publisher import NoPath
32
from ivle.webapp.breadcrumbs import Breadcrumber
27
from ivle.webapp.base.plugins import OverlayPlugin
34
31
class XHTMLView(BaseView):
41
38
template = 'template.html'
43
breadcrumb_text = None
45
def __init__(self, *args, **kwargs):
46
super(XHTMLView, self).__init__(*args, **kwargs)
48
self.overlay_blacklist = []
50
self.plugin_scripts = {}
51
self.plugin_styles = {}
52
self.scripts_init = []
54
self.extra_breadcrumbs = []
55
self.overlay_blacklist = []
57
def get_context_ancestry(self, req):
58
return req.publisher.get_ancestors(self.context)
60
def filter(self, stream, ctx):
41
overlay_blacklist = []
43
def __init__(self, req, **kwargs):
45
setattr(self, key, kwargs[key])
63
47
def render(self, req):
64
48
req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
72
56
app_template = os.path.join(os.path.dirname(
73
57
inspect.getmodule(self).__file__), self.template)
58
req.write_html_head_foot = False
74
59
loader = genshi.template.TemplateLoader(".", auto_reload=True)
75
60
tmpl = loader.load(app_template)
76
app = self.filter(tmpl.generate(viewctx), viewctx)
61
app = tmpl.generate(viewctx)
79
63
for plugin in self.plugin_scripts:
80
64
for path in self.plugin_scripts[plugin]:
81
view_scripts.append(media_url(req, plugin, path))
65
req.scripts.append(media_url(req, plugin, path))
84
67
for plugin in self.plugin_styles:
85
68
for path in self.plugin_styles[plugin]:
86
view_styles.append(media_url(req, plugin, path))
69
req.styles.append(media_url(req, plugin, path))
89
72
ctx = genshi.template.Context()
91
overlay_bits = self.render_overlays(req) if req.user else [[]]*4
92
ctx['overlays'] = overlay_bits[0]
94
ctx['styles'] = [media_url(req, CorePlugin, 'ivle.css')]
95
ctx['styles'] += view_styles
96
ctx['styles'] += overlay_bits[1]
98
ctx['scripts'] = [media_url(req, CorePlugin, path) for path in
99
('util.js', 'json2.js', 'md5.js')]
100
ctx['scripts'].append(media_url(req, '+external/jquery', 'jquery.js'))
101
ctx['scripts'] += view_scripts
102
ctx['scripts'] += overlay_bits[2]
104
ctx['scripts_init'] = self.scripts_init + overlay_bits[3]
73
# XXX: Leave this here!! (Before req.styles is read)
74
ctx['overlays'] = self.render_overlays(req)
75
ctx['app_styles'] = req.styles
76
ctx['scripts'] = req.scripts
77
ctx['scripts_init'] = req.scripts_init
105
78
ctx['app_template'] = app
106
ctx['title_img'] = media_url(req, CorePlugin,
107
"images/chrome/root-breadcrumb.png")
109
ancestry = self.get_context_ancestry(req)
113
crumber = Breadcrumber(req)
115
ctx['breadcrumbs'] = []
116
if not req.publicmode:
117
for ancestor in ancestry:
118
crumb = crumber.crumb(ancestor)
122
if hasattr(crumb, 'extra_breadcrumbs_before'):
123
ctx['breadcrumbs'].extend(crumb.extra_breadcrumbs_before)
124
ctx['breadcrumbs'].append(crumb)
125
if hasattr(crumb, 'extra_breadcrumbs_after'):
126
ctx['breadcrumbs'].extend(crumb.extra_breadcrumbs_after)
128
# If the view has specified text for a breadcrumb, add one.
129
if self.breadcrumb_text:
130
ctx['breadcrumbs'].append(ViewBreadcrumb(req, self))
132
# Allow the view to add its own fake breadcrumbs.
133
ctx['breadcrumbs'].extend(self.extra_breadcrumbs)
135
79
self.populate_headings(req, ctx)
136
80
tmpl = loader.load(os.path.join(os.path.dirname(__file__),
137
81
'ivle-headings.html'))
152
95
ctx['nick'] = req.user.nick
154
97
ctx['login'] = None
155
ctx['logged_in'] = False
156
98
ctx['publicmode'] = req.publicmode
157
if hasattr(self, 'help'):
158
ctx['help_path'] = self.help
160
99
ctx['apps_in_tabs'] = []
161
for plugin in req.config.plugin_index[ViewPlugin]:
162
if not hasattr(plugin, 'tabs'):
165
for tab in plugin.tabs:
166
# tab is a tuple: name, title, desc, icon, path, weight, admin
167
# (Admin is optional, defaults to false)
169
new_app['this_app'] = hasattr(self, 'tab') \
170
and tab[0] == self.tab
173
if tab[3] is not None:
174
new_app['has_icon'] = True
175
icon_url = media_url(req, plugin, tab[3])
176
new_app['icon_url'] = icon_url
177
if new_app['this_app']:
178
ctx['favicon'] = icon_url
180
new_app['has_icon'] = False
181
# The following check is here, so it is AFTER setting the
182
# icon, but BEFORE actually installing the tab in the menu
183
if len(tab) > 6 and tab[6]:
185
if not (req.user and req.user.admin):
187
new_app['path'] = req.make_path(tab[4])
188
new_app['desc'] = tab[2]
189
new_app['name'] = tab[1]
190
new_app['weight'] = tab[5]
191
ctx['apps_in_tabs'].append(new_app)
193
ctx['apps_in_tabs'].sort(key=lambda tab: tab['weight'])
100
for urlname in ivle.conf.apps.apps_in_tabs:
102
app = ivle.conf.apps.app_url[urlname]
103
new_app['this_app'] = hasattr(self, 'appname') \
104
and urlname == self.appname
106
new_app['has_icon'] = True
107
icon_dir = ivle.conf.apps.app_icon_dir
108
icon_url = ivle.util.make_path(os.path.join(icon_dir, app.icon))
109
new_app['icon_url'] = icon_url
110
if new_app['this_app']:
111
ctx['favicon'] = icon_url
113
new_app['has_icon'] = False
114
new_app['path'] = ivle.util.make_path(urlname)
115
new_app['desc'] = app.desc
116
new_app['name'] = app.name
117
ctx['apps_in_tabs'].append(new_app)
195
119
def render_overlays(self, req):
196
120
"""Generate XML streams for the overlays.
213
131
#TODO: Re-factor this to look nicer
214
132
for mplugin in overlay.plugin_scripts:
215
133
for path in overlay.plugin_scripts[mplugin]:
216
scripts.append(media_url(req, mplugin, path))
134
req.scripts.append(media_url(req, mplugin, path))
218
136
for mplugin in overlay.plugin_styles:
219
137
for path in overlay.plugin_styles[mplugin]:
220
styles.append(media_url(req, mplugin, path))
222
scripts_init += overlay.plugin_scripts_init
138
req.styles.append(media_url(req, mplugin, path))
140
req.scripts_init += overlay.plugin_scripts_init
224
142
overlays.append(overlay.render(req))
225
return (overlays, styles, scripts, scripts_init)
228
def get_error_view(cls, e):
229
view_map = {HTTPError: XHTMLErrorView,
230
Unauthorized: XHTMLUnauthorizedView}
231
for exccls in inspect.getmro(type(e)):
232
if exccls in view_map:
233
return view_map[exccls]
235
class XHTMLErrorView(XHTMLView):
236
template = 'xhtmlerror.html'
238
def __init__(self, req, context, lastobj):
239
super(XHTMLErrorView, self).__init__(req, context)
240
self.lastobj = lastobj
242
def get_context_ancestry(self, req):
243
return req.publisher.get_ancestors(self.lastobj)
245
def populate(self, req, ctx):
247
ctx['exception'] = self.context
249
class XHTMLUnauthorizedView(XHTMLErrorView):
250
template = 'xhtmlunauthorized.html'
252
def __init__(self, req, exception, lastobj):
253
super(XHTMLUnauthorizedView, self).__init__(req, exception, lastobj)
255
if not req.publicmode and req.user is None:
256
# Not logged in. Redirect to login page.
260
query_string = '?url=' + urllib.quote(req.uri, safe="/~")
261
req.throw_redirect('/+login' + query_string)
265
class ViewBreadcrumb(object):
266
def __init__(self, req, context):
268
self.context = context
272
return self.context.breadcrumb_text