Optimized performance while rendering references and computed fields and allowed computed fields to be shown asynchronously.
This commit is contained in:
parent
7d3ac9112b
commit
88cd4f7c46
|
@ -265,7 +265,7 @@ class Type:
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission, specificWritePermission,
|
searchable, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, colspan, master, masterValue, focus,
|
||||||
historized):
|
historized, sync):
|
||||||
# The validator restricts which values may be defined. It can be an
|
# The validator restricts which values may be defined. It can be an
|
||||||
# interval (1,None), a list of string values ['choice1', 'choice2'],
|
# interval (1,None), a list of string values ['choice1', 'choice2'],
|
||||||
# a regular expression, a custom function, a Selection instance, etc.
|
# a regular expression, a custom function, a Selection instance, etc.
|
||||||
|
@ -349,6 +349,9 @@ class Type:
|
||||||
# If we must keep track of changes performed on a field, "historized"
|
# If we must keep track of changes performed on a field, "historized"
|
||||||
# must be set to True.
|
# must be set to True.
|
||||||
self.historized = historized
|
self.historized = historized
|
||||||
|
# self.sync below determines if the field representations will be
|
||||||
|
# retrieved in a synchronous way by the browser or not (Ajax).
|
||||||
|
self.sync = self.formatSync(sync)
|
||||||
self.id = id(self)
|
self.id = id(self)
|
||||||
self.type = self.__class__.__name__
|
self.type = self.__class__.__name__
|
||||||
self.pythonType = None # The True corresponding Python type
|
self.pythonType = None # The True corresponding Python type
|
||||||
|
@ -450,6 +453,16 @@ class Type:
|
||||||
else:
|
else:
|
||||||
return self.pageShow
|
return self.pageShow
|
||||||
|
|
||||||
|
def formatSync(self, sync):
|
||||||
|
'''Creates a dictionary indicating, for every layout type, if the field
|
||||||
|
value must be retrieved synchronously or not.'''
|
||||||
|
if isinstance(sync, bool):
|
||||||
|
sync = {'edit': sync, 'view': sync, 'cell': sync}
|
||||||
|
for layoutType in ('edit', 'view', 'cell'):
|
||||||
|
if layoutType not in sync:
|
||||||
|
sync[layoutType] = False
|
||||||
|
return sync
|
||||||
|
|
||||||
def formatLayouts(self, layouts):
|
def formatLayouts(self, layouts):
|
||||||
'''Standardizes the given p_layouts. .'''
|
'''Standardizes the given p_layouts. .'''
|
||||||
# First, get the layouts as a dictionary, if p_layouts is None or
|
# First, get the layouts as a dictionary, if p_layouts is None or
|
||||||
|
@ -651,7 +664,7 @@ class Integer(Type):
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, colspan, master,
|
||||||
masterValue, focus, historized)
|
masterValue, focus, historized, True)
|
||||||
self.pythonType = long
|
self.pythonType = long
|
||||||
|
|
||||||
def validateValue(self, obj, value):
|
def validateValue(self, obj, value):
|
||||||
|
@ -690,7 +703,7 @@ class Float(Type):
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
False, specificReadPermission, specificWritePermission,
|
False, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, colspan, master, masterValue, focus,
|
||||||
historized)
|
historized, True)
|
||||||
self.pythonType = float
|
self.pythonType = float
|
||||||
|
|
||||||
def getFormattedValue(self, obj, value):
|
def getFormattedValue(self, obj, value):
|
||||||
|
@ -851,7 +864,7 @@ class String(Type):
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, colspan, master,
|
||||||
masterValue, focus, historized)
|
masterValue, focus, historized, True)
|
||||||
self.isSelect = self.isSelection()
|
self.isSelect = self.isSelection()
|
||||||
# Default width and height vary according to String format
|
# Default width and height vary according to String format
|
||||||
if width == None:
|
if width == None:
|
||||||
|
@ -1016,14 +1029,13 @@ class Boolean(Type):
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, colspan, master,
|
||||||
masterValue, focus, historized)
|
masterValue, focus, historized, True)
|
||||||
self.pythonType = bool
|
self.pythonType = bool
|
||||||
|
|
||||||
def getDefaultLayouts(self):
|
def getDefaultLayouts(self):
|
||||||
return {'view': 'l;f!_', 'edit': Table('f;lrv;=', width=None)}
|
return {'view': 'l;f!_', 'edit': Table('f;lrv;=', width=None)}
|
||||||
|
|
||||||
def getFormattedValue(self, obj, value):
|
def getFormattedValue(self, obj, value):
|
||||||
if value in nullValues: return ''
|
|
||||||
if value: res = obj.translate('yes', domain='plone')
|
if value: res = obj.translate('yes', domain='plone')
|
||||||
else: res = obj.translate('no', domain='plone')
|
else: res = obj.translate('no', domain='plone')
|
||||||
return res
|
return res
|
||||||
|
@ -1057,7 +1069,7 @@ class Date(Type):
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, colspan, master,
|
||||||
masterValue, focus, historized)
|
masterValue, focus, historized, True)
|
||||||
|
|
||||||
def getCss(self, layoutType):
|
def getCss(self, layoutType):
|
||||||
if layoutType == 'edit': return ('jscalendar/calendar-system.css',)
|
if layoutType == 'edit': return ('jscalendar/calendar-system.css',)
|
||||||
|
@ -1110,7 +1122,7 @@ class File(Type):
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
False, specificReadPermission, specificWritePermission,
|
False, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, colspan, master, masterValue, focus,
|
||||||
historized)
|
historized, True)
|
||||||
|
|
||||||
def getValue(self, obj):
|
def getValue(self, obj):
|
||||||
value = Type.getValue(self, obj)
|
value = Type.getValue(self, obj)
|
||||||
|
@ -1210,11 +1222,13 @@ class Ref(Type):
|
||||||
self.select = select
|
self.select = select
|
||||||
# Maximum number of referenced objects shown at once.
|
# Maximum number of referenced objects shown at once.
|
||||||
self.maxPerPage = maxPerPage
|
self.maxPerPage = maxPerPage
|
||||||
|
# Specifies sync
|
||||||
|
sync = {'view': False, 'edit':True}
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
False, specificReadPermission, specificWritePermission,
|
False, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, colspan, master, masterValue, focus,
|
||||||
historized)
|
historized, sync)
|
||||||
self.validable = self.link
|
self.validable = self.link
|
||||||
|
|
||||||
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
||||||
|
@ -1273,7 +1287,7 @@ class Computed(Type):
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, method=None, plainText=True, master=None,
|
colspan=1, method=None, plainText=True, master=None,
|
||||||
masterValue=None, focus=False, historized=False):
|
masterValue=None, focus=False, historized=False, sync=True):
|
||||||
# The Python method used for computing the field value
|
# The Python method used for computing the field value
|
||||||
self.method = method
|
self.method = method
|
||||||
# Does field computation produce plain text or XHTML?
|
# Does field computation produce plain text or XHTML?
|
||||||
|
@ -1281,7 +1295,8 @@ class Computed(Type):
|
||||||
Type.__init__(self, None, multiplicity, index, default, optional,
|
Type.__init__(self, None, multiplicity, index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed, False,
|
False, show, page, group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, colspan, master, masterValue, focus, historized)
|
height, colspan, master, masterValue, focus, historized,
|
||||||
|
sync)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
def getValue(self, obj):
|
def getValue(self, obj):
|
||||||
|
@ -1297,7 +1312,7 @@ class Computed(Type):
|
||||||
res = str(e)
|
res = str(e)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getFormattedValue(self, obj, value): return self.getValue(obj)
|
def getFormattedValue(self, obj, value): return value
|
||||||
|
|
||||||
class Action(Type):
|
class Action(Type):
|
||||||
'''An action is a workflow-independent Python method that can be triggered
|
'''An action is a workflow-independent Python method that can be triggered
|
||||||
|
@ -1325,7 +1340,8 @@ class Action(Type):
|
||||||
Type.__init__(self, None, (0,1), index, default, optional,
|
Type.__init__(self, None, (0,1), index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed, False,
|
False, show, page, group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, colspan, master, masterValue, focus, historized)
|
height, colspan, master, masterValue, focus, historized,
|
||||||
|
False)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
||||||
|
@ -1377,7 +1393,8 @@ class Info(Type):
|
||||||
Type.__init__(self, None, (0,1), index, default, optional,
|
Type.__init__(self, None, (0,1), index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed, False,
|
False, show, page, group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, colspan, master, masterValue, focus, historized)
|
height, colspan, master, masterValue, focus, historized,
|
||||||
|
False)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
class Pod(Type):
|
class Pod(Type):
|
||||||
|
@ -1407,7 +1424,7 @@ class Pod(Type):
|
||||||
False, show, page, group, layouts, move, indexed,
|
False, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, colspan, master,
|
||||||
masterValue, focus, historized)
|
masterValue, focus, historized, False)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
# Workflow-specific types ------------------------------------------------------
|
# Workflow-specific types ------------------------------------------------------
|
||||||
|
|
|
@ -300,25 +300,14 @@ class AbstractMixin:
|
||||||
'''Returns the method named p_methodName.'''
|
'''Returns the method named p_methodName.'''
|
||||||
return getattr(self, methodName, None)
|
return getattr(self, methodName, None)
|
||||||
|
|
||||||
def getFieldValue(self, name, useParamValue=False, value=None,
|
def getFieldValue(self, name):
|
||||||
formatted=True):
|
'''Returns the database value of field named p_name for p_self.'''
|
||||||
'''Returns the value of field named p_name for this object (p_self).
|
return self.getAppyType(name).getValue(self)
|
||||||
|
|
||||||
If p_useParamValue is True, the method uses p_value instead of the
|
def getFormattedFieldValue(self, name, value):
|
||||||
real field value (useful for rendering a value from the object
|
'''Gets a nice, string representation of p_value which is a value from
|
||||||
history, for example).
|
field named p_name.'''
|
||||||
|
return self.getAppyType(name).getFormattedValue(self, value)
|
||||||
If p_formatted is False, it will return the true database
|
|
||||||
(or default) value. Else, it will produce a nice, string and
|
|
||||||
potentially translated value.'''
|
|
||||||
appyType = self.getAppyType(name)
|
|
||||||
# Which value will we use ?
|
|
||||||
if not useParamValue:
|
|
||||||
value = appyType.getValue(self)
|
|
||||||
# Return the value as is if it is None or forMasterId
|
|
||||||
if not formatted: return value
|
|
||||||
# Return the formatted value else
|
|
||||||
return appyType.getFormattedValue(self, value)
|
|
||||||
|
|
||||||
def _appy_getRefs(self, fieldName, ploneObjects=False,
|
def _appy_getRefs(self, fieldName, ploneObjects=False,
|
||||||
noListIfSingleObj=False, startNumber=None):
|
noListIfSingleObj=False, startNumber=None):
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ModelClass:
|
||||||
_appy_notinit = ('id', 'type', 'pythonType', 'slaves', 'phase', 'pageShow',
|
_appy_notinit = ('id', 'type', 'pythonType', 'slaves', 'phase', 'pageShow',
|
||||||
'isSelect', 'hasLabel', 'hasDescr', 'hasHelp',
|
'isSelect', 'hasLabel', 'hasDescr', 'hasHelp',
|
||||||
'master_css', 'layouts', 'required', 'filterable',
|
'master_css', 'layouts', 'required', 'filterable',
|
||||||
'validable', 'backd', 'isBack')
|
'validable', 'backd', 'isBack', 'sync')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _appy_addField(klass, fieldName, fieldType, classDescr):
|
def _appy_addField(klass, fieldName, fieldType, classDescr):
|
||||||
|
|
|
@ -157,6 +157,12 @@
|
||||||
}
|
}
|
||||||
askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/ref', 'viewContent',params);
|
askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/ref', 'viewContent',params);
|
||||||
}
|
}
|
||||||
|
function askComputedField(hookId, objectUrl, fieldName) {
|
||||||
|
// Sends an Ajax request for getting the content of a computed field
|
||||||
|
var params = {'fieldName': fieldName};
|
||||||
|
askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/computed', 'viewContent',
|
||||||
|
params);
|
||||||
|
}
|
||||||
|
|
||||||
// Function used by checkbox widgets for having radio-button-like behaviour
|
// Function used by checkbox widgets for having radio-button-like behaviour
|
||||||
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
|
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
|
||||||
|
@ -455,7 +461,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr tal:repeat="change event/changes/items" valign="top">
|
<tr tal:repeat="change event/changes/items" valign="top">
|
||||||
<td tal:content="python: tool.translate(change[1][1])"></td>
|
<td tal:content="python: tool.translate(change[1][1])"></td>
|
||||||
<td tal:define="appyValue python: contextObj.getFieldValue(change[0], useParamValue=True, value=change[1][0]);
|
<td tal:define="appyValue python: contextObj.getFormattedFieldValue(change[0], change[1][0]);
|
||||||
appyType python:contextObj.getAppyType(change[0], asDict=True);
|
appyType python:contextObj.getAppyType(change[0], asDict=True);
|
||||||
severalValues python: (appyType['multiplicity'][1] > 1) or (appyType['multiplicity'][1] == None)">
|
severalValues python: (appyType['multiplicity'][1] > 1) or (appyType['multiplicity'][1] == None)">
|
||||||
<span tal:condition="not: severalValues" tal:replace="appyValue"></span>
|
<span tal:condition="not: severalValues" tal:replace="appyValue"></span>
|
||||||
|
|
|
@ -1,7 +1,26 @@
|
||||||
<tal:comment replace="nothing">View macro for a Computed.</tal:comment>
|
<tal:comment replace="nothing">View macro for a Computed.</tal:comment>
|
||||||
<metal:view define-macro="view">
|
<metal:view define-macro="view">
|
||||||
<span tal:condition="widget/plainText" tal:replace="value"/>
|
<tal:sync condition="sync">
|
||||||
<span tal:condition="not: widget/plainText" tal:replace="structure value"/>
|
<span tal:condition="widget/plainText" tal:replace="value"/>
|
||||||
|
<span tal:condition="not: widget/plainText" tal:replace="structure value"/>
|
||||||
|
</tal:sync>
|
||||||
|
<tal:async condition="not: sync">
|
||||||
|
<div tal:define= "ajaxHookId python: contextObj.UID() + name"
|
||||||
|
tal:attributes = "id ajaxHookId">
|
||||||
|
<script language="javascript"
|
||||||
|
tal:content="python: 'askComputedField(\'%s\',\'%s\',\'%s\')' % (ajaxHookId, contextObj.absolute_url(), name)">
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</tal:async>
|
||||||
|
</metal:view>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">Ajax-called view content of a non sync Computed field.</tal:comment>
|
||||||
|
<metal:view define-macro="viewContent"
|
||||||
|
tal:define="name request/fieldName;
|
||||||
|
widget python: contextObj.getAppyType(name, asDict=True);
|
||||||
|
value python: contextObj.getFieldValue(name);
|
||||||
|
sync python:True">
|
||||||
|
<metal:call use-macro="portal/skyn/widgets/computed/macros/view"/>
|
||||||
</metal:view>
|
</metal:view>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Edit macro for a Computed.</tal:comment>
|
<tal:comment replace="nothing">Edit macro for a Computed.</tal:comment>
|
||||||
|
|
|
@ -54,8 +54,9 @@
|
||||||
tal:define="contextMacro python: portal.skyn.widgets;
|
tal:define="contextMacro python: portal.skyn.widgets;
|
||||||
layout python: widget['layouts'][layoutType];
|
layout python: widget['layouts'][layoutType];
|
||||||
name widget/name;
|
name widget/name;
|
||||||
value python: contextObj.getFieldValue(name);
|
sync python: widget['sync'][layoutType];
|
||||||
rawValue python: contextObj.getFieldValue(name, formatted=False);
|
rawValue python: sync and contextObj.getFieldValue(name) or None;
|
||||||
|
value python: sync and contextObj.getFormattedFieldValue(name, rawValue) or None;
|
||||||
requestValue python: request.get(name, None);
|
requestValue python: request.get(name, None);
|
||||||
inRequest python: request.has_key(name);
|
inRequest python: request.has_key(name);
|
||||||
errors errors | python: ();
|
errors errors | python: ();
|
||||||
|
|
Loading…
Reference in a new issue