# HG changeset patch # User Daniel Diniz # Date 1246889607 -7200 # Node ID a944c0169ad8da4a00d12e5955526ee2f7c754ac # Parent af2874bc01f3aefb70578790583f0b57cf482855 Added ability to add custom tooltips and UI improvements. Reviewed by: Lennard de Rijk diff -r af2874bc01f3 -r a944c0169ad8 app/soc/content/css/soc-090627.css --- a/app/soc/content/css/soc-090627.css Mon Jul 06 15:06:05 2009 +0200 +++ b/app/soc/content/css/soc-090627.css Mon Jul 06 16:13:27 2009 +0200 @@ -654,7 +654,6 @@ border: 5px solid #F7CA75; padding: 15px; /*max-width: 700px;*/ - float: left; } @@ -662,9 +661,8 @@ /* TODO(ajaksu) remove if unnecessary */ } -div #survey_widget tr { - float: left; - clear: both; +div #survey_widget table { + width:100% } div #survey_widget th, @@ -674,9 +672,14 @@ /* fields */ -div #survey_widget textarea { +div #survey_widget textarea.long_answer { padding: 10px; - width: 300px; + width: 500px; +} + +div #survey_widget textarea.tooltip_entry { + padding: 10px; + width: 80%; } div #survey_widget input.text_question { @@ -748,19 +751,15 @@ div #survey_widget th, div #survey_widget td, div #survey_widget select { - max-width:700px; } div #survey_widget td { - display: block; } div #survey_widget label { - font-size: 18px; } div #survey_widget fieldset select { - display:block; } div #survey_widget fieldset textarea, diff -r af2874bc01f3 -r a944c0169ad8 app/soc/content/js/survey-edit-090703.js --- a/app/soc/content/js/survey-edit-090703.js Mon Jul 06 15:06:05 2009 +0200 +++ b/app/soc/content/js/survey-edit-090703.js Mon Jul 06 16:13:27 2009 +0200 @@ -76,6 +76,18 @@ } ); + // add index information to choice fields + widget.find('[name=create-option-button]').each( + function () { + $( + '#index_for_' + $(this).attr('value') + ) + .val( + $(this).getPosition() + ); + } + ); + widget.find('.long_answer').each( function () { $(this).attr('name', SURVEY_PREFIX + $(this).getPosition() + @@ -159,7 +171,7 @@ } ); - widget.find('.long_answer').each( + widget.find('.long_answer, .tooltip_entry').each( function () { if ($(this).val().length < 1 || $(this).val() === DEFAULT_LONG_ANSWER_TEXT) { @@ -350,7 +362,7 @@ ); // don't save default value - widget.find('.long_answer').each( + widget.find('.long_answer, .tooltip_entry').each( function () { if ($(this).val() === DEFAULT_LONG_ANSWER_TEXT) { $(this).val(''); @@ -397,9 +409,9 @@ // get position of survey field getPosition: function () { - var this_row = $(this).parents('tr:first'); - var this_table = this_row.parents('table:first'); - var position = this_table.find('tr').index(this_row) + '__'; + var this_fieldset = $(this).parents('fieldset:first'); + var this_table = this_fieldset.parents('table:first'); + var position = this_table.find('fieldset').index(this_fieldset) + '__'; return position; } }); @@ -555,7 +567,7 @@ var new_field = false; var type = button_id + "__"; - var field_count = survey_table.find('tr').length; + var field_count = survey_table.find('fieldset').length; var new_field_count = field_count + 1 + '__'; var MIN_ROWS = 10; @@ -586,7 +598,7 @@ ].join(""); break; case "long_answer": - field_count = survey_table.find('tr').length; + field_count = survey_table.find('fieldset').length; new_field_count = field_count + 1 + '__'; new_field = ['
\n', '', @@ -628,7 +640,7 @@ '"/>' ].join(""); - field_count = survey_table.find('tr').length; + field_count = survey_table.find('fieldset').length; new_field_count = field_count + 1 + '__'; var formatted_name = (SURVEY_PREFIX + new_field_count + type + field_name); diff -r af2874bc01f3 -r a944c0169ad8 app/soc/templates/soc/survey/universal_choice_editor.html --- a/app/soc/templates/soc/survey/universal_choice_editor.html Mon Jul 06 15:06:05 2009 +0200 +++ b/app/soc/templates/soc/survey/universal_choice_editor.html Mon Jul 06 16:13:27 2009 +0200 @@ -1,5 +1,8 @@
+ + + + + + + + + + + + +
{# Drop-down setting whether question is required #}
- + +
{# Drop-down setting whether question allows comments #}
- + +
{# Question type drop-down #} - + {# Render widget drop-down #} +
+ +
+ {# Each choice field has a hidden input where its options' order is stored. #} +{# The index for choice questions is also kept in a hidden input. #} + {# Open the ordered list. #}
    diff -r af2874bc01f3 -r a944c0169ad8 app/soc/views/helper/surveys.py --- a/app/soc/views/helper/surveys.py Mon Jul 06 15:06:05 2009 +0200 +++ b/app/soc/views/helper/surveys.py Mon Jul 06 16:13:27 2009 +0200 @@ -186,7 +186,11 @@ else: key_val = getattr(self.survey_record, key, None) if is_multi and isinstance(key_val, basestring): + # TODO(ajaksu): find out if we still need this safety net key_val = key_val.split(',') + elif not is_multi and isinstance(key_val, list): + # old pick_multi record for a question that is now single choice + key_val = key_val[0] if key_val else '' data[key] = key_val @@ -207,7 +211,7 @@ post_dict = post_dict or {} self.survey_fields = {} schema = SurveyContentSchema(self.survey_content.schema) - extra_attrs = {} + attrs = {} # figure out whether we want a read-only view read_only = self.read_only @@ -217,8 +221,9 @@ survey_entity = self.survey_logic.getSurveyForContent(survey_content) deadline = survey_entity.survey_end read_only = deadline and (datetime.datetime.now() > deadline) - else: - extra_attrs['disabled'] = 'disabled' + + if read_only: + attrs['disabled'] = 'disabled' # add unordered fields to self.survey_fields for field in self.survey_content.dynamic_properties(): @@ -239,7 +244,12 @@ # check if question is required, it's never required when editing required = schema.getRequired(field) - kwargs = dict(label=label, req=required) + + tip = schema.getTip(field) + kwargs = dict(label=label, req=required, tip=tip) + + # copy attrs + extra_attrs = attrs.copy() # add new field addField(field, value, extra_attrs, schema, **kwargs) @@ -258,15 +268,13 @@ survey_order = self.survey_content.getSurveyOrder() # first, insert dynamic survey fields - for position, property in survey_order.items(): - position = position * 2 - fields.insert(position, property, self.survey_fields[property]) + for position, property in sorted(survey_order.items()): + fields.insert(len(fields) + 1, property, self.survey_fields[property]) # add comment if field has one and this isn't an edit view property = COMMENT_PREFIX + property if property in self.survey_fields: - fields.insert(position - 1, property, - self.survey_fields[property]) + fields.insert(len(fields) + 1, property, self.survey_fields[property]) return fields def addLongField(self, field, value, attrs, schema, req=True, label='', @@ -429,7 +437,9 @@ attrs: the attrs for the widget tip: tooltip text for this field """ + attrs['class'] = 'comment' + attrs['rows'] = '1' widget = widgets.Textarea(attrs=attrs) comment_field = CharField(help_text=tip, required=False, label='Add a Comment (optional)', widget=widget, initial=comment) @@ -494,10 +504,10 @@ if label is None: continue - tip = 'Please provide an answer to this question.' + tip = schema.getTip(field) kwargs = schema.getEditFieldArgs(field, value, tip, label) - kwargs['widget'] = schema.getEditWidget(field, extra_attrs) + kwargs['widget'] = schema.getEditWidget(field, extra_attrs, tip) # add new field self.survey_fields[field] = schema.getEditField(field)(**kwargs) @@ -539,11 +549,21 @@ """Fetch question type for field e.g. short_answer, pick_multi, etc. Args: - field: name of the field to get the type from + field: name of the field to get the type for """ return self.schema[field]["type"] + def getTip(self, field): + """Fetch question help text, used for tooltips. + + Args: + field: name of the field to get the tooltip for + """ + + return self.schema[field].get('tip', '') + + def getRequired(self, field): """Check whether survey question is required. @@ -600,11 +620,11 @@ if kind in CHOICE_TYPES: kwargs['choices'] = tuple([(val, val) for val in value]) else: - kwargs['initial'] = value + kwargs['initial'] = tip return kwargs - def getEditWidget(self, field, attrs): + def getEditWidget(self, field, attrs, tip): """Get survey editing widget for questions. """ @@ -615,14 +635,15 @@ if kind in CHOICE_TYPES: widget = UniversalChoiceEditor render = self.getRender(field) - args = kind, render, is_required, has_comment + args = kind, render, is_required, has_comment, tip else: args = is_required, has_comment if kind == 'long_answer': - attrs['class'] = "text_question" widget = LongTextarea elif kind == 'short_answer': widget = ShortTextInput + attrs = attrs.copy() + attrs['class'] = kind kwargs = dict(attrs=attrs) @@ -636,10 +657,9 @@ logging.error('field %s not found in schema %s' % (field, str(self.schema))) return - elif 'question' in self.schema[field]: + else: label = self.schema[field].get('question') or field - else: - label = field + return label @@ -649,8 +669,8 @@ Allows adding and removing options, re-ordering and editing option text. """ - def __init__(self, kind, render, is_required, has_comment, attrs=None, - choices=()): + def __init__(self, kind, render, is_required, has_comment, tip, + attrs=None, choices=()): """ params: kind: question kind (one of selection, pick_multi or pick_quant) @@ -669,6 +689,7 @@ self.render_as = render self.is_required = is_required self.has_comment = has_comment + self.tooltip_content = tip or '' def render(self, name, value, attrs=None, choices=()): """Render UCE widget. @@ -708,6 +729,9 @@ choices[i] = option_value context['choices'] = choices + tooltip_content = escape(forms.util.smart_unicode(self.tooltip_content)) + context['tooltip_content'] = tooltip_content + template = 'soc/survey/universal_choice_editor.html' return loader.render_to_string(template, context) diff -r af2874bc01f3 -r a944c0169ad8 app/soc/views/models/survey.py --- a/app/soc/views/models/survey.py Mon Jul 06 15:06:05 2009 +0200 +++ b/app/soc/views/models/survey.py Mon Jul 06 16:13:27 2009 +0200 @@ -348,7 +348,6 @@ if 'NEW_' + name in POST: # new Choice question, set generic type and get its index schema[name] = {'type': 'choice'} - schema[name]['index'] = int(POST['index_for_' + name]) if name in schema and schema[name]['type'] in CHOICE_TYPES: # build an index:content dictionary @@ -358,7 +357,7 @@ else: survey_fields[name] = {int(number): value} - elif key.startswith('survey__'): # new Text question + elif key.startswith('survey__'): # Text question # this is super ugly but unless data is serialized the regex is needed prefix = re.compile('survey__([0-9]{1,3})__') prefix_match = re.match(prefix, key) @@ -373,10 +372,15 @@ # should only match one if ptype + "__" in field_name: field_name = field_name.replace(ptype + "__", "") - schema[field_name] = {} + if field_name not in schema: + schema[field_name]= {} schema[field_name]["index"] = index schema[field_name]["type"] = ptype + # store text question tooltip from the input/textarea value + schema[field_name]["tip"] = value + + # add the question as a dynamic property to survey_content survey_fields[field_name] = value def getSchemaOptions(self, schema, survey_fields, POST): @@ -397,6 +401,10 @@ schema[key]['render'] = RENDER[POST[render_for]] schema[key]['type'] = RENDER_TYPES[POST[render_for]] + # set the choice question's tooltip + tip_for = 'tip_for_' + key + schema[key]['tip'] = POST.get(tip_for) + # handle reordering fields ordered = False order = 'order_for_' + key @@ -422,7 +430,7 @@ # set 'question' entry (free text label for question) in schema question_for = 'NEW_' + key - if question_for in POST: + if question_for in POST and POST[question_for]: schema[key]["question"] = POST[question_for] # set wheter the question is required @@ -433,6 +441,11 @@ comment_for = 'comment_for_' + key schema[key]['has_comment'] = BOOL[POST[comment_for]] + # set the question index from JS-calculated value + index_for = 'index_for_' + key + if index_for in POST: + schema[key]['index'] = int(POST[index_for].replace('__', '')) + def createGet(self, request, context, params, seed): """Pass the question types for the survey creation template. """