~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/base/xhtml.py

  • Committer: William Grant
  • Date: 2010-02-15 05:37:50 UTC
  • Revision ID: grantw@unimelb.edu.au-20100215053750-hihmegnp8e7dshc2
Ignore test coverage files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
import inspect
21
21
import os.path
 
22
import urllib
22
23
 
23
24
import genshi.template
24
25
 
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
29
 
import ivle.conf
30
 
import ivle.util
 
31
from ivle.webapp.publisher import NoPath
 
32
from ivle.webapp.breadcrumbs import Breadcrumber
31
33
 
32
34
class XHTMLView(BaseView):
33
35
    """
37
39
    """
38
40
 
39
41
    template = 'template.html'
40
 
    plugin_scripts = {}
41
 
    plugin_styles = {}
42
 
    overlay_blacklist = []
43
 
 
44
 
    def __init__(self, req, **kwargs):
45
 
        for key in kwargs:
46
 
            setattr(self, key, kwargs[key])
 
42
    allow_overlays = True
 
43
    breadcrumb_text = None
 
44
 
 
45
    def __init__(self, *args, **kwargs):
 
46
        super(XHTMLView, self).__init__(*args, **kwargs)
 
47
 
 
48
        self.overlay_blacklist = []
 
49
 
 
50
        self.plugin_scripts = {}
 
51
        self.plugin_styles = {}
 
52
        self.scripts_init = []
 
53
 
 
54
        self.extra_breadcrumbs = []
 
55
        self.overlay_blacklist = []
 
56
 
 
57
    def get_context_ancestry(self, req):
 
58
        return req.publisher.get_ancestors(self.context)
 
59
 
 
60
    def filter(self, stream, ctx):
 
61
        return stream
47
62
 
48
63
    def render(self, req):
49
64
        req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
56
71
        # view.
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)
63
77
 
 
78
        view_scripts = []
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))
67
82
 
 
83
        view_styles = []
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))
71
87
 
72
88
        # Global template
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
 
90
 
 
91
        overlay_bits = self.render_overlays(req) if req.user else [[]]*4
 
92
        ctx['overlays'] = overlay_bits[0]
 
93
 
 
94
        ctx['styles'] = [media_url(req, CorePlugin, 'ivle.css')]
 
95
        ctx['styles'] += view_styles
 
96
        ctx['styles'] += overlay_bits[1]
 
97
 
 
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]
 
103
 
 
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")
 
108
        try:
 
109
            ancestry = self.get_context_ancestry(req)
 
110
        except NoPath:
 
111
            ancestry = []
 
112
 
 
113
        crumber = Breadcrumber(req)
 
114
 
 
115
        ctx['breadcrumbs'] = []
 
116
        for ancestor in ancestry:
 
117
            crumb = crumber.crumb(ancestor)
 
118
            if crumb is None:
 
119
                continue
 
120
 
 
121
            if hasattr(crumb, 'extra_breadcrumbs_before'):
 
122
                ctx['breadcrumbs'].extend(crumb.extra_breadcrumbs_before)
 
123
            ctx['breadcrumbs'].append(crumb)
 
124
            if hasattr(crumb, 'extra_breadcrumbs_after'):
 
125
                ctx['breadcrumbs'].extend(crumb.extra_breadcrumbs_after)
 
126
 
 
127
        # If the view has specified text for a breadcrumb, add one.
 
128
        if self.breadcrumb_text:
 
129
            ctx['breadcrumbs'].append(ViewBreadcrumb(req, self))
 
130
 
 
131
        # Allow the view to add its own fake breadcrumbs.
 
132
        ctx['breadcrumbs'].extend(self.extra_breadcrumbs)
 
133
 
80
134
        self.populate_headings(req, ctx)
81
135
        tmpl = loader.load(os.path.join(os.path.dirname(__file__), 
82
136
                                                        'ivle-headings.html'))
87
141
 
88
142
    def populate_headings(self, req, ctx):
89
143
        ctx['favicon'] = None
90
 
        ctx['root_dir'] = ivle.conf.root_dir
91
 
        ctx['public_host'] = ivle.conf.public_host
 
144
        ctx['root_dir'] = req.config['urls']['root']
 
145
        ctx['public_host'] = req.config['urls']['public_host']
 
146
        ctx['svn_base'] = req.config['urls']['svn_addr']
92
147
        ctx['write_javascript_settings'] = req.write_javascript_settings
93
148
        if req.user:
94
149
            ctx['login'] = req.user.login
98
153
            ctx['login'] = None
99
154
            ctx['logged_in'] = False
100
155
        ctx['publicmode'] = req.publicmode
 
156
        if hasattr(self, 'help'):
 
157
            ctx['help_path'] = self.help
 
158
 
101
159
        ctx['apps_in_tabs'] = []
102
 
        for urlname in ivle.conf.apps.apps_in_tabs:
103
 
            new_app = {}
104
 
            app = ivle.conf.apps.app_url[urlname]
105
 
            new_app['this_app'] = hasattr(self, 'appname') \
106
 
                                  and urlname == self.appname
107
 
            if app.icon:
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
114
 
            else:
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)
120
 
            
 
160
        for plugin in req.config.plugin_index[ViewPlugin]:
 
161
            if not hasattr(plugin, 'tabs'):
 
162
                continue
 
163
 
 
164
            for tab in plugin.tabs:
 
165
                # tab is a tuple: name, title, desc, icon, path, weight, admin
 
166
                # (Admin is optional, defaults to false)
 
167
                new_app = {}
 
168
                new_app['this_app'] = hasattr(self, 'tab') \
 
169
                                      and tab[0] == self.tab
 
170
 
 
171
                # Icon name
 
172
                if tab[3] is not None:
 
173
                    new_app['has_icon'] = True
 
174
                    icon_url = media_url(req, plugin, tab[3])
 
175
                    new_app['icon_url'] = icon_url
 
176
                    if new_app['this_app']:
 
177
                        ctx['favicon'] = icon_url
 
178
                else:
 
179
                    new_app['has_icon'] = False
 
180
                # The following check is here, so it is AFTER setting the
 
181
                # icon, but BEFORE actually installing the tab in the menu
 
182
                if len(tab) > 6 and tab[6]:
 
183
                    # Admin-only tab
 
184
                    if not (req.user and req.user.admin):
 
185
                        break
 
186
                new_app['path'] = req.make_path(tab[4])
 
187
                new_app['desc'] = tab[2]
 
188
                new_app['name'] = tab[1]
 
189
                new_app['weight'] = tab[5]
 
190
                ctx['apps_in_tabs'].append(new_app)
 
191
 
 
192
        ctx['apps_in_tabs'].sort(key=lambda tab: tab['weight'])
 
193
 
121
194
    def render_overlays(self, req):
122
195
        """Generate XML streams for the overlays.
123
196
        
125
198
        scripts_init.
126
199
        """
127
200
        overlays = []
128
 
        for plugin in req.plugin_index[OverlayPlugin]:
 
201
        styles = []
 
202
        scripts = []
 
203
        scripts_init = []
 
204
        if not self.allow_overlays:
 
205
            return (overlays, styles, scripts, scripts_init)
 
206
 
 
207
        for plugin in req.config.plugin_index[OverlayPlugin]:
129
208
            for overclass in plugin.overlays:
130
209
                if overclass in self.overlay_blacklist:
131
210
                    continue
133
212
                #TODO: Re-factor this to look nicer
134
213
                for mplugin in overlay.plugin_scripts:
135
214
                    for path in overlay.plugin_scripts[mplugin]:
136
 
                        req.scripts.append(media_url(req, mplugin, path))
 
215
                        scripts.append(media_url(req, mplugin, path))
137
216
 
138
217
                for mplugin in overlay.plugin_styles:
139
218
                    for path in overlay.plugin_styles[mplugin]:
140
 
                        req.styles.append(media_url(req, mplugin, path))
 
219
                        styles.append(media_url(req, mplugin, path))
141
220
 
142
 
                req.scripts_init += overlay.plugin_scripts_init
 
221
                scripts_init += overlay.plugin_scripts_init
143
222
 
144
223
                overlays.append(overlay.render(req))
145
 
        return overlays
 
224
        return (overlays, styles, scripts, scripts_init)
146
225
 
147
226
    @classmethod
148
227
    def get_error_view(cls, e):
155
234
class XHTMLErrorView(XHTMLView):
156
235
    template = 'xhtmlerror.html'
157
236
 
158
 
    def __init__(self, req, exception):
159
 
        self.context = exception
 
237
    def __init__(self, req, context, lastobj):
 
238
        super(XHTMLErrorView, self).__init__(req, context)
 
239
        self.lastobj = lastobj
 
240
 
 
241
    def get_context_ancestry(self, req):
 
242
        return req.publisher.get_ancestors(self.lastobj)
160
243
 
161
244
    def populate(self, req, ctx):
 
245
        ctx['req'] = req
162
246
        ctx['exception'] = self.context
163
247
 
164
248
class XHTMLUnauthorizedView(XHTMLErrorView):
165
249
    template = 'xhtmlunauthorized.html'
166
250
 
167
 
    def __init__(self, req, exception):
168
 
        super(XHTMLUnauthorizedView, self).__init__(req, exception)
169
 
        if req.user is None:
 
251
    def __init__(self, req, exception, lastobj):
 
252
        super(XHTMLUnauthorizedView, self).__init__(req, exception, lastobj)
 
253
 
 
254
        if not req.publicmode and req.user is None:
170
255
            # Not logged in. Redirect to login page.
171
 
            req.throw_redirect('/') # XXX: Need proper URL.
 
256
            if req.uri == '/':
 
257
                query_string = ''
 
258
            else:
 
259
                query_string = '?url=' + urllib.quote(req.uri, safe="/~")
 
260
            req.throw_redirect('/+login' + query_string)
172
261
 
173
262
        req.status = 403
 
263
 
 
264
class ViewBreadcrumb(object):
 
265
    def __init__(self, req, context):
 
266
        self.req = req
 
267
        self.context = context
 
268
 
 
269
    @property
 
270
    def text(self):
 
271
        return self.context.breadcrumb_text