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
145
if hasattr(self, 'help'):
146
ctx['help_path'] = self.help
101
148
ctx['apps_in_tabs'] = []
102
for urlname in ivle.conf.apps.apps_in_tabs:
104
app = ivle.conf.apps.app_url[urlname]
105
new_app['this_app'] = hasattr(self, 'appname') \
106
and urlname == self.appname
108
new_app['has_icon'] = True
109
icon_dir = ivle.conf.apps.app_icon_dir
110
icon_url = ivle.util.make_path(os.path.join(icon_dir, app.icon))
111
new_app['icon_url'] = icon_url
112
if new_app['this_app']:
113
ctx['favicon'] = icon_url
115
new_app['has_icon'] = False
116
new_app['path'] = ivle.util.make_path(urlname)
117
new_app['desc'] = app.desc
118
new_app['name'] = app.name
119
ctx['apps_in_tabs'].append(new_app)
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'])
121
176
def render_overlays(self, req):
122
177
"""Generate XML streams for the overlays.
133
194
#TODO: Re-factor this to look nicer
134
195
for mplugin in overlay.plugin_scripts:
135
196
for path in overlay.plugin_scripts[mplugin]:
136
req.scripts.append(media_url(req, mplugin, path))
197
scripts.append(media_url(req, mplugin, path))
138
199
for mplugin in overlay.plugin_styles:
139
200
for path in overlay.plugin_styles[mplugin]:
140
req.styles.append(media_url(req, mplugin, path))
201
styles.append(media_url(req, mplugin, path))
142
req.scripts_init += overlay.plugin_scripts_init
203
scripts_init += overlay.plugin_scripts_init
144
205
overlays.append(overlay.render(req))
206
return (overlays, styles, scripts, scripts_init)
148
209
def get_error_view(cls, e):
155
216
class XHTMLErrorView(XHTMLView):
156
217
template = 'xhtmlerror.html'
158
def __init__(self, req, exception):
159
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)
161
226
def populate(self, req, ctx):
162
228
ctx['exception'] = self.context
164
230
class XHTMLUnauthorizedView(XHTMLErrorView):
165
231
template = 'xhtmlunauthorized.html'
167
def __init__(self, req, exception):
168
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:
170
237
# Not logged in. Redirect to login page.
171
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