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

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

Let's define our own action decorator class which allows setting button styles.

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