Skip to content

Instantly share code, notes, and snippets.

@m-bo-one
Created December 15, 2015 21:14
Show Gist options
  • Save m-bo-one/d247ae4f1161402dbb57 to your computer and use it in GitHub Desktop.
Save m-bo-one/d247ae4f1161402dbb57 to your computer and use it in GitHub Desktop.
function AnswerProcessor() {
//class containing logic and data to manipulate questions
this.commentCharsMaxConst = 250;
this.stats_timer = false;
this.show_skip_timer = false;
this.init = function(categories){
this.questions = [];
this.timeouts = {};
this.categories = categories;
this.straightCycle = false;
//init
_.forEach(categories, function(c){
_.forEach(c.questions, function(q){
q.category = c;
this.questions.push(q);
}, this);
}, this);
this.renderOverallProgress();
_.forEach(this.categories, function(c){
this.renderCategoryProgress(c);
},this);
var question = this.findNextQuestion();
var _this = this,
timeout = 0;
if (!is_wide()) timeout = 1000;
setTimeout(function() {
_this.renderQuestion(question, detachQuiz, attachQuiz);
_this.checkProgress(question);
_this.bindDomEvents();
}, timeout);
};
this.getCheckAnswer = function() {
return $('input:radio.polifit-choice:checked').val();
}
this.updateCommentEditCounter = function() {
var value = $('.question-comment-edit textarea').val();
var counterEl = $('#question-comment-chars');
var valueLen = typeof(value) == 'string' ? value.length : 0;
var left = this.commentCharsMaxConst - valueLen;
counterEl.text(left);
if (left < 0) {
counterEl.css('color', 'red');
} else {
counterEl.css('color', '');
}
if (left < 0 || valueLen == 0) {
$('#de_answer_comment').attr("disabled", "disabled");
} else {
$('#de_answer_comment').removeAttr("disabled");
}
}
this.bindDomEvents = function() {
var _this = this; //save the refference as there's lot of jquery
$('.question-comment-edit textarea').on('input propertychange', function(v) {
_this.updateCommentEditCounter();
});
$('.q-action').on(touchendOrClick, function (event) {
var choice = _this.getCheckAnswer();
var q = $('#quiz1').data('question');
_this.stopTimer(q);
_this.answerQuestion(q, choice);
_this.scrollToHeader();
return false;
});
$('.q-skip').on(touchendOrClick, function (event) {
var q = $('#quiz1').data('question');
_this.stopTimer(q);
_this.answerQuestion(q, 2);
_this.scrollToHeader();
return false;
});
$('.quiz-category').on('click', function(event){ //click because we have lot of scroll here
_this.straightCycle = true;
var category = _this.findCategory($(this).data('id'));
var question = category.questions[0];
_this.renderQuestion(question);
});
$('input.polifit-choice').on('click', function(event){ // tap doesn't work for inputs (?)
var q = $('#quiz1').data('question');
var val = $(this).val();
if (val != 2)
this.stats_timer = setTimeout(function() {
$('#quiz1 .percentage').stop().fadeIn('fast');
}, 500);
if (_this.findQuestion(q).value !== null){
_this.stopTimer(q);
_this.startTimer(q, val);
}
if (POLITICIAN) {
$('.question-comment-edit-but').removeClass('turnoff');
}
});
$('.quiz-progress').on(clickEvent, '.question-indicator', function (event) {
_this.straightCycle = true;
var q = $(this).data('id');
var question = _this.findQuestion(q);
_this.renderQuestion(question);
});
$('.badge').on('click', function(event){
event.preventDefault();
});
$('.quiz-question .question-info-but').on(clickEvent, function(event){
var $this = $(this);
if($this.hasClass('active')){
$('.question-info').slideUp('fast', function(){
$this.removeClass('active');
});
}else{
$this.addClass('active');
$('.question-info').slideDown('fast');
}
return false;
});
if (!is_wide()) {
$('.quiz-question .question-detail-but').on(clickEvent, function(event){
var $this = $(this);
if($this.hasClass('active-marker')){
$('.question-comment').slideUp(900, function(){
$this.removeClass('active-marker');
});
}else{
$this.addClass('active-marker');
$('.question-comment').slideDown(900);
}
return false;
});
} else {
$('.quiz-question .question-detail-but').hide();
}
// answer comment edit
$('.quiz-question .question-comment-edit-but').on(clickEvent, function(ev) {
var commentDiv = $('.question-comment-edit');
if (commentDiv.hasClass('turnoff')) {
commentDiv.slideDown('fast', function() {
commentDiv.removeClass('turnoff');
});
} else {
commentDiv.slideUp('fast', function() {
commentDiv.addClass('turnoff');
});
}
});
$('#de_answer_comment').on(clickEvent, function(ev) {
var questionId = $('#quiz1').data('question');
var comment = $('.question-comment-edit textarea').val();
var choice = _this.getCheckAnswer();
_this.saveQuestion(questionId, choice, function() {
_this.saveComment(questionId, comment);
});
ev.preventDefault();
return false;
});
$('.quiz-question').swipe({
allowPageScroll:"vertical",
swipe: function(event, direction) {
var $head = $('.panel-item.active');
var $this = $(this);
var question;
var questionId = $('#quiz1').data('question');
var choice = _this.getCheckAnswer();
if (direction == 'left') {
question = _this.saveQuestion(questionId, choice);
_this.checkProgress(question);
_this.renderCategoryProgress(question.category);
_this.renderOverallProgress();
_this.straightCycle = true;
question = _this.findNextQuestion(questionId);
_this.straightCycle = false;
if (question.category.id == $('#quiz1').data('category')) {
$(this).hide("slide", { direction: "left" }, 'fast');
$(this).show("slide", { direction: "right" }, 'fast');
_this.scrollToHeader();
}
}
else if (direction == 'right') {
question = _this.findPreviousQuestion(questionId);
if (question.category.id == $('#quiz1').data('category')) {
$(this).hide("slide", { direction: "right" }, 'fast');
$(this).show("slide", { direction: "left" }, 'fast');
_this.scrollToHeader();
}
}
setTimeout(function(){
_this.renderQuestion(question);
}, 200);
}
})
};
this.scrollToHeader = function () {
if (!is_wide()) {
var $head = $('.panel-item.active');
$('html, body').animate({
scrollTop: $head.offset().top
}, 300);
}
}
this.answerQuestion = function(questionId, value){
var question = this.saveQuestion(questionId, value);
this.checkProgress(question);
this.renderCategoryProgress(question.category);
this.renderOverallProgress();
var next = this.findNextQuestion(questionId);
if (typeof(next)!= 'undefined'){
this.renderQuestion(next);
}
};
this.findQuestion = function(questionId) {
return _.find(this.questions, {'id':questionId},this);
};
this.findCategory = function(CategoryId) {
return _.find(this.categories, {'id':CategoryId},this);
};
this.findNextQuestion = function(currentQuestionId){
//if straightCycle just cycle through questions
//else cycle through unanswered
//
if (typeof(currentQuestionId) === 'undefined'){
currentQuestionId = -1;
index = -1;
}else{
var question = this.findQuestion(currentQuestionId);
var index = _.findIndex(this.questions, question);
}
if (this.straightCycle){
if (index+1 === this.questions.length){
return this.questions[0];
} else {
return this.questions[index+1];
}
}else{
var nextNotAnswered = _.filter(this.questions.slice(index+1),
{'value':null})[0];
if (typeof(nextNotAnswered) !== 'undefined'){
return nextNotAnswered;
} else { //start from begining
var notAnswered = _.filter(this.questions,
{'value':null})[0];
if (typeof(notAnswered) !== 'undefined'){
return notAnswered;
}else{
this.straightCycle = true;
return this.findNextQuestion();
}
}
}
};
this.findPreviousQuestion = function(currentQuestionId){
//not mingling with straightcycle
var questions = this.questions;
var question = this.findQuestion(currentQuestionId);
var index = _.findIndex(questions, question);
if (index-1 < 0){
return this.questions[this.questions.length-1];
} else {
return this.questions[index-1];
}
};
this.saveComment = function(questionId, value){
var question = this.findQuestion(questionId);
if (!value) value = '';
question.comment = value;
$('#de_answer_comment').hide();
$.ajax({
type: 'POST',
dataType: 'json',
url: CONFIG.commentSaveUrl,
data: { 'comment': value, 'question': questionId },
success: function(res) {
var message;
if (res && res.success) {
message = $('.question-comment-edit .succ');
} else {
message = $('.question-comment-edit .err');
}
message.show();
setTimeout(function() { message.fadeOut(); }, 3000);
},
error: function() {
$('.question-comment-edit .err').show();
setTimeout(function() { $('.question-comment-edit .err').fadeOut(); }, 3000);
},
complete: function() {
$('#de_answer_comment').show();
}
});
return question;
};
this.saveQuestion = function(questionId, value, complete){
var question = this.findQuestion(questionId);
if(typeof(value) === 'undefined') value = null; //love js
if(question.value !== value){
question.value = value;
var options = {
type: 'POST',
dataType: 'json',
url: CONFIG.saveUrl,
data: {'answer': value, 'question': questionId},
};
if (typeof(complete) == 'function') {
options.complete = complete;
}
$.ajax(options);
} else {
if (typeof(complete) == 'function') {
complete.apply(this);
}
}
return question;
};
this.calculateProgress = function(category){
if (typeof(category) === 'undefined'){
var questions = this.questions;
}else{
var questions = category.questions;
}
var answeredCount = 0;
_.forEach(questions, function(q){
if (q.value !== null) answeredCount+=1});;
return {
count: questions.length,
total: answeredCount
}
}
this.setCommentInputValue = function(value) {
$('.question-comment-edit textarea').val(value);
this.updateCommentEditCounter();
}
this.renderQuestion = function(question, beforeRender, afterRender) {
//accept question and functions that are ysed as callbacks for render process
//typically used for attaching / deataching quiz block.
if (!beforeRender || typeof(beforeRender) !== "function") beforeRender = detachQuiz;
if (!afterRender || typeof(afterRender) !== "function") afterRender = attachQuiz;
var _this = this;
//ugly hack, but we have to much of different behaviours for ui :(
if (question.category.id != $('#quiz1').data('category')){
shouldMoveQuestion = true; // global variable, what a shame
}else{
shouldMoveQuestion = false;
}
function swapQuestion(){
var $categoryBlock;
if ($('#cat-0') == undefined) {
$categoryBlock = $('#cat-'+question.category.id);
} else {
$categoryBlock = $('#cat-0');
}
if (!$categoryBlock.hasClass('active')){
$('.quiz-category').removeClass('active');
$categoryBlock.addClass('active');
}
//swap html
var $head = $('.panel-item.active');
var quiz1 = $('#quiz1');
quiz1.data('question', question.id);
quiz1.data('category', question.category.id);
quiz1.find('.question-title').html(question.text);
quiz1.find('.question-info').hide();
if (this.show_skip_timer) {
clearTimeout(this.show_skip_timer);
this.show_skip_timer = false;
};
var $skip = quiz1.find('.button-wrapper .q-skip');
if ($skip.length) {
$skip.stop().hide();
this.show_skip_timer = setTimeout(function () {
$skip.show('fast').css("display", "inline-block");
}, 6000);
}
quiz1.find('.badge').removeClass('active');
quiz1.find('.badge').removeClass('active-marker');
$('.reatach-wrapper-title a').removeClass('active');
if (question.extra_info){
quiz1.find('.question-info-but').removeClass('disabled');
quiz1.find('.question-info').html(question.extra_info);
}else{
quiz1.find('.question-info-but').addClass('disabled');
}
_this.setCommentInputValue(question.comment ? question.comment : '');
if (question.other_comment) {
$('.reatach-wrapper-title a').removeClass('disabled');
quiz1.find('.question-detail-but').removeClass('disabled');
quiz1.find('.question-comment').text(question.other_comment);
//quiz1.find('.question-comment').show();
} else {
quiz1.find('.question-comment').text('');
quiz1.find('.question-comment').hide();
$('.reatach-wrapper-title a').addClass('disabled');
quiz1.find('.question-detail-but').addClass('disabled');
quiz1.find('.question-detail-but').removeClass('active');
}
if (this.stats_timer) {
clearTimeout(this.stats_timer);
this.stats_timer = false;
}
quiz1.find('.percentage').stop().hide();
var text;
for (var i=0; i<5; i++) {
if (question.stats !== null){
text = question.stats[i] + '%';
} else {
text = '';
}
quiz1.find('.answer.pc-'+i).text(text);
}
_this.renderQuestionsProgress(question);
// Use default value for question
if (question.value !== null){
quiz1.find('#answer-'+question.value).prop('checked', true);
quiz1.find('#answer-'+question.value).trigger('change');
if (POLITICIAN) {
$('.question-comment-edit-but').removeClass('turnoff');
}
}else{
quiz1.find('input:radio.polifit-choice').removeAttr('checked');
quiz1.find('input:radio.polifit-choice').trigger('change');
if (POLITICIAN) {
$('.question-comment-edit-but').addClass('turnoff');
}
var commentDiv = $('.question-comment-edit');
if (!commentDiv.hasClass('turnoff')) {
commentDiv.hide();
commentDiv.addClass('turnoff');
}
// HACK: choose 'undecided' by default
quiz1.find('#answer-2').prop('checked', true);
}
//attach back
afterRender();
}
beforeRender(swapQuestion);
}
this.renderQuestionsProgress = function(question){
var renderedHtml = "";
_.forEach(question.category.questions, function(q){
var cls = "";
if (q.id == question.id) cls = 'active';
if (q.value !== null) cls += ' done'
else( cls += ' future');
var piece = '<li data-id="'+q.id+'" class="question-indicator '+cls+'"></li>';
renderedHtml+=piece
});
$('.quiz-progress>ul').html(renderedHtml);
};
this.renderCategoryProgress = function(category){
var progress = this.calculateProgress(category);
var $category = $('#cat-'+category.id);
var count = progress.count;
if (count == 0) { count++; }
this.renderProgressBar($category, (progress.total/count)*100);
}
this.renderOverallProgress = function(){
var progress = this.calculateProgress();
var count = progress.count;
if (count == 0) { count++; }
progress = Math.round(progress.total * 100.0 / count);
renderRoundProgressBar(progress, '.active-border.enabled','#EFEFEF');
this.renderProgressBar($('#total_progress'), progress);
}
this.renderProgressBar = function($category, progress) {
var $progressEl = $category.find('progress');
var $progressNum = $category.find('span.panel-item-percentage');
var trickyRound = function (num) {
num = Math.round(num)
if (num === 99) num = 100 ;
if (num === 1) num = 0 ;
return num
}
progress = trickyRound(progress);
$progressEl.animate({value:progress},500);
$progressNum.each(function () {
var $this = $(this),
initProgress = $this.text();
jQuery({ Counter: initProgress }).animate({
Counter : progress}, {
duration: 500,
easing: 'swing',
step: function () {
$this.text(trickyRound(this.Counter));
},
// let animation complete for slow connection
complete: function () {
$this.text(trickyRound(this.Counter));
}
});
});
}
this.checkProgress = function(question){
//various situations during progress
var questions = this.questions,
notAnsweredQuestions = _.filter(questions,
{'value':null}),
$container = $('.st-container'),
sidebarWasShown = sessionStorage.getItem('sidebarWasShown');
//passing last question, no matter survey is complete
//that's what customer wants
if (question == _.last(questions) && notAnsweredQuestions.length){
if (!CONFIG.beenThere){
switchUrlWithSplash(CONFIG.finishedUrl, 'fast');
return;
}else{
this.straightCycle = false;
}
}
//just answered last question
if (!notAnsweredQuestions.length && CONFIG.beenThere < 100){
// show overlay
$.get(SURVEY_COMPLETED); // send ajax get for ga
setTimeout(function() {
$.magnificPopup.open({
items:{
type: 'inline',
mainClass: 'mfp-done',
src:'#survey-complete-popup'
},
callbacks: {
beforeClose: function() {
switchUrlWithSplash(CONFIG.finishedUrl);
}
},
fixedContentPos: true,
closeOnContentClick: true
});
}, 1000);
}
};
this.startTimer = function(questionId, value) {
var timeoutID = window.setTimeout(function (_this) {
_this.saveQuestion(questionId, value);
}, 3000, this);
this.timeouts[String(questionId)] = timeoutID;
}
this.stopTimer = function(questionId) {
var timeoutID = this.timeouts[String(questionId)]
window.clearTimeout(timeoutID);
}
};
function AnswerComparisonProcessor(){
//makes the same, but shows responses compared to other
this.renderQuestion = function(question, beforeRender, afterRender){
//reatachInner
$('.other-answer').removeClass('other-answer');
$('.you').remove();
$('.him').remove();
$('.his-answer').remove();
//this is the way they do 'super' in javascript
_.bind(this.__proto__.renderQuestion, this, question)(detachInner,
attachInner);
$('#label-answer-'+question.value).prepend('<span class="you">You</span>');
if (question.other_answer !== null){
$('#label-answer-'+question.other_answer).addClass('other-answer');
$('#label-answer-'+question.other_answer).after('<div class="his-answer"><span class="him">' + CONFIG.politician+'</span></div>');
// firefox hack
setTimeout(function(){
$('.his-answer').css('top', '0px');
setTimeout(function(){
$('.his-answer').css('top', '');
}, 10);
}, 10);
}
}
this.checkProgress = function (question) {
//do something
}
this.calculateProgress = function (category) {
if (typeof(category) !== 'undefined'){
var maxvalue = 4,
total = 0,
count = 0;
_.forEach(category.questions, function(question) {
if (question.value !== null && question.other_answer !== null){
questiondiff = (maxvalue-Math.abs(question.value-question.other_answer))/maxvalue;
total += questiondiff;
count++;
}
});
return {
total: total,
count: count
}
}else{
return {
total: 0,
count: 0
}
}
}
this.renderOverallProgress = function(){
var total = 0,
count = 0;
_.forEach(this.categories, function(category) {
var progress = this.calculateProgress(category);
var $category = $('#match-category-'+category.id);
this.renderProgressBar($category, (progress.total/progress.count)*100);
total+=progress.total;
count+=progress.count
},this);
if (count == 0) { count++; }
avg = Math.round(total*100/count);
renderRoundProgressBar(avg);
if (!window.CONFIG.friend_page){
$('.percent').html(avg+'%');
}
};
$('.polifit-choice').on('click', function(event){
$('.you').fadeOut('fast');
});
}
AnswerComparisonProcessor.prototype = new AnswerProcessor();
function initialAttach() {
//TODO not used anymore. was used to attach question without animating to it. delete it after 20 oct 2014
var $el = $('.reatachable');
if (!is_wide()){
var $head = $('.panel-item.active');
$el.detach().insertAfter($head);
}else{
var $reatachWrapper = $('.reatach-wrapper');
$el.detach().appendTo($reatachWrapper);
$reatachWrapper.show()
}
shouldMoveQuestion = false;
$el.slideDown();
}
(function ($, touch, window, undefined) {
var namespace = 'drag', cfg = {
distance: 20, // minimum
direction: 'all'
};
var previousPoint = {x: 0, y: 0};
var isDragging = false;
touch.track(namespace, {
touchstart: function (event, state, start) {
state[namespace] = {
finger: start.point.length
};
previousPoint.x = start.point[0].x;
previousPoint.y = start.point[0].y;
isDragging = false;
},
touchmove: function (event, state, move) {
if (!state[namespace]) return;
var opt = $.extend(cfg, event.data);
// if another finger was used then increment the amount of fingers used
state[namespace].finger = move.point.length > state[namespace].finger ? move.point.length : state[namespace].finger;
state[namespace].distance = touch.calc.getDistance(state.start.point[0], move.point[0]);
state[namespace].angle = touch.calc.getAngle(state.start.point[0], move.point[0]);
state[namespace].direction = touch.calc.getDirection(state[namespace].angle);
state[namespace].deltaX = move.point[0].x - previousPoint.x;
state[namespace].deltaY = move.point[0].y - previousPoint.y;
//previousPoint.x = move.point[0].x;
//previousPoint.y = move.point[0].y;
if (state[namespace].distance > opt.distance) {
if (!isDragging) {
var startEvent = $.Event(namespace+"start", touch.addEventParam(state.start));
$(event.target).trigger(startEvent);
isDragging = true;
}
$(event.target).trigger($.Event(namespace, touch.addEventParam(move, state[namespace])));
}
},
touchend: function (event, state, end) {
previousPoint.x = 0;
previousPoint.y = 0;
if (isDragging) {
$(event.target).trigger($.Event(namespace+"stop", touch.addEventParam(end)));
isDragging = false;
}
}
});
}(jQuery, jQuery.toe, this));
(function() {
$(document).ready(function() {
var touchables = 'label.tapwait';
var startPositions = [];
var labelsMargins = [];
var labelsCurrentTranslate = 0;
var currentDraggedObject = null;
//var labelsHammers = [];
/*
$('.polifit-choice').on('change', function(ev) {
$('.polifit-choice').each(function(index, el) {
// labelsHammers[index].set({ enable: el.checked});
});
});
*/
var initStartPositions = function() {
startPositions = [];
$(touchables).each(function (index, el) {
startPositions.push($(el).position().left);
});
}
$(touchables).on('touchmove', function(ev) {
ev.preventDefault();
});
$(touchables).each(function (index, el) {
var that = $(el);
var ml = parseInt(that.css('marginLeft')) + parseInt(that.css('paddingLeft'));
var mr = parseInt(that.css('marginRight')) + parseInt(that.css('paddingRight'));
startPositions.push(that.position().left);
labelsMargins.push({ left: ml, right: mr});
that.on('drag', { distance: -1 }, function(ev) {
/// needed for Android browser
// event.preventDefault();
/// need to prevent text selection while moving
ev.preventDefault();
if (this != currentDraggedObject) {
return;
}
var left = that.position().left;
var deltaX = ev.deltaX;
var marginLeft = labelsMargins[index].left - labelsMargins[0].left;
var marginRight = labelsMargins[index].left - labelsMargins[labelsMargins.length-1].left;
if (startPositions[index] + deltaX < startPositions[0]-marginLeft) deltaX = -startPositions[index] + startPositions[0] - marginLeft;
if (startPositions[index] + deltaX + marginRight > startPositions[startPositions.length-1]) deltaX = startPositions[startPositions.length-1] - startPositions[index] - marginRight;
labelsCurrentTranslate = deltaX;
var tr = 'translateX(' + deltaX + 'px)';
that.css({transform: tr});
// that.css({transform: tr, '-moz-transform' : tr, '-ms-transform' : tr, '-webkit-transform' : tr});
});
that.on('dragstart', function(ev) {
currentDraggedObject = this;
//ev.preventDefault();
that.css({'z-index': '100'});
initStartPositions();
});
that.on('dragstop', function(ev) {
currentDraggedObject = null;
/// this is for ios hack
that.removeClass('tap-active');
$('label.tapwait.tap-passive').removeClass('tap-passive');
var currentPos = that.position().left;
var i = 0;
for(; i < startPositions.length - 1; i++) {
var distance = startPositions[i + 1] - startPositions[i];
if (currentPos < startPositions[i] + distance / 2) {
break;
}
}
var answerEl = $('#answer-' + i);
setTimeout(function() {
if (index != i) {
if (that.find('.you').length > 0) {
$('.you').remove();
$('#label-answer-'+i).prepend('<span class="you">You</span>');
}
}
if (answerEl.length > 0) {
answerEl[0].checked = true;
answerEl.attr('checked',true);
answerEl.click();
//labelsHammers[index].set({ enable: false});
//labelsHammers[i].set({ enable: true});
}
that.css({transform: 'translateX(0px)'});
that.css({'z-index': '2'});
}, 0);
});
});
// if (POLITICIAN) {
// $('.question-comment-edit-but').removeClass('turnoff');
// }
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment