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
RevLine 
[7195]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##
[4584]18"""Basic layout components.
19"""
[6030]20import os
[4584]21import grok
[7254]22from datetime import date, datetime
[6030]23import grokcore.view
[7328]24from cgi import escape
25from zope.i18nmessageid import Message
[5998]26from hurry.resource import mode
[7274]27from megrok.layout import Page, Layout, Form, EditForm, DisplayForm, AddForm
[5048]28from z3c.flashmessage.interfaces import IMessageSource, IMessageReceiver
29from zope.component import getUtility, queryUtility, ComponentLookupError
[6193]30from zope.formlib.utility import setUpWidgets
[7328]31from grokcore.formlib.formlib import Action
[4584]32from zope.interface import Interface
[6193]33from zope.site.hooks import getSite
[7321]34from waeup.sirp.interfaces import ISIRPObject, IUserAccount
[5961]35from waeup.sirp.browser.interfaces import ITheme
[7442]36from waeup.sirp.browser.theming import get_all_themes, SIRPThemeBase
[6642]37from waeup.sirp.students.interfaces import IStudentNavigation
[7240]38from waeup.sirp.applicants.interfaces import IApplicant
[6687]39from waeup.sirp.authentication import get_principal_role_manager
[4584]40
41grok.templatedir('templates')
[6030]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'
[4649]45
[6030]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
[7243]50default_primary_nav_template = grokcore.view.PageTemplateFile(
51    os.path.join('templates', 'primarynavtab.pt'))
52default_primary_nav_template.__grok_name__ = 'default_primary_nav'
[6030]53
[7445]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
[7328]79class jsaction(grok.action):
[7243]80
[7328]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"'
[7442]97                ' class="btn" onclick="return confirmPost(%s)" />' %
[7328]98                (self.__name__, self.__name__, escape(label, quote=True), self.msg)
99                )
100
[4756]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
[5048]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
[4584]126class UtilityView(object):
127    """A view mixin with useful methods.
128
[4649]129    The ``pnav`` attribute (a number) tells, to which primary
130    navigation tab a page declares to belong.
[4584]131    """
[4592]132    title = u'' # What appears in the content title...
[4649]133    pnav = 0 # Primary navigation index...
[6193]134
[4584]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
[7442]143    def flash(self, message, type='alert-message warning'):
[4584]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
[7442]152class SIRPLayout(UtilityView,Layout):
[4584]153    """A megrok.layout.Layout with additional methods.
154    """
155    grok.baseclass()
[6193]156
[7442]157class SIRPForm(UtilityView,Form):
[7274]158    """A megrok.layout.Form with additional methods.
159    """
160    grok.baseclass()
161
162    def setUpWidgets(self,ignore_request=False):
[7321]163        super(SIRPForm,self).setUpWidgets(ignore_request)
[7274]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
[7442]171class SIRPPage(UtilityView,Page):
[4584]172    """A megrok.layout page with additional methods.
173    """
174    grok.baseclass()
175
[7442]176class SIRPDisplayFormPage(UtilityView,DisplayForm):
[4584]177    """A megrok.layout.DisplayForm with additional methods.
178    """
179    grok.baseclass()
[6030]180    template = default_waeup_display_template
[4584]181
[7442]182class SIRPEditFormPage(UtilityView,EditForm):
[4584]183    """A megrok.layout.EditForm with additional methods.
184    """
185    grok.baseclass()
[6030]186    template = default_waeup_edit_template
[6193]187
[6025]188    def setUpWidgets(self,ignore_request=False):
[7321]189        super(SIRPEditFormPage,self).setUpWidgets(ignore_request)
[6025]190        if self.widgets.get('title'):
191            self.widgets['title'].displayWidth = 80
[6132]192        if self.widgets.get('frontpage'):
193            self.widgets['frontpage'].width = 70
[6342]194        if self.widgets.get('phone'):
195            self.widgets['phone'].displayWidth = 13
196        if self.widgets.get('notice'):
197            self.widgets['notice'].height = 3
[4584]198
[7442]199class SIRPAddFormPage(UtilityView,AddForm):
[4584]200    """A megrok.layout.AddForm with additional methods.
201    """
202    grok.baseclass()
[6967]203    template = default_waeup_edit_template
[4584]204
[7321]205class SiteLayout(SIRPLayout):
[4584]206    """ The general site layout.
207    """
[7321]208    grok.context(ISIRPObject)
[4584]209
[5966]210    #: An instance of the default theme to use for the site layout
[7442]211    default_theme = SIRPThemeBase()
[6690]212    stafftemp = grok.PageTemplateFile('templates/staffsitelayout.pt')
213    studenttemp = grok.PageTemplateFile('templates/studentsitelayout.pt')
[5966]214
[4987]215    @property
216    def site(self):
217        return grok.getSite()
[6193]218
[4780]219    def getAppTitle(self):
[6907]220        return getattr(grok.getSite()['configuration'], 'name', u'Sample University')
[6193]221
[4614]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'
[6193]227
[4592]228    def getUserTitle(self):
[4649]229        """Return principal title of current user.
230        """
[4592]231        usertitle = self.request.principal.title
232        if usertitle == 'Unauthenticated User':
[5387]233            return u'Anonymous User'
[4592]234        return usertitle
[4649]235
[5433]236    def getUserId(self):
237        """Return id of current user.
238        """
239        userid = self.request.principal.id
240        return userid
241
[7240]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
[6642]254    def getStudentName(self):
255        """Return the student name.
256        """
257        if IStudentNavigation.providedBy(self.context):
[7364]258            return self.context.getStudent().display_fullname
[6642]259        return
260
[7240]261    def getApplicantName(self):
262        """Return the applicant name.
263        """
264        if IApplicant.providedBy(self.context):
265            return self.context.fullname
266        return
[6687]267
[7254]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
[4584]274    def update(self):
[5966]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        """
[5998]288        mode('minified')
[6907]289        theme_name = getattr(grok.getSite()['configuration'], 'skin', '')
[5966]290        theme = queryUtility(ITheme, name=theme_name,
291                             default=self.default_theme)
[5961]292        for resource in theme.getResources():
293            resource.need()
294        return
[6193]295
[6690]296    def render(self):
[7240]297        if self.isStudent() or self.isApplicant() or not self.isAuthenticated():
[6690]298            return self.studenttemp.render(self)
299        return self.stafftemp.render(self)
Note: See TracBrowser for help on using the repository browser.