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

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

Add 'acronym' to IConfigurationContainer.

  • Property svn:keywords set to Id
File size: 10.6 KB
Line 
1## $Id: layout.py 7456 2012-01-12 12:13:36Z 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 getAppAcronym(self):
233        return getattr(grok.getSite()['configuration'], 'acronym', u'Acronym')
234
235    def isAuthenticated(self):
236        """Return True if the calling user is authenticated.
237        """
238        usertitle = self.request.principal.title
239        return usertitle != 'Unauthenticated User'
240
241    def getUserTitle(self):
242        """Return principal title of current user.
243        """
244        usertitle = self.request.principal.title
245        if usertitle == 'Unauthenticated User':
246            return u'Anonymous User'
247        return usertitle
248
249    def getUserId(self):
250        """Return id of current user.
251        """
252        userid = self.request.principal.id
253        return userid
254
255    def isStudent(self):
256        usertype = getattr(self.request.principal, 'user_type', None)
257        if not usertype:
258            return False
259        return self.request.principal.user_type == 'student'
260
261    def isApplicant(self):
262        usertype = getattr(self.request.principal, 'user_type', None)
263        if not usertype:
264            return False
265        return self.request.principal.user_type == 'applicant'
266
267    def getStudentName(self):
268        """Return the student name.
269        """
270        if IStudentNavigation.providedBy(self.context):
271            return self.context.getStudent().display_fullname
272        return
273
274    def getApplicantName(self):
275        """Return the applicant name.
276        """
277        if IApplicant.providedBy(self.context):
278            return self.context.fullname
279        return
280
281    def formatDatetime(self,datetimeobj):
282        if isinstance(datetimeobj, datetime):
283            return datetimeobj.strftime("%Y-%m-%d %H:%M:%S")
284        else:
285            return None
286
287    def update(self):
288        """Include the resources required by the chosen skin/theme.
289
290        University instances provide a 'skin' attribute, that should
291        hold the internal name of a theme.
292
293        A theme in the waeup.sirp sense consists of a list of
294        CSS/JavaScript resources defined in the
295        :mod:`waeup.sirp.browser.resources` module.
296
297        If the context University object has no such attribute or the
298        set value is not a valid theme name, we pick 'gray waeup
299        theme' as default.
300        """
301        mode('minified')
302        theme_name = getattr(grok.getSite()['configuration'], 'skin', '')
303        theme = queryUtility(ITheme, name=theme_name,
304                             default=self.default_theme)
305        for resource in theme.getResources():
306            resource.need()
307        return
308
309    def render(self):
310        if self.isStudent() or self.isApplicant() or not self.isAuthenticated():
311            return self.studenttemp.render(self)
312        return self.stafftemp.render(self)
Note: See TracBrowser for help on using the repository browser.