From a6f5a115d2dae6cc435b56dae362a19561756eee Mon Sep 17 00:00:00 2001 From: nathanbegbie Date: Mon, 6 Nov 2017 14:20:01 +0200 Subject: [PATCH 1/8] Use hidden input + dropdown widget with js intialization for rule block --- molo/surveys/blocks.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/molo/surveys/blocks.py b/molo/surveys/blocks.py index 59b2f9e..7e61046 100644 --- a/molo/surveys/blocks.py +++ b/molo/surveys/blocks.py @@ -147,6 +147,12 @@ def clean(self, value): class RuleSelectBlock(blocks.CharBlock): + def __init__(self, *args, **kwargs): + super(RuleSelectBlock, self).__init__(*args, **kwargs) + self.field.widget = SelectAndHiddenWidget() + + def js_initializer(self): + return 'newRuleAdded' class Meta: icon = 'cog' From aed63d7506564a2c307e5100fd867a26af32c121 Mon Sep 17 00:00:00 2001 From: nathanbegbie Date: Mon, 6 Nov 2017 14:21:43 +0200 Subject: [PATCH 2/8] Check to see whether CombinationRule streamfield has correct structure --- molo/surveys/rules.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/molo/surveys/rules.py b/molo/surveys/rules.py index 646129a..d3d272d 100644 --- a/molo/surveys/rules.py +++ b/molo/surveys/rules.py @@ -8,6 +8,7 @@ from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ +from wagtail.wagtailcore.blocks.stream_block import StreamBlockValidationError from wagtail.wagtailadmin.edit_handlers import ( FieldPanel, FieldRowPanel, @@ -391,5 +392,36 @@ def description(self): 'particular combination of rules'), } + def clean(self): + super(CombinationRule, self).clean() + if isinstance(self.body.stream_data[0], dict): + newData = [block['type'] for block in self.body.stream_data] + elif isinstance(self.body.stream_data[0], tuple): + newData = [block[0] for block in self.body.stream_data] + + if len(newData) % 3 != 0: + raise StreamBlockValidationError(non_block_errors=[_( + 'Rule Combination must follow the ' + ' pattern.')]) + + iterations = len(newData) / 3 + print iterations + for i in range(iterations): + first_rule_index = (i * 3) + operator_index = (i * 3) + 1 + second_rule_index = (i * 3) + 2 + + if((newData[first_rule_index] == 'Rule' or + newData[first_rule_index] == 'NestedLogic') and + (newData[operator_index] == 'Operator') and + (newData[second_rule_index] == 'Rule' or + newData[second_rule_index] == 'NestedLogic')): + pass + else: + raise StreamBlockValidationError(non_block_errors=[_( + 'Rule Combination must follow the ' + ' pattern.')]) + + class Meta: verbose_name = _('Rule Combination') From 09f8db5bd45507673de046776a8d4a33a3b02bf1 Mon Sep 17 00:00:00 2001 From: nathanbegbie Date: Mon, 6 Nov 2017 14:22:30 +0200 Subject: [PATCH 3/8] Add JS to infer rule reference in RuleCombination by rule type and order --- molo/surveys/static/js/survey-admin.js | 202 ++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 1 deletion(-) diff --git a/molo/surveys/static/js/survey-admin.js b/molo/surveys/static/js/survey-admin.js index 5bb3f06..cb52c7b 100644 --- a/molo/surveys/static/js/survey-admin.js +++ b/molo/surveys/static/js/survey-admin.js @@ -1,5 +1,4 @@ $(function(){ - console.log('loaded') var multi_step_checkbox = $('#id_multi_step'); var multi_step_label = $('label[for=id_multi_step]'); @@ -52,4 +51,205 @@ $(function(){ enableDisplayDirect(); } }); + + window.rules = [ + 'Time Rule', + 'Day Rule', + 'Referral Rule', + 'Visit Count Rule', + 'Article Tag Rule', + 'Query Rule', + 'Device Rule', + 'User Is Logged In Rule', + 'Comment Data Rule', + 'Profile Data Rule', + 'Survey Submission Data Rule', + 'Group Membership Rule', + ] + + window.ruleIndex = {}; + window.ruleFields = []; + + window.initRuleIndex = function(){ + rules.map(function(ruleTitle) { + var ruleInfo = { + ruleName: ruleTitle, + form: $('[id*="' + ruleTitle.replace(/ /g, "").toLowerCase() + '"]').filter('ul'), + blockIds: [], + updateBlock: function(){ + this.blockIds = $.map(this.form.children('li').not('.deleted'), function(arg, index){ + return arg.id + }); + }, + deleteBlock: function(id){ + var index = this.blockIds.indexOf(id); + this.updateBlock(); + var deletedOptionValue = this.ruleName.replace(/ /g, "") + "_" + String(index); + deleteRuleFromField(deletedOptionValue); + }, + } + ruleInfo.updateBlock(); + window.ruleIndex[ruleInfo.form.attr("id")] = ruleInfo; + }) + } + + + + window.extractRuleInfo = function(){ + var ruleValueTextPairs = [] + $.each(ruleIndex, function(index_outer, form){ + $.each(form.blockIds, function(index_inner, value) { + ruleValueTextPairs.push({ + "value": form.ruleName.replace(" ", "") + "_" + String(index_inner), + "text": form.ruleName + " " + String(index_inner + 1), + }); + }); + }); + return ruleValueTextPairs; + } + + window.addUpdateTrigger = function(obj, form_id, block_id){ + obj.click(function(){ + window.deleteFromRuleIndex(form_id, block_id); + }); + } + + window.addActionToExistingDeleteButtons = function(){ + // TODO exclude ruleCombination + var forms = $('[id*="rule_related-FORMS"]') + .not("#id_surveys_combinationrule_related-FORMS") + .filter("ul"); + + forms.map(function(index, form) { + $("#" + form.id) + .children("li") + .not(".deleted") + .map(function(index, block) { // TODO: check you can use .each instead + var deleteButton = $("#" + block.id).find('button[title^="Delete"]'); + window.addUpdateTrigger(deleteButton, form.id, block.id); + }); + }); + }; + + window.deleteFromRuleIndex = function(form_id, block_id){ + var block = ruleIndex[form_id] + block.deleteBlock(block_id); + }; + + window.attachActionToRuleCreators = function() { + var some_rules = $('[id*="rule_related-ADD"]').filter("a").not("#id_surveys_combinationrule_related-ADD"); + $.map(some_rules, function(val, i) { + val.addEventListener("click", function() { + var id = $(this).attr('id'); + var form_id = id.replace('ADD', 'FORMS'); + var form = $("#" + form_id); + var newBlock = form.children(':last'); + // upate Index of Rules + ruleIndex[form_id].updateBlock(); + updateRuleOptions(); + // add event listener to new Delete Button + var newDeleteButton = newBlock.find('button[title^="Delete"]'); + window.addUpdateTrigger(newDeleteButton, form.attr("id"), newBlock.attr("id")); + }, false); + }); + }; + + var createSelectManager = function(id){ + var selectRuleField = { + hiddenInput: $('#' + id + '_0'), + select: $('#' + id + '_1'), + repopulateOptions: function(){ + var ruleInfo = extractRuleInfo() + var select = this.select; + select.children().remove(); + select.append($("")); + $.each(ruleInfo, function(index, option) { + select.append($('