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

« back to all changes in this revision

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

  • Committer: matt.giuca
  • Date: 2009-01-19 10:34:45 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:1169
Changed svn:ignore on trunk - no longer need to ignore bin or svn directories
    (bin is in repo, svn is gone).
Added .bzrignore, for Bazaar branches of this repository.

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