[IMP] Code cleaning and refactoring

bzr revid: rim@openerp.com-20131125080446-kail7m6xav7gf0xg
This commit is contained in:
Richard Mathot (OpenERP) 2013-11-25 09:04:46 +01:00
parent 72e33b8cfe
commit 5b92704e41
5 changed files with 357 additions and 454 deletions

View File

@ -1 +1,22 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-TODAY OpenERP S.A. <http://www.openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import main

View File

@ -22,6 +22,7 @@
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website.models import website
from openerp.osv import fields
from openerp import SUPERUSER_ID
import werkzeug
@ -48,9 +49,9 @@ class WebsiteSurvey(http.Controller):
surveys = survey_obj.browse(cr, uid, survey_ids, context=context)
return request.website.render('survey.list', {'surveys': surveys})
# Survey displaying
@website.route(['/survey/fill/<model("survey.survey"):survey>',
'/survey/fill/<model("survey.survey"):survey>/<string:token>'],
@website.route(['/survey/fill/<model("survey.survey"):survey>/<string:token>'],
type='http', auth='public', multilang=True)
def fill_survey(self, survey, token=None, **post):
'''Display and validates a survey'''
@ -58,6 +59,8 @@ class WebsiteSurvey(http.Controller):
survey_obj = request.registry['survey.survey']
user_input_obj = request.registry['survey.user_input']
# Mettre methode start survey sur objet survey
# In case of bad survey, redirect to surveys list
if survey_obj.exists(cr, uid, survey.id, context=context) == []:
return werkzeug.utils.redirect("/survey/")
@ -68,7 +71,7 @@ class WebsiteSurvey(http.Controller):
# In case of non open surveys
if survey.state != 'open':
return request.website.render("survey.notopen")
return request.website.render("survey.notopen")
# If enough surveys completed
if survey.user_input_limit > 0:
@ -91,35 +94,34 @@ class WebsiteSurvey(http.Controller):
else:
user_input = user_input_obj.browse(cr, uid, [user_input_id], context=context)[0]
# Prevent opening of the survey if the deadline has turned out
# ! This will NOT disallow access to users who have already partially filled the survey !
# if user_input.deadline > fields.date.now() and user_input.state == 'new':
# return request.website.render("survey.notopen")
# TODO check if this is ok
_logger.debug('Incoming data: %s', post)
# if user input.state = new => page -1
# sinon, chercher la dernière page sur laquelle on a des infos enregistrées
# si c'est la dernière, afficher la page de conclusion
# Select the right page
# Display success message if totally succeeded
if post and post['next'] == "finished":
# if user_input.state == 'new' and not post: # Intro page
# data = {'survey': survey, 'page': None, 'token': user_input.token}
# return request.website.render('survey.survey', data)
if user_input.state == 'new': # First page
page, page_nr, last = self.find_next_page(survey, user_input)
data = {'survey': survey, 'page': page, 'page_nr': page_nr, 'token': user_input.token}
if last:
data.update({'last': True})
return request.website.render('survey.survey', data)
elif user_input.state == 'done': # Display success message
return request.website.render('survey.finished', {'survey': survey})
# Page selection
pagination = {'current': -1, 'next': 0}
# Default pagination if first opening
if 'current' in post and 'next' in post and post['next'] != "finished":
oldnext = int(post['next'])
if oldnext not in range(0, len(survey.page_ids)):
raise Exception("This page does not exist")
else:
pagination['current'] = oldnext
if oldnext == len(survey.page_ids) - 1:
pagination['next'] = 'finished'
else:
pagination['next'] = oldnext + 1
return request.website.render('survey.survey',
{'survey': survey,
'pagination': pagination,
'token': user_input.token})
elif user_input.state == 'skip':
page, page_nr, last = self.find_next_page(survey, user_input)
if last:
data.update({'last': True})
data = {'survey': survey, 'page': page, 'page_nr': page_nr, 'token': user_input.token}
else:
return request.website.render("website.403")
# @website.route(['/survey/prefill/<model("survey.survey"):survey>'], type='json', auth='public', multilang=True):
@ -134,21 +136,30 @@ class WebsiteSurvey(http.Controller):
type='http', auth='public', multilang=True)
def submit(self, survey, **post):
_logger.debug('Incoming data: %s', post)
page_nr = int(post['current'])
questions = survey.page_ids[page_nr].question_ids
page_id = int(post['page_id'])
cr, uid, context = request.cr, request.uid, request.context
questions_obj = request.registry['survey.question']
questions_ids = questions_obj.search(cr, uid, [('page_id', '=', page_id)],
context=context)
questions = questions_obj.browse(cr, uid, questions_ids, context=context)
errors = {}
for question in questions:
answer_tag = "%s_%s_%s" % (survey.id, page_nr, question.id)
errors.update(self.validate_question(survey.id, page_nr, question, post, answer_tag))
answer_tag = "%s_%s_%s" % (survey.id, page_id, question.id)
errors.update(self.validate_question(question, post, answer_tag))
ret = {}
if (len(errors) != 0):
ret['errors'] = errors
else:
cr, uid, context = request.cr, request.uid, request.context
user_input_obj = request.registry['survey.user_input']
try:
user_input_id = user_input_obj.search(cr, uid, [('token', '=', post['token'])])[0]
except IndexError: # Invalid token
return request.website.render("website.403")
# Store here data if allowed
ret['redirect'] = "nexturl"
ret['redirect'] = True
return json.dumps(ret)
# Printing routes
@ -161,9 +172,31 @@ class WebsiteSurvey(http.Controller):
{'survey': survey,
'pagination': pagination})
# Pagination
def find_next_page(self, survey, user_input):
''' Find the browse record of the first unfilled page '''
if not user_input.user_input_line_ids:
return survey.page_ids[0], 0, len(survey.page_ids) == 1
else:
filled_pages = set()
for user_input_line in user_input.user_input_line_ids:
filled_pages.add(user_input_line.page_id)
last = False
page_nr = 0
nextpage = None
for page in survey.pages_ids:
if page in filled_pages:
page_nr = page_nr + 1
else:
nextpage = page
if page_nr == len(survey.pages_ids):
last = True
return nextpage, page_nr, last
# Validation methods
def validate_question(self, survey_id, page_nr, question, post, answer_tag):
def validate_question(self, question, post, answer_tag):
''' Routing to the right question valider, depending on question type '''
try:
checker = getattr(self, 'validate_' + question.type)
@ -171,9 +204,9 @@ class WebsiteSurvey(http.Controller):
_logger.warning(question.type + ": This type of question has no validation method")
return {}
else:
return checker(survey_id, page_nr, question, post, answer_tag)
return checker(question, post, answer_tag)
def validate_free_text(self, survey_id, page_nr, question, post, answer_tag):
def validate_free_text(self, question, post, answer_tag):
errors = {}
answer = post[answer_tag].strip()
# Empty answer to mandatory question
@ -181,7 +214,7 @@ class WebsiteSurvey(http.Controller):
errors.update({answer_tag: question.constr_error_msg})
return errors
def validate_textbox(self, survey_id, page_nr, question, post, answer_tag):
def validate_textbox(self, question, post, answer_tag):
errors = {}
answer = post[answer_tag].strip()
# Empty answer to mandatory question
@ -232,7 +265,7 @@ class WebsiteSurvey(http.Controller):
pass
return errors
def validate_numerical_box(self, survey_id, page_nr, question, post, answer_tag):
def validate_numerical_box(self, question, post, answer_tag):
errors = {}
answer = post[answer_tag].strip()
# Empty answer to mandatory question
@ -246,7 +279,7 @@ class WebsiteSurvey(http.Controller):
errors.update({answer_tag: question.constr_error_msg})
return errors
def validate_datetime(self, survey_id, page_nr, question, post, answer_tag):
def validate_datetime(self, question, post, answer_tag):
errors = {}
answer = post[answer_tag].strip()
# Empty answer to mandatory question
@ -256,20 +289,17 @@ class WebsiteSurvey(http.Controller):
# TODO when datepicker will be available
return errors
# def validate_simple_choice(self, survey_id, page_nr, question, post, answer_tag):
# answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
# def validate_simple_choice(self, question, post, answer_tag):
# problems = []
# if question.constr_mandatory:
# problems = problems + self.__has_empty_input(question, post, answer_tag)
# return problems
# def validate_multiple_choice(self, survey_id, page_nr, question, post, answer_tag):
# answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
# def validate_multiple_choice(self, question, post, answer_tag):
# problems = []
# return problems
# def validate_matrix(self, survey_id, page_nr, question, post, answer_tag):
# answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
# def validate_matrix(self, question, post, answer_tag):
# problems = []
# return problems

View File

@ -76,7 +76,7 @@ class survey_survey(osv.osv):
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid,
'web.base.url')
for survey_browse in self.browse(cr, uid, ids, context=context):
res[survey_browse.id] = urljoin(base_url, "survey/fill/%s/"
res[survey_browse.id] = urljoin(base_url, "survey/start/%s/"
% survey_browse.id)
return res
@ -96,7 +96,7 @@ class survey_survey(osv.osv):
[('draft', 'Draft'), ('open', 'Open'), ('close', 'Closed'),
('cancel', 'Cancelled')], 'Status', required=1, readonly=1,
translate=1),
'visible_to_user': fields.boolean('Visible in the Surveys menu',
'visible_to_user': fields.boolean('Public in website',
help="If unchecked, only invited users will be able to open the survey."),
'auth_required': fields.boolean('Login required',
help="Users with a public link will be requested to login before taking part to the survey",
@ -113,7 +113,7 @@ class survey_survey(osv.osv):
'user_input_ids': fields.one2many('survey.user_input', 'survey_id',
'User responses', readonly=1),
'public_url': fields.function(_get_public_url,
string="Public link", searchable=True, type="char", store=True),
string="Public link", type="char"),
'email_template_id': fields.many2one('email.template',
'Email Template', ondelete='set null'),
'thank_you_message': fields.html('Thank you message', translate=True,
@ -364,11 +364,15 @@ class survey_question(osv.osv):
'question_id', 'Suggested answers', oldname='answer_choice_ids'),
# Display options
'simple_choice_display': fields.selection([('1col', '1 column choices'),
('2col', '2 columns choices'),
('3col', '3 columns choices'),
('horizontal', 'Horizontal choices'),
('dropdown', 'Dropdown menu')], 'Display mode'),
'column_nb': fields.selection([('12', '1 column choices'),
('6', '2 columns choices'),
('4', '3 columns choices'),
('3', '4 columns choices'),
('2', '6 columns choices')
], 'Number of columns'),
'display_mode': fields.selection([('columns', 'Columns'),
('dropdown', 'Dropdown menu')
], 'Display mode'),
# Comments
'comments_allowed': fields.boolean('Allow comments',
@ -417,7 +421,8 @@ class survey_question(osv.osv):
_defaults = {
'page_id': lambda s, cr, uid, c: c.get('page_id'),
'type': 'free_text',
'simple_choice_display': '1col',
'column_nb': '12',
'display_mode': 'dropdown',
'constr_type': 'at least',
'constr_minimum_req_ans': 1,
'constr_error_msg': lambda s, cr, uid, c:
@ -579,9 +584,9 @@ class survey_user_input(osv.osv):
'Answer Type', required=1, oldname="response_type"),
'state': fields.selection([('new', 'Not started yet'),
('skip', 'Partially completed'),
('done', 'Completed'),
('test', 'Test')], 'Status',
('done', 'Completed')], 'Status',
readonly=True),
'test_entry': fields.boolean('Test entry'),
# Optional Identification data
'token': fields.char("Identification token", readonly=1),
@ -692,19 +697,20 @@ class survey_user_input_line(osv.osv):
_columns = {
'user_input_id': fields.many2one('survey.user_input', 'User Input',
ondelete='cascade', required=1),
'survey_id': fields.many2one('survey.survey', 'Survey', required=1,
readonly=1, ondelete='cascade'),
'date_create': fields.datetime('Create Date', required=1), # drop
'skipped': fields.boolean('Skipped'),
'survey_id': fields.related('user_input_id', 'survey_id',
type="many2one", relation="survye.survey", string='Survey'),
'question_id': fields.many2one('survey.question', 'Question',
ondelete='restrict'),
'page_id': fields.related('question_id', 'page_id', type='many2one',
relation='survey.page', string="Page"),
'date_create': fields.datetime('Create Date', required=1), # drop
'skipped': fields.boolean('Skipped'),
'answer_type': fields.selection([('textbox', 'Text box'),
('numerical_box', 'Numerical box'),
('free_text', 'Free Text'),
('datetime', 'Date and Time'),
('checkbox', 'Checkbox'),
], 'Question Type', required=1),
('checkbox', 'Checkbox')],
'Question Type', required=1),
'value_text': fields.char("Text answer"),
'value_number': fields.float("Numerical answer"),
'value_date': fields.datetime("Date answer"),

View File

@ -423,7 +423,9 @@
<!-- Labels -->
<group colspan="2" string="Choice of answers" attrs="{'invisible':[('type','not in',['simple_choice', 'multiple_choice'])]}">
<field colspan="2" name="simple_choice_display" string="Display mode" />
<field colspan="2" name="display_mode" string="Display mode" attrs="{'invisible':[('type','not in',['simple_choice'])]}"/>
<field colspan="2" name="column_nb" string="Number of columns" attrs="{'invisible':[('display_mode','=','dropdown'), ('type','=','simple_choice')]}"/>
<field colspan="2" name="labels_ids" nolabel="1" context="{'default_question_id': active_id}">
<tree string="Suggested answers" editable="bottom">
<field name="sequence" widget="handle"/>

View File

@ -1,419 +1,263 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- List of all the surveys -->
<template id="list" name="Survey List">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<h1>Open surveys</h1>
<div class="table-responsive">
<table class="table table-hover">
<tr><th>Title</th><th>Category</th></tr>
<t t-foreach="surveys" t-as="survey">
<tr>
<td><a t-att-href="survey.public_url"><span t-field="survey.title" /></a></td>
<td><span t-field="survey.category"/></td>
</tr>
</t>
</table>
</div>
</div>
</div>
</t>
</template>
<!-- Thank you message when the survey is completed -->
<template id="finished" name="Survey Finished">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="jumbotron">
<h1>Thank you!</h1>
<div t-field="survey.thank_you_message" />
</div>
</div>
</div>
</t>
</template>
<!-- Message when the survey is not open -->
<template id="notopen" name="Survey not open">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="jumbotron">
<h1>Not open</h1>
<p>This survey is not open. Thank you for your interest!</p>
</div>
</div>
</div>
</t>
</template>
<!-- A survey -->
<template id="survey" name="Survey">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/survey/static/src/js/survey.js" />
</t>
<div class="wrap">
<div class="container">
<div class="row">
<div class="col-md-12">
<t t-if="pagination['current'] == -1">
<div class='jumbotron'>
<h1><span t-field='survey.title'/></h1>
<div t-field='survey.description' />
<form role="form" method="post" t-att-name="survey.id.__str__() + '_-1'" t-att-action="'/survey/fill/%s/%s' % (survey.id, token)" target="">
<input type="hidden" name="current" t-att-value="pagination['current'].__str__()" />
<input type="hidden" name="next" t-att-value="pagination['next'].__str__()" />
<input type="submit" class="btn btn-primary btn-lg active" value="Take survey"/>
</form>
</div>
</t>
<t t-if="pagination['current'] != -1">
<t t-set='page' t-value="survey.page_ids[pagination['current']]" />
<t t-call="survey.page" />
</t>
</div>
</div>
</div>
</div>
</t>
</template>
<!-- Navigation & Submission -->
<template id="navsub" name="Footer for navigation and submission">
<div class="text-center">
<t t-if="pagination['current'] != -1 and survey.users_can_go_back"><input type="button" class="btn active survey-btn" value="Previous page"/></t>
<t t-if="pagination['current'] != -1 and pagination['next'] != 'finished'"><input type="submit" class="btn btn-primary active survey-btn" value="Next page"/></t>
<t t-if="pagination['next'] == 'finished'"><input type="submit" class="btn btn-success active survey-btn" value="Submit survey"/></t>
</div>
</template>
<!-- A page -->
<template id="page" name="Page">
<div class="page-header">
<h1><span t-field='page.title' /></h1>
<div t-field='page.description'/>
<progress t-att-value="pagination['current']+1" t-att-max="len(survey.page_ids)"><t t-raw='"Page %s on %s" % (pagination["current"]+1, len(survey.page_ids))' /></progress>
</div>
<form role="form" method="post" class="js_surveyform" t-att-name="survey.id.__str__() + '_' + pagination['current'].__str__()" t-att-action="'/survey/fill/' + survey.id.__str__()" t-att-data-prefill="'/survey/prefill/' + survey.id.__str__()" t-att-data-validate="'/survey/validate/' + survey.id.__str__()" t-att-data-submit="'/survey/submit/' + survey.id.__str__()">
<input type="hidden" name="current" t-att-value="pagination['current'].__str__()" />
<input type="hidden" name="next" t-att-value="pagination['next'].__str__()" />
<t t-foreach='page.question_ids' t-as='question'>
<t t-set="prefix" t-value="'%s_%s_%s' % (survey.id, pagination['current'], question.id)" />
<t t-call='survey.question'/>
</t>
<t t-call='survey.navsub' />
</form>
</template>
<!-- A question -->
<template id='question' name='Question'>
<div class="js_question-wrapper" t-att-id="prefix">
<t t-if="question.type in ['free_text']"><t t-call="survey.free_text"/></t>
<t t-if="question.type in ['textbox']"><t t-call="survey.textbox"/></t>
<t t-if="question.type in ['numerical_box']"><t t-call="survey.numerical_box"/></t>
<t t-if="question.type in ['datetime']"><t t-call="survey.datetime"/></t>
<t t-if="question.type in ['simple_choice']"><t t-call="survey.simple_choice"/></t>
<t t-if="question.type in ['multiple_choice']"><t t-call="survey.multiple_choice"/></t>
<t t-if="question.type in ['matrix']"><t t-call="survey.matrix"/></t>
<div class="js_errzone alert alert-danger" style="display:none;"></div>
</div>
</template>
<!-- Question widgets -->
<template id="free_text" name="Free text box">
<h2><span t-field='question.question' /><t t-if="question.constr_mandatory"><abbr title="This question is mandatory." class="text-danger">*</abbr></t></h2>
<p class="text-muted"><t t-if="question.description"><span t-field='question.description'/></t></p>
<textarea class="form-control" rows="3" t-att-name="prefix"></textarea>
</template>
<template id="textbox" name="Text box">
<h2><span t-field='question.question' /><t t-if="question.constr_mandatory"><abbr title="This question is mandatory." class="text-danger">*</abbr></t></h2>
<p class="text-muted"><t t-if="question.description"><span t-field='question.description'/></t></p>
<input type="text" class="form-control" t-att-name="prefix"/>
</template>
<template id="numerical_box" name="Numerical box">
<h2><span t-field='question.question' /><t t-if="question.constr_mandatory"><abbr title="This question is mandatory." class="text-danger">*</abbr></t></h2>
<p class="text-muted"><t t-if="question.description"><span t-field='question.description'/></t></p>
<input type="number" step=".1" class="form-control" t-att-name="prefix"/>
</template>
<template id="datetime" name="Numerical box">
<h2><span t-field='question.question' /><t t-if="question.constr_mandatory"><abbr title="This question is mandatory." class="text-danger">*</abbr></t></h2>
<p class="text-muted"><t t-if="question.description"><span t-field='question.description'/></t></p>
<input type="datetime-local" class="form-control" t-att-name="prefix" placeholder="jj-mm-aaaa hh:mm" />
</template>
<template id="simple_choice" name="Simple choice">
<h2><span t-field='question.question' /><t t-if="question.constr_mandatory"><abbr title="This question is mandatory." class="text-danger">*</abbr></t></h2>
<p class="text-muted"><t t-if="question.description"><span t-field='question.description'/></t></p>
<t t-if="question.simple_choice_display == 'dropdown'">
<div class="js_drop row">
<div class="col-md-6">
<select class="form-control" t-att-name="prefix">
<option disabled="1" selected="1">Choose...</option>
<t t-foreach='question.labels_ids' t-as='label'>
<option><t t-esc='label.value'/></option>
<data>
<!-- List of all the surveys -->
<template id="list" name="Survey List">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<h1>Open surveys</h1>
<div class="table-responsive">
<table class="table table-hover">
<tr><th>Title</th><th>Category</th></tr>
<t t-foreach="surveys" t-as="survey">
<tr>
<td><a t-att-href="survey.public_url" t-field="survey.title" /></td>
<td><span t-field="survey.category"/></td>
</tr>
</t>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<option class="js_other_option"><span t-esc="question.children_ids[0].question" /></option>
</t>
</select>
</table>
</div>
<div class="col-md-6">
</div>
</div>
</t>
</template>
<!-- Thank you message when the survey is completed -->
<template id="finished" name="Survey Finished">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="jumbotron">
<h1>Thank you!</h1>
<div t-field="survey.thank_you_message" />
</div>
</div>
</div>
</t>
</template>
<!-- Message when the survey is not open -->
<template id="notopen" name="Survey not open">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="jumbotron">
<h1>Not open</h1>
<p>This survey is not open. Thank you for your interest!</p>
</div>
</div>
</div>
</t>
</template>
<!-- First page of a survey -->
<template id="survey_init" name="Survey">
<t t-call="website.layout">
<div class="wrap">
<div class="oe_structure" />
<div class="container">
<div class='jumbotron mt32'>
<h1 t-field='survey.title' />
<div t-field='survey.description' />
<a class="btn btn-primary btn-lg" t-att-href="'/survey/fill/%s/%s' % (survey.id, token)">
Start Survey
</a>
</div>
</div>
<div class="oe_structure" />
</div>
</t>
</template>
<!-- A survey -->
<template id="survey" name="Survey">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/survey/static/src/js/survey.js" />
</t>
<div class="wrap">
<div class="oe_structure"/>
<div class="container">
<t t-call="survey.page" />
</div>
<div class="oe_structure"/>
</div>
</t>
</template>
<!-- A page -->
<template id="page" name="Page">
<div class="page-header">
<progress t-att-value="page_nr + 1" t-att-max="len(survey.page_ids)" class="pull-right">
Page <span t-raw='page_nr + 1'/> on <span t-raw="len(survey.page_ids)"/>
</progress>
<h1 t-field='page.title' />
<div t-field='page.description'/>
</div>
<form role="form" method="post" class="js_surveyform" t-att-name="'%s_%s' % (survey.id, page.id)" t-att-action="'/survey/fill/%s/%s' % (survey.id, token)" t-att-data-prefill="'/survey/prefill/%s' % (survey.id)" t-att-data-validate="'/survey/validate/%s' % (survey.id)" t-att-data-submit="'/survey/submit/%s' % (survey.id)">
<input type="hidden" name="page_id" t-att-value="page.id" />
<input type="hidden" name="token" t-att-value="token" />
<t t-foreach='page.question_ids' t-as='question'>
<t t-set="prefix" t-value="'%s_%s_%s' % (survey.id, page.id, question.id)" />
<div class="js_question-wrapper" t-att-id="prefix">
<h2>
<span t-field='question.question' />
<abbr t-if="question.constr_mandatory" title="This question is mandatory." class="text-danger">*</abbr>
</h2>
<p class="text-muted"><t t-if="question.description"><span t-field='question.description'/></t></p>
<t t-if="question.type in ['free_text']"><t t-call="survey.free_text"/></t>
<t t-if="question.type in ['textbox']"><t t-call="survey.textbox"/></t>
<t t-if="question.type in ['numerical_box']"><t t-call="survey.numerical_box"/></t>
<t t-if="question.type in ['datetime']"><t t-call="survey.datetime"/></t>
<t t-if="question.type in ['simple_choice']"><t t-call="survey.simple_choice"/></t>
<t t-if="question.type in ['multiple_choice']"><t t-call="survey.multiple_choice"/></t>
<t t-if="question.type in ['matrix']"><t t-call="survey.matrix"/></t>
<div class="js_errzone alert alert-danger" style="display:none;"></div>
</div>
</t>
<div class="text-center mt16 mb16">
<button t-if="survey.users_can_go_back and page_nr > 0" type="submit" class="btn btn-default">Previous page</button>
<button t-if="not last" type="submit" class="btn btn-primary">Next page</button>
<button type="submit" t-if="last" class="btn btn-primary">Submit survey</button>
</div>
</form>
</template>
<!-- Question widgets -->
<template id="free_text" name="Free text box">
<textarea class="form-control" rows="3" t-att-name="prefix"></textarea>
</template>
<template id="textbox" name="Text box">
<input type="text" class="form-control" t-att-name="prefix"/>
</template>
<template id="numerical_box" name="Numerical box">
<input type="number" step=".1" class="form-control" t-att-name="prefix"/>
</template>
<template id="datetime" name="Datetime box">
<input type="datetime-local" class="form-control" t-att-name="prefix" placeholder="jj-mm-aaaa hh:mm" />
</template>
<template id="simple_choice" name="Simple choice">
<div t-if="question.display_mode == 'dropdown'" class="js_drop row">
<div class="col-md-6">
<select class="form-control" t-att-name="prefix">
<option disabled="1" selected="1">Choose...</option>
<t t-foreach='question.labels_ids' t-as='label'>
<option><t t-esc='label.value'/></option>
</t>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<input type="text" class="form-control" t-att-name="prefix+'_other'" data-oe-survey-othert="1"/>
<option class="js_other_option"><span t-esc="question.children_ids[0].question" /></option>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div>
<span t-field="question.children_ids[0].question" />
<input type="text" class="form-control" t-att-name="prefix+'_comments'"/>
</div>
</t>
</div>
</select>
</div>
</t>
<t t-if="question.simple_choice_display == 'horizontal'">
<div class="js_radio">
<t t-foreach='question.labels_ids' t-as='label'>
<label class="radio-inline">
<input type="radio" t-att-name="prefix" t-att-value='label.id' />
<span t-field='label.value'/>
</label>
</t>
<div class="col-md-6">
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm js_comments">
<span class="input-group-addon"><input type="radio" t-att-name="prefix" data-oe-survey-otherr="1"/><span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix" data-oe-survey-othert="1"/>
</div>
<input type="text" class="form-control" t-att-name="prefix+'_other'" data-oe-survey-othert="1"/>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div>
<span t-field="question.children_ids[0].question" />
<input type="text" class="form-control" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
<input type="text" class="form-control" t-att-name="prefix+'_comments'"/>
</div>
</t>
</div>
</t>
<t t-if="question.simple_choice_display == '1col'">
<div class="js_radio">
<t t-foreach='question.labels_ids' t-as='label'>
<div class="radio">
<label>
<input type="radio" t-att-name="prefix" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</div>
</t>
</div>
<div t-if="question.display_mode == 'columns' " class="row js_radio">
<div t-foreach='question.labels_ids' t-as='label' t-attf-class="col-md-#{question.column_nb}">
<label>
<input type="radio" t-att-name="prefix" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_comments col-md-12" >
<label>
<input type="radio" t-att-name="prefix" />
<span t-field="question.children_ids[0].question" />
</label>
<input type="text" class="form-control" t-att-name="'%s_%s' % (prefix, question.children_ids[0].id)"/>
</div>
<div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-md-12">
<span t-field="question.children_ids[0].question"/>
<input type="text" class="form-control" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
</div>
</template>
<!--
<template id="simple_choice" name="Simple choice">
<t t-if="question.choices_display == 'dropdown'">
<div class="js_drop row">
<div class="col-md-6">
<select class="form-control" t-att-name="prefix">
<option disabled="1" selected="1">Choose...</option>
<t t-foreach='question.labels_ids' t-as='label'>
<option><t t-esc='label.value'/></option>
</t>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<option class="js_other_option"><span t-esc="question.children_ids[0].question" /></option>
</t>
</select>
</div>
<div class="col-md-6">
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm js_comments">
<span class="input-group-addon"><input type="radio" t-att-name="prefix" data-oe-survey-otherr="1"/><span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix" data-oe-survey-othert="1"/>
</div>
<input type="text" class="form-control" t-att-name="prefix+'_other'" data-oe-survey-othert="1"/>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div>
<span t-field="question.children_ids[0].question" />
<input type="text" class="form-control" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
<input type="text" class="form-control" t-att-name="prefix+'_comments'"/>
</div>
</t>
</div>
</t>
<t t-if="question.simple_choice_display == '2col'">
<div class="js_radio">
</div>
</t>
</template> -->
<template id="multiple_choice" name="Multiple choice">
<div class="row">
<div t-foreach='question.labels_ids' t-as='label' t-attf-class="col-md-#{question.column_nb}">
<label>
<input type="checkbox" t-att-name="'%s_%s' % (prefix, label.id)" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_ck_comments col-md-12" >
<label>
<input type="checkbox" t-att-name="prefix + '_other'" />
<span t-field="question.children_ids[0].question" />
</label>
<input type="text" class="form-control" t-att-name="'%s_%s' % (prefix, question.children_ids[0].id)"/>
</div>
<div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-md-12">
<span t-field="question.children_ids[0].question"/>
<input type="text" class="form-control" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
</div>
</template>
<!-- Printable view of a survey (all pages) -->
<template id="survey_print" name="Survey">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="row">
<t t-foreach='question.labels_ids' t-as='label'>
<div class="radio col-md-6">
<label>
<input type="radio" t-att-name="prefix" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</div>
</t>
</div>
<div class="row">
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm js_comments col-md-6">
<span class="input-group-addon"><input type="radio" t-att-name="prefix" data-oe-survey-otherr="1"/><span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix" data-oe-survey-othert="1"/>
</div>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div class="col-md-6">
<span t-field="question.children_ids[0].question" />
<input type="text" class="form-control" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
</t>
</div>
</div>
</t>
<t t-if="question.simple_choice_display == '3col'">
<div class="js_radio">
<div class="row">
<t t-foreach='question.labels_ids' t-as='label'>
<div class="radio col-md-4">
<label>
<input type="radio" t-att-name="prefix" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</div>
</t>
</div>
<div class="row">
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm js_comments col-md-4">
<span class="input-group-addon"><input type="radio" t-att-name="prefix" data-oe-survey-otherr="1"/><span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix" data-oe-survey-othert="1"/>
</div>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div class="col-md-4">
<span t-field="question.children_ids[0].question" />
<input type="text" class="form-control" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
</t>
</div>
</div>
</t>
</template>
<template id="multiple_choice" name="Multiple choice">
<h2><span t-field='question.question' /><t t-if="question.constr_mandatory"><abbr title="This question is mandatory." class="text-danger">*</abbr></t></h2>
<p class="text-muted"><t t-if="question.description"><span t-field='question.description'/></t></p>
<t t-if="question.simple_choice_display == 'horizontal'">
<div>
<t t-foreach='question.labels_ids' t-as='label'>
<label class="checkbox-inline">
<input type="checkbox" t-att-name="prefix + '_' + label.id.__str__()" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</t>
<div>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm col-md-4 js_ck_comments">
<span class="input-group-addon"><input type="checkbox" t-att-name="prefix + '_other'" /> <span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix + '_' + question.children_ids[0].id.__str__()"/>
</div>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div class="row">
<span t-field="question.children_ids[0].question" class="col-md-4"/>
<input type="text" class="form-control col-md-4" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
</t>
</div>
</div>
</t>
<t t-if="question.simple_choice_display == '1col'">
<div>
<t t-foreach='question.labels_ids' t-as='label'>
<div class="checkbox">
<label>
<input type="checkbox" t-att-name="prefix + '_' + label.id.__str__()" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
<div class='jumbotron'>
<h1><span t-field='survey.title'/></h1>
<t t-if="survey.description is not False"><p><span t-field='survey.description'/></p></t>
</div>
</t>
<div>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm js_ck_comments">
<span class="input-group-addon"><input type="checkbox" t-att-name="prefix + '_other'" /> <span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix + '_' + question.children_ids[0].id.__str__()"/>
</div>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div class="row">
<span t-field="question.children_ids[0].question" class="col-md-4"/>
<input type="text" class="form-control col-md-4" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
<t t-foreach="survey.page_ids" t-as="page">
<t t-call="survey.page" />
<hr/>
</t>
</div>
</div>
</t>
<t t-if="question.simple_choice_display == '2col'">
<div class="row">
<t t-foreach='question.labels_ids' t-as='label'>
<div class="checkbox col-md-6">
<label>
<input type="checkbox" t-att-name="prefix + '_' + label.id.__str__()" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</div>
</t>
<div>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm col-md-6 js_ck_comments">
<span class="input-group-addon"><input type="checkbox" t-att-name="prefix + '_other'" /> <span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix + '_' + question.children_ids[0].id.__str__()"/>
</div>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div class="row">
<span t-field="question.children_ids[0].question" class="col-md-4"/>
<input type="text" class="form-control col-md-4" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
</t>
</div>
</div>
</t>
<t t-if="question.simple_choice_display == '3col'">
<div class="row">
<t t-foreach='question.labels_ids' t-as='label'>
<div class="checkbox col-md-4">
<label>
<input type="checkbox" t-att-name="prefix + '_' + label.id.__str__()" t-att-value='label.value' />
<span t-field='label.value'/>
</label>
</div>
</t>
<div>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div class="input-group input-group-sm col-md-4 js_ck_comments">
<span class="input-group-addon"><input type="checkbox" t-att-name="prefix + '_other'" /> <span t-field="question.children_ids[0].question" /></span>
<input type="text" class="form-control" t-att-name="prefix + '_' + question.children_ids[0].id.__str__()"/>
</div>
</t>
<t t-if='question.comments_allowed and not question.comment_count_as_answer'>
<div class="row">
<span t-field="question.children_ids[0].question" class="col-md-4"/>
<input type="text" class="form-control col-md-4" t-att-name="prefix+'_comments'" data-oe-survey-othert="1"/>
</div>
</t>
</div>
</div>
</t>
</template>
<!-- Printable view of a survey (all pages) -->
<template id="survey_print" name="Survey">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="row">
<div class='jumbotron'>
<h1><span t-field='survey.title'/></h1>
<t t-if="survey.description is not False"><p><span t-field='survey.description'/></p></t>
</div>
<t t-foreach="survey.page_ids" t-as="page">
<t t-call="survey.page" />
<hr/>
</t>
</div>
</div>
</div>
</t>
</template>
</data>
</div>
</t>
</template>
</data>
</openerp>