24
24
import genshi.template
26
26
from ivle.webapp.media import media_url
27
from ivle.webapp.core import Plugin as CorePlugin
28
27
from ivle.webapp.base.views import BaseView
29
28
from ivle.webapp.base.plugins import ViewPlugin, OverlayPlugin
30
29
from ivle.webapp.errors import HTTPError, Unauthorized
31
from ivle.webapp.publisher import NoPath
32
from ivle.webapp.breadcrumbs import Breadcrumber
34
33
class XHTMLView(BaseView):
41
40
template = 'template.html'
42
43
allow_overlays = True
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):
44
overlay_blacklist = []
46
def __init__(self, req, **kwargs):
48
setattr(self, key, kwargs[key])
63
50
def render(self, req):
64
51
req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
72
59
app_template = os.path.join(os.path.dirname(
73
60
inspect.getmodule(self).__file__), self.template)
61
req.write_html_head_foot = False
74
62
loader = genshi.template.TemplateLoader(".", auto_reload=True)
75
63
tmpl = loader.load(app_template)
76
app = self.filter(tmpl.generate(viewctx), viewctx)
64
app = tmpl.generate(viewctx)
79
66
for plugin in self.plugin_scripts:
80
67
for path in self.plugin_scripts[plugin]:
81
view_scripts.append(media_url(req, plugin, path))
68
req.scripts.append(media_url(req, plugin, path))
84
70
for plugin in self.plugin_styles:
85
71
for path in self.plugin_styles[plugin]:
86
view_styles.append(media_url(req, plugin, path))
72
req.styles.append(media_url(req, plugin, path))
89
75
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]
76
# XXX: Leave this here!! (Before req.styles is read)
77
ctx['overlays'] = self.render_overlays(req)
78
ctx['app_styles'] = req.styles
79
ctx['scripts'] = req.scripts
80
ctx['scripts_init'] = req.scripts_init
105
81
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
123
82
self.populate_headings(req, ctx)
124
83
tmpl = loader.load(os.path.join(os.path.dirname(__file__),
125
84
'ivle-headings.html'))
131
90
def populate_headings(self, req, ctx):
132
91
ctx['favicon'] = None
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
ctx['root_dir'] = ivle.conf.root_dir
93
ctx['public_host'] = ivle.conf.public_host
136
94
ctx['write_javascript_settings'] = req.write_javascript_settings
138
96
ctx['login'] = req.user.login
146
104
ctx['help_path'] = self.help
148
106
ctx['apps_in_tabs'] = []
149
for plugin in req.config.plugin_index[ViewPlugin]:
107
for plugin in req.plugin_index[ViewPlugin]:
150
108
if not hasattr(plugin, 'tabs'):
153
111
for tab in plugin.tabs:
154
112
# tab is a tuple: name, title, desc, icon, path
156
new_app['this_app'] = hasattr(self, 'tab') \
157
and tab[0] == self.tab
114
new_app['this_app'] = hasattr(self, 'appname') \
115
and tab[0] == self.appname
160
118
if tab[3] is not None:
194
149
#TODO: Re-factor this to look nicer
195
150
for mplugin in overlay.plugin_scripts:
196
151
for path in overlay.plugin_scripts[mplugin]:
197
scripts.append(media_url(req, mplugin, path))
152
req.scripts.append(media_url(req, mplugin, path))
199
154
for mplugin in overlay.plugin_styles:
200
155
for path in overlay.plugin_styles[mplugin]:
201
styles.append(media_url(req, mplugin, path))
156
req.styles.append(media_url(req, mplugin, path))
203
scripts_init += overlay.plugin_scripts_init
158
req.scripts_init += overlay.plugin_scripts_init
205
160
overlays.append(overlay.render(req))
206
return (overlays, styles, scripts, scripts_init)
209
164
def get_error_view(cls, e):
216
171
class XHTMLErrorView(XHTMLView):
217
172
template = 'xhtmlerror.html'
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)
174
def __init__(self, req, exception):
175
self.context = exception
226
177
def populate(self, req, ctx):
228
178
ctx['exception'] = self.context
230
180
class XHTMLUnauthorizedView(XHTMLErrorView):
231
181
template = 'xhtmlunauthorized.html'
233
def __init__(self, req, exception, lastobj):
234
super(XHTMLUnauthorizedView, self).__init__(req, exception, lastobj)
183
def __init__(self, req, exception):
184
super(XHTMLUnauthorizedView, self).__init__(req, exception)
236
if not req.publicmode and req.user is None:
237
187
# Not logged in. Redirect to login page.
241
query_string = '?url=' + urllib.quote(req.uri, safe="/~")
242
req.throw_redirect('/+login' + query_string)
188
req.throw_redirect('/+login?' +
189
urllib.urlencode([('url', req.uri)]))
246
class ViewBreadcrumb(object):
247
def __init__(self, req, context):
249
self.context = context
253
return self.context.breadcrumb_text