[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
This commit is contained in:
David Beguin
2019-11-19 12:52:22 +00:00
parent f462bf0d93
commit ee0b11f2ce
4 changed files with 200 additions and 137 deletions
+9 -11
View File
@@ -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):
@@ -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 {
+179 -117
View File
@@ -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{
$('#table_question_'+question_id+' tbody tr:lt('+ limit * num +'):gt('+min+')').removeClass('d-none');
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 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','');
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);
}
});
// 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');
}
}).hover(function(){
if(document.URL.indexOf("finished") != -1){
$(this)[0].style.cursor = 'default';
}
});
return queryString;
},
});
return publicWidget.registry.SurveyResultWidget;
});
+5 -5
View File
@@ -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>