datawinners/media/javascript/entity/questionnaire_helper.js
//DW is the global name space for DataWinner
DW.init_inform_datasender_about_changes = function () {
var kwargs = {container: "#inform_datasender_about_changes",
is_continue: true,
title: gettext('Inform Your Data Senders about the Changes'),
continue_handler: function () {
if (typeof(this.redirect_url) != "undefined") {
window.location.replace(this.redirect_url);
}
},
cancel_handler: this.continue_handler
};
DW.inform_datasender_about_changes = new DW.warning_dialog(kwargs);
};
DW.init_empty_questionnaire_warning = function () {
var kwargs = {container: "#no_questions_exists", title: gettext('Warning: Empty questionnaire') };
DW.empty_questionnaire_warning = new DW.warning_dialog(kwargs);
}
DW.check_empty_questionnaire = function () {
if (questionnaireViewModel.questions().length == 0) {
DW.empty_questionnaire_warning.show_warning();
return false;
}
return true;
}
DW.instruction_template = {
"number": gettext("Answer must be a number."),
"min_number": gettext("Answer must be a number. The minimum is %d."),
"max_number": gettext("Answer must be a number. The maximum is %d."),
"range_number": gettext("Answer must be a number between %d-%d."),
"text": gettext("Answer must be a word"),
"unique_id_type": gettext("Answer must be the Identification Number of the %s you are reporting on."),
"unique_id": gettext("Answer must be an Identification Number."),
"max_text": gettext("Answer must be a word %d characters maximum"),
"date": gettext("Answer must be a date in the following format: %s. Example: %s"),
"single_select": gettext("Choose 1 answer from the list. Example: a"),
"multi_select": gettext("Choose 1 or more answers from the list. Example: a or ab "),
"gps": gettext("Answer must be GPS coordinates in the following format (latitude,longitude). Example: -18.1324,27.6547"),
"dd.mm.yyyy": "25.12.2011",
"mm.dd.yyyy": "12.25.2011",
"mm.yyyy": "12.2011",
"short_code_question": gettext("Answer must be 20 characters maximum"),
"telephone_number": gettext("Answer must be country code plus telephone number. Example: 261333745269")
};
DW.date_template = {
"dd.mm.yyyy": gettext("day.month.year"),
"mm.dd.yyyy": gettext("month.day.year"),
"mm.yyyy": gettext("month.year")
};
DW.question = function (question) {
var defaults = {
name: '',
code: "code",
required: true,
language: 'en',
choices: [],
length_limiter: "length_unlimited",
length: {
min: 1,
max: ""
},
range: {
min: "",
max: ""
},
label: "",
date_format: "mm.yyyy",
instruction: gettext("Answer must be a text"),
newly_added_question: false,
event_time_field_flag: false,
unique_id_type: null
};
// Extend will override the default values with the passed values(question), And take the values from defaults when its not present in question
//first argument "true" in extend field shows that appent values in default
this.options = $.extend(true, defaults, question);
this._init();
};
DW.initChoices = function (choices) {
var final_choices = [];
$.each(choices, function (index, choice) {
var display_choice = {};
display_choice['text'] = ko.observable(choice.text);
display_choice['val'] = ko.observable(choice.val);
final_choices.push(DW.ko.createValidatableObservableObject({value: display_choice}));
});
return final_choices;
};
DW.question.prototype = {
_init: function () {
var self = this;
var q = this.options;
this.newly_added_question = ko.observable(q.newly_added_question);
this.range_min = DW.ko.createValidatableObservable({value: q.range.min});
this.event_time_field_flag = ko.observable(q.event_time_field_flag);
//This condition required especially because in DB range_max is a mandatory field
this.range_max = DW.ko.createValidatableObservable({value: q.range.max});
this.min_length = ko.observable(q.length.min);
this.max_length = DW.ko.createValidatableObservable({value: q.length.max});
this.name = q.name;
this.title = DW.ko.createValidatableObservable({value: q.label});
this.code = ko.observable(q.code);
this.type = ko.observable(q.type);
this.isEntityQuestion = ko.observable(q.type == 'short_code');
this.uniqueIdType = DW.ko.createValidatableObservable({value: q.unique_id_type});
this.showDateFormats = ko.computed(function () {
return this.type() == "date";
}, this);
this.showAddRange = ko.computed(function () {
return this.type() == 'integer';
}, this);
this.showAddTextLength = ko.computed(function () {
return this.type() == 'text' && !this.isEntityQuestion();
}, this);
this.required = ko.observable(q.required);
this.answerType = DW.ko.createValidatableObservable();
this.display = ko.computed(function () {
return this.title();
}, this);
this.answerType.subscribe(function (selected_answer_type) {
if (selected_answer_type === "" || this.isEntityQuestion()) return;
_clearErrors();
DW.change_question_type_for_selected_question(selected_answer_type);
}, this);
var _clearErrors = function () {
self.max_length.clearError();
self.range_max.clearError();
self.range_min.clearError();
self.uniqueIdType.clearError();
_clearChoiceErrors();
};
var initialValues = DW.initChoices(q.choices);
this.choices = ko.observableArray(initialValues);
this.choiceCanBeDeleted = ko.computed(function () {
return this.choices().length > 1;
}, this);
this.removeOptionFromQuestion = function (choice) {
self.checkForQuestionnaireChange(choice.value);
var choices = self.choices();
var indexOfChoice = $.inArray(choice, choices);
var lastChoiceValue = choice.value.val();
var i = indexOfChoice + 1;
for (i; i < choices.length; i = i + 1) {
choices[i].value.val(lastChoiceValue);
lastChoiceValue = DW.next_option_value(lastChoiceValue);
}
self.choices.remove(choice);
};
var _clearChoiceErrors = function () {
ko.utils.arrayForEach(self.choices(), function (choice) {
choice.clearError();
});
};
var _validateChoice = function (choice) {
if (choice.value.text())
choice.clearError();
else
choice.setError(gettext("This field is required."))
};
this.addOptionToQuestion = function () {
var selectedQuestionCode = "a";
var choiceText = "";
if (this.choices().length > 0) {
var lastChoice = this.choices()[this.choices().length - 1];
selectedQuestionCode = DW.next_option_value(lastChoice.value.val());
}
else {
choiceText = gettext("default");
}
var choiceItemText = ko.observable(choiceText);
var choiceItem = DW.ko.createValidatableObservableObject({
value: {
text: choiceItemText,
val: ko.observable(selectedQuestionCode)
}
});
choiceItemText.subscribe(function () {
_validateChoice(this);
}, choiceItem);
this.choices.push(choiceItem);
};
this.showAddChoice = function () {
if (this.isAChoiceTypeQuestion() == "choice") {
return true;
}
return false;
};
self.showUniqueId = ko.computed(function () {
var isUniqueId = this.answerType() == "unique_id";
if (isUniqueId)
//Notifying parent view model when selected question is of type unique id.
ko.postbox.publish("uniqueIdTypeSelected", "");
return isUniqueId;
}, self);
this.checkForQuestionnaireChange = function (choice) {
if (_.any($(this.options.choices), function (v) {
return v.val == choice.val;
})) {
DW.questionnaire_was_changed = true;
}
};
this.date_format = ko.observable(q.date_format);
this.length_limiter = ko.observable(q.length.max ? "length_limited" : "length_unlimited");
this.showLengthLimiter = ko.computed(function () {
return this.length_limiter() == 'length_limited';
}, this);
this.length_limiter.subscribe(function (new_length_limiter) {
if (new_length_limiter == 'length_unlimited')
this.max_length("");
this.max_length.clearError();
}, this);
this.instruction = ko.dependentObservable({
read: function () {
if (this.isEntityQuestion() && this.max_length() == 20) {
return DW.instruction_template.short_code_question;
}
if (this.type() == "text") {
if (this.max_length() != "" && this.max_length() > 0) {
return $.sprintf(DW.instruction_template.max_text, this.max_length());
}
return DW.instruction_template.text;
}
if (this.type() == "telephone_number") {
return $.sprintf(DW.instruction_template.telephone_number);
}
if (this.type() == "list") {
return DW.instruction_template.text;
}
if (this.type() == "integer") {
if (this.range_min() == "" && this.range_max() == "") {
return DW.instruction_template.number;
}
else if (this.range_min() == "" && !_.isNaN(parseInt(this.range_max()))) {
return $.sprintf(DW.instruction_template.max_number, this.range_max());
}
else if (this.range_max() == "" && !_.isNaN(parseInt(this.range_min()))) {
return $.sprintf(DW.instruction_template.min_number, this.range_min());
}
else if (!_.isNaN(parseInt(this.range_max())) && !_.isNaN(parseInt(this.range_min())) && this.range_max.valid())
return $.sprintf(DW.instruction_template.range_number, this.range_min(), this.range_max());
else
return DW.instruction_template.number;
}
if (this.type() == "date") {
return $.sprintf(DW.instruction_template.date, DW.date_template[this.date_format()], DW.instruction_template[this.date_format()]);
}
if (this.type() == "geocode") {
return DW.instruction_template.gps;
}
if (this.type() == "select1") {
return DW.instruction_template.single_select;
}
if (this.type() == "select") {
return DW.instruction_template.multi_select;
}
if (this.type() == "unique_id") {
if (this.uniqueIdType()) {
return $.sprintf(DW.instruction_template.unique_id_type, this.uniqueIdType());
}
return DW.instruction_template.unique_id;
}
return "No instruction can be generated";
},
owner: this
});
this.canBeDeleted = function () {
if (DW.isRegistrationQuestionnaire()) {
return (!this.isEntityQuestion() && this.name != 'name');
} else {
return (!this.isEntityQuestion());
}
};
this.isAChoiceTypeQuestion = ko.dependentObservable({
read: function () {
return this.type() == "select" || this.type() == "select1" ? "choice" : "none";
},
write: function (value) {
this.type(this.type() == "" ? "select" : "select1");
},
owner: this
});
this.validate = function () {
//triggering change to cause subscribers to validate
this.title.valueHasMutated();
this.answerType.valueHasMutated();
this.max_length.valueHasMutated();
this.range_min.valueHasMutated();
this.range_max.valueHasMutated();
this.uniqueIdType.valueHasMutated();
var isChoiceAnswerValid = true;
if (this.showAddChoice()) {
ko.utils.arrayForEach(this.choices(), function (choice) {
choice.value.text.valueHasMutated();
isChoiceAnswerValid &= choice.valid();
});
}
return this.title.valid() && this.answerType.valid() && this.max_length.valid()
&& this.range_min.valid() && this.range_max.valid() && isChoiceAnswerValid && this.uniqueIdType.valid();
};
this._initializeObservableValidations();
this._initializeObservers();
},
_validateMinRangeIsLessThanMaxRange: function () {
var min_range = parseInt(this.range_min());
var max_range = parseInt(this.range_max());
if (!this.range_min().match(/^-?\d+$/) || !this.range_max().match(/^-?\d+$/))
return;
if (min_range > max_range)
this.range_max.setError(gettext("Max should be greater than min."));
else
this.range_max.clearError();
},
_initializeObservers: function () {
this.answerType.subscribe(function (newAnswerType) {
if (newAnswerType == "choice" && this.choices().length == 0)
this.addOptionToQuestion();
}, this);
},
_initializeObservableValidations: function () {
this.title.subscribe(function () {
DW.ko.mandatoryValidator(this.title);
}, this);
this.max_length.subscribe(function () {
if (!this.showLengthLimiter())
return;
DW.ko.mandatoryValidator(this.max_length);
this.max_length.valid() && DW.ko.postiveNumberValidator(this.max_length);
}, this);
this.answerType.subscribe(function () {
if (!this.isEntityQuestion()) DW.ko.mandatoryValidator(this.answerType);
}, this);
this.range_min.subscribe(function () {
if (!this.showAddRange())
return;
DW.ko.numericValidator(this.range_min);
this._validateMinRangeIsLessThanMaxRange();
}, this);
this.range_max.subscribe(function () {
if (!this.showAddRange())
return;
DW.ko.numericValidator(this.range_max);
this._validateMinRangeIsLessThanMaxRange();
}, this);
this.uniqueIdType.subscribe(function () {
if (!this.showUniqueId())
return;
DW.ko.mandatoryValidator(this.uniqueIdType);
DW.set_questionnaire_was_change();
}, this);
}
};
DW.change_question_title_for_reporting_period = function (replaceto, replacewith) {
$(questionnaireViewModel.questions()).each(function (question) {
if (questionnaireViewModel.selectedQuestion().event_time_field_flag()) {
var question_title = questionnaireViewModel.selectedQuestion().title();
questionnaireViewModel.selectedQuestion().title(question_title.replace(replaceto, replacewith));
}
});
questionnaireViewModel.questions.valueHasMutated();
};
DW.removeQuestionCheckForRegistration = function (question) {
if (!DW.has_submission_delete_warning_for_entity.is_continue && DW.questionnaire_has_submission() && !question.newly_added_question()) {
questionnaireViewModel.setQuestionToBeDeleted(question);
DW.has_submission_delete_warning_for_entity.show_warning();
} else {
questionnaireViewModel.removeQuestion(question);
}
};
DW.isRegistrationQuestionnaire = function () {
return $('#qtype').val() == 'subject';
};
DW.next_question_name_generator = function () {
if (!DW.isRegistrationQuestionnaire()) {
return 'Question ' + ($('div.question_list ol li').length + 1 );
}
var questionPattern = /^Question \d+$/;
var max = 1;
var questionName = "";
var current = 1;
for (var i = 0; i < questionnaireViewModel.questions().length; i++) {
questionName = questionnaireViewModel.questions()[i].name();
current = parseInt(questionName.substring(9));
if (questionPattern.test(questionName) && max < current) {
max = current;
}
}
return 'Question ' + (Math.max(max, $('div.question_list ol li').length) + 1);
};
DW.next_option_value = function (lastChoice) {
var nextOption = "a";
if (lastChoice.charCodeAt(lastChoice.length - 1) == 122) {
if (lastChoice.length == 2) {
nextOption = String.fromCharCode(lastChoice.charCodeAt(0) + 1) + "a";
} else {
nextOption = "1a";
}
} else {
nextOption = (lastChoice.length == 2) ? lastChoice[0] : "";
nextOption += String.fromCharCode(lastChoice.charCodeAt(lastChoice.length - 1) + 1);
}
return nextOption;
}
DW.option_warning_dialog = {
init: function () {
DW.option_warning_dialog.continueEventHandler = function () {
};
DW.option_warning_dialog.cancelEventHandler = function () {
};
DW.option_warning_dialog.dialog_id = "#option_warning_message";
DW.option_warning_dialog.init_warning_dialog();
DW.option_warning_dialog.bind_cancel_link();
DW.option_warning_dialog.bind_continue();
DW.option_warning_dialog.bind_close();
},
init_warning_dialog: function () {
$(DW.option_warning_dialog.dialog_id).dialog({
title: gettext("Warning !!"),
modal: true,
autoOpen: false,
height: 'auto',
width: 500,
closeText: 'hide'
});
},
bind_cancel_link: function () {
$(DW.option_warning_dialog.dialog_id + "_cancel").bind("click", function () {
$(DW.option_warning_dialog.dialog_id).dialog("close");
DW.option_warning_dialog.cancelEventHandler();
DW.hide_dialog_overlay();
});
},
bind_close: function () {
$('.ui-icon-closethick').bind("click", function () {
$(DW.option_warning_dialog.dialog_id).dialog("close");
DW.option_warning_dialog.cancelEventHandler();
DW.hide_dialog_overlay();
});
},
bind_continue: function () {
$(DW.option_warning_dialog.dialog_id + "_continue").bind("click", function () {
$(DW.option_warning_dialog.dialog_id).dialog("close");
DW.option_warning_dialog.continueEventHandler();
DW.hide_dialog_overlay();
});
},
show_warning: function (message) {
$("#option_warning_text")[0].innerHTML = message;
$(DW.option_warning_dialog.dialog_id).dialog("open");
DW.show_dialog_overlay();
}
};
DW.close_the_tip_on_period_question = function () {
if ($("#question_title").hasClass("blue_frame")) {
$("#question_title").removeClass("blue_frame");
}
if ($("#periode_green_message").length > 0) {
$("#periode_green_message").hide();
}
}
DW.show_completly_selected_question = function () {
var div_top = $('div.questions').position().top;
var height = parseInt($('div.questions ol li.question_selected').css("height"), 10);
var question_top = $('div.questions ol li.question_selected').position().top;
if (div_top + 399 < question_top + height) {
var scrolltop = question_top + height - div_top - 392 + $("div.questions").scrollTop();
$("div.questions").scrollTop(scrolltop);
}
if (question_top < div_top + 15) {
var scrolltop = $("div.questions").scrollTop() - (div_top + 15 - question_top);
$("div.questions").scrollTop(scrolltop);
}
}
DW.questionnaire_has_submission = function () {
var subject_questionnaire = (typeof(is_edit) == "undefined");
if (subject_questionnaire) {
var entity_type = $("#entity-type").val();
var url_get = $.sprintf("/questionnaire/entities/%s/", entity_type);
} else {
var form_code = $("#saved-questionnaire-code").val();
var url_get = $.sprintf("/project/has_submission/%s/", form_code);
}
$.ajaxSetup({async: false});
var return_value = true;
$.blockUI({ message: '<h1><img src="/media/images/ajax-loader.gif"/><span class="loading">' + gettext("Just a moment") + '...</span></h1>', css: { width: '275px'}});
$.ajax({
type: 'GET',
url: url_get,
success: function (response) {
$.ajaxSetup({async: true});
$.unblockUI();
if (subject_questionnaire) {
return_value = response.length != 0;
} else {
var response_data = JSON.parse(response);
return_value = response_data.has_data;
}
}
});
return return_value;
}
DW.init_question_constraints = function () {
questionnaireViewModel.selectedQuestion().range_min("");
questionnaireViewModel.selectedQuestion().range_max("");
questionnaireViewModel.selectedQuestion().min_length(1);
questionnaireViewModel.selectedQuestion().max_length("");
questionnaireViewModel.selectedQuestion().length_limiter("length_unlimited");
questionnaireViewModel.selectedQuestion().addOptionToQuestion();
};
DW.change_question_type_for_selected_question = function (type_selector) {
if (type_selector == "choice") {
var old_type = questionnaireViewModel.selectedQuestion().type();
if (old_type != 'select') {
questionnaireViewModel.selectedQuestion().isAChoiceTypeQuestion("choice");
}
} else {
questionnaireViewModel.selectedQuestion().type(type_selector);
}
questionnaireViewModel.selectedQuestion.valueHasMutated();
questionnaireViewModel.questions.valueHasMutated();
};
DW.set_questionnaire_was_change = function () {
DW.questionnaire_was_changed = true;
};
$(document).ready(function () {
//TODO: Move to KO viewModel
var change_selector = "#range_min, #range_max, #max_length, [name='text_length'], [name='date_format'], #qustion_title";
change_selector += ", [name='answer_type'], [name='project_language'], #questionnaire_title, #questionnaire-code";
$(document).on('change', change_selector, DW.set_questionnaire_was_change);
//END
DW.has_submission_delete_warning = (function () {
var kwargs = {
container: "#submission_exists",
is_continue: false,
title: gettext('Warning: Your Collected Data Will be Lost'),
continue_handler: function () {
questionnaireViewModel.removeMarkedQuestion();
},
height: 170
};
return new DW.warning_dialog(kwargs);
}());
});
DW.isQuestionsReOrdered = function (existing_questions) {
var new_question_codes = ko.utils.arrayMap(questionnaireViewModel.questions(), function (question) {
return question.code();
});
return !_.isEqual(new_question_codes, DW.existing_question_codes);
};
DW.addNewQuestion = function () {
if (!questionnaireViewModel.validateSelectedQuestion())
return;
questionnaireViewModel.addQuestion();
DW.close_the_tip_on_period_question();
};
DW.CancelQuestionnaireWarningDialog = function (options) {
var self = this;
var successCallBack = options.successCallBack;
var isQuestionnaireModified = options.isQuestionnaireModified;
this.init = function () {
self.cancelDialog = $("#cancel_questionnaire_warning_message");
self.ignoreButton = self.cancelDialog.find(".no_button");
self.saveButton = self.cancelDialog.find(".yes_button");
self.cancelButton = self.cancelDialog.find("#cancel_dialog");
_initializeDialog();
_initializeIgnoreButtonHandler();
_initializeCancelButtonHandler();
_initializeSaveButtonHandler();
_initializeLinkBindings();
};
var _initializeDialog = function () {
self.cancelDialog.dialog({
title: gettext("You Have Unsaved Changes"),
modal: true,
autoOpen: false,
width: 550,
closeText: 'hide'
});
};
var _initializeIgnoreButtonHandler = function () {
self.ignoreButton.bind('click', function () {
self.cancelDialog.dialog("close");
return _redirect();
});
};
var _initializeCancelButtonHandler = function () {
self.cancelButton.bind('click', function () {
self.cancelDialog.dialog("close");
return false;
});
};
var _initializeSaveButtonHandler = function () {
self.saveButton.bind('click', function () {
if (questionnaireViewModel.validateSelectedQuestion() && questionnaireViewModel.validateQuestionnaireDetails()) {
successCallBack(function () {
return _redirect();
});
}
self.cancelDialog.dialog("close");
});
};
var _redirect = function () {
window.location.href = redirect_url;
return true;
};
var _initializeLinkBindings = function () {
$("a[href]:visible, a#back_to_create_options, a#cancel_questionnaire").not(".add_link, .preview-navigation a, .sms_tester, .delete_project, #dw_help_link").bind('click', {self: this}, function (event) {
var that = event.data.self;
redirect_url = $(this).attr("href");
if (isQuestionnaireModified()) {
self.cancelDialog.dialog("open");
return false;
}
else
return _redirect();
});
};
};
DW.UniqueIdHelpSection = function(){
function _closeDialogHandler(){
$("#unique_id_learn_more_form").dialog('close');
}
function _initializeDialog(dialogSection){
dialogSection.dialog({
autoOpen: false,
width: 940,
modal: true,
position:"top",
title: gettext("Learn More About Identification Numbers"),
zIndex: 1100,
open: function(){
$(".learn_more_accordion").accordion({collapsible: true,active: false});
},
close: function(){
$(".learn_more_accordion").accordion( "destroy" );
}
});
dialogSection.off('click', '#close_unique_id_learn_more_section', _closeDialogHandler);
dialogSection.on('click', '#close_unique_id_learn_more_section', _closeDialogHandler);
}
this.init = function(){
$("#question-detail-panel").on('click', '#unique_id_learn_more_link', function(){
var dialogSection = $("#unique_id_learn_more_form");
_initializeDialog(dialogSection);
dialogSection.removeClass("none");
dialogSection.dialog("open");
dialogSection.parent(".ui-dialog")[0].scrollIntoView();
});
}
};
$(document).ready(function () {
$(document).ajaxStop($.unblockUI);
});