[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:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user