[pod] When inserting an image via statement do... from document(...), parameter 'sizeUnit' can now be 'pc' (percentage): in this case, percentages are expressed as a tuple (widthPercentage, heightPercentage) in parameter 'size' and must be integers from 1 to 100. [bin] backup.py: better error handling when contacting SMTP server. [gen] Calendar widget for Date fields: bugfix (when the date range is in reverse chronological order). [gen] Ref field: added hook 'afterLink' allowing to execute a method just after an object has been linked. [gen] Ref field: added attribute 'unlinkElement' allowing to define a specific condition for unlinking a given object (before, it was only possible to define, in attribute 'unlink', a global condition allowing to unlink any object from the Ref. [gen] Bugfix: the link to the home page, when clicking on the logo, is fixed.
This commit is contained in:
parent
268309045a
commit
25f0e8184e
|
@ -172,6 +172,9 @@ class ZodbBackuper:
|
|||
if res:
|
||||
w('Could not send mail to some recipients. %s' % str(res))
|
||||
w('Done.')
|
||||
except smtplib.SMTPException, sme:
|
||||
w('Error while contacting SMTP server %s (%s).' % \
|
||||
(self.options.smtpServer, str(se)))
|
||||
except socket.error, se:
|
||||
w('Could not connect to SMTP server %s (%s).' % \
|
||||
(self.options.smtpServer, str(se)))
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.9.0
|
||||
0.9.1
|
||||
|
|
|
@ -267,7 +267,9 @@ class Date(Field):
|
|||
'''Gets the Javascript init code for displaying a calendar popup for
|
||||
this field, for an input named p_name (which can be different from
|
||||
self.name if, ie, it is a search field).'''
|
||||
# Always express the range of years in chronological order.
|
||||
years = [years[0], years[-1]]
|
||||
years.sort()
|
||||
return 'Calendar.setup({inputField: "%s", button: "%s_img", ' \
|
||||
'onSelect: onSelectDate, range:[%d,%d]});' % \
|
||||
(name, name, years[0], years[-1])
|
||||
'onSelect: onSelectDate, range:%s})' % (name, name, str(years))
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -123,7 +123,7 @@ class Ref(Field):
|
|||
onclick=":'onDeleteObject(%s)' % q(tiedUid)"/>
|
||||
</td>
|
||||
<!-- Unlink -->
|
||||
<td if="mayUnlink">
|
||||
<td if="mayUnlink and field.mayUnlinkElement(obj, tied)">
|
||||
<img var="imgName=linkList and 'unlinkUp' or 'unlink'; action='unlink'"
|
||||
class="clickable" title=":_('object_unlink')" src=":url(imgName)"
|
||||
onclick=":'onLink(%s,%s,%s,%s)' % (q(action), q(zobj.id), \
|
||||
|
@ -471,8 +471,9 @@ class Ref(Field):
|
|||
|
||||
def __init__(self, klass=None, attribute=None, validator=None,
|
||||
multiplicity=(0,1), default=None, add=False, addConfirm=False,
|
||||
delete=None, noForm=False, link=True, unlink=None, insert=None,
|
||||
beforeLink=None, afterUnlink=None, back=None, show=True,
|
||||
delete=None, noForm=False, link=True, unlink=None,
|
||||
unlinkElement=None, insert=None, beforeLink=None,
|
||||
afterLink=None, afterUnlink=None, back=None, show=True,
|
||||
page='main', group=None, layouts=None, showHeaders=False,
|
||||
shownInfo=(), select=None, maxPerPage=30, move=0,
|
||||
indexed=False, searchable=False, specificReadPermission=False,
|
||||
|
@ -516,6 +517,11 @@ class Ref(Field):
|
|||
# By default, one may unlink objects via a Ref for which one can
|
||||
# link objects.
|
||||
self.unlink = bool(self.link)
|
||||
# "unlink" above is a global flag. If it is True, you can go further and
|
||||
# determine, for every linked object, if it can be unlinked or not by
|
||||
# defining a method in parameter "unlinkElement" below. This method
|
||||
# accepts the linked object as unique arg.
|
||||
self.unlinkElement = unlinkElement
|
||||
# When an object is inserted through this Ref field, at what position is
|
||||
# it inserted? If "insert" is:
|
||||
# None, it will be inserted at the end;
|
||||
|
@ -535,11 +541,15 @@ class Ref(Field):
|
|||
# maintained in the order of their insertion.
|
||||
self.insert = insert
|
||||
# Immediately before an object is going to be linked via this Ref field,
|
||||
# method specified in "beforeLink" wil be executed if specified and will
|
||||
# method potentially specified in "beforeLink" will be executed and will
|
||||
# take the object to link as single parameter.
|
||||
self.beforeLink = beforeLink
|
||||
# Immediately after an object has been linked via this Ref field, method
|
||||
# potentially specified in "afterLink" will be executed and will take
|
||||
# the linked object as single parameter.
|
||||
self.afterLink = afterLink
|
||||
# Immediately after an object as been unlinked from this Ref field,
|
||||
# method specified in "afterUnlink" will be executed if specified and
|
||||
# method potentially specified in "afterUnlink" will be executed and
|
||||
# will take the unlinked object as single parameter.
|
||||
self.afterUnlink = afterUnlink
|
||||
self.back = None
|
||||
|
@ -937,6 +947,8 @@ class Ref(Field):
|
|||
refs.data.sort(key=lambda uid:self.insert[1](obj, \
|
||||
tool.getObject(uid, appy=True)))
|
||||
refs._p_changed = 1
|
||||
# Execute self.afterLink if present
|
||||
if self.afterLink: self.afterLink(obj, value)
|
||||
# Update the back reference
|
||||
if not back: self.back.linkObject(value, obj, back=True)
|
||||
|
||||
|
@ -945,7 +957,9 @@ class Ref(Field):
|
|||
p_obj through this Ref field.'''
|
||||
zobj = obj.o
|
||||
# Security check
|
||||
if not noSecurity: zobj.mayEdit(self.writePermission, raiseError=True)
|
||||
if not noSecurity:
|
||||
zobj.mayEdit(self.writePermission, raiseError=True)
|
||||
self.mayUnlinkElement(obj, value, raiseError=True)
|
||||
# p_value can be a list of objects
|
||||
if type(value) in sutils.sequenceTypes:
|
||||
for v in value: self.unlinkObject(obj, v, back=back)
|
||||
|
@ -1053,6 +1067,17 @@ class Ref(Field):
|
|||
q(addConfirmMsg))
|
||||
return res
|
||||
|
||||
def mayUnlinkElement(self, obj, tied, raiseError=False):
|
||||
'''May we unlink from this Ref field this specific p_tied object?'''
|
||||
if not self.unlinkElement: return True
|
||||
res = self.unlinkElement(obj, tied)
|
||||
if res: return True
|
||||
else:
|
||||
if not raiseError: return
|
||||
# Raise an exception.
|
||||
obj.o.raiseUnauthorized('field.unlinkElement prevents you to ' \
|
||||
'unlink this object.')
|
||||
|
||||
def getCbJsInit(self, obj):
|
||||
'''When checkboxes are enabled, this method defines a JS associative
|
||||
array (named "_appy_objs_cbs") that will store checkboxes' statuses.
|
||||
|
@ -1215,16 +1240,21 @@ class Ref(Field):
|
|||
# Perform the action on every target. Count the number of failed
|
||||
# operations.
|
||||
failed = 0
|
||||
mustDelete = action == 'delete_many'
|
||||
singleAction = action.split('_')[0]
|
||||
mustDelete = singleAction == 'delete'
|
||||
for target in targets:
|
||||
if mustDelete:
|
||||
# Delete
|
||||
if target.o.mayDelete(): target.o.delete()
|
||||
else: failed += 1
|
||||
else:
|
||||
# Link or unlink
|
||||
exec 'self.%sObject(appyObj, target)' % \
|
||||
action.split('_')[0]
|
||||
# Link or unlink. For unlinking, we need to perform an
|
||||
# additional check.
|
||||
if (singleAction == 'unlink') and \
|
||||
not self.mayUnlinkElement(appyObj, target):
|
||||
failed += 1
|
||||
else:
|
||||
exec 'self.%sObject(appyObj, target)' % singleAction
|
||||
if failed:
|
||||
msg = obj.translate('action_partial', mapping={'nb':failed})
|
||||
urlBack = obj.getUrl(rq['HTTP_REFERER'])
|
||||
|
|
|
@ -153,7 +153,7 @@ class User(ModelClass):
|
|||
'toTool']
|
||||
# All methods defined below are fake. Real versions are in the wrapper.
|
||||
title = gen.String(show=False, indexed=True)
|
||||
gm = {'group': 'main', 'width': 25}
|
||||
gm = {'group': 'main', 'width': 34}
|
||||
def showName(self): pass
|
||||
name = gen.String(show=showName, **gm)
|
||||
firstName = gen.String(show=showName, **gm)
|
||||
|
|
BIN
gen/ui/space.gif
BIN
gen/ui/space.gif
Binary file not shown.
Before Width: | Height: | Size: 43 B After Width: | Height: | Size: 43 B |
|
@ -187,8 +187,8 @@ class AbstractWrapper(object):
|
|||
style=":url(bannerName, bg=True) + '; background-repeat:no-repeat;\
|
||||
position:relative'">
|
||||
<!-- Logo (transparent clickable zone by default) -->
|
||||
<div align=":dleft" style="position: absolute"><a href="/">
|
||||
<img src=":url('logo')"/></a></div>
|
||||
<div align=":dleft" style="position: absolute">
|
||||
<a href=":ztool.getSiteUrl()"><img src=":url('logo')"/></a></div>
|
||||
|
||||
<!-- Top links -->
|
||||
<div style="margin-top: 4px" align=":dright">
|
||||
|
|
|
@ -54,7 +54,6 @@ class BufferAction:
|
|||
'''Gets the line describing exception p_e, containing the exception
|
||||
class, message and line number.'''
|
||||
return '%s: %s' % (e.__class__.__name__, str(e))
|
||||
return '%s.%s: %s' % (e.__module__, e.__class__.__name__, str(e))
|
||||
|
||||
def manageError(self, result, context, errorMessage, dumpTb=True):
|
||||
'''Manage the encountered error: dump it into the buffer or raise an
|
||||
|
|
|
@ -383,7 +383,7 @@ class ImageImporter(DocImporter):
|
|||
self.format = 'png'
|
||||
# Retrieve image size from self.size.
|
||||
width = height = None
|
||||
if self.size:
|
||||
if self.size and (self.sizeUnit != 'pc'):
|
||||
width, height = self.size
|
||||
if self.sizeUnit == 'px':
|
||||
# Convert it to cm
|
||||
|
@ -397,6 +397,10 @@ class ImageImporter(DocImporter):
|
|||
# If width and/or height is missing, compute it.
|
||||
if not width or not height:
|
||||
width, height = getSize(self.importPath, self.format)
|
||||
if self.sizeUnit == 'pc':
|
||||
# Apply the given percentage to the real width and height.
|
||||
width = width * (float(self.size[0])/100)
|
||||
height = height * (float(self.size[1])/100)
|
||||
if width != None:
|
||||
size = ' %s:width="%fcm" %s:height="%fcm"' % (s, width, s, height)
|
||||
else:
|
||||
|
|
|
@ -314,7 +314,8 @@ class Renderer:
|
|||
(width, height) expressing size in p_sizeUnit (see below).
|
||||
If not specified, size will be computed from image info;
|
||||
* p_sizeUnit is the unit for p_size elements, it can be "cm"
|
||||
(centimeters) or "px" (pixels);
|
||||
(centimeters), "px" (pixels) or "pc" (percentage). Percentages, in
|
||||
p_size, must be expressed as integers from 1 to 100.
|
||||
* if p_style is given, it is the content of a "style" attribute,
|
||||
containing CSS attributes. If "width" and "heigth" attributes are
|
||||
found there, they will override p_size and p_sizeUnit.
|
||||
|
|
Loading…
Reference in a new issue