summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Beguin <dbe@odoo.com>2019-04-09 15:07:12 +0000
committerDavid Beguin <dbe@odoo.com>2019-11-19 12:52:22 +0000
commitee0b11f2ce68fc103b990a4a40fcd871db31562a (patch)
treec325fd821b00a0d313046b45241271283e0a2e5b
parentf462bf0d9374a8360ed95f4c70f0e9fc6b3dcb68 (diff)
[REF] survey : make survey result a widget
This commit cake the survey result analysis js constroller become a widget. This also simplify style rules using CSS (was handled in JS). This also modifies the handling of filters to use real and correctly formated GET parameters. Redirect url with parameters are now handled automatically using URLSearchParams() instead of building manually the query string. Task ID : 1930132 PR #32419
-rw-r--r--addons/survey/controllers/main.py20
-rw-r--r--addons/survey/static/src/css/survey_result.css11
-rw-r--r--addons/survey/static/src/js/survey_result.js296
-rw-r--r--addons/survey/views/survey_templates.xml10
4 files changed, 200 insertions, 137 deletions
diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py
index 08a8421578a..ba124dc9632 100644
--- a/addons/survey/controllers/main.py
+++ b/addons/survey/controllers/main.py
@@ -382,12 +382,9 @@ class Survey(http.Controller):
result_template = 'survey.result'
current_filters = []
filter_display_data = []
- filter_finish = False
answers = survey.user_input_ids.filtered(lambda answer: answer.state != 'new' and not answer.test_entry)
- if 'finished' in post:
- post.pop('finished')
- filter_finish = True
+ filter_finish = post.get('finished') == 'true'
if post or filter_finish:
filter_data = self._get_filter_data(post)
current_filters = survey.filter_input_ids(filter_data, filter_finish)
@@ -504,13 +501,14 @@ class Survey(http.Controller):
def _get_filter_data(self, post):
"""Returns data used for filtering the result"""
filters = []
- for ids in post:
- #if user add some random data in query URI, ignore it
- try:
- row_id, answer_id = ids.split(',')
- filters.append({'row_id': int(row_id), 'answer_id': int(answer_id)})
- except:
- return filters
+ filters_data = post.get('filters')
+ if filters_data:
+ for data in filters_data.split('|'):
+ try:
+ row_id, answer_id = data.split(',')
+ filters.append({'row_id': int(row_id), 'answer_id': int(answer_id)})
+ except:
+ return filters
return filters
def page_range(self, total_record, limit):
diff --git a/addons/survey/static/src/css/survey_result.css b/addons/survey/static/src/css/survey_result.css
index 967ea1bd74e..dda0022abe6 100644
--- a/addons/survey/static/src/css/survey_result.css
+++ b/addons/survey/static/src/css/survey_result.css
@@ -20,6 +20,10 @@
cursor: pointer;
}
+.o_active_filter {
+ cursor:default;
+}
+
.nvtooltip h5 {
margin: 0;
line-height: 18px;
@@ -32,14 +36,13 @@
border-radius: 5px 5px 0 0;
}
-
.survey_answer i {
padding:3px;
cursor:pointer;
+ visibility:hidden;
}
-
-.survey_answer i.invisible {
- visibility: hidden!important;
+.survey_answer:hover i {
+ visibility: visible;
}
@media print {
diff --git a/addons/survey/static/src/js/survey_result.js b/addons/survey/static/src/js/survey_result.js
index 4d5148faf89..9152ca8f7fe 100644
--- a/addons/survey/static/src/js/survey_result.js
+++ b/addons/survey/static/src/js/survey_result.js
@@ -1,43 +1,100 @@
odoo.define('survey.result', function (require) {
'use strict';
-require('web.dom_ready');
var _t = require('web.core')._t;
+var ajax = require('web.ajax');
+var publicWidget = require('web.public.widget');
-if(!$('.js_surveyresult').length) {
- return Promise.reject("DOM doesn't contain '.js_surveyresult'");
-}
+// The given colors are the same as those used by D3
+var D3_COLORS = ["#1f77b4","#ff7f0e","#aec7e8","#ffbb78","#2ca02c","#98df8a","#d62728",
+ "#ff9896","#9467bd","#c5b0d5","#8c564b","#c49c94","#e377c2","#f7b6d2",
+ "#7f7f7f","#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5"];
- // The given colors are the same as those used by D3
- var D3_COLORS = ["#1f77b4","#ff7f0e","#aec7e8","#ffbb78","#2ca02c","#98df8a","#d62728",
- "#ff9896","#9467bd","#c5b0d5","#8c564b","#c49c94","#e377c2","#f7b6d2",
- "#7f7f7f","#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5"];
+publicWidget.registry.SurveyResultWidget = publicWidget.Widget.extend({
+ selector: '.o_survey_result',
+ events: {
+ 'click td.survey_answer i.fa-filter': '_onSurveyAnswerFilterClick',
+ 'click .clear_survey_filter': '_onClearFilterClick',
+ 'click span.filter-all': '_onFilterAllClick',
+ 'click span.filter-finished': '_onFilterFinishedClick',
+ },
- //Script For Pagination
- var survey_pagination = $('.pagination');
- $.each(survey_pagination, function(index, pagination){
- var question_id = $(pagination).attr("data-question_id");
- var limit = $(pagination).attr("data-record_limit"); //Number of Record Par Page. If you want to change number of record per page, change record_limit in pagination template.
- $('#table_question_'+ question_id +' tbody tr:lt('+limit+')').removeClass('d-none');
- $('#pagination_'+question_id+' li a').click(function(event){
- event.preventDefault();
- $('#pagination_'+question_id+' li').removeClass('active');
- $(this).parent('li').addClass('active');
- $('#table_question_'+ question_id +' tbody tr').addClass('d-none');
- var num = $(this).text();
- var min = (limit * (num-1))-1;
- if (min == -1){
- $('#table_question_'+ question_id +' tbody tr:lt('+ limit * num +')').removeClass('d-none');
+ //--------------------------------------------------------------------------
+ // Widget
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ start: function () {
+ var superDef = this._super.apply(this, arguments);
+ var self = this;
+
+ //Script For Pagination
+ var survey_pagination = $('.pagination');
+ $.each(survey_pagination, function(index, pagination){
+ var question_id = $(pagination).attr("data-question_id");
+ var limit = $(pagination).attr("data-record_limit"); //Number of Record Par Page. If you want to change number of record per page, change record_limit in pagination template.
+ self.$('#table_question_'+ question_id +' tbody tr:lt('+limit+')').removeClass('d-none');
+ self.$('#pagination_'+question_id+' li a').click(function(event){
+ event.preventDefault();
+ self.$('#pagination_'+question_id+' li').removeClass('active');
+ $(this).parent('li').addClass('active');
+ self.$('#table_question_'+ question_id +' tbody tr').addClass('d-none');
+ var num = $(this).text();
+ var min = (limit * (num-1))-1;
+ if (min === -1){
+ self.$('#table_question_'+ question_id +' tbody tr:lt('+ limit * num +')').removeClass('d-none');
+ }
+ else{
+ self.$('#table_question_'+question_id+' tbody tr:lt('+ limit * num +'):gt('+min+')').removeClass('d-none');
+ }
+ });
+ self.$('#pagination_'+question_id+' li:first').addClass('active').find('a').click();
+ });
+
+ //Script For Graph
+ var survey_graphs = self.$('.survey_graph');
+ $.each(survey_graphs, function(index, graph){
+ var question_id = $(graph).attr("data-question_id");
+ var graph_type = $(graph).attr("data-graph_type");
+ var graph_data = JSON.parse($(graph).attr("graph-data"));
+ var containerSelector = '#graph_question_' + question_id;
+ var chartConfig;
+ if(graph_type === 'multi_bar'){
+ chartConfig = self._initMultibarChart(graph_data);
+ self._loadChart(chartConfig, containerSelector);
+ }
+ else if(graph_type === 'bar'){
+ chartConfig = self._initBarChart(graph_data);
+ self._loadChart(chartConfig, containerSelector);
+ }
+ else if(graph_type === 'pie'){
+ chartConfig = self._initPieChart(graph_data);
+ self._loadChart(chartConfig, containerSelector);
}
- else{
- $('#table_question_'+question_id+' tbody tr:lt('+ limit * num +'):gt('+min+')').removeClass('d-none');
+ else if (graph_type === 'doughnut') {
+ var quizz_score = $(graph).attr("quizz-score") || 0.0;
+ chartConfig = init_doughnut_chart(graph_data, quizz_score);
+ self._loadChart(chartConfig, containerSelector);
}
});
- $('#pagination_'+question_id+' li:first').addClass('active').find('a').click();
- });
+
+ var $scoringResultsChart = $('#scoring_results_chart');
+ if ($scoringResultsChart.length > 0) {
+ var chartConfig = self._initPieChart($scoringResultsChart.data('graph_data'));
+ self._loadChart(chartConfig, '#scoring_results_chart');
+ }
+
+ return superDef;
+ },
+
+ // -------------------------------------------------------------------------
+ // Private - Tools
+ // -------------------------------------------------------------------------
// Custom Tick fuction for replacing long text with '...'
- var customtick_function = function (tick_limit) {
+ _customTick: function (tick_limit) {
return function(label) {
if (label.length <= tick_limit) {
return label;
@@ -46,10 +103,10 @@ if(!$('.js_surveyresult').length) {
return label.slice(0, tick_limit) + '...';
}
};
- };
+ },
//initialize MultiBar Chart
- function init_multibar_chart (graph_data) {
+ _initMultibarChart: function (graph_data) {
var chartConfig = {
type: 'bar',
data: {
@@ -71,7 +128,7 @@ if(!$('.js_surveyresult').length) {
scales: {
xAxes: [{
ticks: {
- callback: customtick_function(25),
+ callback: this._customTick(25),
},
}],
yAxes: [{
@@ -90,10 +147,10 @@ if(!$('.js_surveyresult').length) {
},
};
return chartConfig;
- }
+ },
//initialize discreteBar Chart
- function init_bar_chart(graph_data){
+ _initBarChart: function (graph_data) {
var chartConfig = {
type: 'bar',
data: {
@@ -120,7 +177,7 @@ if(!$('.js_surveyresult').length) {
scales: {
xAxes: [{
ticks: {
- callback: customtick_function(35),
+ callback: this._customTick(35),
},
}],
yAxes: [{
@@ -135,10 +192,10 @@ if(!$('.js_surveyresult').length) {
},
};
return chartConfig;
- }
+ },
- //initialize Pie Chart
- function init_pie_chart(graph_data){
+ //initialize Pie Chart
+ _initPieChart: function (graph_data) {
var data = graph_data.map(function (point) {
return point.count;
});
@@ -155,13 +212,13 @@ if(!$('.js_surveyresult').length) {
return D3_COLORS[index % 20];
}),
}]
- }
+ }
};
return chartConfig;
- }
+ },
//initialize doughnut Chart
- function init_doughnut_chart(graph_data, quizz_score){
+ _init_doughnut_chart: function (graph_data, quizz_score){
var data = graph_data.map(function (point) {
return point.count;
});
@@ -190,91 +247,96 @@ if(!$('.js_surveyresult').length) {
}
//load chart to svg element chart:initialized chart, response:AJAX response, quistion_id:if of survey question, tick_limit:text length limit
- function load_chart(chartConfig, containerSelector){
- var $container = $(containerSelector).css({position: 'relative'});
+ _loadChart: function (chartConfig, containerSelector) {
+ var $container = this.$(containerSelector).css({position: 'relative'});
var $canvas = $container.find('canvas');
var ctx = $canvas.get(0).getContext('2d');
return new Chart(ctx, chartConfig);
- }
+ },
- //Script For Graph
- var survey_graphs = $('.survey_graph');
- $.each(survey_graphs, function(index, graph){
- var question_id = $(graph).attr("data-question_id");
- var graph_type = $(graph).attr("data-graph_type");
- var graph_data = JSON.parse($(graph).attr("graph-data"));
- var containerSelector = '#graph_question_' + question_id;
- var chartConfig;
- if(graph_type == 'multi_bar'){
- chartConfig = init_multibar_chart(graph_data);
- load_chart(chartConfig, containerSelector);
- }
- else if(graph_type == 'bar'){
- chartConfig = init_bar_chart(graph_data);
- load_chart(chartConfig, containerSelector);
- }
- else if(graph_type == 'pie'){
- chartConfig = init_pie_chart(graph_data);
- load_chart(chartConfig, containerSelector);
- }
- else if (graph_type === 'doughnut') {
- var quizz_score = $(graph).attr("quizz-score") || 0.0;
- chartConfig = init_doughnut_chart(graph_data, quizz_score);
- return load_chart(chartConfig, containerSelector);
- }
- });
+ // -------------------------------------------------------------------------
+ // Handlers
+ // -------------------------------------------------------------------------
- var $scoringResultsChart = $('#scoring_results_chart');
- if ($scoringResultsChart.length > 0) {
- var chartConfig = init_pie_chart($scoringResultsChart.data('graph_data'));
- load_chart(chartConfig, '#scoring_results_chart');
- }
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onSurveyAnswerFilterClick: function (ev) {
+ var cell = $(ev.target);
+ var row_id = cell.data('row_id') | 0;
+ var answer_id = cell.data('answer_id');
- // Script for filter
- $('td.survey_answer').hover(function(){
- $(this).find('i.fa-filter').removeClass('invisible');
- }, function(){
- $(this).find('i.fa-filter').addClass('invisible');
- });
- $('td.survey_answer i.fa-filter').click(function(){
- var cell = $(this);
- var row_id = cell.attr('data-row_id') | 0;
- var answer_id = cell.attr('data-answer_id');
- if(document.URL.indexOf("?") == -1){
- window.location.href = document.URL + '?' + encodeURI(row_id + ',' + answer_id);
- }
- else {
- window.location.href = document.URL + '&' + encodeURI(row_id + ',' + answer_id);
- }
- });
+ var params = this._getQueryStringParams();
+ var filters = params['filters'] ? params['filters'] + "|" + row_id + ',' + answer_id : row_id + ',' + answer_id
+ params['filters'] = filters;
- // for clear all filters
- $('.clear_survey_filter').click(function(){
- window.location.href = document.URL.substring(0,document.URL.indexOf("?"));
- });
- $('span.filter-all').click(function(){
- event.preventDefault();
- if(document.URL.indexOf("finished") != -1){
- window.location.href = document.URL.replace('?finished&','?').replace('&finished&','&').replace('?finished','').replace('&finished','');
- }
- }).hover(function(){
- if(document.URL.indexOf("finished") == -1){
- $(this)[0].style.cursor = 'default';
- }
- });
- // toggle finished/all surveys filter
- $('span.filter-finished').click(function(){
- event.preventDefault();
- if(document.URL.indexOf("?") == -1){
- window.location.href = document.URL + '?' + encodeURI('finished');
- }
- else if(document.URL.indexOf("finished") == -1){
- window.location.href = document.URL + '&' + encodeURI('finished');
+ window.location.href = window.location.pathname + '?' + this._toQueryString(params);
+ },
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onClearFilterClick: function (ev) {
+ var params = this._getQueryStringParams();
+ delete params['filters'];
+ delete params['finished'];
+ window.location.href = window.location.pathname + '?' + this._toQueryString(params);
+ },
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onFilterAllClick: function (ev) {
+ var params = this._getQueryStringParams();
+ delete params['finished'];
+ window.location.href = window.location.pathname + '?' + this._toQueryString(params);
+ },
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onFilterFinishedClick: function (ev) {
+ var params = this._getQueryStringParams();
+ params['finished'] = true;
+ window.location.href = window.location.pathname + '?' + this._toQueryString(params);
+ },
+
+ // TODO DBE : Remove the two next functions in v13 and use URLSearchParams instead (see task id : 1985506)
+ // as IE will not be supported anymore in v13.
+ _getQueryStringParams: function () {
+ var paramsDict = {};
+ var params = window.location.search.split('?');
+ if (params.length === 1) {
+ return paramsDict;
}
- }).hover(function(){
- if(document.URL.indexOf("finished") != -1){
- $(this)[0].style.cursor = 'default';
+ params = params[1].split('&');
+ params.forEach(function (param) {
+ var paramKeyValue = param.split('=');
+ paramsDict[paramKeyValue[0]] = paramKeyValue.length === 2 ? paramKeyValue[1] : null;
+ });
+ return paramsDict;
+ },
+
+ _toQueryString: function (paramsDict) {
+ var queryString = "";
+ _.each(paramsDict, function (value, key) {
+ if (value) {
+ queryString += key + '=' + value + '&';
+ } else {
+ queryString += key + '&';
+ }
+ });
+ if (queryString.length > 0) {
+ queryString = queryString.substring(0, queryString.length-1);
}
- });
+ return queryString;
+ },
+});
+
+return publicWidget.registry.SurveyResultWidget;
});
diff --git a/addons/survey/views/survey_templates.xml b/addons/survey/views/survey_templates.xml
index 4adc39682f8..3e2128a13b0 100644
--- a/addons/survey/views/survey_templates.xml
+++ b/addons/survey/views/survey_templates.xml
@@ -550,7 +550,7 @@
<template id="result" name="Survey Result">
<t t-call="survey.layout">
<div class="oe_structure" id="oe_structure_survey_result_1"/>
- <div class="container js_surveyresult">
+ <div class="container o_survey_result">
<t t-call="survey.back" />
<div class="jumbotron mt32">
<h1><span t-field="survey.title" />
@@ -564,10 +564,10 @@
<div class="card-header"><span class="fa fa-filter"></span> Filters <span t-if="filter_display_data" class="float-right text-primary clear_survey_filter"><i class="fa fa-times"></i> Clear All Filters</span></div>
<div class="card-body">
<span t-if="filter_finish == True">
- <span class="badge badge-secondary only_left_radius filter-all">All surveys</span><span class="badge badge-primary only_right_radius filter-finished">Finished surveys</span>
+ <span class="badge badge-secondary only_left_radius filter-all">All surveys</span><span class="badge badge-primary only_right_radius filter-finished o_active_filter">Finished surveys</span>
</span>
<span t-if="filter_finish == False">
- <span class="badge badge-primary only_left_radius filter-all">All surveys</span><span class="badge badge-secondary only_right_radius filter-finished">Finished surveys</span>
+ <span class="badge badge-primary only_left_radius filter-all o_active_filter">All surveys</span><span class="badge badge-secondary only_right_radius filter-finished">Finished surveys</span>
</span>
<span t-foreach="filter_display_data" t-as="filter_data">
<span class="badge badge-primary only_left_radius"><i class="fa fa-filter" role="img" aria-label="Filter" title="Filter"></i></span><span class="badge badge-primary no_radius" t-esc="filter_data['question_text']"></span><span class="badge badge-success only_right_radius" t-esc="' > '.join(filter_data['labels'])"></span>
@@ -758,7 +758,7 @@
<td class="survey_answer">
<span t-esc="round(user_input['count']*100.0/(input_summary['answered'] or 1),2)"></span> %
<span t-esc="user_input['count']" class="badge badge-primary">Vote</span>
- <i class="fa fa-filter text-primary invisible survey_filter" t-att-data-question_id="question.id" t-att-data-answer_id="user_input['answer_id']" role="img" aria-label="Filter question" title="Filter question"/>
+ <i class="fa fa-filter text-primary survey_filter" t-att-data-question_id="question.id" t-att-data-answer_id="user_input['answer_id']" role="img" aria-label="Filter question" title="Filter question"/>
</td>
<td t-if="question_with_correct_answers" t-esc="user_input['answer_score']">
</td>
@@ -818,7 +818,7 @@
</td>
<td class="survey_answer" t-foreach="matrix_result['answers']" t-as="answer_id">
<span t-esc="round(matrix_result['result'][(row_id,answer_id)]*100.0/(input_summary['answered'] or 1),2)"></span> %
- <span class="badge badge-primary" t-esc="matrix_result['result'][(row_id,answer_id)]"></span><i class="fa fa-filter text-primary invisible survey_filter" t-att-data-question_id="question.id" t-att-data-row_id="row_id" t-att-data-answer_id="answer_id" role="img" aria-label="Survey filter" title="Survey filter"></i>
+ <span class="badge badge-primary" t-esc="matrix_result['result'][(row_id,answer_id)]"></span><i class="fa fa-filter text-primary survey_filter" t-att-data-question_id="question.id" t-att-data-row_id="row_id" t-att-data-answer_id="answer_id" role="img" aria-label="Survey filter" title="Survey filter"></i>
</td>
</tr>
</tbody>