~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: 2009-07-30 08:11:33 UTC
  • mto: (1294.2.116 ui-the-third)
  • mto: This revision was merged to the branch mainline in revision 1353.
  • Revision ID: grantw@unimelb.edu.au-20090730081133-qpf554hidfzm7ogs
Router->Publisher

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE - Informatics Virtual Learning Environment
 
2
# Copyright (C) 2007-2009 The University of Melbourne
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 
 
18
# Author: Nick Chadwick
 
19
 
 
20
import inspect
 
21
import os.path
 
22
import urllib
 
23
 
 
24
import genshi.template
 
25
 
 
26
from ivle.webapp.media import media_url
 
27
from ivle.webapp.core import Plugin as CorePlugin
 
28
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
 
 
32
class XHTMLView(BaseView):
 
33
    """
 
34
    A view which provides a base class for views which need to return XHTML
 
35
    It is expected that apps which use this view will be written using Genshi
 
36
    templates.
 
37
    """
 
38
 
 
39
    template = 'template.html'
 
40
 
 
41
    plugin_scripts = {}
 
42
    plugin_styles = {}
 
43
    scripts_init = []
 
44
 
 
45
    allow_overlays = True
 
46
    overlay_blacklist = []
 
47
 
 
48
    def filter(self, stream, ctx):
 
49
        return stream
 
50
 
 
51
    def render(self, req):
 
52
        req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
 
53
 
 
54
        # View template
 
55
        viewctx = genshi.template.Context()
 
56
        self.populate(req, viewctx)
 
57
 
 
58
        # The template is found in the directory of the module containing the
 
59
        # view.
 
60
        app_template = os.path.join(os.path.dirname(
 
61
                        inspect.getmodule(self).__file__), self.template) 
 
62
        loader = genshi.template.TemplateLoader(".", auto_reload=True)
 
63
        tmpl = loader.load(app_template)
 
64
        app = self.filter(tmpl.generate(viewctx), viewctx)
 
65
 
 
66
        view_scripts = []
 
67
        for plugin in self.plugin_scripts:
 
68
            for path in self.plugin_scripts[plugin]:
 
69
                view_scripts.append(media_url(req, plugin, path))
 
70
 
 
71
        view_styles = []
 
72
        for plugin in self.plugin_styles:
 
73
            for path in self.plugin_styles[plugin]:
 
74
                view_styles.append(media_url(req, plugin, path))
 
75
 
 
76
        # Global template
 
77
        ctx = genshi.template.Context()
 
78
 
 
79
        overlay_bits = self.render_overlays(req) if req.user else [[]]*4
 
80
        ctx['overlays'] = overlay_bits[0]
 
81
 
 
82
        ctx['styles'] = [media_url(req, CorePlugin, 'ivle.css')]
 
83
        ctx['styles'] += view_styles
 
84
        ctx['styles'] += overlay_bits[1]
 
85
 
 
86
        ctx['scripts'] = [media_url(req, CorePlugin, path) for path in
 
87
                           ('util.js', 'json2.js', 'md5.js')]
 
88
        ctx['scripts'].append(media_url(req, '+external/jquery', 'jquery.js'))
 
89
        ctx['scripts'] += view_scripts
 
90
        ctx['scripts'] += overlay_bits[2]
 
91
 
 
92
        ctx['scripts_init'] = self.scripts_init + overlay_bits[3]
 
93
        ctx['app_template'] = app
 
94
        ctx['title_img'] = media_url(req, CorePlugin,
 
95
                                     "images/chrome/title.png")
 
96
        self.populate_headings(req, ctx)
 
97
        tmpl = loader.load(os.path.join(os.path.dirname(__file__), 
 
98
                                                        'ivle-headings.html'))
 
99
        req.write(tmpl.generate(ctx).render('xhtml', doctype='xhtml'))
 
100
        
 
101
    def populate(self, req, ctx):
 
102
        raise NotImplementedError()
 
103
 
 
104
    def populate_headings(self, req, ctx):
 
105
        ctx['favicon'] = None
 
106
        ctx['root_dir'] = req.config['urls']['root']
 
107
        ctx['public_host'] = req.config['urls']['public_host']
 
108
        ctx['svn_base'] = req.config['urls']['svn_addr']
 
109
        ctx['write_javascript_settings'] = req.write_javascript_settings
 
110
        if req.user:
 
111
            ctx['login'] = req.user.login
 
112
            ctx['logged_in'] = True
 
113
            ctx['nick'] = req.user.nick
 
114
        else:
 
115
            ctx['login'] = None
 
116
            ctx['logged_in'] = False
 
117
        ctx['publicmode'] = req.publicmode
 
118
        if hasattr(self, 'help'):
 
119
            ctx['help_path'] = self.help
 
120
 
 
121
        ctx['apps_in_tabs'] = []
 
122
        for plugin in req.config.plugin_index[ViewPlugin]:
 
123
            if not hasattr(plugin, 'tabs'):
 
124
                continue
 
125
 
 
126
            for tab in plugin.tabs:
 
127
                # tab is a tuple: name, title, desc, icon, path
 
128
                new_app = {}
 
129
                new_app['this_app'] = hasattr(self, 'tab') \
 
130
                                      and tab[0] == self.tab
 
131
 
 
132
                # Icon name
 
133
                if tab[3] is not None:
 
134
                    new_app['has_icon'] = True
 
135
                    icon_url = media_url(req, plugin, tab[3])
 
136
                    new_app['icon_url'] = icon_url
 
137
                    if new_app['this_app']:
 
138
                        ctx['favicon'] = icon_url
 
139
                else:
 
140
                    new_app['has_icon'] = False
 
141
                new_app['path'] = req.make_path(tab[4])
 
142
                new_app['desc'] = tab[2]
 
143
                new_app['name'] = tab[1]
 
144
                new_app['weight'] = tab[5]
 
145
                ctx['apps_in_tabs'].append(new_app)
 
146
 
 
147
        ctx['apps_in_tabs'].sort(key=lambda tab: tab['weight'])
 
148
 
 
149
    def render_overlays(self, req):
 
150
        """Generate XML streams for the overlays.
 
151
        
 
152
        Returns a list of streams. Populates the scripts, styles, and 
 
153
        scripts_init.
 
154
        """
 
155
        overlays = []
 
156
        styles = []
 
157
        scripts = []
 
158
        scripts_init = []
 
159
        if not self.allow_overlays:
 
160
            return (overlays, styles, scripts, scripts_init)
 
161
 
 
162
        for plugin in req.config.plugin_index[OverlayPlugin]:
 
163
            for overclass in plugin.overlays:
 
164
                if overclass in self.overlay_blacklist:
 
165
                    continue
 
166
                overlay = overclass(req)
 
167
                #TODO: Re-factor this to look nicer
 
168
                for mplugin in overlay.plugin_scripts:
 
169
                    for path in overlay.plugin_scripts[mplugin]:
 
170
                        scripts.append(media_url(req, mplugin, path))
 
171
 
 
172
                for mplugin in overlay.plugin_styles:
 
173
                    for path in overlay.plugin_styles[mplugin]:
 
174
                        styles.append(media_url(req, mplugin, path))
 
175
 
 
176
                scripts_init += overlay.plugin_scripts_init
 
177
 
 
178
                overlays.append(overlay.render(req))
 
179
        return (overlays, styles, scripts, scripts_init)
 
180
 
 
181
    @classmethod
 
182
    def get_error_view(cls, e):
 
183
        view_map = {HTTPError:    XHTMLErrorView,
 
184
                    Unauthorized: XHTMLUnauthorizedView}
 
185
        for exccls in inspect.getmro(type(e)):
 
186
            if exccls in view_map:
 
187
                return view_map[exccls]
 
188
 
 
189
class XHTMLErrorView(XHTMLView):
 
190
    template = 'xhtmlerror.html'
 
191
 
 
192
    def populate(self, req, ctx):
 
193
        ctx['req'] = req
 
194
        ctx['exception'] = self.context
 
195
 
 
196
class XHTMLUnauthorizedView(XHTMLErrorView):
 
197
    template = 'xhtmlunauthorized.html'
 
198
 
 
199
    def __init__(self, req, exception):
 
200
        super(XHTMLUnauthorizedView, self).__init__(req, exception)
 
201
 
 
202
        if req.user is None:
 
203
            # Not logged in. Redirect to login page.
 
204
            if req.uri == '/':
 
205
                query_string = ''
 
206
            else:
 
207
                query_string = '?url=' + urllib.quote(req.uri, safe="/~")
 
208
            req.throw_redirect('/+login' + query_string)
 
209
 
 
210
        req.status = 403