class FormBoxWidget(Widget.Widget): """ A widget that display a form within a form. A first purpose of this widget is to display addresses in a different order for every localisation. A second purpose of this widget is to represent a single value (ex. a number, a date) into multiple forms. We need for that purpose a script to assemble a value out of A third purpose is to display values on subobjects and, if necessary, create such objects ? WARNING: this is still pre-alpha code for experimentation. Do not use in production. """ property_names = Widget.Widget.property_names + [ 'formbox_target_id', \ 'context_method_id', \ ] # This name was changed to prevent naming collision with ProxyField formbox_target_id = fields.StringField( 'formbox_target_id', title='Form ID', description=("ID of the form which must be rendered in this box."), default="", required=0) context_method_id = fields.StringField( 'context_method_id', title='Context method ID', description=("ID of the method that returns a context for this box."), default="", required=0) default = fields.StringField('default', title='Default', description=("A default value (not used)."), default="", required=0) def render_view(self, field, value, REQUEST, render_prefix=None): """ Render a view form in a field """ return self.render(field, None, value, REQUEST, render_prefix) def render(self, field, key, value, REQUEST, render_prefix=None): """ Render a form in a field """ target_id = field.get_value('formbox_target_id') if target_id: with getFormBoxContext(field, REQUEST) as context: return getattr(context, target_id)(REQUEST=REQUEST, key_prefix=key) return ''
class FormBoxWidget(Widget.Widget): """ A widget that display a form within a form. A first purpose of this widget is to display addresses in a different order for every localisation. A second purpose of this widget is to represent a single value (ex. a number, a date) into multiple forms. We need for that purpose a script to assemble a value out of A third purpose is to display values on subobjects and, if necessary, create such objects ? WARNING: this is still pre-alpha code for experimentation. Do not use in production. """ property_names = Widget.Widget.property_names + [ 'formbox_target_id', \ ] # This name was changed to prevent naming collision with ProxyField formbox_target_id = fields.StringField( 'formbox_target_id', title='Form ID', description=("ID of the form which must be rendered in this box."), default="", required=0) default = fields.StringField('default', title='Default', description=("A default value (not used)."), default="", required=0) def render(self, field, key, value, REQUEST, render_prefix=None): """ Render a form in a field """ here = REQUEST['here'] # If 'cell' is not defined, we define 'cell' just same as 'here', so # that we can use the same formbox for both ListBox and non-ListBox # using 'cell' parameter. if not REQUEST.has_key('cell'): REQUEST.set('cell', here) result = '' target_id = field.get_value('formbox_target_id') if target_id not in (None, ''): try: form = getattr(here, target_id) except AttributeError: LOG('FormBox', WARNING, 'Could not get a form from formbox %s in %s' % \ (field.id, field.aq_parent.id)) else: result = form(REQUEST=REQUEST, key_prefix=key) return result
class GadgetWidget(Widget.Widget): """ A widget that displays a renderjs gadget """ property_names = Widget.Widget.property_names + \ ['gadget_url', 'js_sandbox', 'extra', 'renderjs_extra'] default = Widget.TextWidget.default renderjs_extra = fields.ListTextAreaField('renderjs_extra', title="RenderJS extra", description=( "More parameters passed to the renderJS's render method."), default=[], required=0) gadget_url = fields.StringField('gadget_url', title='Gadget Url', description=("The url of the html page containing the \ gadget"), default='', required=0) js_sandbox = fields.StringField('js_sandbox', title='Gadget Sandbox', description=("Gadget sandbox"), default='', required=0) def render(self, field, key, value, REQUEST, render_prefix=None): return self.render_view(field, value, REQUEST, render_prefix, key) def render_view(self, field, value, REQUEST=None, render_prefix=None, key=None): kw = { 'data-gadget-sandbox': field.get_value('js_sandbox'), 'data-gadget-url': field.get_value('gadget_url'), 'data-gadget-value': value, 'data-gadget-renderjs-extra': dumps(dict(field.get_value('renderjs_extra'))) } if key is not None: kw['data-gadget-editable'] = key return Widget.render_element("div", extra=field.get_value('extra'), **kw) def get_javascript_list(self, field, REQUEST=None): """ Returns list of javascript needed by the widget """ js_list = ['rsvp.js', 'renderjs.js', 'erp5_gadgetfield.js'] result = [] try: for js_file in js_list: result.append(field.restrictedTraverse(js_file).absolute_url()) except KeyError: LOG('keyError:', ERROR, 'Error Value: %s' % js_file) return [] return result
class InputButtonWidget(Widget.Widget): """ InputButton widget Displays an input button. """ property_names = Widget.Widget.property_names + ['name', 'extra', 'image'] default = fields.StringField( 'default', title='Button text', description= ("You can place text here that will be used as the value (button text)" ), default="Submit", required=1) name = fields.StringField('name', title='Name', description=("The Name of the submit button."), default='', required=0) css_class = fields.StringField( 'css_class', title='CSS class', description=( "The CSS class of the field. This can be used to style your " "formulator fields using cascading style sheets. Not required."), default="hidden_label", required=0) image = fields.StringField( 'image', title='Image', description=("The image of the button (if any)."), default='', required=0) def render(self, field, key, value, REQUEST, render_prefix=None): """Render input button. """ render_kw = { 'name': field.get_value('name'), 'css_class': field.get_value('css_class'), 'value': field.get_value('default'), 'extra': field.get_value('extra') } image = field.get_value('image') if image: html_type = "image" render_kw['src'] = image else: html_type = "submit" return Widget.render_element('input', type=html_type, **render_kw)
class ProxyWidget(Widget.Widget): """ A widget that renders itself as a field from another form after changing its title and id. It is recommended to define a master form on which complex fields with a lot of TALES are defined in order to minimize code duplication. """ property_names = [ 'form_id', 'field_id', 'target', ] form_id = fields.StringField( 'form_id', title='Form ID', description= \ "ID of the master form.", default="", required=1) field_id = fields.StringField( 'field_id', title='Field ID', description= \ "ID of the field in the master form.", default="", required=1) target = fields.HyperLinkField( 'target', title='Proxy Target', description="Link to the master field edit form", default='Click to edit the target', href='manage_edit_target', required=0) # Field API Methods, delegated to the template field widget render = WidgetDelegatedMethod('render', default='') render_htmlgrid = WidgetDelegatedMethod('render_htmlgrid', default='') render_view = WidgetDelegatedMethod('render_view', default='') render_pdf = WidgetDelegatedMethod('render_pdf', default='') render_css = WidgetDelegatedMethod('render_css', default='') render_dict = WidgetDelegatedMethod('render_dict', default=None) render_odf = WidgetDelegatedMethod('render_odf', default='') render_odt = WidgetDelegatedMethod('render_odt', default=None) render_odt_view = WidgetDelegatedMethod('render_odt_view', default=None) render_odt_variable = WidgetDelegatedMethod('render_odt_variable', default=None) render_odg = WidgetDelegatedMethod('render_odg', default=None) get_javascript_list = WidgetDelegatedMethod('get_javascript_list', default=[])
class GadgetWidget(Widget.TextWidget): """ A widget that displays a renderjs gadget """ property_names = Widget.TextWidget.property_names + \ ['gadget_url', 'js_sandbox'] gadget_url = fields.StringField( 'gadget_url', title='Gadget Url', description=("The url of the html page containing the \ gadget"), default='', required=0) js_sandbox = fields.StringField('js_sandbox', title='Gadget Sandbox', description=("Gadget sandbox"), default='', required=0) def render(self, field, key, value, REQUEST, render_prefix=None): return self.render_view(field, value, REQUEST, render_prefix, key) def render_view(self, field, value, REQUEST=None, render_prefix=None, key=None): kw = {} kw['data-gadget-url'] = field.get_value('gadget_url') kw['data-gadget-scope'] = field.id if key is not None: kw['data-gadget-editable'] = key kw['class'] = "gadget" kw['data-gadget-value'] = value kw['data-gadget-sandbox'] = field.get_value('js_sandbox') return Widget.render_element("div", **kw) def get_javascript_list(self, field, REQUEST=None): """ Returns list of javascript needed by the widget """ js_list = ['rsvp.js', 'renderjs.js', 'erp5_gadgetfield.js'] result = [] try: for js_file in js_list: result.append(field.restrictedTraverse(js_file).absolute_url()) except KeyError: LOG('keyError:', ERROR, 'Error Value: %s' % js_file) return [] return result
class PatternValidator(StringValidator): # does the real work checker = PatternChecker.PatternChecker() property_names = StringValidator.property_names + ['pattern'] message_names = StringValidator.message_names + ['pattern_not_matched'] pattern = fields.StringField( 'pattern', title="Pattern", required=1, default="", description=( "The pattern the value should conform to. Patterns are " "composed of digits ('d'), alphabetic characters ('e') and " "alphanumeric characters ('f'). Any other character in the pattern " "should appear literally in the value in that place. Internal " "whitespace is checked as well but may be included in any amount. " "Example: 'dddd ee' is a Dutch zipcode (postcode). ")) pattern_not_matched = _("The entered value did not match the pattern.") def check(self, field, value, failover=False): value = StringValidator.check(self, field, value, failover) if not failover and value: result = self.checker.validate_value([field.get_value('pattern')], value) if result is None: self.raise_error('pattern_not_matched', field) return result return value
class TextWidget(Widget): """Text widget """ property_names = Widget.property_names +\ ['display_width', 'display_maxwidth', 'extra'] default = fields.StringField( 'default', title='Default', description=( "You can place text here that will be used as the default " "value of the field, unless the programmer supplies an override " "when the form is being generated."), default="", required=0) display_width = fields.IntegerField( 'display_width', title='Display width', description=("The width in characters. Required."), default=20, required=1) display_maxwidth = fields.IntegerField( 'display_maxwidth', title='Maximum input', description=( "The maximum input in characters that the widget will allow. " "Required. If set to 0 or is left empty, there is no maximum. " "Note that is client side behavior only."), default="", required=0) def render(self, field, key, value, REQUEST): """Render text input field. """ extra = field.get_value('extra') css_class = field.get_value('css_class') kw = { 'type': "text", 'name': key, 'css_class': css_class, 'value': value, 'size': field.get_value('display_width'), 'extra': extra } if not extra or not id_value_re.search(extra): kw['id'] = field.generate_field_html_id(key) display_maxwidth = field.get_value('display_maxwidth') or 0 if display_maxwidth > 0: kw['maxlength'] = display_maxwidth contents = render_element("input", **kw) return render_element("div", contents=contents, css_class=css_class) def render_view(self, field, value): return render_value(value)
class ReportBoxWidget(Widget.Widget): property_names = list(Widget.Widget.property_names) property_names.append('report_method') # XXX this is only needed on bootstrap default = fields.StringField('default', title='Default', description="", default="", required=0) report_method = fields.StringField('report_method', title='Report Method', description="", default="", required=0) def render_view(self, field, value, REQUEST=None, key='reportbox', render_prefix=None): """ """ if REQUEST is None: REQUEST = get_request() return self.render(field, key, value, REQUEST) def render(self, field, key, value, REQUEST, render_prefix=None): """ """ form = getattr(field, 'aq_parent', None) if form is not None: obj = getattr(form, 'aq_parent', None) else: obj = None if obj is not None: report_method = guarded_getattr(obj, field['report_method']) if callable(report_method): return report_method()
def create_settings_form(): form = Form_create_settings_form() report_method = fields.StringField( 'report_method', title='Report Method', description=('The method to get a list of items (object, form,' ' parameters) to aggregate in a single Report'), default='', required=0) form.add_fields([report_method]) return form
class FormBoxValidator(Validator.Validator): """ Validate all fields of the form and return the result as a single variable. """ validator_form_field_prefix = fields.StringField( 'validator_form_field_prefix', title='Validator Form Field Prefix', description= "Field prefix value used when validating fields", default="my_", display_width=40, required=1 ) property_names = Validator.Validator.property_names + \ ['validator_form_field_prefix'] message_names = Validator.Validator.message_names + \ ['form_invalidated', 'required_not_found'] form_invalidated = "Form invalidated." required_not_found = 'Input is required but no input given.' def validate(self, field, key, REQUEST): # TODO: Handle 'cell' for validation inside listboxes, # like it is done for rendering. formbox_target_id = field.get_value('formbox_target_id') if not formbox_target_id: return None # Get current error fields current_field_errors = REQUEST.get('field_errors', []) with getFormBoxContext(field, REQUEST) as here: # XXX Hardcode script name result, result_type = here.Base_edit(formbox_target_id, silent_mode=1, key_prefix=key, field_prefix=field.get_value('validator_form_field_prefix')) if result_type == 'edit': return FormBoxEditor(result, here) elif result_type == 'form': formbox_field_errors = REQUEST.get('field_errors', []) current_field_errors.extend(formbox_field_errors) REQUEST.set('field_errors', current_field_errors) getattr(here, formbox_target_id).validate_all_to_request(REQUEST, key_prefix=key) else: raise NotImplementedError(result_type)
class ItemsWidget(Widget): """A widget that has a number of items in it. """ items = fields.ListTextAreaField( 'items', title='Items', description= ("Items in the field. Each row should contain an " "item. Use the | (pipe) character to separate what is shown " "to the user from the submitted value. If no | is supplied, the " "shown value for the item will be identical to the submitted value. " "Internally the items property returns a list. If a list item " "is a single value, that will be used for both the display and " "the submitted value. A list item can also be a tuple consisting " "of two elements. The first element of the tuple should be a string " "that is name of the item that should be displayed. The second " "element of the tuple should be the value that will be submitted. " "If you want to override this property you will therefore have " "to return such a list."), default=[], width=20, height=5, required=0) # NOTE: for ordering reasons (we want extra at the end), # this isn't in the base class property_names list, but # instead will be referred to by the subclasses. extra_item = fields.StringField( 'extra_item', title='Extra per item', description= ("A string containing extra HTML code for attributes. This " "string will be literally included each of the rendered items of the " "field. This property can be useful if you want " "to add a disabled attribute to disable all contained items, for " "instance."), default="", required=0)
class LinesTextAreaWidget(TextAreaWidget): property_names = Widget.property_names +\ ['width', 'height', 'view_separator', 'extra'] default = fields.LinesField( 'default', title='Default', description=("Default value of the lines in the widget."), default=[], width=20, height=3, required=0) view_separator = fields.StringField( 'view_separator', title='View separator', description=( "When called with render_view, this separator will be used to " "render individual items."), width=20, default='<br />\n', whitespace_preserve=1, required=1) def render(self, field, key, value, REQUEST): if is_sequence(value): value = string.join(value, "\n") return TextAreaWidget.render(self, field, key, value, REQUEST) def render_view(self, field, value): return render_value(value, field.get_value('view_separator')) def render_hidden(self, field, key, value, REQUEST): if value is None: return '' if is_sequence(value): value = '\n'.join(value) # reuse method from base class return Widget.render_hidden(self, field, key, value, REQUEST)
def create_settings_form(): """Create settings form for ZMIForm. """ form = BasicForm('manage_settings') title = fields.StringField('title', title="Title", required=0, default="") description = fields.TextAreaField('description', title="Description", required=0, default="") row_length = fields.IntegerField('row_length', title='Number of groups in row (in order tab)', required=1, default=4) name = fields.StringField('name', title="Form name", required=0, default="") pt = fields.StringField('pt', title="Page Template", required=0, default="") action = fields.StringField('action', title='Form action', required=0, default="") update_action = fields.StringField('update_action', title='Form update action', required=0, default="") update_action_title = fields.StringField('update_action_title', title="Update Action Title", required=0, default="") method = fields.ListField('method', title='Form method', items=[('POST', 'POST'), ('GET', 'GET')], required=1, size=1, default='POST') enctype = fields.ListField('enctype', title='Form enctype', items=[('No enctype', ""), ('application/x-www-form-urlencoded', 'application/x-www-form-urlencoded'), ('multipart/form-data', 'multipart/form-data')], required=0, size=1, default=None) encoding = fields.StringField('encoding', title='Encoding of pages the form is in', default="UTF-8", required=1) stored_encoding = fields.StringField('stored_encoding', title='Encoding of form properties', default='UTF-8', required=1) unicode_mode = fields.CheckBoxField('unicode_mode', title='Form properties are unicode', default=0, required=1) edit_order = fields.LinesField('edit_order', title='Setters for these properties should be' '<br /> called by edit() in the defined order') form.add_fields([title, description, row_length, name, pt, action, update_action, update_action_title, method, enctype, encoding, stored_encoding, unicode_mode, edit_order]) return form
def getExtraPropertyList(self): return [ fields.StringField(**self._dynamic_property_list[0]), fields.PasswordField(**self._dynamic_property_list[1]), fields.CheckBoxField(**self._dynamic_property_list[2]) ]
class MultiItemsWidget(ItemsWidget): """A widget with a number of items that has multiple selectable items. """ default = fields.LinesField( 'default', title='Default', description=( "The initial selections of the widget. This is a list of " "zero or more values. If you override this property from Python " "your code should return a Python list."), width=20, height=3, default=[], required=0) view_separator = fields.StringField( 'view_separator', title='View separator', description=( "When called with render_view, this separator will be used to " "render individual items."), width=20, default='<br />\n', whitespace_preserve=1, required=1) def render_items(self, field, key, value, REQUEST): # need to deal with single item selects if not is_sequence(value): value = [value] items = field.get_value('items') css_class = field.get_value('css_class') extra_item = field.get_value('extra_item') field_html_id = field.generate_field_html_id(key) index = 0 rendered_items = [] for item in items: index += 1 if is_sequence(item): item_text, item_value = item else: item_text = item item_value = item if item_value in value: rendered_item = self.render_selected_item( item_text, item_value, key, css_class, extra_item, field_html_id + str(index)) else: rendered_item = self.render_item(item_text, item_value, key, css_class, extra_item, field_html_id + str(index)) rendered_items.append(rendered_item) return rendered_items def render_items_view(self, field, value): if not is_sequence(value): value = [value] items = field.get_value('items') d = {} for item in items: if is_sequence(item): item_text, item_value = item else: item_text = item item_value = item d[item_value] = item_text result = [] for e in value: result.append(d[e]) return result def render_view(self, field, value): if value is None: return '' return render_value(self.render_items_view(field, value), field.get_value('view_separator')) def render_hidden(self, field, key, value, REQUEST): if value is not None and not is_sequence(value): value = [value] # reuse method from base class render_item_hidden = Widget.render_hidden result = [] for v in value: result.append(render_item_hidden(self, field, key, v, REQUEST)) return ''.join(result)
class POSBoxWidget(Widget.Widget): """ A widget that display a point of sales UI. """ property_names = Widget.Widget.property_names + [ 'html_ZPT', \ 'javascript_ZPT', \ 'css_ZPT', \ 'getResourceByReference_ZPT', \ 'createOrder_script', \ 'portal_types', \ 'display_fastResourceEntry', \ 'portal_type_fastResourceEntry', \ 'resource_category_fastResourceEntry', \ 'barcodeStartString', \ 'pos_layout', \ 'barcodeStopString', \ 'display_bgcolor', \ 'display_txtcolor', \ 'order_summary_aLine', \ 'order_summary_anotherLine' ] default = fields.StringField( 'default', title='Default', description=( "Default value of the text in the widget."), default="", required=0) html_ZPT = fields.StringField( 'html_ZPT', title='Page Template for HTML', description=( "Page Template for generating POSBox UI HTML"), default="POSBox", required=1) javascript_ZPT = fields.StringField( 'javascript_ZPT', title='Page Template for JavaScript', description=( "Page Template for generating JavaScript's options"), default="POSBox_js", required=1) css_ZPT = fields.StringField( 'css_ZPT', title="Page Template for CSS", description=( "Page Template for generating dynamic CSS"), default="POSBox_css", required=1) getResourceByReference_ZPT = fields.StringField( 'getResourceByReference_ZPT', title="Page Template for generating resource's XML", description=( "Page template which generates the XML of the resource when asking for a referencce"), default="getResourceByReference", required=1) createOrder_script = fields.StringField( 'createOrder_script', title="Python script for creating the order", description=( "Python script which create the order from the XML sended by POS"), default="createOrder", required=1) display_fastResourceEntry = fields.ListField( 'display_fastResourceEntry', title='Display Fast Resource Entry Block', description=( "Is the fast resource entry block displayed ?"), default='False', items=['True', 'False'], size=1, required=1, group="Fast Product Entry") portal_type_fastResourceEntry = fields.StringField( 'portal_type_fastResourceEntry', title='Portal Type of resources', description=( "What is the portal type of resources in fast resource entry block"), default='', required=0, group="Fast Product Entry") portal_types = fields.ListTextAreaField( 'portal_types', title='Portal Types', description=( "The allowed resource to be requested by reference. Required."), default=[], required=1) resource_category_fastResourceEntry = fields.StringField( 'resource_category_fastResourceEntry', title='Top level Resource Category', description=( "The ProductLine that is a the top level of fast resource entry"), default='', required=0, group="Fast Product Entry") pos_layout = fields.ListField( 'pos_layout', title='Layout', description=( "How is the layout organised"), default='', items=[ 'Summary of the order on the left' , 'Summary of the order on the right' , ], size=1, required=1) barcodeStartString = fields.StringField( 'barcodeStartString', title='Barcode Prefix String', description=( "The string which is prefixed by the barcode while reading"), default="#", required=1, group="barcode") barcodeStopString = fields.StringField( 'barcodeStopString', title='Barcode Suffix String', description=( "The string which is prefixed by the barcode while reading"), default="#", required=1, group="barcode") display_bgcolor = fields.StringField( 'display_bgcolor', title='Background color', description=( "Color in html hex format (#000000 by ex.)"), default="#ffffcc", required=0, group="display area") display_txtcolor = fields.StringField( 'display_txtcolor', title='Text color', description=( "Color in html hex format (#000000 by ex.)"), default="#000000", required=0, group="display area") order_summary_aLine = fields.StringField( 'order_summary_aLine', title="Order line background color 1", description=( "Background color of a order line in order summary view"), default="#e3e3e3", required=0, group="order summary") order_summary_anotherLine = fields.StringField( 'order_summary_anotherLine', title="Order line background color 2", description=( "Background color of another order line in order summary view"), default="#ffffff", required=0, group="order summary") def render(self, field, key, value, REQUEST, render_prefix=None): """ Render point of sales widget. """ here = REQUEST['here'] page_template = getattr(here,field.get_value("html_ZPT")) return "<!-- Generated by render -->\n%s" % page_template() def render_css(self, field, key, value, REQUEST): here = REQUEST['here'] page_template = getattr(here,field.get_value("css_ZPT")) return "<!-- Generated by render_css -->\n%s" % page_template( display_txtcolor = field.get_value("display_txtcolor"), display_bgcolor = field.get_value("display_bgcolor"), pos_layout_left = (field.get_value("pos_layout") == 'Summary of the order on the left'), order_summary_aLine = field.get_value("order_summary_aLine"), order_summary_anotherLine = field.get_value("order_summary_anotherLine"), fastResourceEntry_display = field.get_value("display_fastResourceEntry"), ) def render_javascript(self, field, key, value, REQUEST, render_prefix=None): here = REQUEST['here'] page_template = getattr(here,field.get_value("javascript_ZPT")) return "<!-- Generated by render_javascript -->\n%s" % page_template( getResourceByReference_ZPT = field.get_value('getResourceByReference_ZPT'), createOrder_script = field.get_value('createOrder_script'), portal_types = "portal_type:list=" + "&portal_type:list=".join([url_quote_plus(x[0]) for x in field.get_value('portal_types')]), barcodeStartString = field.get_value('barcodeStartString'), barcodeStopString = field.get_value('barcodeStopString'), fastResourceEntry_display = field.get_value("display_fastResourceEntry"), portal_type_fastResourceEntry = field.get_value('portal_type_fastResourceEntry'), resource_category_fastResourceEntry = field.get_value('resource_category_fastResourceEntry') ) def render_view(self, field, value, REQUEST=None, render_prefix=None): """ Render point of sales widget """ return "<p>Generated by render_view</p>"
class VideoWidget(Widget.TextWidget): """ A widget that displays a Video HTML element. This widget is intended to be used in conjunction with WebSite. """ property_names = Widget.TextWidget.property_names + \ ['video_controls', 'video_error_message', 'video_loop', \ 'video_width', 'video_height', 'video_preload', \ 'video_autoplay', 'js_enabled', 'video_player'] video_controls = fields.CheckBoxField( 'video_controls', title='Video Controls', description=("Controls to be used in Video Player."), default=1, required=0) video_error_message = fields.StringField( 'video_error_message', title='Video Error Message', description=("Error message to be showed when \ user's browser does not support the video tag."), default='Your browser does not support video tag.', required=0) video_loop = fields.CheckBoxField( 'video_loop', title='Video Loop', description=("Specifies that the video file \ will start over again, every time it is finished."), default=0, required=0) video_width = fields.IntegerField( 'video_width', title='Video Width', description=("The width to be used when playing the video."), default=160, required=0) video_height = fields.IntegerField( 'video_height', title='Video Height', description=("The height to be used when playing the video."), default=85, required=0) video_preload = fields.CheckBoxField( 'video_preload', title='Video Preload', description=("Configure that you would like to \ start downloading the video file as soon as possible."), default=1, required=0) video_autoplay = fields.CheckBoxField( 'video_autoplay', title='Video Autoplay', description=("Configure that you would like to \ start downloading and playing the video file as soon as possible."), default=0, required=0) js_enabled = fields.CheckBoxField( 'js_enabled', title='Enable on the fly video player change (based on java script)', description= 'Define if javascript is enabled or not on the current Video', default=1, required=0) video_player = fields.ListField( 'video_player', title='Video Player', description=("The video player to be used to show video."), default="html5_video", required=1, size=1, items=[ ('HTML5 Video', 'html5_video'), ('Flowplayer', 'flowplayer'), ]) def render(self, field, key, value, REQUEST, render_prefix=None): return self.render_view(field, value, REQUEST, render_prefix) def render_view(self, field, value, REQUEST=None, render_prefix=None): if value is None: return '' video_player = field.get_value('video_player') if video_player == 'html5_video': extra_kw = {} if field.get_value('video_autoplay'): extra_kw['autoplay'] = 'autoplay' if field.get_value('video_controls'): extra_kw['controls'] = 'controls' if field.get_value('video_loop'): extra_kw['loop'] = 'loop' if field.get_value('video_preload'): extra_kw['preload'] = 'preload' return Widget.render_element( "video", src=value, extra=field.get_value('extra'), width=field.get_value('video_width'), height=field.get_value('video_height'), contents=field.get_value('video_error_message'), **extra_kw) elif video_player == 'flowplayer': a_element = Widget.render_element("a", href="%s" % value, style="display:block;width:%spx;height:%spx;" % \ (field.get_value('video_width'), field.get_value('video_height'),), id="player") script_element = """<script language="JavaScript"> flowplayer("player", "%s/flowplayer.swf"); </script>""" % self.getContext( field, REQUEST).getPortalObject().portal_url() return ' '.join([a_element, script_element]) def get_javascript_list(self, field, REQUEST=None): """ Returns list of javascript needed by the widget """ if field.get_value('js_enabled'): video_player = field.get_value('video_player') context = self.getContext(field, REQUEST) if video_player == 'html5_video': # XXX Instead of harcoding library name # it should be better to call a python script, as # it is done on type base method. return ['%s/html5media.min.js' % context.portal_url()] elif video_player == 'flowplayer': return ['%s/flowplayer.min.js' % context.portal_url()] else: return [] def getContext(self, field, REQUEST): """Return the context of rendering this Field. """ value = REQUEST.get('here') if value is None: value = self.getForm(field).aq_parent return value def getForm(self, field): """Return the form which contains the Field. """ return field.aq_parent
class MultiRelationStringFieldWidget(Widget.LinesTextAreaWidget, Widget.TextWidget, Widget.ListWidget): """ RelationStringField widget Works like a string field but includes one buttons - one search button which updates the field and sets a relation - creates object if not there """ local_property_names = [ 'update_method', 'jump_method', 'allow_jump', 'base_category', 'portal_type', 'allow_creation', 'container_getter_id', 'context_getter_id', 'catalog_index', 'relation_setter_id', 'relation_form_id', 'columns', 'sort', 'parameter_list', 'list_method', 'first_item', 'items', 'proxy_listbox_ids', 'size', 'extra_item', ] property_names = Widget.LinesTextAreaWidget.property_names + \ Widget.TextWidget.property_names + \ local_property_names # XXX Field to remove... update_method = fields.StringField( 'update_method', title='Update Method', description=("The method to call to set the relation. Required."), default="Base_validateRelation", required=1) jump_method = fields.StringField( 'jump_method', title='Jump Method', description=("The method to call to jump to the relation. Required."), default="Base_jumpToRelatedDocument", required=1) allow_jump = fields.CheckBoxField( 'allow_jump', title='Allow Jump', description=("Do we allow to jump to the relation ?"), default=1, required=0) base_category = fields.StringField( 'base_category', title='Base Category', description=("The method to call to set the relation. Required."), default="", required=1) portal_type = fields.ListTextAreaField( 'portal_type', title='Portal Type', description=("The method to call to set the relation. Required."), default="", required=1) allow_creation = fields.CheckBoxField( 'allow_creation', title='Allow Creation', description=("Do we allow to create new objects ?"), default=1, required=0) container_getter_id = fields.StringField( 'container_getter_id', title='Container Getter Method', description=("The method to call to get a container object."), default="", required=0) context_getter_id = fields.StringField( 'context_getter_id', title='Context Getter Method', description=("The method to call to get the context."), default="", required=0) catalog_index = fields.StringField( 'catalog_index', title='Catalog Index', description=("The method to call to set the relation. Required."), default="", required=1) # XXX Is it a good idea to keep such a field ?? # User can redefine setter method with a script (and so, don't use the API) relation_setter_id = fields.StringField( 'relation_setter_id', title='Relation Update Method', description=("The method to invoke in order to update the relation"), default="", required=0) relation_form_id = fields.StringField( 'relation_form_id', title='Relation Form', description=("Form to display relation choices"), default="", required=0) size = fields.IntegerField( 'size', title='Size', description=( "The display size in rows of the field. If set to 1, the " "widget will be displayed as a drop down box by many browsers, " "if set to something higher, a list will be shown. Required."), default=1, required=1) columns = fields.ListTextAreaField( 'columns', title="Columns", description=("A list of attributes names to display."), default=[], required=0) sort = fields.ListTextAreaField( 'sort', title='Default Sort', description=('The default sort keys and order'), default=[], required=0) parameter_list = fields.ListTextAreaField( 'parameter_list', title="Parameter List", description=("A list of paramters used for the portal_catalog."), default=[], required=0) list_method = fields.MethodField('list_method', title='List Method', description=('The method to use to list' 'objects'), default='', required=0) proxy_listbox_ids = fields.ListTextAreaField( 'proxy_listbox_ids', title='Proxy Listbox IDs', description=('A list of listbox that can be used as proxy'), default='', required=0) # delete double in order to keep a usable ZMI... # XXX need to keep order ! #property_names = dict([(i,0) for i in property_names]).keys() _v_dict = {} _v_property_name_list = [] for property_name in property_names: if not _v_dict.has_key(property_name): _v_property_name_list.append(property_name) _v_dict[property_name] = 1 property_names = _v_property_name_list default_widget_rendering_instance = Widget.LinesTextAreaWidgetInstance def _getContextValue(self, field, REQUEST): """Return result of evaluated method defined by context_getter_id or here. """ context_getter_id = field.get_value('context_getter_id') here = REQUEST['here'] if context_getter_id: return getattr(here, context_getter_id)() return here def _generateRenderValueList(self, field, key, value_list, REQUEST): result_list = [] need_validation = 0 #################################### # Check value #################################### if isinstance(value_list, StringType): # Value is a string, reformat it correctly value_list = value_list.split("\n") else: # We get a list # rather than displaying nothing, display a marker when the # property is not set # XXX Translate ? value_list = [(x or NO_VALUE) for x in value_list] # Check all relation for i in range(len(value_list)): ################################### # Sub field ################################### relation_field_id = field.generate_subfield_key("%s_%s" % \ (SUB_FIELD_ID, i), key=key) relation_item_id = field.generate_subfield_key("%s_%s" % \ (ITEM_ID, i), key=key) relation_item_list = REQUEST.get(relation_item_id, None) value = value_list[i] if (relation_item_list is not None) and \ (value != ''): need_validation = 1 # If we get a empty string, display nothing ! if value != '': result_list.append( (Widget.TextWidgetInstance, relation_field_id, relation_item_list, value, i)) if not need_validation: ################################### # Main field ################################### result_list = [(Widget.LinesTextAreaWidgetInstance, None, [], value_list, None)] return result_list def render(self, field, key, value, REQUEST, render_prefix=None): """ Render text input field. """ html_string = '' relation_field_index = REQUEST.get('_v_relation_field_index', 0) render_parameter_list = self._generateRenderValueList( field, key, value, REQUEST) #################################### # Render subfield #################################### html_string_list = [] for widget_instance, relation_field_id, relation_item_list, \ value_instance, sub_index in render_parameter_list: sub_html_string = widget_instance.render(field, key, value_instance, REQUEST) here = self._getContextValue(field, REQUEST) portal = here.getPortalObject() autocomplete_enabled = getattr(portal.portal_skins, 'erp5_autocompletion_ui', None) if autocomplete_enabled: sub_html_string += self.render_autocomplete(field, key) if relation_item_list is not None: #################################### # Render wheel #################################### if not autocomplete_enabled: sub_html_string += self.render_wheel( field, value_instance, REQUEST, relation_index=relation_field_index, sub_index=sub_index) if relation_item_list: #################################### # Render listfield #################################### REQUEST['relation_item_list'] = relation_item_list sub_html_string += ' %s ' % \ Widget.ListWidgetInstance.render( field, relation_field_id, None, REQUEST) REQUEST['relation_item_list'] = None html_string_list.append(sub_html_string) #################################### # Generate html #################################### html_string = '<br/>'.join(html_string_list) #################################### # Render jump #################################### if (value == field.get_value('default')): # XXX Default rendering with value... relation_html_string = self.render_relation_link( field, value, REQUEST) if relation_html_string != '': html_string += ' %s' % relation_html_string #################################### # Update relation field index #################################### REQUEST.set('_v_relation_field_index', relation_field_index + 1) return html_string def render_view(self, field, value, REQUEST=None, render_prefix=None): """ Render read only field. """ html_string = '' here = self._getContextValue(field, REQUEST) portal_url = here.getPortalObject().portal_url portal_url_string = portal_url() if (value not in ((), [], None, '')) and \ field.get_value('allow_jump'): string_list = [] base_category = field.get_value('base_category') portal_type = map(lambda x: x[0], field.get_value('portal_type')) kw = {} for k, v in field.get_value('parameter_list'): kw[k] = v accessor_name = 'get%sValueList' % ''.join( [part.capitalize() for part in base_category.split('_')]) jump_reference_list = getattr(here, accessor_name)( portal_type=portal_type, filter=kw) if not isinstance(value, (list, tuple)): value = value, for jump_reference, display_value in zip(jump_reference_list, value): string_list.append('<a class="relationfieldlink" href="%s">%s</a>' % \ (jump_reference.absolute_url(), display_value)) html_string = '<br />'.join(string_list) else: html_string = self.default_widget_rendering_instance.render_view( field, value, REQUEST=REQUEST) if REQUEST is None: REQUEST = get_request() relation_html_string = self.render_relation_link( field, value, REQUEST) if relation_html_string != '': html_string += ' %s' % relation_html_string extra = field.get_value('extra') if extra not in (None, ''): html_string = "<div %s>%s</div>" % (extra, html_string) css_class = field.get_value('css_class') if css_class not in ('', None): # All strings should be escaped before rendering in HTML # except for editor field html_string = "<span class='%s'>%s</span>" % (css_class, html_string) return html_string def render_autocomplete(self, field, key): """ Use jquery-ui autocompletion for all relation fields by default, requiring only erp5_autocompletion_ui bt5 to be installed """ # XXX: Allow to specify more parameters to jquery-ui autocomplete widget? import json return """ <script type="text/javascript"> $(document).ready(function() { $("input[name='%s']").ERP5Autocomplete({search_portal_type: %s, search_catalog_key: "%s"}); }); </script>""" % (key, json.dumps(map(lambda x: x[0], field.get_value('portal_type'))), field.get_value('catalog_index')) def render_wheel(self, field, value, REQUEST, relation_index=0, sub_index=None, render_prefix=None): """ Render wheel used to display a listbox """ here = self._getContextValue(field, REQUEST) portal_url = here.getPortalObject().portal_url portal_url_string = portal_url() portal_selections_url_string = here.portal_url.getRelativeContentURL( here.portal_selections) if sub_index is None: sub_index_string = '' else: sub_index_string = '_%s' % sub_index return ' <input type="image" ' \ 'src="%s/images/exec16.png" value="update..." ' \ 'name="%s/viewSearchRelatedDocumentDialog%s%s' \ ':method"/>' % \ (portal_url_string, portal_selections_url_string, relation_index, sub_index_string) def render_relation_link(self, field, value, REQUEST, render_prefix=None): """ Render link to the related object. """ html_string = '' here = REQUEST.get('cell', self._getContextValue(field, REQUEST)) portal_url = here.getPortalObject().portal_url portal_url_string = portal_url() if (value not in ((), [], None, '')) and \ field.get_value('allow_jump'): # Keep the selection name in the URL if REQUEST.get('selection_name') is not None: selection_name_html = '&selection_name=%s&selection_index=%s' % \ (REQUEST.get('selection_name'), REQUEST.get('selection_index')) else: selection_name_html = '' if REQUEST.get('ignore_layout') is not None: selection_name_html += '&ignore_layout:int=%s' % int( REQUEST.get('ignore_layout', 0)) # Generate plan link html_string += '<a href="%s/%s?field_id=%s&form_id=%s%s">' \ '<img src="%s/images/jump.png" alt="jump" />' \ '</a>' % \ (here.absolute_url(), field.get_value('jump_method'), field.id, field.aq_parent.id, selection_name_html, portal_url_string) return html_string
class DateTimeWidget(Widget): property_names = Widget.property_names +\ ['default_now', 'date_separator', 'time_separator', 'input_style', 'input_order', 'date_only', 'hide_day', 'ampm_time_style', 'calendar_picker', 'calendar_start'] default = fields.DateTimeField('default', title="Default", description=("The default datetime."), default=None, display_style="text", display_order="ymd", input_style="text", required=0) default_now = fields.CheckBoxField( 'default_now', title="Default to now", description=( "Default date and time will be the date and time at showing of " "the form (if the default is left empty)."), default=0) date_separator = fields.StringField( 'date_separator', title='Date separator', description=("Separator to appear between year, month, day."), default="/", required=0, display_width=2, display_maxwith=2, max_length=2) time_separator = fields.StringField( 'time_separator', title='Time separator', description=("Separator to appear between hour and minutes."), default=":", required=0, display_width=2, display_maxwith=2, max_length=2) input_style = fields.ListField( 'input_style', title="Input style", description=("The type of input used. 'text' will show the date part " "as text, while 'list' will use dropdown lists instead."), default="text", items=[("text", "text"), ("list", "list")], size=1) input_order = fields.ListField( 'input_order', title="Input order", description=("The order in which date input should take place. Either " "year/month/day, day/month/year or month/day/year."), default="ymd", items=[("year/month/day", "ymd"), ("day/month/year", "dmy"), ("month/day/year", "mdy")], required=1, size=1) date_only = fields.CheckBoxField( 'date_only', title="Display date only", description=("Display the date only, not the time."), default=0) hide_day = fields.CheckBoxField('hide_day', title="Hide day field", description=("Hide the day field."), default=0) ampm_time_style = fields.CheckBoxField( 'ampm_time_style', title="AM/PM time style", description=("Display time in am/pm format."), default=0) calendar_picker = fields.CheckBoxField( 'calendar_picker', title="Enable calendar picker", description= ("Displays a floating calendar to select the date. " "The js calendar is located here: http://www.dynarch.com/projects/calendar/old/" ), default=0) calendar_start = fields.ListField( 'calendar_start', title="Starting day of week", description=( "The starting day of the week for the floating calendar."), default="Sunday", items=[ ("Sunday", "0"), ("Monday", "1"), ("Tuesday", "2"), ("Wednesday", "3"), ("Thursday", "4"), ("Friday", "5"), ("Saturday", "6"), ], required=0, size=1) has_html_id = False # FIXME: do we want to handle 'extra'? def render(self, field, key, value, REQUEST): use_ampm = field.get_value('ampm_time_style') hide_day = field.get_value('hide_day') calendar_picker = field.get_value('calendar_picker') start_day = field.get_value('calendar_start') # FIXME: backwards compatibility hack: if not hasattr(field, 'sub_form'): from StandardFields import create_datetime_text_sub_form field.sub_form = create_datetime_text_sub_form() if value is None and field.get_value('default_now'): value = DateTime() # Allow subfields to get their values even when default_now is set. if REQUEST is not None and \ REQUEST.form.has_key(field.generate_subfield_key('year')): value = None if value is None: year = None month = None day = None hour = None minute = None ampm = None else: if not isinstance(value, DateTime): value = DateTime(value) year = "%04d" % value.year() month = "%02d" % value.month() day = "%02d" % value.day() if use_ampm: hour = "%02d" % value.h_12() else: hour = "%02d" % value.hour() minute = "%02d" % value.minute() ampm = value.ampm() input_order = field.get_value('input_order') if input_order == 'ymd': order = [('year', year), ('month', month), ('day', day)] elif input_order == 'dmy': order = [('day', day), ('month', month), ('year', year)] elif input_order == 'mdy': order = [('month', month), ('day', day), ('year', year)] result = [] hidden_day_part = "" for sub_field_name, sub_field_value in order: if hide_day and (sub_field_name == 'day'): dayvalue = sub_field_value if dayvalue is None: dayvalue = "01" sub_key = field.generate_subfield_key(sub_field_name) sub_field = field.sub_form.get_field(sub_field_name) hidden_day_part = sub_field.widget.\ render_hidden(sub_field, sub_key, dayvalue, REQUEST) else: result.append( field.render_sub_field(sub_field_name, sub_field_value, REQUEST)) date_result = string.join(result, field.get_value('date_separator')) day_id = field.sub_form.get_field('day').generate_field_html_id( "subfield_" + field.id + "_day") month_id = field.sub_form.get_field('month').generate_field_html_id( "subfield_" + field.id + "_month") year_id = field.sub_form.get_field('year').generate_field_html_id( "subfield_" + field.id + "_year") select_day = '' if hidden_day_part: date_result += hidden_day_part else: #get the proper html id select_day = 'document.getElementById("' + day_id + '").value = RegExp.$3;' calendar_popup = '' html_id = field.generate_field_html_id(key) if calendar_picker: calendar_popup = ' ' + render_element( 'button', css_class='kupu-button kupu-link-reference calendar-button', style='padding: 0px 0px 0px 0px', id=html_id + '_calendar', title='set date', contents=' ') + """<script type="text/javascript"> setTimeout(function(){Calendar.setup({inputField : '%s_hiddeninput', ifFormat : '%%Y/%%m/%%d %%%s:%%M %%P', showsTime : '%s', button : '%s_calendar', weekNumbers: false, timeFormat: '%s', date: (new Date()).setHours(0,0,0,0), firstDay: '%s'})},100);</script>""" % ( html_id, use_ampm and 'I' or 'H', field.get_value('date_only') and 'false' or 'true', html_id, use_ampm and '12' or '24', start_day, ) if not field.get_value('date_only'): time_result = (field.render_sub_field('hour', hour, REQUEST) + field.get_value('time_separator') + field.render_sub_field('minute', minute, REQUEST)) hour_id = field.sub_form.get_field('hour').generate_field_html_id( "subfield_" + field.id + "_hour") minute_id = field.sub_form.get_field( 'minute').generate_field_html_id("subfield_" + field.id + "_minute") ampm_id = field.sub_form.get_field('ampm').generate_field_html_id( "subfield_" + field.id + "_ampm") if use_ampm: time_result += ' ' + field.render_sub_field( 'ampm', ampm, REQUEST) calendar_popup += calendar_picker and render_element( 'input', type='hidden', id=html_id + '_hiddeninput', onchange= 'var pattern = /(\d{4})\/(\d{2})\/(\d{2}) (\d{2}):(\d{2}) (am|pm)/; if (pattern.exec(this.value)) { document.getElementById("' + year_id + '").value = RegExp.$1; document.getElementById("' + month_id + '").value = RegExp.$2; ' + select_day + ' document.getElementById("' + hour_id + '").value = RegExp.$4; document.getElementById("' + minute_id + '").value = RegExp.$5; ' + str(use_ampm and 'document.getElementById("' + ampm_id + '").value = RegExp.$6;' or '') + ' }') or '' return date_result + ' ' + time_result + calendar_popup else: calendar_popup += calendar_picker and render_element( 'input', type='hidden', id=html_id + '_hiddeninput', onchange= 'var pattern = /(\d{4})\/(\d{2})\/(\d{2}) (\d{2}):(\d{2}) (am|pm)/; if (pattern.exec(this.value)) { document.getElementById("' + year_id + '").value = RegExp.$1; document.getElementById("' + month_id + '").value = RegExp.$2; ' + select_day + ' }') or '' return date_result + calendar_popup def render_hidden(self, field, key, value, REQUEST): result = [] if value is None and field.get_value('default_now'): value = DateTime() sub_values = {} subfields = ['year', 'month', 'day'] if value is not None: if not isinstance(value, DateTime): value = DateTime(value) sub_values['year'] = '%04d' % value.year() sub_values['month'] = "%02d" % value.month() sub_values['day'] = "%02d" % value.day() if not field.get_value('date_only'): use_ampm = field.get_value('ampm_time_style') subfields.extend(['hour', 'minute']) if use_ampm: subfields.append('ampm') if value is not None: if use_ampm: sub_values['hour'] = "%02d" % value.h_12() sub_values['ampm'] = value.ampm() else: sub_values['hour'] = "%02d" % value.hour() sub_values['minute'] = "%02d" % value.minute() for subfield in subfields: # XXX it would be nicer to pass the hidden value somewhere # to the subfields, but ... sub_key = field.generate_subfield_key(subfield) sub_field = field.sub_form.get_field(subfield) result.append( sub_field.widget.render_hidden(sub_field, sub_key, sub_values.get(subfield), REQUEST)) return ''.join(result) def render_view(self, field, value): if value is None: return '' use_ampm = field.get_value('ampm_time_style') if not isinstance(value, DateTime): value = DateTime(value) year = "%04d" % value.year() month = "%02d" % value.month() day = "%02d" % value.day() if use_ampm: hour = "%02d" % value.h_12() else: hour = "%02d" % value.hour() minute = "%02d" % value.minute() ampm = value.ampm() order = field.get_value('input_order') if order == 'ymd': output = [year, month, day] elif order == 'dmy': output = [day, month, year] elif order == 'mdy': output = [month, day, year] date_result = string.join(output, field.get_value('date_separator')) if not field.get_value('date_only'): time_result = hour + field.get_value('time_separator') + minute if use_ampm: time_result += ' ' + ampm return date_result + ' ' + time_result else: return date_result
class ParallelListWidget(Widget.MultiListWidget, Widget.ListWidget): """ Make the MultilistField more usable for the user. ParallelListWidget display a list of (Multi)ListField. Each can be required. Separation of items list is made with a Hash Script, which take the items list in input, and return a list of dictionnaries. Each dictionnary describes a (Multi)ListField. The keys are: - key: default: default - required: {1, 0} default: 0 - field_type: {ListField, MultiListField} default: MultiListField - item_list: [(display, value), ...] default: [] - value: default: [] - is_right_display: {1, 0} default: 0 """ property_names = ( lambda name_list, name_set=set(): # delete double (but preserve order) in order to keep a usable ZMI... [x for x in name_list if not (x in name_set or name_set.add(x))] )(Widget.MultiListWidget.property_names + Widget.ListWidget.property_names + ['hash_script_id']) hash_script_id = fields.StringField( 'hash_script_id', title='Hash script', description=("The method to call to hash items list."), required=0) def __init__(self): """ Generate some subwidget used for rendering. """ self.sub_widget = { 'ListField': Widget.ListWidgetInstance, 'MultiListField': Widget.MultiListWidgetInstance, } def render(self, field, key, value, REQUEST, render_prefix=None): hash_list = generateSubForm(field, value, REQUEST) # Call render on each sub field sub_field_render_list = [] for sub_field_property_dict in hash_list: sub_field_render_list.append( self.render_sub_field(field, key, sub_field_property_dict['value'], REQUEST, sub_field_property_dict)) # Aggregate all renders html_string = field.get_value('view_separator').\ join(sub_field_render_list) return html_string def render_htmlgrid(self, field, key, value, REQUEST, render_prefix=None): hash_list = generateSubForm(field, value, REQUEST) # Call render on each sub field sub_field_render_list = [] for sub_field_property_dict in hash_list: sub_field_render_list.append( (sub_field_property_dict['title'], self.render_sub_field(field, key, sub_field_property_dict['value'], REQUEST, sub_field_property_dict))) return sub_field_render_list def render_sub_field(self, field, key, value, REQUEST, sub_field_property_dict, render_prefix=None): """ Render dynamically a subfield """ for parameter in ('title', 'required', 'size'): REQUEST.set(KEYWORD % parameter, sub_field_property_dict[parameter]) REQUEST.set(KEYWORD % 'default', "") REQUEST.set(KEYWORD % 'first_item', 0) REQUEST.set(KEYWORD % 'items', sub_field_property_dict['item_list']) sub_widget = self.sub_widget[sub_field_property_dict['field_type']] if sub_field_property_dict.get('editable', 1): result = sub_widget.render(field, field.generate_subfield_key( sub_field_property_dict['key'], key=key), sub_field_property_dict['value'], REQUEST=REQUEST) else: result = sub_widget.render_view(field, sub_field_property_dict['value'], REQUEST) for parameter in ('title', 'required', 'size', 'default', 'first_item', 'items'): # As it doesn't seem possible to delete value in the REQUEST, # use a marker REQUEST.set(KEYWORD % parameter, MARKER) return result def render_odt(self, field, value, as_string, ooo_builder, REQUEST, render_prefix, attr_dict, local_name): """ """ return Widget.MultiListWidget.render_odt(self, field, value, as_string, ooo_builder, REQUEST, render_prefix, attr_dict, local_name) def render_odt_view(self, field, value, as_string, ooo_builder, REQUEST, render_prefix, attr_dict, local_name): """ """ return Widget.MultiListWidget.render_odt_view(self, field, value, as_string, ooo_builder, REQUEST, render_prefix, attr_dict, local_name)
class ImageFieldWidget(Widget.TextWidget): """ImageField widget. Renders an HTML <img> element where the src is the 'default' field value. The 'description' field value is used as 'alt' attribute. The image size is calculated using 'image_display'. """ property_names = Widget.TextWidget.property_names + \ ['image_display', 'image_format','image_quality', 'image_pre_converted_only'] image_display = fields.StringField( 'image_display', title='Image Display', description= ("The display size. See erp5.component.document.Image.default_displays_id_list " "for possible values. This is only used with ERP5 Images."), default='thumbnail', required=0) image_format = fields.StringField( 'image_format', title='Image Format', description=("The format in which the image should be converted to. " "This is only used with ERP5 Images."), default='', required=0) image_quality = fields.IntegerField( 'image_quality', title='Image Quality', description=("The quality used when converting the image. " "This is only used with ERP5 Images."), default=75, required=0) image_pre_converted_only = fields.CheckBoxField( 'image_pre_converted_only', title='Image Pre Converted Only', description=( "Return image only if it is already pre converted in cache. " "This is only used with ERP5 Images."), default=False, required=0) def render(self, field, key, value, REQUEST, render_prefix=None): """Render image field as a link to the image """ return self.render_view(field, value, REQUEST=REQUEST) def render_view(self, field, value, REQUEST=None, render_prefix=None): """Render image field as a link to the image """ # Url is already defined in value if value is None: return '' image = value alt = field.get_value('description') or \ field.get_value('title') css_class = field.get_value('css_class') extra = field.get_value('extra') options = {} options['display'] = field.get_value('image_display') options['format'] = field.get_value('image_format') options['quality'] = field.get_value('image_quality') pre_converted_only = field.get_value('image_pre_converted_only') if pre_converted_only: # only add if it's True as conversion machine assume that if it is missing # then conversion should happen "on the fly" options['pre_converted_only'] = pre_converted_only parameters = '&'.join(['%s=%s' % (k, v) for k, v in options.items() \ if v]) if parameters: image = '%s?%s' % (image, parameters) return Widget.render_element( "img", alt=alt, src=image, css_class=css_class, extra=extra, ) def render_odg_view(self, field, value, as_string, ooo_builder, REQUEST, render_prefix, attr_dict, local_name): """ return an image xml node rendered in odg format if as_string is True (default) the returned value is a string (xml reprensation of the node), if it's False, the value returned is the node object. attr_dict can be used for additional parameters (like style). """ if attr_dict is None: attr_dict = {} draw_frame_node = None if value in ('', None): return None path = '/'.join(REQUEST.physicalPathFromURL(value)) path = path.encode() image_object = field.getPortalObject().restrictedTraverse(path) display = field.get_value('image_display') format = field.get_value('image_format') quality = field.get_value('image_quality') image_parameter_dict = {'format': format} if display: image_parameter_dict['display'] = display if quality: image_parameter_dict['quality'] = quality # convert the image using fields parameters. In this way, if an image # is displayed in the form as a thumbnail, it will be added in the odg # document as thumbnail size/quality content_type, image_data = image_object.convert(**image_parameter_dict) image = OFSImage('', '', image_data) width = image.width height = image.height if image_data is None: return draw_frame_node # Big images are cut into smaller chunks, so it's required to cast to # str. See OFS/Image -> _read_data method for more information image_data = str(image_data) format = content_type.split('/')[-1] # add the image to the odg document picture_path = ooo_builder.addImage(image=image_data, format=format, content_type=content_type) # create the xml nodes related to the image draw_frame_tag_name = '{%s}%s' % (DRAW_URI, 'frame') draw_frame_node = Element(draw_frame_tag_name, nsmap=NSMAP) draw_frame_node.attrib.update( attr_dict.get(draw_frame_tag_name, {}).pop(0)) # set the size of the image if display is not None: # if the image width and height are not on defined, use current # width and height if (image_object.getWidth(), image_object.getHeight()) not in \ ((-1, -1), (0,0)): width, height = image_object._getAspectRatioSize(width, height) if draw_frame_node.attrib.get('{%s}width' % SVG_URI) and \ draw_frame_node.attrib.get('{%s}height' % SVG_URI): # if a size already exist from attr_dict, try to resize the image to # fit this size (image should not be biger than size from attr_dict) # devide the value by 20 to have cm instead of px width, height = self._getPictureSize( width / 20., height / 20., target_width=draw_frame_node.attrib.get( '{%s}width' % SVG_URI, ''), target_height=draw_frame_node.attrib.get( '{%s}height' % SVG_URI, '')) draw_frame_node.set('{%s}width' % SVG_URI, str(width)) draw_frame_node.set('{%s}height' % SVG_URI, str(height)) image_tag_name = '{%s}%s' % (DRAW_URI, 'image') image_node = Element(image_tag_name, nsmap=NSMAP) image_node.attrib.update(attr_dict.get(image_tag_name, []).pop()) image_node.set('{%s}href' % XLINK_URI, picture_path) draw_frame_node.append(image_node) if as_string: return etree.tostring(draw_frame_node) return draw_frame_node def _getPictureSize(self, picture_width, picture_height, target_width, target_height): # if not match causes exception width_tuple = re.match("(\d[\d\.]*)(.*)", target_width).groups() height_tuple = re.match("(\d[\d\.]*)(.*)", target_height).groups() unit = width_tuple[1] w = float(width_tuple[0]) h = float(height_tuple[0]) aspect_ratio = 1 try: # try image properties aspect_ratio = picture_width / picture_height except (TypeError, ZeroDivisionError): try: # try Image Document API height = picture_height if height: aspect_ratio = picture_width / height except AttributeError: # fallback to Photo API height = float(picture_height) if height: aspect_ratio = picture_width / height resize_w = h * aspect_ratio resize_h = w / aspect_ratio if resize_w < w: w = resize_w elif resize_h < h: h = resize_h return (str(w) + unit, str(h) + unit)
class ZGDChartWidget(Widget.Widget): """ This is the class used in order to include inside ERP5 some very nice charts """ property_names = Widget.Widget.property_names +\ ['selection_name','default_params','chart_title', 'data_method','chart_style','x_title','y_title', 'bg_transparent'] default = fields.TextAreaField( 'default', title='Default', description=("Default value of the text in the widget."), default="", width=20, height=3, required=0) selection_name = fields.StringField( 'selection_name', title='Selection Name', description=('The name of the selection to store' 'params of selection'), default='', required=0) data_method = fields.StringField( 'data_method', title='Data Method', description=('The method wich returns data'), default='', required=0) chart_style = fields.StringField('chart_style', title='Chart Style', description=('The kind of Chart we want'), default='bar_3d', required=0) chart_title = fields.StringField( 'chart_title', title='Chart Title', description=('The Title on the top of the chart'), default='', required=0) x_title = fields.StringField('x_title', title='X Title', description=('The Title for the X axis'), default='', required=0) y_title = fields.StringField('y_title', title='Y Title', description=('The Title for the Y axis'), default='', required=0) default_params = fields.ListTextAreaField( 'default_params', title="Default Parameters", description=("Default Parameters for the List Method."), default=[], required=0) bg_transparent = fields.CheckBoxField( 'bg_transparent', title='Transparent Background', description=('Allows to set the background transparent'), default='', required=0) def render(self, field, key, value, REQUEST, render_prefix=None): """ This is where most things happens """ main_content = "" here = REQUEST['here'] selection_name = field.get_value('selection_name') default_params = field.get_value('default_params') chart_title = field.get_value('chart_title') data_method = field.get_value('data_method') chart_style = field.get_value('chart_style') x_title = field.get_value('x_title') y_title = field.get_value('y_title') bg_transparent = field.get_value('bg_transparent') selection = here.portal_selections.getSelectionFor(selection_name, REQUEST=REQUEST) LOG( 'ZGDChart.render', 0, 'selection: %s, selection_name: %s' % (str(selection), str(selection_name))) # This is the default data, this is just in the case there is not method given data = {'chart_data': []} # Retrieve the data with the data_method if hasattr(here, data_method): LOG('ZGDChart.render', 0, 'found method') data_method = getattr(here, data_method) data['chart_data'] = data_method() data['chart_parameter'] = { 'zgdchart_runtime_title': chart_title, 'zgdchart_runtime_xtitle': x_title, 'zgdchart_runtime_ytitle': y_title, 'zgdchart_runtime_type': 'Line_3D', 'zgdchart_runtime_bg_transparent': bg_transparent } # Creation selection if needed if selection is None: selection = Selection(selection_name, params=data) else: LOG('ZGDChart.render', 0, 'selection is not None') kw = {'params': data} selection.edit(**kw) here.portal_selections.setSelectionFor(selection_name, selection, REQUEST=REQUEST) if len(data['chart_data']) > 0: main_content = """\ <div class="ChartContent"> <table border="0" cellpadding="0" cellspacing="0""> <tr> <td valign="middle" align="center" nowrap> <img src="%s" title="Chart" border="0" alt="img"/"> </td> </tr> </table> </div>""" % str(chart_style + '?selection_name=' + selection_name) return main_content
class GadgetFieldValidator(Validator.Validator): property_names = Validator.Validator.property_names + [ 'data_url', 'validator_form_id', 'validator_field_id' ] data_url = fields.CheckBoxField( 'data_url', title='Data Url', description=("Checked if gadget return data url."), default=0) validator_form_id = fields.StringField( 'validator_form_id', title='Validator Form ID', description= "ID of the validator field's form. Default is the current form", default="", display_width=40, required=0) validator_field_id = fields.StringField( 'validator_field_id', title='Validator Field ID', description="ID of the validator field.", default="", display_width=40, required=0) message_names = Validator.Validator.message_names + ['no_validator'] no_validator = 'Does not support this operation.' def getValidatorField(self, field): """Get an external validator field located in the same form. """ field_id = field.id validator_form_id = field.get_value('validator_form_id') validator_field_id = field.get_value('validator_field_id') validator_form = field.aq_parent if (validator_form_id): if '/' in validator_form_id: portal = field.getPortalObject() portal_skins = portal.portal_skins # If a / is in the form_id, it means that skin_folder is explicitly # defined. If so, prevent acquisition to get the form. aq_validator_form = aq_base(portal_skins).unrestrictedTraverse( validator_form_id, None) if aq_validator_form is not None: validator_form = portal_skins.unrestrictedTraverse( validator_form_id) else: validator_form = getattr(validator_form, validator_form_id, None) if (validator_form is not None) and validator_field_id: if validator_form.has_field(validator_field_id, include_disabled=1): return validator_form.get_field(validator_field_id, include_disabled=1) return None def validate(self, field, key, REQUEST): validator_field = self.getValidatorField(field) if validator_field is None: # not editable if no validator self.raise_error('no_validator', field) else: value = validator_field._validate_helper(key, REQUEST) if value is not None: if field.get_value('data_url'): value = value.split(",")[1] return StringIO(value.decode('base64')) return value
class DurationWidget(Widget.IntegerWidget): """ Duration Widget is used to enter time duration. It may be used in movement of Labour (in Task, Calendat Period, ...). Time duration in ERP5 are saved ALWAYS IN SECOND. The field purpose is to display second quantity in hour, minute and second, in order to make it more readable. XXX This field is experimental, and unstable. Do not use it. """ title = fields.StringField('title', title='Title. ' \ '(Warning! Do not use this field!)', description=( "The title of this field. This is the title of the field that " "will appear in the form when it is displayed. Required."), default="", required=1) def render_view(self, field, value, REQUEST=None, render_prefix=None): sub_field_render_list = [] for title, sub_key, convertion in (('Hour', 'hour', HOUR_IN_SECOND), ('Minute', 'minute', MINUTE_IN_SECOND)): if value == '': sub_value = '' else: sub_value, value = divmod(value, convertion) sub_field_render_list.append( self.render_sub_field_view(field, sub_value, REQUEST=REQUEST)) # Render second sub_field_render_list.append( self.render_sub_field_view(field, value, REQUEST=REQUEST)) return ':'.join(sub_field_render_list) def render(self, field, key, value, REQUEST, render_prefix=None): sub_field_render_list = [] for title, sub_key, convertion in (('Hour', 'hour', HOUR_IN_SECOND), ('Minute', 'minute', MINUTE_IN_SECOND)): if value == '': sub_value = '' else: sub_value, value = divmod(value, convertion) sub_field_render_list.append( self.render_sub_field(field, key, sub_value, REQUEST, sub_key)) # Render second sub_field_render_list.append( self.render_sub_field(field, key, value, REQUEST, 'second')) return ':'.join(sub_field_render_list) def render_sub_field_view(self, field, value, REQUEST=None, render_prefix=None): """ Render dynamically a subfield """ return self.render_view(field, value, REQUEST=REQUEST) def render_sub_field(self, field, key, value, REQUEST, keyword, render_prefix=None): """ Render dynamically a subfield """ return Widget.IntegerWidget.render( self, field, field.generate_subfield_key(keyword, key=key), value, REQUEST)
class MatrixBoxWidget(Widget.Widget): """ An UI widget which displays a matrix Don't forget that you can use tales expressions for every field, so this is really usefull if you want to use fonctions instead of predefined variables. A function is provided to - access a cell - modify a cell """ property_names = Widget.Widget.property_names +\ ['cell_base_id', 'cell_portal_type', 'lines', 'columns', 'tabs', 'as_cell_range_script_id', 'getter_method', 'editable_attributes', 'global_attributes', 'cell_getter_method', 'update_cell_range', 'url_cells' ] default = fields.TextAreaField( 'default', title='Default', description=("Default value of the text in the widget."), default="", width=20, height=3, required=0) as_cell_range_script_id = fields.StringField( 'as_cell_range_script_id', title='Cell range method', description=( "Method returning columns, lines and tabs. The method is passed" " matrixbox=True, base_id=base_id as arguments."), default='', required=0) columns = fields.ListTextAreaField( 'columns', title="Columns", description=( "This defines columns of the matrixbox. " "This should be a list of couples, " "couple[0] is the variation, and couple[1] is the name displayed " "to the user.\n" "For example (('color/blue', 'Bleu'), ('color/red','Red')).\n" " Deprecated, use cell range method instead"), default=[], required=0) lines = fields.ListTextAreaField( 'lines', title="Lines", description= ("This defines lines of the matrixbox. This should be a list of couples, " "couple[0] is the variation, and couple[1] is the name displayed " "to the user.\n" "For example (('size/baby/02','baby/02'),('size/baby/03','baby/03')).\n" "Deprecated, use cell range method instead"), default=[], required=0) tabs = fields.ListTextAreaField( 'tabs', title="Tabs", description=( "This defines tabs. You can use it with the same way as Lines " "and Columns.\n" "This is used only if you have more than 2 kinds of variations.\n" "Deprecated, use cell range method instead"), default=[], required=0) # XXX ListTextAreaField ? cell_range = fields.ListTextAreaField( 'cell_range', title="Cell Range", description=("This defines the range of the matrix."), default=[], required=0) getter_method = fields.StringField( 'getter_method', title='Getter method', description= ("You can specify a specific method in order to retrieve the context. " "This field can be empty, if so the MatrixBox will use the default " "context."), default='', required=0) cell_getter_method = fields.StringField( 'cell_getter_method', title='Cell Getter method', description= ("You can specify a method in order to retrieve cells. This field can " "be empty, if so the MatrixBox will use the default method : getCell." ), default='', required=0) new_cell_method = fields.MethodField( 'new_cell_method', title='New Cell method', description=( "You can specify a specific method in order to create cells. " "This field can be empty, if so the MatrixBox will use the default " "method : newCell."), default='', required=0) editable_attributes = fields.ListTextAreaField( 'editable_attributes', title="Editable Properties", description=( "A list of attributes which are set by hidden fields called " "matrixbox_attribute_name. This is used " "when we want to specify a computed value for each cell"), default=[], required=0) global_attributes = fields.ListTextAreaField( 'global_attributes', title="Global Properties", description=( "An optional list of globals attributes which are set by hidden " "fields and which are applied to each cell. " "This is used if we want to set the same value for every cell"), default=[], required=0) cell_base_id = fields.StringField( 'cell_base_id', title='Base id for cells', description=( "The Base id for cells : this is the name used to store cells, " "we usually use names like : 'movement', 'path', ... "), default='cell', required=0) cell_portal_type = fields.StringField( 'cell_portal_type', title='Portal Type for cells', description=( "The Portal Type for cells : This is the portal type used to " "create a new cell."), default='Mapped Value', required=0) update_cell_range = fields.CheckBoxField( 'update_cell_range', title="Update Cell Range", description=("The cell range should be updated upon edit."), default=0) url_cells = fields.ListTextAreaField( 'url_cells', title="URL Cells", description=( "An optional list of cells which can provide a custom URL." "If no url cell is used, then no link is displayed."), default=[], required=0) def render(self, field, key, value, REQUEST, render_format='html', render_prefix=None): """ This is where most things happen. This method renders a list of items """ # First grasp the variables we may need here = REQUEST['here'] form = field.aq_parent field_title = field.get_value('title') cell_base_id = field.get_value('cell_base_id') context = here getter_method_id = field.get_value('getter_method') if getter_method_id not in (None, ''): context = getattr(here, getter_method_id)() if context is None: return '' as_cell_range_script_id = field.get_value('as_cell_range_script_id') extra_dimension_category_list_list = [None] if as_cell_range_script_id: lines = [] columns = [] tabs = [] dimension_list = guarded_getattr(context, as_cell_range_script_id)( matrixbox=True, base_id=cell_base_id) len_dimension_list = len(dimension_list) if len_dimension_list: if len_dimension_list == 1: lines, = dimension_list elif len_dimension_list == 2: lines, columns = dimension_list elif len_dimension_list >= 3: lines, columns, tabs = dimension_list[:3] if len_dimension_list > 3: extra_dimension_list = dimension_list[3:] extra_dimension_category_label_dict = {} extra_dimension_category_index_dict = {} for extra_dimension in extra_dimension_list: for index, (category, label) in enumerate(extra_dimension): extra_dimension_category_label_dict[ category] = label extra_dimension_category_index_dict[ category] = index from Products.ERP5Type.Utils import cartesianProduct extra_dimension_category_list_list = cartesianProduct( [[category for category, label in extra_dimension] for extra_dimension in extra_dimension_list]) else: lines = field.get_value('lines') columns = field.get_value('columns') tabs = field.get_value('tabs') field_errors = REQUEST.get('field_errors', {}) cell_getter_method_id = field.get_value('cell_getter_method') if cell_getter_method_id not in (None, ''): cell_getter_method = getattr(context, cell_getter_method_id) else: cell_getter_method = context.getCell editable_attributes = field.get_value('editable_attributes') url_cells = field.get_value('url_cells') url_cell_dict = dict(url_cells) # This is required when we have no tabs if len(tabs) == 0: tabs = [(None, None)] # This is required when we have no columns if len(columns) == 0: columns = [(None, None)] column_ids = [x[0] for x in columns] line_ids = [x[0] for x in lines] tab_ids = [x[0] for x in tabs] editable_attribute_ids = [x[0] for x in editable_attributes] # THIS MUST BE REMOVED - WHY IS THIS BAD ? # IT IS BAD BECAUSE TAB_IDS DO NOT DEFINE A RANGE.... # here.setCellRange(line_ids, column_ids, base_id=cell_base_id) # result for the list render list_result = [] url = REQUEST.URL list_html = '' for extra_dimension_category_list in extra_dimension_category_list_list: if extra_dimension_category_list is None: extra_dimension_label = '' extra_dimension_position = () extra_dimension_index = '' extra_dimension_category_list = [] else: extra_dimension_label = ',' + ','.join([ extra_dimension_category_label_dict[category] for category in extra_dimension_category_list ]) extra_dimension_position = tuple([ extra_dimension_category_index_dict[category] for category in extra_dimension_category_list ]) extra_dimension_index = '_' + '_'.join( map(str, extra_dimension_position)) # Create one table per tab k = 0 kwd = dict(base_id=cell_base_id) for tab in tabs: tab_id = tab[0] if (tab_id is not None) and \ (not isinstance(tab_id, (list, tuple))): tab_id = [tab_id] if render_format == 'list': list_result_tab = [[tab[1]]] # Create the header of the table - this should probably become DTML first_tab = tab[1] or '' header = """\ <!-- Matrix Content --> <div class="matrixbox_label_tab">%s</div> <div class="MatrixContent"> <table> """ % (first_tab + extra_dimension_label) # Create the footer. This should be replaced by DTML # And work as some kind of parameter footer = """\ <tr> <td colspan="%i" class="Data footer"> </td> </tr> </table> </div> """ % (len(columns) + 1) list_header = """\ <tr class="matrixbox_label_line"><td class=\"Data\"></td> """ for cname in columns: first_column = cname[1] or '' list_header = list_header + ( "<td class=\"Data\">%s</td>\n" % first_column) if render_format == 'list': list_result_tab[0].append(cname[1]) list_header = list_header + "</tr>" # Build Lines i = 0 j = 0 list_body = '' for l in lines: if not i % 2: td_css = 'DataA' else: td_css = 'DataB' list_body = list_body + '\n<tr class=\"%s\"><td class=\"matrixbox_label_column\">%s</td>' % ( td_css, str(l[1])) j = 0 if render_format == 'list': list_result_lines = [str(l[1])] for c in columns: has_error = False column_id = c[0] if (column_id is not None) and \ (not isinstance(column_id, (list, tuple))): column_id = [column_id] if column_id is None: kw = [l[0]] elif tab_id is None: kw = [l[0], c[0]] else: kw = [l[0], c[0] ] + tab_id + extra_dimension_category_list cell = cell_getter_method(*kw, **kwd) REQUEST['cell'] = cell REQUEST['cell_index'] = kw cell_body = '' cell_url = None for attribute_id in editable_attribute_ids: if attribute_id in url_cell_dict: url_method_id = url_cell_dict[attribute_id] if url_method_id not in (None, ''): url_method = getattr( cell, url_method_id, None) if url_method is not None: try: cell_url = url_method( brain=cell, cell_index=kw, cell_position=( (i, j, k) + extra_dimension_position)) except (ConflictError, RuntimeError): raise except: LOG('MatrixBox', WARNING, 'Could not evaluate the url ' 'method %r with %r' % (url_method, cell), error=sys.exc_info()) else: LOG( 'MatrixBox', WARNING, 'Could not find the url method %s' % (url_method_id, )) my_field_id = '%s_%s' % (field.id, attribute_id) if form.has_field(my_field_id): my_field = form.get_field(my_field_id) key = my_field.id + '_cell_%s_%s_%s%s' % ( i, j, k, extra_dimension_index) default_value = my_field.get_value( 'default', cell=cell, cell_index=kw, cell_position=((i, j, k) + extra_dimension_position)) display_value = default_value if field_errors: # Display previous value in case of any error in this form because # we have no cell to get value from display_value = REQUEST.get( 'field_%s' % key, default_value) if cell is not None: if render_format == 'html': cell_html = my_field.render( value=display_value, REQUEST=REQUEST, key=key) if cell_url: # don't make a link if widget is editable if not my_field.get_value( 'editable', cell=cell, cell_index=kw, cell_position=( (i, j, k) + extra_dimension_position )): cell_html = "<a href='%s'>%s</a>" % ( cell_url, cell_html) if key in field_errors: # Display error message if this cell has an error has_error = True cell_body += '<span class="input">%s</span>%s' % ( cell_html, translateString( field_errors[key]. error_text)) else: cell_body += '<span class="input">%s</span>' % ( cell_html) else: if render_format == 'html': if key in field_errors: # Display error message if this cell has an error has_error = True cell_body += '<span class="input">%s</span>%s' % ( my_field.render( value=display_value, REQUEST=REQUEST, key=key), translateString( field_errors[key]. error_text)) else: cell_body += '<span class="input">%s</span>' %\ my_field.render( value=display_value, REQUEST=REQUEST, key=key) if render_format == 'list': # list rendering doesn't make difference when cell exists or not list_result_lines.append({ 'default': default_value, 'value': display_value, 'key': key, 'type': my_field.meta_type if my_field.meta_type != "ProxyField" else my_field. getRecursiveTemplateField().meta_type, 'field_id': my_field.id, 'error_text': u"%s" % (translateString( field_errors[key].error_text) if key in field_errors else '') }) css = td_css if has_error: css = 'error' list_body = list_body + \ ('<td class=\"%s\">%s</td>' % (css, cell_body)) j += 1 list_body = list_body + '</tr>' i += 1 if render_format == 'list': list_result_tab.append(list_result_lines) list_html += header + list_header + \ list_body + footer k += 1 if render_format == 'list': list_result.append(list_result_tab) # XXX Does not leave garbage in REQUEST['cell'], because some other # fields also use that key... REQUEST.other.pop('cell', None) REQUEST.other.pop('cell_index', None) if render_format == 'list': return list_result return list_html
class GadgetWidget(Widget.TextWidget): """ A widget that displays a renderjs gadget """ property_names = Widget.TextWidget.property_names + \ ['gadget_html', 'gadget_cached', 'gadget_cache_id', 'gadget_property', 'gadget_connection', 'gadget_id'] gadget_html = fields.StringField( 'gadget_html', title='Gadget Html', description=("The id of the html page containing the \ gadget"), default='', required=0) gadget_id = fields.StringField('gadget_id', title='Gadget Id', description=("The id of the gadget"), default='', required=0) gadget_cache_id = fields.StringField( 'gadget_cache_id', title='Gadget Cache Id', description=("The id of the cache in localstorage"), default='', required=0) gadget_property = fields.StringField( 'gadget_property', title='Gadget Properties', description=("Json Data used to initialize the gadget"), default='', required=0) gadget_connection = fields.StringField( 'gadget_connection', title='Gadget Connections', description=("Json Data used to define interactions"), default='', required=0) gadget_cached = fields.CheckBoxField( 'gadget_cached', title='Gadget Cached', description=("The rendering of the gadget will be \ cached in localstorage."), default=0, required=0) def render(self, field, key, value, REQUEST, render_prefix=None): return self.render_view(field, value, REQUEST, render_prefix) def render_view(self, field, value, REQUEST=None, render_prefix=None): kw = {} gadget_mapping = { "gadget_cached": "data-gadget-cacheable", "gadget_cache_id": "data-gadget-cache-id", "gadget_html": "data-gadget", "gadget_id": "id", "gadget_connection": "data-gadget-connection", "gadget_property": "data-gadget-property" } for property_name in gadget_mapping.keys(): property_value = field.get_value(property_name) if property_value or property_name == "gadget_html": kw[gadget_mapping[property_name]] = property_value return Widget.render_element("div", **kw)
class OOoChartWidget(Widget.Widget): """ This class is capabale of producing ODF charts based on data obtained through a listbox. Some properties are useless http://books.evc-cit.info/odbook/ch08.html#chart-plot-area-example - mean-value - error-margin - error-upper-limit - error-lower-limit - error-category - error-percentage - chart-japanese-candle-stick and stock-with-volume,chart:stock-updown-bars. These attributs are used with a chart:stock """ property_names = list(Widget.Widget.property_names) # XXX The description says it's not used # but removing 'default' breaks ODT/ODS rendering ... default = fields.StringField( 'default', title='Default', description=("A default value (not used)."), default="", required=0) listbox_form_id = fields.StringField( 'listbox_form_id', title='ListBox Form ID', description=("ID of the master form."), default="", required=0) property_names.append('listbox_form_id') listbox_id = fields.StringField( 'listbox_id', title='ListBox ID', description=("ID of the listbox in the master form."), default="", required=0) property_names.append('listbox_id') image_display = fields.ListField('image_display', title='Image Display', description=("Render size of this chart in HTML mode."), default='medium', items=[('thumbnail','thumbnail'), ('xsmall', 'xsmall'), ('small', 'small'), ('medium', 'medium'), ('large', 'large'), ('xlarge', 'xlarge'), ], size=1) property_names.append('image_display') image_format = fields.StringField('image_format', title='Image Format', description=( "The format in which the chart should be converted to."), default='png', required=0) property_names.append('image_format') ooo_template = fields.StringField('ooo_template', title='OOo Template', description=('The ID of a OOo Page Template' 'to render the ListBox'), default='ERP5Site_viewChart', required=0) property_names.append('ooo_template') chart_type = fields.ListField('chart_type', title='Chart Type', description=('Type of the Chart'), default='chart:bar', items=[('bar', 'chart:bar'), ('circle', 'chart:circle'), ('line', 'chart:line'), ('scatter', 'chart:scatter'), ('area', 'chart:area'), ], size=0) property_names.append('chart_type') colour_column_list = fields.ListTextAreaField('colour_column_list', title="Data Color", description=( "A list of colors for each data associated to a column."), default=[], required=0) property_names.append('colour_column_list') # vertical ="true" chart_position = fields.ListField('chart_position', title='Bar Position', description=( 'Render the bar in horizontal position or vertical position'), default='false', items=[('horizontal', 'true'), ('vertical', 'false'), ], size=0) property_names.append('chart_position') #legend of the chart or not chart_legend = fields.CheckBoxField('chart_legend', title='Chart Legend', description=('Show Chart Legend or no'), default=1, required=0) property_names.append('chart_legend') position_legend = fields.ListField('position_legend', title='Legend Position', description=( 'Legend Position according to the graph'), default='end', items=[('bottom', 'bottom'), ('end', 'end'), ('start', 'start'), ('top', 'top'), ], size=1) property_names.append('position_legend') #legend of the chart or not chart_title_or_no = fields.CheckBoxField('chart_title_or_no', title='Chart Title ', description=('Show Title on Graph or no '), default=1, required=0) property_names.append('chart_title_or_no') # Axis x_axis_property_list = fields.ListTextAreaField('x_axis_property_list', title="X-Axis Properties", description="Examples of recognized properties:" " 'chart:visible'," " 'chart:display-label'," " 'chart:label-arrangement'," " 'chart:tick-marks-major-inner'," " 'chart:reverse-direction'," " 'chart:logarithmic'," " 'chart:text-overlap'," " 'chart:origin'," " 'text:line-break'," " 'style:rotation-angle'...", default=(), required=0) property_names.append('x_axis_property_list') y_axis_property_list = fields.ListTextAreaField('y_axis_property_list', title="Y-Axis Properties", default=(), required=0) property_names.append('y_axis_property_list') #grid or not grid_graph = fields.CheckBoxField('grid_graph', title='Chart Grid ', description=('Show Grid or no'), default=1, required=0) property_names.append('grid_graph') grid_size = fields.ListField('grid_size', title='Grid Size', description=( 'Render a big grid size or a small grid size'), default='major', items=[('major', 'major'), ('minor', 'minor'), ], size=0) property_names.append('grid_size') user_data_title = fields.StringField('user_data_title', title="Overide Labelled Column ID", description=( "Column Id choose by user to define the label."), required=0) property_names.append('user_data_title') user_column_id_list = fields.ListTextAreaField('user_column_id_list', title="Overide Column Ids", description=( "A list of column Ids choose by user to draw the graph."), default=[], required=0) property_names.append('user_column_id_list') chart_stacked = fields.CheckBoxField('chart_stacked', title='Stacked Data', description=('stacked data or not'), default=0, required=0) property_names.append('chart_stacked') #connect-bars="false" connect_bars = fields.CheckBoxField('connect_bars', title='Connect Bars', description=(''), default=0, required=0) property_names.append('connect_bars') chart_three_dimensional = fields.CheckBoxField('chart_three_dimensional', title='3D', description=( 'Render the chart in three dimensions rather in flat mode'), default=0, required=0) property_names.append('chart_three_dimensional') #deep="false" deep = fields.CheckBoxField('deep', title='Deep', description=('Deep'), default=0, required=0) property_names.append('deep') # sector_pie_offset Default:0 sector_pie_offset = fields.IntegerField('sector_pie_offset', title='Sector Pie Offset', description=(''), default=0, required=0) property_names.append('sector_pie_offset') #interpolation="none", cubic-spline, b-spline interpolation = fields.ListField('interpolation', title='Interpolation', description=(''), default='none', items=[('none', 'none'), ('cubic-spline', 'cubic-spline'), ('b-spline', 'b-spline')], size=1) property_names.append('interpolation') #symbol-type="none", automatic symbol_type = fields.ListField('symbol_type', title='Symbol Type', description=(''), default='none', items=[('none', 'none'), ('automatic', 'automatic'),], size=1) property_names.append('symbol_type') #lines-used="0" lines_used = fields.ListField('lines_used', title='Lines Used', description=(''), default='0', items=[('0', '0'), ('1', '1')], size=1) property_names.append('lines_used') #series-source=columns or rows series_source = fields.ListField('series_source', title='Series Source', description=(''), default='columns', items=[('columns', 'columns'), ('rows', 'rows'),], size=1) property_names.append('series_source') #regression-type="none" linear logarithmic exponential power regression_type = fields.ListField('regression_type', title='Regression Type', description=(''), default='none', items=[('none', 'none'), ('linear', 'linear'), ('logarithmic', 'logarithmic'), ('exponential', 'exponential'), ('power', 'power')], size=1) property_names.append('regression_type') #data-label-number="none" value percentage data_label_number = fields.ListField('data_label_number', title='Data Label Number', description=(''), default='none', items=[('none', 'none'), ('value', 'value'), ('percentage', 'percentage')], size=1) property_names.append('data_label_number') #data-label-text="false" data_label_text = fields.CheckBoxField('data_label_text', title='Data Label Text', description=(''), default=0, required=0) property_names.append('data_label_text') #data-label-symbol="false" data_label_symbol = fields.CheckBoxField('data_label_symbol', title='Data Label Symbol', description=(''), default=0, required=0) property_names.append('data_label_symbol') def getArgumentDict(self, field, REQUEST): """ Build argument Dict """ def stringBoolean(value): return str(bool(value)).lower() form = field.aq_parent listbox_form_id = field.get_value('listbox_form_id') if listbox_form_id in ('', None): listbox_form_id = form.getId() listbox_id = field.get_value('listbox_id') if listbox_id in ('', None): listbox_id = 'listbox' render_prefix = REQUEST.get('render_prefix') extra_argument_dict = dict( render_prefix = render_prefix, chart_form_id = listbox_form_id, chart_field_id = listbox_id, chart_title = field.get_value('title'), chart_type = field.get_value('chart_type'), colour_column_list = field.get_value('colour_column_list'), user_column_id_list = field.get_value('user_column_id_list'), user_data_title= field.get_value('user_data_title'), chart_position = field.get_value('chart_position'), chart_legend = stringBoolean(field.get_value('chart_legend')), chart_title_or_no = stringBoolean(field.get_value('chart_title_or_no')), x_axis_property_dict = dict(field.get_value('x_axis_property_list')), y_axis_property_dict = dict(field.get_value('y_axis_property_list')), grid_graph = stringBoolean(field.get_value('grid_graph')), grid_size=field.get_value('grid_size'), chart_three_dimensional = stringBoolean(field.get_value('chart_three_dimensional')), deep = stringBoolean(field.get_value('deep')), chart_stacked = stringBoolean(field.get_value('chart_stacked')), sector_pie_offset = field.get_value('sector_pie_offset'), interpolation = field.get_value('interpolation'), symbol_type = field.get_value('symbol_type'), lines_used = field.get_value('lines_used'), connect_bars = stringBoolean(field.get_value('connect_bars')), series_source = field.get_value('series_source'), regression_type = field.get_value('regression_type'), data_label_number = field.get_value('data_label_number'), data_label_text = stringBoolean(field.get_value('data_label_text')), data_label_symbol = stringBoolean(field.get_value('data_label_symbol')), position_legend=field.get_value('position_legend'), ) for k, v in extra_argument_dict.items(): if REQUEST.get(k) is None: REQUEST.form[k] = v return extra_argument_dict def render_view(self, field, value, REQUEST=None, key=None, render_format='html', render_prefix=None): """ Render a Chart in read-only. """ if REQUEST is None: REQUEST=get_request() return self.render(field, key, value, REQUEST, render_format=render_format, render_prefix=render_prefix) def render_odf(self, field, key, value, REQUEST, render_format='ooo', render_prefix=None): """ Render a Chart for ODT Style. """ if REQUEST is None: REQUEST=get_request() form = field.aq_parent here = getattr(form, 'aq_parent', REQUEST) REQUEST.set('render_prefix', render_prefix) #needed to update REQUEST argument_dict = self.getArgumentDict(field, REQUEST) from xml.marshal.generic import dumps dump_args = dumps(argument_dict) #remove xml declaration (first processing node) dump_args = dump_args[dump_args.index('?>')+2:] content = '''<office:include path="%s/ERP5Site_buildChart" xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed">%s</office:include> ''' % (here.getPath(), dump_args) return content def render(self, field, key, value, REQUEST, render_format='html', render_prefix=None): """ Render a chart. render_format -- If the format is set to html, render the chart as a URL to ourselves with a png render_format If the format is set to 'raw', render the chart as raw XML. If the format is set to an image type (ex. png) render the chart using that format. """ title = field.get_value('title') alt = field.get_value('description') or title form = field.aq_parent if not render_prefix: render_prefix = REQUEST.get('render_prefix') # Find the applicable context here = getattr(form, 'aq_parent', REQUEST) # Update the render format based on REQUEST parameters render_format = getattr(REQUEST, 'render_format', render_format) if render_format == 'html': css_class = field.get_value('css_class') format = field.get_value('image_format') or 'png' query_dict = dict(REQUEST.form.items()) query_dict.update(render_format=format != 'raw' and format or '', render_prefix=render_prefix, display=field.get_value('image_display')) # XXX make_query does not handle tuples properly so listbox should be # not editable (otherwise, REQUEST.form may contain listbox=()). url = '%s/%s/%s?%s' % (here.absolute_url(), form.getId(), field.getId(), make_query(query_dict)) if format in VALID_IMAGE_FORMAT_LIST: return '''<div class="OOoChartContent"> <img class="%s" src="%s" title="%s" alt="%s"/"> </div>''' % (css_class, url, title, alt) elif format == 'raw': UrlIconOOo = '%s/misc_/ERP5OOo/OOo.png' % REQUEST['BASEPATH1'] return '''<div class="OOoChartContent"> <a href="%s"><img src="%s" alt="OOo"/></a> </div>''' % (url, UrlIconOOo) elif format == 'pdf': UrlIconPdf = '%s/misc_/ERP5Form/PDF.png' % REQUEST['BASEPATH1'] return '''<div class="OOoChartContent"> <a href="%s"><img src="%s" alt="PDF" /></a> </div>''' % (url, UrlIconPdf) else: raise NotImplementedError, 'Format: %s not handled' % format extra_context = self.getArgumentDict(field, REQUEST) method_id = field.get_value('ooo_template') # Find the page template ooo_template = getattr(here, method_id) # Render the chart return ooo_template(format=render_format, **extra_context)
class MultiRelationStringFieldWidget(Widget.LinesTextAreaWidget, Widget.TextWidget, Widget.ListWidget): """ RelationStringField widget Works like a string field but includes one buttons - one search button which updates the field and sets a relation - creates object if not there """ local_property_names = [ 'update_method', 'jump_method', 'allow_jump', 'base_category', 'portal_type', 'allow_creation', 'container_getter_id', 'context_getter_id', 'catalog_index', 'relation_setter_id', 'relation_form_id', 'columns', 'sort', 'parameter_list', 'list_method', 'first_item', 'items', 'proxy_listbox_ids', 'size', 'extra_item', ] property_names = ( lambda name_list, name_set=set(): # delete double (but preserve order) in order to keep a usable ZMI... [x for x in name_list if not (x in name_set or name_set.add(x))] )(Widget.LinesTextAreaWidget.property_names + Widget.TextWidget.property_names + local_property_names) # XXX Field to remove... update_method = fields.StringField( 'update_method', title='Update Method', description=("The method to call to set the relation. Required."), default="Base_validateRelation", required=1) jump_method = fields.StringField( 'jump_method', title='Jump Method', description=("The method to call to jump to the relation. Required."), default="Base_jumpToRelatedDocument", required=1) allow_jump = fields.CheckBoxField( 'allow_jump', title='Allow Jump', description=("Do we allow to jump to the relation ?"), default=1, required=0) base_category = fields.StringField( 'base_category', title='Base Category', description=("The method to call to set the relation. Required."), default="", required=1) portal_type = fields.ListTextAreaField( 'portal_type', title='Portal Type', description=("The method to call to set the relation. Required."), default="", required=0) allow_creation = fields.CheckBoxField( 'allow_creation', title='Allow Creation', description=("Do we allow to create new objects ?"), default=1, required=0) container_getter_id = fields.StringField( 'container_getter_id', title='Container Getter Method', description=("The method to call to get a container object."), default="", required=0) context_getter_id = fields.StringField( 'context_getter_id', title='Context Getter Method', description=("The method to call to get the context."), default="", required=0) catalog_index = fields.StringField( 'catalog_index', title='Catalog Index', description=("The method to call to set the relation. Required."), default="", required=1) # XXX Is it a good idea to keep such a field ?? # User can redefine setter method with a script (and so, don't use the API) relation_setter_id = fields.StringField( 'relation_setter_id', title='Relation Update Method', description=("The method to invoke in order to update the relation"), default="", required=0) relation_form_id = fields.StringField( 'relation_form_id', title='Relation Form', description=("Form to display relation choices"), default="", required=0) size = fields.IntegerField( 'size', title='Size', description=( "The display size in rows of the field. If set to 1, the " "widget will be displayed as a drop down box by many browsers, " "if set to something higher, a list will be shown. Required."), default=1, required=1) columns = fields.ListTextAreaField( 'columns', title="Columns", description=("A list of attributes names to display."), default=[], required=0) sort = fields.ListTextAreaField( 'sort', title='Default Sort', description=('The default sort keys and order'), default=[], required=0) parameter_list = fields.ListTextAreaField( 'parameter_list', title="Parameter List", description=("A list of paramters used for the portal_catalog."), default=[], required=0) list_method = fields.MethodField('list_method', title='List Method', description=('The method to use to list' 'objects'), default='', required=0) proxy_listbox_ids = fields.ListTextAreaField( 'proxy_listbox_ids', title='Proxy Listbox IDs', description=('A list of listbox that can be used as proxy'), default='', required=0) default_widget_rendering_instance = Widget.LinesTextAreaWidgetInstance def _getContextValue(self, field, REQUEST): """Return result of evaluated method defined by context_getter_id or here. """ context_getter_id = field.get_value('context_getter_id') here = REQUEST['here'] if context_getter_id: return getattr(here, context_getter_id)() return here def _generateRenderValueList(self, field, key, value_list, REQUEST): if isinstance(value_list, basestring): # Value is a string, reformat it correctly value_list = value_list.split("\n") else: # We get a list # rather than displaying nothing, display a marker when the # property is not set # XXX Translate ? value_list = [(x or NO_VALUE) for x in value_list] generate_subfield_key = field.generate_subfield_key need_validation = False result_list = [] for index, value in enumerate(value_list): relation_item_list = REQUEST.get( generate_subfield_key( "%s_%s" % (ITEM_ID, index), key=key, ), None, ) # If we get a empty string, display nothing ! if value: need_validation |= relation_item_list is not None result_list.append(( Widget.TextWidgetInstance, generate_subfield_key( "%s_%s" % (SUB_FIELD_ID, index), key=key, ), relation_item_list, value, index, ), ) if need_validation: return result_list return [(Widget.LinesTextAreaWidgetInstance, None, [], value_list, None)] def render(self, field, key, value, REQUEST, render_prefix=None): """ Render text input field. """ portal = self._getContextValue(field, REQUEST).getPortalObject() autocomplete_enabled = getattr( portal.portal_skins, 'erp5_autocompletion_ui', None, ) is not None relation_field_index = REQUEST.get('_v_relation_field_index', 0) html_string_list = [] for (widget_instance, relation_field_id, relation_item_list, value_instance, sub_index) in self._generateRenderValueList( field, key, value, REQUEST, ): sub_html_string = widget_instance.render( field, key, value_instance, REQUEST, ) if autocomplete_enabled: sub_html_string += self.render_autocomplete(field, key) if relation_item_list is not None: if not autocomplete_enabled: sub_html_string += self.render_wheel( field, value_instance, REQUEST, relation_index=relation_field_index, sub_index=sub_index, ) if relation_item_list: REQUEST['relation_item_list'] = relation_item_list sub_html_string += NBSP + Widget.ListWidgetInstance.render( field, relation_field_id, None, REQUEST, ) + NBSP REQUEST['relation_item_list'] = None html_string_list.append(sub_html_string) html_string = '<br/>'.join(html_string_list) if (value == field.get_value('default')): # XXX Default rendering with value... relation_html_string = self.render_relation_link( field, value, REQUEST) if relation_html_string: html_string += NBSP + NBSP + relation_html_string REQUEST.set('_v_relation_field_index', relation_field_index + 1) return html_string def render_view(self, field, value, REQUEST=None, render_prefix=None): """ Render read only field. """ if (value not in ((), [], None, '')) and field.get_value('allow_jump'): if not isinstance(value, (list, tuple)): value = value, html_string = '<br />'.join( '<a class="relationfieldlink" href="%s">%s</a>' % ( escape(jump_reference.absolute_url()), escape(display_value), ) for jump_reference, display_value in zip( getattr( self._getContextValue(field, REQUEST), 'get%sValueList' % ''.join(part.capitalize() for part in field.get_value( 'base_category').split('_')))( portal_type=[ x[0] for x in field.get_value('portal_type') ], filter=dict(field.get_value('parameter_list')), ), value, )) else: html_string = self.default_widget_rendering_instance.render_view( field, value, REQUEST=REQUEST, ) if REQUEST is None: REQUEST = get_request() relation_html_string = self.render_relation_link( field, value, REQUEST) if relation_html_string: html_string += NBSP + NBSP + relation_html_string extra = field.get_value('extra') if extra not in (None, ''): html_string = "<div %s>%s</div>" % (extra, html_string) css_class = field.get_value('css_class') if css_class not in ('', None): html_string = '<span class="%s">%s</span>' % ( escape(css_class), html_string, ) return html_string def render_autocomplete(self, field, key): """ Use jquery-ui autocompletion for all relation fields by default, requiring only erp5_autocompletion_ui bt5 to be installed """ # XXX: Allow to specify more parameters to jquery-ui autocomplete widget? return """ <script type="text/javascript"> $(document).ready(function() { $("input[name='%s']").ERP5Autocomplete({search_portal_type: %s, search_catalog_key: "%s"}); }); </script>""" % ( escape(key), escape(json.dumps([x[0] for x in field.get_value('portal_type')])), escape(field.get_value('catalog_index')), ) def render_wheel(self, field, value, REQUEST, relation_index=0, sub_index=None, render_prefix=None): """ Render wheel used to display a listbox """ here = self._getContextValue(field, REQUEST) portal_url = here.getPortalObject().portal_url if sub_index is None: sub_index_string = '' else: sub_index_string = '_%s' % sub_index return ' <input type="image" ' \ 'src="%s/images/exec16.png" alt="update..." ' \ 'name="%s/viewSearchRelatedDocumentDialog%s%s' \ ':method"/>' % ( escape(portal_url()), escape(portal_url.getRelativeContentURL(here.portal_selections)), escape(str(relation_index)), escape(sub_index_string), ) def render_relation_link(self, field, value, REQUEST, render_prefix=None): """ Render link to the related object. """ if value not in ((), [], None, '') and field.get_value('allow_jump'): # If we this relation field is used as a listbox/matrixbox editable # field, then the context of this cell is set in REQUEST. XXX this is not # 100% reliable way, maybe we need something to know that the field is # beeing rendered as an editable field. cell = REQUEST.get('cell') here = (cell if cell is not None else self._getContextValue( field, REQUEST)) # Keep the selection name in the URL selection_name = REQUEST.get('selection_name') if selection_name is not None: selection_name_html = '&selection_name=%s&selection_index=%s' % ( escape(selection_name), escape(str(REQUEST.get('selection_index', 0))), ) else: selection_name_html = '' ignore_layout = REQUEST.get('ignore_layout') if ignore_layout is not None: selection_name_html += '&ignore_layout:int=%s' % int( ignore_layout) # Generate plan link return '<a href="%s/%s?field_id=%s&form_id=%s%s">' \ '<img src="%s/images/jump.png" alt="jump" />' \ '</a>' % ( escape(here.absolute_url()), escape(field.get_value('jump_method')), escape(field.id), escape(field.aq_parent.id), escape(selection_name_html), escape(here.getPortalObject().portal_url()), ) return ''
class ZPyChartWidget(Widget.Widget): """ A widget to generate pychart charts in multiple formats Chart definition is defined in a script. Some parameters are defined through Web UI. Web UI parameters are intended to be specialised through Proxy fields. """ property_names = Widget.Widget.property_names+\ [ 'selection_name', 'data_method', 'chart_title', 'x_title', 'y_title',] default = fields.StringField( 'default', title='Default', description=("Default value of the text in the widget."), default="", required=0) selection_name = fields.StringField( 'selection_name', title='Selection Name', description=('The name of the selection to store' 'params of selection'), default='', required=0) data_method = fields.StringField( 'data_method', title='Data Method', description=('The method wich returns data'), default='', required=0) chart_title = fields.StringField( 'chart_title', title='Chart Title', description=('The Title on the top of the chart'), default='', required=0) x_title = fields.StringField('x_title', title='X Title', description=('The Title for the X axis'), default='', required=0) y_title = fields.StringField('y_title', title='Y Title', description=('The Title for the Y axis'), default='', required=0) def render(self, field, key, value, REQUEST, render_prefix=None): """ Here, we just generate tags which will later call download """ # Get standard parameters selection_name = field.get_value('selection_name') chart_title = field.get_value('chart_title') data_method = field.get_value('data_method') x_title = field.get_value('x_title') y_title = field.get_value('y_title') # Retrieve the data and set the selection if data_method is not None if data_method: here = REQUEST.get('here', self) if getattr(here, data_method, None) is not None: data_method = getattr(here, data_method) # Retrieve selection selection = here.portal_selections.getSelectionFor( selection_name, REQUEST=REQUEST) # Define the new selection data_method selection.edit( method_id=data_method) # XXX This is probably wrong # Return an image field return """<img src="%s/download?selection_name=%s&chart_title=%s&data_method=%s&x_title=%s&y_title=%s"/>""" % ( field.absolute_url(), selection_name, chart_title, data_method, x_title, y_title)