[gen] Allow to show the cumulative differences performed on historized String fields with format=String.XHTML.
This commit is contained in:
		
							parent
							
								
									6caeeb1761
								
							
						
					
					
						commit
						ab00917df6
					
				
					 6 changed files with 90 additions and 29 deletions
				
			
		| 
						 | 
					@ -12,6 +12,7 @@ import appy.pod
 | 
				
			||||||
from appy.pod.renderer import Renderer
 | 
					from appy.pod.renderer import Renderer
 | 
				
			||||||
from appy.shared.data import countries
 | 
					from appy.shared.data import countries
 | 
				
			||||||
from appy.shared.xml_parser import XhtmlCleaner
 | 
					from appy.shared.xml_parser import XhtmlCleaner
 | 
				
			||||||
 | 
					from appy.shared.diff import HtmlDiff
 | 
				
			||||||
from appy.shared.utils import Traceback, getOsTempFolder, formatNumber, \
 | 
					from appy.shared.utils import Traceback, getOsTempFolder, formatNumber, \
 | 
				
			||||||
                              FileWrapper, sequenceTypes
 | 
					                              FileWrapper, sequenceTypes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -678,8 +679,9 @@ class Type:
 | 
				
			||||||
            layouts['view'].addCssClasses('focus')
 | 
					            layouts['view'].addCssClasses('focus')
 | 
				
			||||||
            layouts['edit'].addCssClasses('focus')
 | 
					            layouts['edit'].addCssClasses('focus')
 | 
				
			||||||
        # If layouts are the default ones, set width=None instead of width=100%
 | 
					        # If layouts are the default ones, set width=None instead of width=100%
 | 
				
			||||||
        # for the field if it is not in a group.
 | 
					        # for the field if it is not in a group (excepted for rich texts).
 | 
				
			||||||
        if areDefault and not self.group:
 | 
					        if areDefault and not self.group and \
 | 
				
			||||||
 | 
					           not ((self.type == 'String') and (self.format == String.XHTML)):
 | 
				
			||||||
            for layoutType in layouts.iterkeys():
 | 
					            for layoutType in layouts.iterkeys():
 | 
				
			||||||
                layouts[layoutType].width = ''
 | 
					                layouts[layoutType].width = ''
 | 
				
			||||||
        # Remove letters "r" from the layouts if the field is not required.
 | 
					        # Remove letters "r" from the layouts if the field is not required.
 | 
				
			||||||
| 
						 | 
					@ -765,10 +767,12 @@ class Type:
 | 
				
			||||||
                return self.default
 | 
					                return self.default
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        '''p_value is a real p_obj(ect) value from a field from this type. This
 | 
					        '''p_value is a real p_obj(ect) value from a field from this type. This
 | 
				
			||||||
           method returns a pretty, string-formatted version, for displaying
 | 
					           method returns a pretty, string-formatted version, for displaying
 | 
				
			||||||
           purposes. Needs to be overridden by some child classes.'''
 | 
					           purposes. Needs to be overridden by some child classes. If
 | 
				
			||||||
 | 
					           p_showChanges is True, the result must also include the changes that
 | 
				
			||||||
 | 
					           occurred on p_value across the ages.'''
 | 
				
			||||||
        if self.isEmptyValue(value): return ''
 | 
					        if self.isEmptyValue(value): return ''
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -971,7 +975,7 @@ class Integer(Type):
 | 
				
			||||||
    def getStorableValue(self, value):
 | 
					    def getStorableValue(self, value):
 | 
				
			||||||
        if not self.isEmptyValue(value): return self.pythonType(value)
 | 
					        if not self.isEmptyValue(value): return self.pythonType(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        if self.isEmptyValue(value): return ''
 | 
					        if self.isEmptyValue(value): return ''
 | 
				
			||||||
        return str(value)
 | 
					        return str(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1009,7 +1013,7 @@ class Float(Type):
 | 
				
			||||||
                      label, sdefault, scolspan)
 | 
					                      label, sdefault, scolspan)
 | 
				
			||||||
        self.pythonType = float
 | 
					        self.pythonType = float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        return formatNumber(value, sep=self.sep[0], precision=self.precision,
 | 
					        return formatNumber(value, sep=self.sep[0], precision=self.precision,
 | 
				
			||||||
                            tsep=self.tsep)
 | 
					                            tsep=self.tsep)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1214,7 +1218,7 @@ class String(Type):
 | 
				
			||||||
                view = 'lc-f'
 | 
					                view = 'lc-f'
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                view = 'l-f'
 | 
					                view = 'l-f'
 | 
				
			||||||
            return {'view': view, 'edit': 'lrv-d-f'}
 | 
					            return {'view': Table(view, width='100%'), 'edit': 'lrv-d-f'}
 | 
				
			||||||
        elif self.isMultiValued():
 | 
					        elif self.isMultiValued():
 | 
				
			||||||
            return {'view': 'l-f', 'edit': 'lrv-f'}
 | 
					            return {'view': 'l-f', 'edit': 'lrv-f'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1246,7 +1250,31 @@ class String(Type):
 | 
				
			||||||
                        type='warning')
 | 
					                        type='warning')
 | 
				
			||||||
        Type.store(self, obj, value)
 | 
					        Type.store(self, obj, value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getDiffValue(self, obj, value):
 | 
				
			||||||
 | 
					        '''Returns a version of p_value that includes the cumulative diffs
 | 
				
			||||||
 | 
					           between  successive versions.'''
 | 
				
			||||||
 | 
					        res = None
 | 
				
			||||||
 | 
					        lastEvent = None
 | 
				
			||||||
 | 
					        for event in obj.workflow_history.values()[0]:
 | 
				
			||||||
 | 
					            if event['action'] != '_datachange_': continue
 | 
				
			||||||
 | 
					            if self.name not in event['changes']: continue
 | 
				
			||||||
 | 
					            if res == None:
 | 
				
			||||||
 | 
					                # We have found the first version of the field
 | 
				
			||||||
 | 
					                res = event['changes'][self.name][0] or ''
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                # We need to produce the difference between current result and
 | 
				
			||||||
 | 
					                # this version.
 | 
				
			||||||
 | 
					                iMsg, dMsg = obj.getHistoryTexts(lastEvent)
 | 
				
			||||||
 | 
					                thisVersion = event['changes'][self.name][0] or ''
 | 
				
			||||||
 | 
					                comparator = HtmlDiff(res, thisVersion, iMsg, dMsg)
 | 
				
			||||||
 | 
					                res = comparator.get()
 | 
				
			||||||
 | 
					            lastEvent = event
 | 
				
			||||||
 | 
					        # Now we need to compare the result with the current version.
 | 
				
			||||||
 | 
					        iMsg, dMsg = obj.getHistoryTexts(lastEvent)
 | 
				
			||||||
 | 
					        comparator = HtmlDiff(res, value or '', iMsg, dMsg)
 | 
				
			||||||
 | 
					        return comparator.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        if self.isEmptyValue(value): return ''
 | 
					        if self.isEmptyValue(value): return ''
 | 
				
			||||||
        res = value
 | 
					        res = value
 | 
				
			||||||
        if self.isSelect:
 | 
					        if self.isSelect:
 | 
				
			||||||
| 
						 | 
					@ -1265,6 +1293,9 @@ class String(Type):
 | 
				
			||||||
                    res = [t('%s_list_%s' % (self.labelId, v)) for v in value]
 | 
					                    res = [t('%s_list_%s' % (self.labelId, v)) for v in value]
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    res = t('%s_list_%s' % (self.labelId, value))
 | 
					                    res = t('%s_list_%s' % (self.labelId, value))
 | 
				
			||||||
 | 
					        elif (self.format == String.XHTML) and showChanges:
 | 
				
			||||||
 | 
					            # Compute the successive changes that occurred on p_value.
 | 
				
			||||||
 | 
					            res = self.getDiffValue(obj, res)
 | 
				
			||||||
        # If value starts with a carriage return, add a space; else, it will
 | 
					        # If value starts with a carriage return, add a space; else, it will
 | 
				
			||||||
        # be ignored.
 | 
					        # be ignored.
 | 
				
			||||||
        if isinstance(res, basestring) and \
 | 
					        if isinstance(res, basestring) and \
 | 
				
			||||||
| 
						 | 
					@ -1477,7 +1508,7 @@ class Boolean(Type):
 | 
				
			||||||
        if value == None: return False
 | 
					        if value == None: return False
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        if value: res = obj.translate('yes')
 | 
					        if value: res = obj.translate('yes')
 | 
				
			||||||
        else:     res = obj.translate('no')
 | 
					        else:     res = obj.translate('no')
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
| 
						 | 
					@ -1542,7 +1573,7 @@ class Date(Type):
 | 
				
			||||||
        except DateTime.DateError, ValueError:
 | 
					        except DateTime.DateError, ValueError:
 | 
				
			||||||
            return obj.translate('bad_date')
 | 
					            return obj.translate('bad_date')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        if self.isEmptyValue(value): return ''
 | 
					        if self.isEmptyValue(value): return ''
 | 
				
			||||||
        tool = obj.getTool().appy()
 | 
					        tool = obj.getTool().appy()
 | 
				
			||||||
        # A problem may occur with some extreme year values. Replace the "year"
 | 
					        # A problem may occur with some extreme year values. Replace the "year"
 | 
				
			||||||
| 
						 | 
					@ -1621,7 +1652,7 @@ class File(Type):
 | 
				
			||||||
        if value: value = FileWrapper(value)
 | 
					        if value: value = FileWrapper(value)
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        if not value: return value
 | 
					        if not value: return value
 | 
				
			||||||
        return value._zopeFile
 | 
					        return value._zopeFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1901,7 +1932,7 @@ class Ref(Type):
 | 
				
			||||||
        if someObjects: return res
 | 
					        if someObjects: return res
 | 
				
			||||||
        return res.objects
 | 
					        return res.objects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getIndexType(self): return 'ListIndex'
 | 
					    def getIndexType(self): return 'ListIndex'
 | 
				
			||||||
| 
						 | 
					@ -2142,7 +2173,7 @@ class Computed(Type):
 | 
				
			||||||
            # self.method is a method that will return the field value
 | 
					            # self.method is a method that will return the field value
 | 
				
			||||||
            return self.callMethod(obj, self.method, raiseOnError=True)
 | 
					            return self.callMethod(obj, self.method, raiseOnError=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value, showChanges=False):
 | 
				
			||||||
        if not isinstance(value, basestring): return str(value)
 | 
					        if not isinstance(value, basestring): return str(value)
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -514,10 +514,10 @@ class BaseMixin:
 | 
				
			||||||
            listType = self.getAppyType(listName)
 | 
					            listType = self.getAppyType(listName)
 | 
				
			||||||
            return listType.getInnerValue(outerValue, name, int(i))
 | 
					            return listType.getInnerValue(outerValue, name, int(i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedFieldValue(self, name, value):
 | 
					    def getFormattedFieldValue(self, name, value, showChanges):
 | 
				
			||||||
        '''Gets a nice, string representation of p_value which is a value from
 | 
					        '''Gets a nice, string representation of p_value which is a value from
 | 
				
			||||||
           field named p_name.'''
 | 
					           field named p_name.'''
 | 
				
			||||||
        return self.getAppyType(name).getFormattedValue(self, value)
 | 
					        return self.getAppyType(name).getFormattedValue(self,value,showChanges)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getRequestFieldValue(self, name):
 | 
					    def getRequestFieldValue(self, name):
 | 
				
			||||||
        '''Gets the value of field p_name as may be present in the request.'''
 | 
					        '''Gets the value of field p_name as may be present in the request.'''
 | 
				
			||||||
| 
						 | 
					@ -991,15 +991,6 @@ class BaseMixin:
 | 
				
			||||||
            return 1
 | 
					            return 1
 | 
				
			||||||
        return 0
 | 
					        return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def hasHistory(self):
 | 
					 | 
				
			||||||
        '''Has this object an history?'''
 | 
					 | 
				
			||||||
        if hasattr(self.aq_base, 'workflow_history') and self.workflow_history:
 | 
					 | 
				
			||||||
            key = self.workflow_history.keys()[0]
 | 
					 | 
				
			||||||
            for event in self.workflow_history[key]:
 | 
					 | 
				
			||||||
                if event['action'] and (event['comments'] != '_invisible_'):
 | 
					 | 
				
			||||||
                    return True
 | 
					 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def findNewValue(self, field, history, stopIndex):
 | 
					    def findNewValue(self, field, history, stopIndex):
 | 
				
			||||||
        '''This function tries to find a more recent version of value of p_field
 | 
					        '''This function tries to find a more recent version of value of p_field
 | 
				
			||||||
           on p_self. It first tries to find it in history[:stopIndex+1]. If
 | 
					           on p_self. It first tries to find it in history[:stopIndex+1]. If
 | 
				
			||||||
| 
						 | 
					@ -1027,6 +1018,20 @@ class BaseMixin:
 | 
				
			||||||
            res.append(msg.encode('utf-8'))
 | 
					            res.append(msg.encode('utf-8'))
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def hasHistory(self, fieldName=None):
 | 
				
			||||||
 | 
					        '''Has this object an history? If p_fieldName is specified, the question
 | 
				
			||||||
 | 
					           becomes: has this object an history for field p_fieldName?'''
 | 
				
			||||||
 | 
					        if hasattr(self.aq_base, 'workflow_history') and self.workflow_history:
 | 
				
			||||||
 | 
					            history = self.workflow_history.values()[0]
 | 
				
			||||||
 | 
					            if not fieldName:
 | 
				
			||||||
 | 
					                for event in history:
 | 
				
			||||||
 | 
					                    if event['action'] and (event['comments'] != '_invisible_'):
 | 
				
			||||||
 | 
					                        return True
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                for event in history:
 | 
				
			||||||
 | 
					                    if (event['action'] == '_datachange_') and \
 | 
				
			||||||
 | 
					                       (fieldName in event['changes']): return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getHistory(self, startNumber=0, reverse=True, includeInvisible=False,
 | 
					    def getHistory(self, startNumber=0, reverse=True, includeInvisible=False,
 | 
				
			||||||
                   batchSize=5):
 | 
					                   batchSize=5):
 | 
				
			||||||
        '''Returns the history for this object, sorted in reverse order (most
 | 
					        '''Returns the history for this object, sorted in reverse order (most
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,6 +198,8 @@ appyLabels = [
 | 
				
			||||||
 ('del_next_events', 'Also delete successive events of the same type.'),
 | 
					 ('del_next_events', 'Also delete successive events of the same type.'),
 | 
				
			||||||
 ('history_insert', 'Inserted by ${userName}'),
 | 
					 ('history_insert', 'Inserted by ${userName}'),
 | 
				
			||||||
 ('history_delete', 'Deleted by ${userName}'),
 | 
					 ('history_delete', 'Deleted by ${userName}'),
 | 
				
			||||||
 | 
					 ('changes_show', 'Show changes'),
 | 
				
			||||||
 | 
					 ('changes_hide', 'Hide changes'),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Some default values for labels whose ids are not fixed (so they can't be
 | 
					# Some default values for labels whose ids are not fixed (so they can't be
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -192,6 +192,14 @@ function askComputedField(hookId, objectUrl, fieldName) {
 | 
				
			||||||
  askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/computed', 'viewContent', params);
 | 
					  askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/computed', 'viewContent', params);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function askField(hookId, objectUrl, layoutType, showChanges){
 | 
				
			||||||
 | 
					  // Sends an Ajax request for getting the content of any field.
 | 
				
			||||||
 | 
					  var fieldName = hookId.split('_')[1];
 | 
				
			||||||
 | 
					  var params = {'fieldName': fieldName, 'layoutType': layoutType,
 | 
				
			||||||
 | 
					                'showChanges': showChanges};
 | 
				
			||||||
 | 
					  askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/show', 'fieldAjax', 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) {
 | 
				
			||||||
  vis = document.getElementById(visibleCheckbox);
 | 
					  vis = document.getElementById(visibleCheckbox);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,7 +73,7 @@
 | 
				
			||||||
<metal:history define-macro="objectHistory"
 | 
					<metal:history define-macro="objectHistory"
 | 
				
			||||||
      tal:define="startNumber request/startNumber|python:0;
 | 
					      tal:define="startNumber request/startNumber|python:0;
 | 
				
			||||||
                  startNumber python: int(startNumber);
 | 
					                  startNumber python: int(startNumber);
 | 
				
			||||||
                  batchSize   python: int(request.get('maxPerPage'));
 | 
					                  batchSize   python: int(request.get('maxPerPage', 5));
 | 
				
			||||||
                  historyInfo python: contextObj.getHistory(startNumber, batchSize=batchSize);
 | 
					                  historyInfo python: contextObj.getHistory(startNumber, batchSize=batchSize);
 | 
				
			||||||
                  objs        historyInfo/events;
 | 
					                  objs        historyInfo/events;
 | 
				
			||||||
                  totalNumber historyInfo/totalNumber;
 | 
					                  totalNumber historyInfo/totalNumber;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,11 +5,12 @@
 | 
				
			||||||
    layoutType         The kind of layout: "view"? "edit"? "cell"?
 | 
					    layoutType         The kind of layout: "view"? "edit"? "cell"?
 | 
				
			||||||
    layout             The layout object that will dictate how object content
 | 
					    layout             The layout object that will dictate how object content
 | 
				
			||||||
                       will be rendered.
 | 
					                       will be rendered.
 | 
				
			||||||
 | 
					    tagId              The ID of the main tag for this layout.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Options:
 | 
					  Options:
 | 
				
			||||||
    contextMacro       The base folder containing the macros to call for
 | 
					    contextMacro       The base folder containing the macros to call for
 | 
				
			||||||
                       rendering the elements within the layout.
 | 
					                       rendering the elements within the layout.
 | 
				
			||||||
                       Defaults to app.ui
 | 
					                       Defaults to app.ui
 | 
				
			||||||
    tagId              The ID of the main tag for this layout.
 | 
					 | 
				
			||||||
    tagName            The name of the main tag for this layout (used
 | 
					    tagName            The name of the main tag for this layout (used
 | 
				
			||||||
                       a.o. for master/slave relationships).
 | 
					                       a.o. for master/slave relationships).
 | 
				
			||||||
    tagCss             Some additional CSS class for the main tag
 | 
					    tagCss             Some additional CSS class for the main tag
 | 
				
			||||||
| 
						 | 
					@ -59,15 +60,19 @@
 | 
				
			||||||
  Optionally:
 | 
					  Optionally:
 | 
				
			||||||
    widgetName         If the field to show is within a List, we cheat and
 | 
					    widgetName         If the field to show is within a List, we cheat and
 | 
				
			||||||
                       include, within the widgetName, the row index.
 | 
					                       include, within the widgetName, the row index.
 | 
				
			||||||
 | 
					    showChanges        Do we need to show a variant of the field showing
 | 
				
			||||||
 | 
					                       successive changes made to it?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</tal:comment>
 | 
					</tal:comment>
 | 
				
			||||||
<metal:field define-macro="field"
 | 
					<metal:field define-macro="field"
 | 
				
			||||||
  tal:define="contextMacro python: app.ui.widgets;
 | 
					  tal:define="contextMacro python: app.ui.widgets;
 | 
				
			||||||
 | 
					              showChanges  showChanges| python:False;
 | 
				
			||||||
              layout       python: widget['layouts'][layoutType];
 | 
					              layout       python: widget['layouts'][layoutType];
 | 
				
			||||||
              name         widgetName| widget/name;
 | 
					              name         widgetName| widget/name;
 | 
				
			||||||
              sync         python: widget['sync'][layoutType];
 | 
					              sync         python: widget['sync'][layoutType];
 | 
				
			||||||
              outerValue   value|nothing;
 | 
					              outerValue   value|nothing;
 | 
				
			||||||
              rawValue     python: contextObj.getFieldValue(name,onlyIfSync=True,layoutType=layoutType,outerValue=outerValue);
 | 
					              rawValue     python: contextObj.getFieldValue(name,onlyIfSync=True,layoutType=layoutType,outerValue=outerValue);
 | 
				
			||||||
              value        python: contextObj.getFormattedFieldValue(name, rawValue);
 | 
					              value        python: contextObj.getFormattedFieldValue(name, rawValue, showChanges);
 | 
				
			||||||
              requestValue python: contextObj.getRequestFieldValue(name);
 | 
					              requestValue python: contextObj.getRequestFieldValue(name);
 | 
				
			||||||
              inRequest    python: request.has_key(name);
 | 
					              inRequest    python: request.has_key(name);
 | 
				
			||||||
              errors       errors | python: ();
 | 
					              errors       errors | python: ();
 | 
				
			||||||
| 
						 | 
					@ -78,10 +83,20 @@
 | 
				
			||||||
              tagCss       tagCss | python:'';
 | 
					              tagCss       tagCss | python:'';
 | 
				
			||||||
              tagCss       python: ('%s %s' % (slaveCss, tagCss)).strip();
 | 
					              tagCss       python: ('%s %s' % (slaveCss, tagCss)).strip();
 | 
				
			||||||
              tagId        python: '%s_%s' % (contextObj.UID(), name);
 | 
					              tagId        python: '%s_%s' % (contextObj.UID(), name);
 | 
				
			||||||
              tagName      python: widget['master'] and 'slave' or ''">
 | 
					              tagName      python: widget['master'] and 'slave' or '';">
 | 
				
			||||||
  <metal:layout use-macro="context/ui/widgets/show/macros/layout"/>
 | 
					  <metal:layout use-macro="context/ui/widgets/show/macros/layout"/>
 | 
				
			||||||
</metal:field>
 | 
					</metal:field>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Call the previous macro, but from Ajax.</tal:comment>
 | 
				
			||||||
 | 
					<metal:afield define-macro="fieldAjax"
 | 
				
			||||||
 | 
					             tal:define="widgetName request/fieldName;
 | 
				
			||||||
 | 
					                         layoutType request/layoutType;
 | 
				
			||||||
 | 
					                         showChanges python: request.get('showChanges', 'False') == 'True';
 | 
				
			||||||
 | 
					                         widget python: contextObj.getAppyType(widgetName, asDict=True);
 | 
				
			||||||
 | 
					                         page widget/pageName">
 | 
				
			||||||
 | 
					 <metal:field use-macro="context/ui/widgets/show/macros/field"/>
 | 
				
			||||||
 | 
					</metal:afield>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<tal:comment replace="nothing">
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
  This macro displays the widget corresponding to a group of widgets.
 | 
					  This macro displays the widget corresponding to a group of widgets.
 | 
				
			||||||
  It requires:
 | 
					  It requires:
 | 
				
			||||||
| 
						 | 
					@ -223,4 +238,4 @@
 | 
				
			||||||
<tal:required metal:define-macro="required"><img tal:attributes="src string: $appUrl/ui/required.gif"/></tal:required>
 | 
					<tal:required metal:define-macro="required"><img tal:attributes="src string: $appUrl/ui/required.gif"/></tal:required>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<tal:comment replace="nothing">Button for showing changes to the field.</tal:comment>
 | 
					<tal:comment replace="nothing">Button for showing changes to the field.</tal:comment>
 | 
				
			||||||
<tal:changes metal:define-macro="changes"><img tal:attributes="src string: $appUrl/ui/changes.png"/></tal:changes>
 | 
					<tal:changes metal:define-macro="changes" tal:condition="python: contextObj.hasHistory(name)"><img style="cursor:pointer" tal:condition="not: showChanges" tal:attributes="src string: $appUrl/ui/changes.png; onclick python: 'askField(\'%s\',\'%s\',\'view\',\'True\')' % (tagId, contextObj.absolute_url()); title python: _('changes_show')"/><img style="cursor:pointer" tal:condition="showChanges" tal:attributes="src string: $appUrl/ui/changesNo.png; onclick python: 'askField(\'%s\',\'%s\',\'view\',\'False\')' % (tagId, contextObj.absolute_url()); title python: _('changes_hide')"/></tal:changes>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue