23
24
import genshi.template
25
26
from ivle.webapp.media import media_url
27
from ivle.webapp.core import Plugin as CorePlugin
26
28
from ivle.webapp.base.views import BaseView
27
from ivle.webapp.base.plugins import OverlayPlugin
29
from ivle.webapp.base.plugins import ViewPlugin, OverlayPlugin
28
30
from ivle.webapp.errors import HTTPError, Unauthorized
31
from ivle.webapp.publisher import NoPath
32
from ivle.webapp.breadcrumbs import Breadcrumber
32
34
class XHTMLView(BaseView):
39
41
template = 'template.html'
42
overlay_blacklist = []
44
def __init__(self, req, **kwargs):
46
setattr(self, key, kwargs[key])
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):
48
63
def render(self, req):
49
64
req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
57
72
app_template = os.path.join(os.path.dirname(
58
73
inspect.getmodule(self).__file__), self.template)
59
req.write_html_head_foot = False
60
74
loader = genshi.template.TemplateLoader(".", auto_reload=True)
61
75
tmpl = loader.load(app_template)
62
app = tmpl.generate(viewctx)
76
app = self.filter(tmpl.generate(viewctx), viewctx)
64
79
for plugin in self.plugin_scripts:
65
80
for path in self.plugin_scripts[plugin]:
66
req.scripts.append(media_url(req, plugin, path))
81
view_scripts.append(media_url(req, plugin, path))
68
84
for plugin in self.plugin_styles:
69
85
for path in self.plugin_styles[plugin]:
70
req.styles.append(media_url(req, plugin, path))
86
view_styles.append(media_url(req, plugin, path))
73
89
ctx = genshi.template.Context()
74
# XXX: Leave this here!! (Before req.styles is read)
75
ctx['overlays'] = self.render_overlays(req)
76
ctx['app_styles'] = req.styles
77
ctx['scripts'] = req.scripts
78
ctx['scripts_init'] = req.scripts_init
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]
79
105
ctx['app_template'] = app
106
ctx['title_img'] = media_url(req, CorePlugin,
107
"images/chrome/root-breadcrumb.png")
109
ctx['ancestry'] = self.get_context_ancestry(req)
113
# If the view has specified text for a breadcrumb, add one.
114
if self.breadcrumb_text:
115
ctx['extra_breadcrumbs'] = [ViewBreadcrumb(req, self)]
117
ctx['extra_breadcrumbs'] = []
119
# Allow the view to add its own fake breadcrumbs.
120
ctx['extra_breadcrumbs'] += self.extra_breadcrumbs
122
ctx['crumb'] = Breadcrumber(req).crumb
80
123
self.populate_headings(req, ctx)
81
124
tmpl = loader.load(os.path.join(os.path.dirname(__file__),
82
125
'ivle-headings.html'))
88
131
def populate_headings(self, req, ctx):
89
132
ctx['favicon'] = None
90
ctx['root_dir'] = ivle.conf.root_dir
91
ctx['public_host'] = ivle.conf.public_host
133
ctx['root_dir'] = req.config['urls']['root']
134
ctx['public_host'] = req.config['urls']['public_host']
135
ctx['svn_base'] = req.config['urls']['svn_addr']
92
136
ctx['write_javascript_settings'] = req.write_javascript_settings
94
138
ctx['login'] = req.user.login
98
142
ctx['login'] = None
99
143
ctx['logged_in'] = False
100
144
ctx['publicmode'] = req.publicmode
101
ctx['apps_in_tabs'] = []
102
145
if hasattr(self, 'help'):
103
146
ctx['help_path'] = self.help
104
for urlname in ivle.conf.apps.apps_in_tabs:
106
app = ivle.conf.apps.app_url[urlname]
107
new_app['this_app'] = hasattr(self, 'appname') \
108
and urlname == self.appname
110
new_app['has_icon'] = True
111
icon_dir = ivle.conf.apps.app_icon_dir
112
icon_url = ivle.util.make_path(os.path.join(icon_dir, app.icon))
113
new_app['icon_url'] = icon_url
114
if new_app['this_app']:
115
ctx['favicon'] = icon_url
117
new_app['has_icon'] = False
118
new_app['path'] = ivle.util.make_path(urlname)
119
new_app['desc'] = app.desc
120
new_app['name'] = app.name
121
ctx['apps_in_tabs'].append(new_app)
148
ctx['apps_in_tabs'] = []
149
for plugin in req.config.plugin_index[ViewPlugin]:
150
if not hasattr(plugin, 'tabs'):
153
for tab in plugin.tabs:
154
# tab is a tuple: name, title, desc, icon, path
156
new_app['this_app'] = hasattr(self, 'tab') \
157
and tab[0] == self.tab
160
if tab[3] is not None:
161
new_app['has_icon'] = True
162
icon_url = media_url(req, plugin, tab[3])
163
new_app['icon_url'] = icon_url
164
if new_app['this_app']:
165
ctx['favicon'] = icon_url
167
new_app['has_icon'] = False
168
new_app['path'] = req.make_path(tab[4])
169
new_app['desc'] = tab[2]
170
new_app['name'] = tab[1]
171
new_app['weight'] = tab[5]
172
ctx['apps_in_tabs'].append(new_app)
174
ctx['apps_in_tabs'].sort(key=lambda tab: tab['weight'])
123
176
def render_overlays(self, req):
124
177
"""Generate XML streams for the overlays.
135
194
#TODO: Re-factor this to look nicer
136
195
for mplugin in overlay.plugin_scripts:
137
196
for path in overlay.plugin_scripts[mplugin]:
138
req.scripts.append(media_url(req, mplugin, path))
197
scripts.append(media_url(req, mplugin, path))
140
199
for mplugin in overlay.plugin_styles:
141
200
for path in overlay.plugin_styles[mplugin]:
142
req.styles.append(media_url(req, mplugin, path))
201
styles.append(media_url(req, mplugin, path))
144
req.scripts_init += overlay.plugin_scripts_init
203
scripts_init += overlay.plugin_scripts_init
146
205
overlays.append(overlay.render(req))
206
return (overlays, styles, scripts, scripts_init)
150
209
def get_error_view(cls, e):
157
216
class XHTMLErrorView(XHTMLView):
158
217
template = 'xhtmlerror.html'
160
def __init__(self, req, exception):
161
self.context = exception
219
def __init__(self, req, context, lastobj):
220
super(XHTMLErrorView, self).__init__(req, context)
221
self.lastobj = lastobj
223
def get_context_ancestry(self, req):
224
return req.publisher.get_ancestors(self.lastobj)
163
226
def populate(self, req, ctx):
164
228
ctx['exception'] = self.context
166
230
class XHTMLUnauthorizedView(XHTMLErrorView):
167
231
template = 'xhtmlunauthorized.html'
169
def __init__(self, req, exception):
170
super(XHTMLUnauthorizedView, self).__init__(req, exception)
233
def __init__(self, req, exception, lastobj):
234
super(XHTMLUnauthorizedView, self).__init__(req, exception, lastobj)
236
if not req.publicmode and req.user is None:
172
237
# Not logged in. Redirect to login page.
173
req.throw_redirect('/') # XXX: Need proper URL.
241
query_string = '?url=' + urllib.quote(req.uri, safe="/~")
242
req.throw_redirect('/+login' + query_string)
246
class ViewBreadcrumb(object):
247
def __init__(self, req, context):
249
self.context = context
253
return self.context.breadcrumb_text