forked from CGM_Public/pretix_original
Allow dependencies between questions (#1202)
- [x] data model - [x] api - [x] backend editor - [x] backend validation logic - [x] frontend display logic - [x] frontend validation logic - [x] test checkout step - [x] test modify order in frontend - [x] test modify order in backend - [x] validation tests - [x] correctly evaluate dependency tree in frontend? - [x] copy events
This commit is contained in:
@@ -1,13 +1,5 @@
|
||||
/*global $,gettext*/
|
||||
|
||||
function question_page_toggle_view() {
|
||||
var show = $("#id_type").val() == "C" || $("#id_type").val() == "M";
|
||||
$("#answer-options").toggle(show);
|
||||
|
||||
show = $("#id_type").val() == "B" && $("#id_required").prop("checked");
|
||||
$(".alert-required-boolean").toggle(show);
|
||||
}
|
||||
|
||||
var waitingDialog = {
|
||||
show: function (message) {
|
||||
"use strict";
|
||||
@@ -34,6 +26,26 @@ var ajaxErrDialog = {
|
||||
}
|
||||
};
|
||||
|
||||
var apiGET = function (url, callback) {
|
||||
$.getJSON(url, function (data) {
|
||||
callback(data);
|
||||
});
|
||||
};
|
||||
|
||||
var i18nToString = function (i18nstring) {
|
||||
var locale = $("body").attr("data-pretixlocale");
|
||||
if (i18nstring[locale]) {
|
||||
return i18nstring[locale];
|
||||
} else if (i18nstring["en"]) {
|
||||
return i18nstring["en"];
|
||||
}
|
||||
for (key in i18nstring) {
|
||||
if (i18nstring[key]) {
|
||||
return i18nstring[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ajaxError(function (event, jqXHR, settings, thrownError) {
|
||||
waitingDialog.hide();
|
||||
var c = $(jqXHR.responseText).filter('.container');
|
||||
@@ -423,6 +435,9 @@ var form_handlers = function (el) {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
el.find("input[name*=question], select[name*=question]").change(questions_toggle_dependent);
|
||||
questions_toggle_dependent();
|
||||
};
|
||||
|
||||
$(function () {
|
||||
@@ -491,14 +506,6 @@ $(function () {
|
||||
window.location.hash = e.target.hash;
|
||||
});
|
||||
|
||||
// Question editor
|
||||
if ($("#answer-options").length) {
|
||||
|
||||
$("#id_type").change(question_page_toggle_view);
|
||||
$("#id_required").change(question_page_toggle_view);
|
||||
question_page_toggle_view();
|
||||
}
|
||||
|
||||
// Event wizard
|
||||
$("#event-slug-random-generate").click(function () {
|
||||
var url = $(this).attr("data-rng-url");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*global $, Morris, gettext*/
|
||||
$(function () {
|
||||
// Question view
|
||||
if (!$("#question-stats").length) {
|
||||
return;
|
||||
}
|
||||
@@ -73,3 +74,66 @@ $(function () {
|
||||
|
||||
// N, S, T
|
||||
});
|
||||
|
||||
$(function () {
|
||||
// Question editor
|
||||
|
||||
if (!$("#answer-options").length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Question editor
|
||||
$("#id_type").change(question_page_toggle_view);
|
||||
$("#id_required").change(question_page_toggle_view);
|
||||
question_page_toggle_view();
|
||||
|
||||
function question_page_toggle_view() {
|
||||
var show = $("#id_type").val() == "C" || $("#id_type").val() == "M";
|
||||
$("#answer-options").toggle(show);
|
||||
|
||||
show = $("#id_type").val() == "B" && $("#id_required").prop("checked");
|
||||
$(".alert-required-boolean").toggle(show);
|
||||
}
|
||||
|
||||
var $val = $("#id_dependency_value");
|
||||
var $dq = $("#id_dependency_question");
|
||||
var oldval = $("#dependency_value_val").text();
|
||||
function update_dependency_options() {
|
||||
$val.parent().find(".loading-indicator").remove();
|
||||
$("#id_dependency_value option").remove();
|
||||
$("#id_dependency_value").prop("required", false);
|
||||
|
||||
var val = $dq.children("option:selected").val();
|
||||
if (!val) {
|
||||
$("#id_dependency_value").show();
|
||||
$val.show();
|
||||
return;
|
||||
}
|
||||
|
||||
$("#id_dependency_value").prop("required", true);
|
||||
$val.hide();
|
||||
$val.parent().append("<div class=\"help-block loading-indicator\"><span class=\"fa" +
|
||||
" fa-cog fa-spin\"></span></div>");
|
||||
|
||||
apiGET('/api/v1/organizers/' + $("body").attr("data-organizer") + '/events/' + $("body").attr("data-event") + '/questions/' + val + '/', function (data) {
|
||||
if (data.type === "B") {
|
||||
$val.append($("<option>").attr("value", "True").text(gettext("Ja")));
|
||||
$val.append($("<option>").attr("value", "False").text(gettext("Nein")));
|
||||
} else {
|
||||
for (var i = 0; i < data.options.length; i++) {
|
||||
var opt = data.options[i];
|
||||
var $opt = $("<option>").attr("value", opt.identifier).text(i18nToString(opt.answer));
|
||||
$val.append($opt);
|
||||
}
|
||||
}
|
||||
if (oldval) {
|
||||
$val.val(oldval);
|
||||
}
|
||||
$val.parent().find(".loading-indicator").remove();
|
||||
$val.show();
|
||||
});
|
||||
}
|
||||
|
||||
update_dependency_options();
|
||||
$dq.change(update_dependency_options);
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ function gettext(msgid) {
|
||||
}
|
||||
return msgid;
|
||||
}
|
||||
|
||||
function ngettext(singular, plural, count) {
|
||||
if (typeof django !== 'undefined' && typeof django.ngettext !== 'undefined') {
|
||||
return django.ngettext(singular, plural, count);
|
||||
@@ -14,7 +15,7 @@ function ngettext(singular, plural, count) {
|
||||
}
|
||||
|
||||
var form_handlers = function (el) {
|
||||
el.find(".datetimepicker").each(function() {
|
||||
el.find(".datetimepicker").each(function () {
|
||||
$(this).datetimepicker({
|
||||
format: $("body").attr("data-datetimeformat"),
|
||||
locale: $("body").attr("data-datetimelocale"),
|
||||
@@ -37,7 +38,7 @@ var form_handlers = function (el) {
|
||||
}
|
||||
});
|
||||
|
||||
el.find(".datepickerfield").each(function() {
|
||||
el.find(".datepickerfield").each(function () {
|
||||
var opts = {
|
||||
format: $("body").attr("data-dateformat"),
|
||||
locale: $("body").attr("data-datetimelocale"),
|
||||
@@ -71,7 +72,7 @@ var form_handlers = function (el) {
|
||||
}
|
||||
});
|
||||
|
||||
el.find(".timepickerfield").each(function() {
|
||||
el.find(".timepickerfield").each(function () {
|
||||
var opts = {
|
||||
format: $("body").attr("data-timeformat"),
|
||||
locale: $("body").attr("data-datetimelocale"),
|
||||
@@ -90,7 +91,7 @@ var form_handlers = function (el) {
|
||||
}
|
||||
};
|
||||
$(this).datetimepicker(opts);
|
||||
});
|
||||
});
|
||||
|
||||
el.find("script[data-replace-with-qr]").each(function () {
|
||||
var $div = $("<div>");
|
||||
@@ -104,7 +105,10 @@ var form_handlers = function (el) {
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
el.find("input[name*=question], select[name*=question]").change(questions_toggle_dependent);
|
||||
questions_toggle_dependent();
|
||||
};
|
||||
|
||||
|
||||
$(function () {
|
||||
@@ -130,7 +134,7 @@ $(function () {
|
||||
$("#voucher-box").slideDown();
|
||||
$("#voucher-toggle").slideUp();
|
||||
});
|
||||
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
$("#ajaxerr").on("click", ".ajaxerr-close", ajaxErrDialog.hide);
|
||||
@@ -140,7 +144,7 @@ $(function () {
|
||||
$('.toggle-variation-description').click(function () {
|
||||
$(this).parent().find('.addon-variation-description').slideToggle();
|
||||
});
|
||||
|
||||
|
||||
// Copy answers
|
||||
$(".js-copy-answers").click(function (e) {
|
||||
e.preventDefault();
|
||||
@@ -153,7 +157,7 @@ $(function () {
|
||||
// Subevent choice
|
||||
if ($(".subevent-toggle").length) {
|
||||
$(".subevent-list").hide();
|
||||
$(".subevent-toggle").css("display", "block").click(function() {
|
||||
$(".subevent-toggle").css("display", "block").click(function () {
|
||||
$(".subevent-list").slideToggle(300);
|
||||
});
|
||||
}
|
||||
@@ -165,7 +169,7 @@ $(function () {
|
||||
var update_cart_form = function () {
|
||||
var is_enabled = $(".product-row input[type=checkbox]:checked, .variations input[type=checkbox]:checked, .product-row input[type=radio]:checked, .variations input[type=radio]:checked").length;
|
||||
if (!is_enabled) {
|
||||
$(".input-item-count").each(function() {
|
||||
$(".input-item-count").each(function () {
|
||||
if ($(this).val() && $(this).val() !== "0") {
|
||||
is_enabled = true;
|
||||
}
|
||||
@@ -185,18 +189,18 @@ $(function () {
|
||||
|
||||
// Invoice address form
|
||||
$("input[data-required-if]").each(function () {
|
||||
var dependent = $(this),
|
||||
dependency = $($(this).attr("data-required-if")),
|
||||
update = function (ev) {
|
||||
var enabled = (dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val();
|
||||
if (!dependent.is("[data-no-required-attr]")) {
|
||||
dependent.prop('required', enabled);
|
||||
}
|
||||
dependent.closest('.form-group').toggleClass('required', enabled);
|
||||
};
|
||||
update();
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("change", update);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("dp.change", update);
|
||||
var dependent = $(this),
|
||||
dependency = $($(this).attr("data-required-if")),
|
||||
update = function (ev) {
|
||||
var enabled = (dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val();
|
||||
if (!dependent.is("[data-no-required-attr]")) {
|
||||
dependent.prop('required', enabled);
|
||||
}
|
||||
dependent.closest('.form-group').toggleClass('required', enabled);
|
||||
};
|
||||
update();
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("change", update);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("dp.change", update);
|
||||
});
|
||||
|
||||
$("input[data-display-dependency]").each(function () {
|
||||
@@ -219,16 +223,16 @@ $(function () {
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("dp.change", update);
|
||||
});
|
||||
|
||||
form_handlers($("body"));
|
||||
form_handlers($("body"));
|
||||
|
||||
// Lightbox
|
||||
lightbox.init();
|
||||
});
|
||||
|
||||
function copy_answers(idx) {
|
||||
var elements = $('*[data-idx="'+idx+'"] input, *[data-idx="'+idx+'"] select, *[data-idx="'+idx+'"] textarea');
|
||||
function copy_answers(idx) {
|
||||
var elements = $('*[data-idx="' + idx + '"] input, *[data-idx="' + idx + '"] select, *[data-idx="' + idx + '"] textarea');
|
||||
var firstAnswers = $('*[data-idx="0"] input, *[data-idx="0"] select, *[data-idx="0"] textarea');
|
||||
elements.each(function(index){
|
||||
elements.each(function (index) {
|
||||
var input = $(this),
|
||||
tagName = input.prop('tagName').toLowerCase(),
|
||||
attributeType = input.attr('type'),
|
||||
@@ -250,14 +254,20 @@ function copy_answers(idx) {
|
||||
break;
|
||||
case "checkbox":
|
||||
case "radio":
|
||||
input.prop("checked", firstAnswers.filter("[name$=" + suffix + "]").prop("checked"));
|
||||
if (input.attr('value')) {
|
||||
input.prop("checked", firstAnswers.filter("[name$=" + suffix + "][value=" + input.attr('value') + "]").prop("checked"));
|
||||
} else {
|
||||
input.prop("checked", firstAnswers.filter("[name$=" + suffix + "]").prop("checked"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
input.val(firstAnswers.filter("[name$=" + suffix + "]").val());
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
input.val(firstAnswers.filter("[name$=" + suffix + "]").val());
|
||||
}
|
||||
}
|
||||
});
|
||||
questions_toggle_dependent(true);
|
||||
}
|
||||
|
||||
|
||||
71
src/pretix/static/pretixpresale/js/ui/questions.js
Normal file
71
src/pretix/static/pretixpresale/js/ui/questions.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/*global $ */
|
||||
|
||||
function questions_toggle_dependent(ev) {
|
||||
function q_should_be_shown($el) {
|
||||
if (!$el.attr('data-question-dependency')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var dependency_name = $el.attr("name").split("_")[0] + "_" + $el.attr("data-question-dependency");
|
||||
var dependency_value = $el.attr("data-question-dependency-value");
|
||||
var $dependency_el;
|
||||
|
||||
if ($("select[name=" + dependency_name + "]").length) {
|
||||
// dependency is type C
|
||||
$dependency_el = $("select[name=" + dependency_name + "]");
|
||||
if (!$dependency_el.closest(".form-group").hasClass("dependency-hidden")) { // do not show things that depend on hidden things
|
||||
return q_should_be_shown($dependency_el) && $dependency_el.val() === dependency_value;
|
||||
}
|
||||
} else if ($("input[type=checkbox][name=" + dependency_name + "]").length) {
|
||||
// dependency type is B or M
|
||||
if (dependency_value === "True" || dependency_value === "False") {
|
||||
$dependency_el = $("input[name=" + dependency_name + "]");
|
||||
if (!$dependency_el.closest(".form-group").hasClass("dependency-hidden")) { // do not show things that depend on hidden things
|
||||
if (dependency_value === "True") {
|
||||
return q_should_be_shown($dependency_el) && $dependency_el.prop('checked');
|
||||
} else {
|
||||
return q_should_be_shown($dependency_el) && !$dependency_el.prop('checked');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$dependency_el = $("input[value=" + dependency_value + "][name=" + dependency_name + "]");
|
||||
if (!$dependency_el.closest(".form-group").hasClass("dependency-hidden")) { // do not show things that depend on hidden things
|
||||
return q_should_be_shown($dependency_el) && $dependency_el.prop('checked');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$("[data-question-dependency]").each(function () {
|
||||
var $dependent = $(this).closest(".form-group");
|
||||
var is_shown = !$dependent.hasClass("dependency-hidden");
|
||||
var should_be_shown = q_should_be_shown($(this));
|
||||
|
||||
if (should_be_shown && !is_shown) {
|
||||
$dependent.stop().removeClass("dependency-hidden");
|
||||
if (!ev) {
|
||||
$dependent.show();
|
||||
} else {
|
||||
$dependent.slideDown();
|
||||
}
|
||||
$dependent.find("input.required-hidden, select.required-hidden, textarea.required-hidden").each(function () {
|
||||
$(this).prop("required", true).removeClass("required-hidden");
|
||||
});
|
||||
} else if (!should_be_shown && is_shown) {
|
||||
if ($dependent.hasClass("has-error") || $dependent.find(".has-error").length) {
|
||||
// Do not hide things with invalid validation
|
||||
return;
|
||||
}
|
||||
$dependent.stop().addClass("dependency-hidden");
|
||||
if (!ev) {
|
||||
$dependent.hide();
|
||||
} else {
|
||||
$dependent.slideUp();
|
||||
}
|
||||
$dependent.find("input[required], select[required], textarea[required]").each(function () {
|
||||
$(this).prop("required", false).addClass("required-hidden");
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user