source: main/waeup.sirp/branches/henrik-bootstrap/src/waeup/sirp/browser/layout.py @ 7450

Last change on this file since 7450 was 7450, checked in by Henrik Bettermann, 13 years ago

Backup today's work (mainly student navigation).

  • Property svn:keywords set to Id
File size: 10.5 KB
Line 
1## $Id: layout.py 7450 2012-01-11 22:51:42Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""Basic layout components.
19"""
20import os
21import grok
22from datetime import date, datetime
23import grokcore.view
24from cgi import escape
25from zope.i18nmessageid import Message
26from hurry.resource import mode
27from megrok.layout import Page, Layout, Form, EditForm, DisplayForm, AddForm
28from z3c.flashmessage.interfaces import IMessageSource, IMessageReceiver
29from zope.component import getUtility, queryUtility, ComponentLookupError
30from zope.formlib.utility import setUpWidgets
31from grokcore.formlib.formlib import Action
32from zope.interface import Interface
33from zope.site.hooks import getSite
34from waeup.sirp.interfaces import ISIRPObject, IUserAccount
35from waeup.sirp.browser.interfaces import ITheme
36from waeup.sirp.browser.theming import get_all_themes, SIRPThemeBase
37from waeup.sirp.students.interfaces import IStudentNavigation
38from waeup.sirp.applicants.interfaces import IApplicant
39from waeup.sirp.authentication import get_principal_role_manager
40
41grok.templatedir('templates')
42default_waeup_display_template = grokcore.view.PageTemplateFile(
43    os.path.join('templates', 'default_waeup_display_form.pt'))
44default_waeup_display_template.__grok_name__ = 'default_waeup_display_form'
45
46default_waeup_edit_template = grokcore.view.PageTemplateFile(
47    os.path.join('templates', 'default_waeup_edit_form.pt'))
48default_waeup_edit_template.__grok_name__ = 'default_waeup_edit_form'
49
50default_primary_nav_template = grokcore.view.PageTemplateFile(
51    os.path.join('templates', 'primarynavtab.pt'))
52default_primary_nav_template.__grok_name__ = 'default_primary_nav'
53
54class action(grok.action):
55
56    def __call__(self, success):
57        action = SIRPAction(self.label, success=success, **self.options)
58        self.actions.append(action)
59        return action
60
61class SIRPAction(Action):
62
63    def __init__(self, label, style='', **options):
64        super(SIRPAction, self).__init__(label, **options)
65        self.style = style
66
67    def render(self):
68        if not self.available():
69            return ''
70        label = self.label
71        if isinstance(label, Message):
72            label = zope.i18n.translate(self.label, context=self.form.request)
73        return ('<input type="submit" id="%s" name="%s" value="%s"'
74                ' class="btn %s"/>' %
75                (self.__name__, self.__name__, escape(label, quote=True),
76                self.style))
77
78class jsaction(grok.action):
79
80    def __call__(self, success):
81        action = JSAction(self.label, success=success, **self.options)
82        self.actions.append(action)
83        return action
84
85class JSAction(Action):
86
87    msg = '\'Are you sure?\''
88
89    def render(self):
90        if not self.available():
91            return ''
92        label = self.label
93        if isinstance(label, Message):
94            label = zope.i18n.translate(self.label, context=self.form.request)
95        return ('<input type="submit" id="%s" name="%s" value="%s"'
96                ' class="btn" onclick="return confirmPost(%s)" />' %
97                (self.__name__, self.__name__, escape(label, quote=True), self.msg)
98                )
99
100def NullValidator(*args, **kw):
101    """A validator that does not validate.
102
103    This is needed especially for cancel buttons. We don't want data
104    to be validated that will be thrown away in the next step.
105
106    You can use it with ``grok.action`` decorator like this::
107
108      @grok.action('Cancel', validator=NullValidator)
109      def cancel(self, **data):
110        self.redirect(<whereever-you-go>)
111    """
112    return dict()
113
114class Messages(grok.View):
115    """Display messages of message receivers.
116    """
117
118    grok.context(Interface)
119
120    @property
121    def messages(self):
122        receiver = getUtility(IMessageReceiver)
123        return receiver.receive()
124
125class UtilityView(object):
126    """A view mixin with useful methods.
127
128    The ``pnav`` attribute (a number) tells, to which primary
129    navigation tab a page declares to belong.
130    """
131    title = u'' # What appears in the content title...
132    pnav = 0 # Primary navigation index...
133
134    def application_url(self, name=None):
135        """Return the URL of the nearest site.
136        """
137        site = getSite()
138        #if not site:
139        #    raise ComponentLookupError("No site found.")
140        return self.url(site, name)
141
142    def flash(self, message, type='alert-message warning'):
143        """Send a short message to the user.
144        """
145        source = queryUtility(IMessageSource, name='session')
146        if source is None:
147            return None
148        source.send(message, type)
149        return True
150
151class SIRPLayout(UtilityView,Layout):
152    """A megrok.layout.Layout with additional methods.
153    """
154    grok.baseclass()
155
156class SIRPForm(UtilityView,Form):
157    """A megrok.layout.Form with additional methods.
158    """
159    grok.baseclass()
160
161    def setUpWidgets(self,ignore_request=False):
162        super(SIRPForm,self).setUpWidgets(ignore_request)
163        # Width parameters will be overridden by Bootstrap
164        # so we have to set the css class
165        if self.widgets.get('subject'):
166            self.widgets['subject'].cssClass = 'span9'
167        if self.widgets.get('body'):
168            self.widgets['body'].height = 10
169        if self.widgets.get('body'):
170            self.widgets['body'].cssClass = 'span9'
171
172class SIRPPage(UtilityView,Page):
173    """A megrok.layout page with additional methods.
174    """
175    grok.baseclass()
176
177class SIRPDisplayFormPage(UtilityView,DisplayForm):
178    """A megrok.layout.DisplayForm with additional methods.
179    """
180    grok.baseclass()
181    template = default_waeup_display_template
182
183class SIRPEditFormPage(UtilityView,EditForm):
184    """A megrok.layout.EditForm with additional methods.
185    """
186    grok.baseclass()
187    template = default_waeup_edit_template
188
189    def setUpWidgets(self,ignore_request=False):
190        super(SIRPEditFormPage,self).setUpWidgets(ignore_request)
191        for widget in self.widgets:
192            if widget.__class__.__name__ == 'TextWidget':
193                widget.cssClass = 'span8'
194            elif widget.__class__.__name__ == 'IntWidget':
195                widget.cssClass = 'span2'
196        #import pdb; pdb.set_trace()
197        if self.widgets.get('title'):
198            self.widgets['title'].cssClass = 'span12'
199        if self.widgets.get('frontpage'):
200            self.widgets['frontpage'].cssClass = 'span12'
201        if self.widgets.get('phone'):
202            self.widgets['phone'].cssClass = 'span4'
203        if self.widgets.get('notice'):
204            self.widgets['notice'].height = 3
205        if self.widgets.get('perm_address'):
206            self.widgets['perm_address'].cssClass = 'span8'
207            self.widgets['perm_address'].height = 10
208
209class SIRPAddFormPage(UtilityView,AddForm):
210    """A megrok.layout.AddForm with additional methods.
211    """
212    grok.baseclass()
213    template = default_waeup_edit_template
214
215class SiteLayout(SIRPLayout):
216    """ The general site layout.
217    """
218    grok.context(ISIRPObject)
219
220    #: An instance of the default theme to use for the site layout
221    default_theme = SIRPThemeBase()
222    stafftemp = grok.PageTemplateFile('templates/staffsitelayout.pt')
223    studenttemp = grok.PageTemplateFile('templates/studentsitelayout.pt')
224
225    @property
226    def site(self):
227        return grok.getSite()
228
229    def getAppTitle(self):
230        return getattr(grok.getSite()['configuration'], 'name', u'Sample University')
231
232    def isAuthenticated(self):
233        """Return True if the calling user is authenticated.
234        """
235        usertitle = self.request.principal.title
236        return usertitle != 'Unauthenticated User'
237
238    def getUserTitle(self):
239        """Return principal title of current user.
240        """
241        usertitle = self.request.principal.title
242        if usertitle == 'Unauthenticated User':
243            return u'Anonymous User'
244        return usertitle
245
246    def getUserId(self):
247        """Return id of current user.
248        """
249        userid = self.request.principal.id
250        return userid
251
252    def isStudent(self):
253        usertype = getattr(self.request.principal, 'user_type', None)
254        if not usertype:
255            return False
256        return self.request.principal.user_type == 'student'
257
258    def isApplicant(self):
259        usertype = getattr(self.request.principal, 'user_type', None)
260        if not usertype:
261            return False
262        return self.request.principal.user_type == 'applicant'
263
264    def getStudentName(self):
265        """Return the student name.
266        """
267        if IStudentNavigation.providedBy(self.context):
268            return self.context.getStudent().display_fullname
269        return
270
271    def getApplicantName(self):
272        """Return the applicant name.
273        """
274        if IApplicant.providedBy(self.context):
275            return self.context.fullname
276        return
277
278    def formatDatetime(self,datetimeobj):
279        if isinstance(datetimeobj, datetime):
280            return datetimeobj.strftime("%Y-%m-%d %H:%M:%S")
281        else:
282            return None
283
284    def update(self):
285        """Include the resources required by the chosen skin/theme.
286
287        University instances provide a 'skin' attribute, that should
288        hold the internal name of a theme.
289
290        A theme in the waeup.sirp sense consists of a list of
291        CSS/JavaScript resources defined in the
292        :mod:`waeup.sirp.browser.resources` module.
293
294        If the context University object has no such attribute or the
295        set value is not a valid theme name, we pick 'gray waeup
296        theme' as default.
297        """
298        mode('minified')
299        theme_name = getattr(grok.getSite()['configuration'], 'skin', '')
300        theme = queryUtility(ITheme, name=theme_name,
301                             default=self.default_theme)
302        for resource in theme.getResources():
303            resource.need()
304        return
305
306    def render(self):
307        if self.isStudent() or self.isApplicant() or not self.isAuthenticated():
308            return self.studenttemp.render(self)
309        return self.stafftemp.render(self)
Note: See TracBrowser for help on using the repository browser.