[gen] List field: bugfix with empty-like values (integer 0 for example). Ref field: bugfix: add a tied object with noForm=True. Calendar: added param 'delete' allowing to define who can delete what event type in the calendar. Added method 'clone' on class appy.Object.

This commit is contained in:
Gaetan Delannay 2015-02-19 13:40:12 +01:00
parent 5ba648fbf0
commit 1f34156437
5 changed files with 35 additions and 18 deletions

View file

@ -40,9 +40,13 @@ class Object:
def get(self, name, default=None): return getattr(self, name, default) def get(self, name, default=None): return getattr(self, name, default)
def __getitem__(self, k): return getattr(self, k) def __getitem__(self, k): return getattr(self, k)
def update(self, other): def update(self, other):
'''Includes information from p_other into p_self.''' '''Includes information from p_other into p_self'''
for k, v in other.__dict__.iteritems(): for k, v in other.__dict__.iteritems():
setattr(self, k, v) setattr(self, k, v)
def clone(self):
res = Object()
res.update(self)
return res
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Hack: class Hack:

View file

@ -89,7 +89,7 @@ class Calendar(Field):
var2="events=field.getEventsAt(zobj, date); var2="events=field.getEventsAt(zobj, date);
spansDays=field.hasEventsAt(zobj, date+1, events); spansDays=field.hasEventsAt(zobj, date+1, events);
mayCreate=mayEdit and not events; mayCreate=mayEdit and not events;
mayDelete=mayEdit and events; mayDelete=mayEdit and events and field.mayDelete(obj,events);
day=date.day(); day=date.day();
dayString=date.strftime('%Y/%m/%d'); dayString=date.strftime('%Y/%m/%d');
js=mayEdit and 'toggleVisibility(this, %s)' % q('img') \ js=mayEdit and 'toggleVisibility(this, %s)' % q('img') \
@ -216,7 +216,7 @@ class Calendar(Field):
mapping=None, label=None, maxEventLength=50, mapping=None, label=None, maxEventLength=50,
otherCalendars=None, additionalInfo=None, startDate=None, otherCalendars=None, additionalInfo=None, startDate=None,
endDate=None, defaultDate=None, preCompute=None, endDate=None, defaultDate=None, preCompute=None,
applicableEvents=None, view=None, xml=None): applicableEvents=None, view=None, xml=None, delete=True):
Field.__init__(self, validator, (0,1), default, show, page, group, Field.__init__(self, validator, (0,1), default, show, page, group,
layouts, move, False, True, False, specificReadPermission, layouts, move, False, True, False, specificReadPermission,
specificWritePermission, width, height, None, colspan, specificWritePermission, width, height, None, colspan,
@ -294,6 +294,9 @@ class Calendar(Field):
# for explaining him why he can, for this day, only create events of a # for explaining him why he can, for this day, only create events of a
# sub-set of the possible event types (or even no event at all). # sub-set of the possible event types (or even no event at all).
self.applicableEvents = applicableEvents self.applicableEvents = applicableEvents
# May the user delete events in this calendar? If "delete" is a method,
# it must accept an event type as single arg.
self.delete = delete
def getPreComputedInfo(self, obj, monthDayOne, grid): def getPreComputedInfo(self, obj, monthDayOne, grid):
'''Returns the result of calling self.preComputed, or None if no such '''Returns the result of calling self.preComputed, or None if no such
@ -573,9 +576,9 @@ class Calendar(Field):
eventSpan = rq.get('eventSpan', None) eventSpan = rq.get('eventSpan', None)
# Split the p_date into separate parts # Split the p_date into separate parts
year, month, day = date.year(), date.month(), date.day() year, month, day = date.year(), date.month(), date.day()
# Check that the "preferences" dict exists or not. # Check that the "preferences" dict exists or not
if not hasattr(obj.aq_base, self.name): if not hasattr(obj.aq_base, self.name):
# 1st level: create a IOBTree whose keys are years. # 1st level: create a IOBTree whose keys are years
setattr(obj, self.name, IOBTree()) setattr(obj, self.name, IOBTree())
yearsDict = getattr(obj, self.name) yearsDict = getattr(obj, self.name)
# Get the sub-dict storing months for a given year # Get the sub-dict storing months for a given year
@ -593,7 +596,7 @@ class Calendar(Field):
events = daysDict[day] events = daysDict[day]
else: else:
daysDict[day] = events = PersistentList() daysDict[day] = events = PersistentList()
# Create and store the event, excepted if an event already exists. # Create and store the event, excepted if an event already exists
if not events: if not events:
event = Object(eventType=eventType) event = Object(eventType=eventType)
events.append(event) events.append(event)
@ -604,6 +607,12 @@ class Calendar(Field):
date = date + 1 date = date + 1
self.createEvent(obj, date, handleEventSpan=False) self.createEvent(obj, date, handleEventSpan=False)
def mayDelete(self, obj, events):
'''May the user delete p_events?'''
if not self.delete: return
if callable(self.delete): return self.delete(obj, events[0].eventType)
return True
def deleteEvent(self, obj, date, handleEventSpan=True): def deleteEvent(self, obj, date, handleEventSpan=True):
'''Deletes an event. It actually deletes all events at p_date. '''Deletes an event. It actually deletes all events at p_date.
If p_handleEventSpan is True, we will use rq["deleteNext"] to If p_handleEventSpan is True, we will use rq["deleteNext"] to

View file

@ -179,7 +179,7 @@ class Group:
return uiGroup return uiGroup
class Column: class Column:
'''Used for describing a column within a Group like defined above.''' '''Used for describing a column within a Group like defined above'''
def __init__(self, width, align="left"): def __init__(self, width, align="left"):
self.width = width self.width = width
self.align = align self.align = align

View file

@ -22,9 +22,11 @@ from appy.gen.layout import Table
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class List(Field): class List(Field):
'''A list.''' '''A list, stored as a list of Object instances ~[Object]~. Every object in
the list has attributes named according to the sub-fields defined in this
List.'''
# PX for rendering a single row. # PX for rendering a single row
pxRow = Px(''' pxRow = Px('''
<tr valign="top" style=":(rowIndex==-1) and 'display: none' or ''"> <tr valign="top" style=":(rowIndex==-1) and 'display: none' or ''">
<td for="info in subFields" if="info[1]" align="center" <td for="info in subFields" if="info[1]" align="center"
@ -38,7 +40,7 @@ class List(Field):
</td> </td>
</tr>''') </tr>''')
# PX for rendering the list (shared between pxView and pxEdit). # PX for rendering the list (shared between pxView and pxEdit)
pxTable = Px(''' pxTable = Px('''
<table var="isEdit=layoutType == 'edit'" if="isEdit or value" <table var="isEdit=layoutType == 'edit'" if="isEdit or value"
id=":'list_%s' % name" class=":isEdit and 'grid' or 'list'" id=":'list_%s' % name" class=":isEdit and 'grid' or 'list'"
@ -177,9 +179,12 @@ class List(Field):
if i == -1: return '' if i == -1: return ''
if not outerValue: return '' if not outerValue: return ''
if i >= len(outerValue): return '' if i >= len(outerValue): return ''
# Return the value, or a potential default value. # Return the value, or a potential default value
return getattr(outerValue[i], name, '') or \ value = getattr(outerValue[i], name, None)
self.getField(name).getValue(obj) or '' if value != None: return value
value = self.getField(name).getValue(obj)
if value != None: return value
return ''
def getCss(self, layoutType, res): def getCss(self, layoutType, res):
'''Gets the CSS required by sub-fields if any.''' '''Gets the CSS required by sub-fields if any.'''

View file

@ -248,6 +248,10 @@ class Ref(Field):
q('%s/search?className=%s&amp;ref=%s:%s' % \ q('%s/search?className=%s&amp;ref=%s:%s' % \
(ztool.absolute_url(), tiedClassName, zobj.id, field.name))"/> (ztool.absolute_url(), tiedClassName, zobj.id, field.name))"/>
</div> </div>
<script>:field.getAjaxData(ajaxHookId, zobj, popup=inPopup, \
checkboxes=checkboxes, startNumber=startNumber, sourceId=zobj.id, \
totalNumber=totalNumber, refFieldName=field.name, \
inPickList=inPickList, numbered=numbered)</script>
<!-- (Top) navigation --> <!-- (Top) navigation -->
<x>:tool.pxNavigate</x> <x>:tool.pxNavigate</x>
@ -261,11 +265,6 @@ class Ref(Field):
var2="columns=ztool.getColumnsSpecifiers(tiedClassName, \ var2="columns=ztool.getColumnsSpecifiers(tiedClassName, \
field.getAttribute(obj, 'shownInfo'), dir); field.getAttribute(obj, 'shownInfo'), dir);
currentNumber=0"> currentNumber=0">
<script>:field.getAjaxData(ajaxHookId, zobj, popup=inPopup, \
checkboxes=checkboxes, startNumber=startNumber, \
totalNumber=totalNumber, sourceId=zobj.id, \
refFieldName=field.name, inPickList=inPickList, \
numbered=numbered)</script>
<tr if="field.showHeaders"> <tr if="field.showHeaders">
<th if="not inPickList and numbered" width=":numbered"></th> <th if="not inPickList and numbered" width=":numbered"></th>