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

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

Final backup for today

  • Property svn:keywords set to Id
File size: 10.5 KB
Line 
1## $Id: layout.py 7448 2012-01-10 22:21: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
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        # Width parameters will be overridden by Bootstrap
165        # so we have to set the css class
166        if self.widgets.get('subject'):
167            self.widgets['subject'].cssClass = 'span9'
168        if self.widgets.get('body'):
169            self.widgets['body'].height = 10
170        if self.widgets.get('body'):
171            self.widgets['body'].cssClass = 'span9'
172
173class SIRPPage(UtilityView,Page):
174    """A megrok.layout page with additional methods.
175    """
176    grok.baseclass()
177
178class SIRPDisplayFormPage(UtilityView,DisplayForm):
179    """A megrok.layout.DisplayForm with additional methods.
180    """
181    grok.baseclass()
182    template = default_waeup_display_template
183
184class SIRPEditFormPage(UtilityView,EditForm):
185    """A megrok.layout.EditForm with additional methods.
186    """
187    grok.baseclass()
188    template = default_waeup_edit_template
189
190    def setUpWidgets(self,ignore_request=False):
191        super(SIRPEditFormPage,self).setUpWidgets(ignore_request)
192        for widget in self.widgets:
193            if widget.__class__.__name__ == 'TextWidget':
194                widget.cssClass = 'span8'
195            elif widget.__class__.__name__ == 'IntWidget':
196                widget.cssClass = 'span2'
197        #import pdb; pdb.set_trace()
198        if self.widgets.get('title'):
199            self.widgets['title'].cssClass = 'span12'
200        if self.widgets.get('frontpage'):
201            self.widgets['frontpage'].cssClass = 'span12'
202        if self.widgets.get('phone'):
203            self.widgets['phone'].cssClass = 'span4'
204        if self.widgets.get('notice'):
205            self.widgets['notice'].height = 3
206        if self.widgets.get('perm_address'):
207            self.widgets['perm_address'].cssClass = 'span8'
208            self.widgets['perm_address'].height = 10
209
210class SIRPAddFormPage(UtilityView,AddForm):
211    """A megrok.layout.AddForm with additional methods.
212    """
213    grok.baseclass()
214    template = default_waeup_edit_template
215
216class SiteLayout(SIRPLayout):
217    """ The general site layout.
218    """
219    grok.context(ISIRPObject)
220
221    #: An instance of the default theme to use for the site layout
222    default_theme = SIRPThemeBase()
223    stafftemp = grok.PageTemplateFile('templates/staffsitelayout.pt')
224    studenttemp = grok.PageTemplateFile('templates/studentsitelayout.pt')
225
226    @property
227    def site(self):
228        return grok.getSite()
229
230    def getAppTitle(self):
231        return getattr(grok.getSite()['configuration'], 'name', u'Sample University')
232
233    def isAuthenticated(self):
234        """Return True if the calling user is authenticated.
235        """
236        usertitle = self.request.principal.title
237        return usertitle != 'Unauthenticated User'
238
239    def getUserTitle(self):
240        """Return principal title of current user.
241        """
242        usertitle = self.request.principal.title
243        if usertitle == 'Unauthenticated User':
244            return u'Anonymous User'
245        return usertitle
246
247    def getUserId(self):
248        """Return id of current user.
249        """
250        userid = self.request.principal.id
251        return userid
252
253    def isStudent(self):
254        usertype = getattr(self.request.principal, 'user_type', None)
255        if not usertype:
256            return False
257        return self.request.principal.user_type == 'student'
258
259    def isApplicant(self):
260        usertype = getattr(self.request.principal, 'user_type', None)
261        if not usertype:
262            return False
263        return self.request.principal.user_type == 'applicant'
264
265    def getStudentName(self):
266        """Return the student name.
267        """
268        if IStudentNavigation.providedBy(self.context):
269            return self.context.getStudent().display_fullname
270        return
271
272    def getApplicantName(self):
273        """Return the applicant name.
274        """
275        if IApplicant.providedBy(self.context):
276            return self.context.fullname
277        return
278
279    def formatDatetime(self,datetimeobj):
280        if isinstance(datetimeobj, datetime):
281            return datetimeobj.strftime("%Y-%m-%d %H:%M:%S")
282        else:
283            return None
284
285    def update(self):
286        """Include the resources required by the chosen skin/theme.
287
288        University instances provide a 'skin' attribute, that should
289        hold the internal name of a theme.
290
291        A theme in the waeup.sirp sense consists of a list of
292        CSS/JavaScript resources defined in the
293        :mod:`waeup.sirp.browser.resources` module.
294
295        If the context University object has no such attribute or the
296        set value is not a valid theme name, we pick 'gray waeup
297        theme' as default.
298        """
299        mode('minified')
300        theme_name = getattr(grok.getSite()['configuration'], 'skin', '')
301        theme = queryUtility(ITheme, name=theme_name,
302                             default=self.default_theme)
303        for resource in theme.getResources():
304            resource.need()
305        return
306
307    def render(self):
308        if self.isStudent() or self.isApplicant() or not self.isAuthenticated():
309            return self.studenttemp.render(self)
310        return self.stafftemp.render(self)
Note: See TracBrowser for help on using the repository browser.