diff --git a/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6 b/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6
index 9c8e4bff..2805c370 100644
--- a/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6
+++ b/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6
@@ -3,6 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators";
export default DateInput.extend({
useNativePicker: false,
+ classNameBindings: ["fieldClass"],
@discourseComputed()
placeholder() {
diff --git a/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6 b/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6
index 44b675b0..1fcb62f5 100644
--- a/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6
+++ b/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6
@@ -2,6 +2,8 @@ import DateTimeInput from "discourse/components/date-time-input";
import discourseComputed from "discourse-common/utils/decorators";
export default DateTimeInput.extend({
+ classNameBindings: ["fieldClass"],
+
@discourseComputed("timeFirst", "tabindex")
timeTabindex(timeFirst, tabindex) {
return timeFirst ? tabindex : tabindex + 1;
diff --git a/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6 b/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6
index 82f9c68b..1406d63b 100644
--- a/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6
+++ b/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6
@@ -2,6 +2,8 @@ import Component from "@ember/component";
import { observes } from "discourse-common/utils/decorators";
export default Component.extend({
+ classNameBindings: ["fieldClass"],
+
@observes("time")
setValue() {
this.set("field.value", this.time.format(this.field.format));
diff --git a/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6 b/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6
index eb5d318b..990d7daa 100644
--- a/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6
+++ b/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6
@@ -4,7 +4,7 @@ import { computed } from "@ember/object";
export default Component.extend(UppyUploadMixin, {
classNames: ["wizard-field-upload"],
- classNameBindings: ["isImage"],
+ classNameBindings: ["isImage", "fieldClass"],
uploading: false,
type: computed(function () {
return `wizard_${this.field.id}`;
diff --git a/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6 b/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6
index 87d5ddb0..64741c6b 100644
--- a/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6
+++ b/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6
@@ -1,3 +1,5 @@
import Component from "@ember/component";
-export default Component.extend({});
+export default Component.extend({
+ classNameBindings: ["fieldClass"],
+});
diff --git a/assets/javascripts/discourse/components/custom-wizard-step.js.es6 b/assets/javascripts/discourse/components/custom-wizard-step.js.es6
index b98db1ab..7c933771 100644
--- a/assets/javascripts/discourse/components/custom-wizard-step.js.es6
+++ b/assets/javascripts/discourse/components/custom-wizard-step.js.es6
@@ -9,6 +9,7 @@ import CustomWizard, {
updateCachedWizard,
} from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard";
import { alias, not } from "@ember/object/computed";
+import discourseLater from "discourse-common/lib/later";
const alreadyWarned = {};
@@ -110,29 +111,22 @@ export default Component.extend({
},
autoFocus() {
- schedule("afterRender", () => {
- const $invalid = $(
- ".wizard-field.invalid:nth-of-type(1) .wizard-focusable"
- );
-
- if ($invalid.length) {
- return $invalid.focus();
- }
-
- $(".wizard-focusable:first").focus();
+ discourseLater(() => {
+ schedule("afterRender", () => {
+ if ($(".invalid .wizard-focusable").length) {
+ this.animateInvalidFields();
+ }
+ });
});
},
animateInvalidFields() {
schedule("afterRender", () => {
- let $element = $(
- ".invalid input[type=text],.invalid textarea,.invalid input[type=checkbox],.invalid .select-kit"
- );
-
- if ($element.length) {
+ let $invalid = $(".invalid .wizard-focusable");
+ if ($invalid.length) {
$([document.documentElement, document.body]).animate(
{
- scrollTop: $element.offset().top - 200,
+ scrollTop: $invalid.offset().top - 200,
},
400
);
diff --git a/assets/javascripts/discourse/helpers/char-counter.js.es6 b/assets/javascripts/discourse/helpers/char-counter.js.es6
deleted file mode 100644
index a700a432..00000000
--- a/assets/javascripts/discourse/helpers/char-counter.js.es6
+++ /dev/null
@@ -1,22 +0,0 @@
-import { registerUnbound } from "discourse-common/lib/helpers";
-import I18n from "I18n";
-import Handlebars from "handlebars";
-
-export default registerUnbound("char-counter", function (body, maxLength) {
- let bodyLength = body ? body.length : 0;
- let finalString;
-
- if (maxLength) {
- let isOverMax = bodyLength > maxLength ? "true" : "false";
- finalString = `
${bodyLength} / ${I18n.t(
- "wizard.x_characters",
- { count: parseInt(maxLength, 10) }
- )}
`;
- } else {
- finalString = `${I18n.t("wizard.x_characters", {
- count: parseInt(bodyLength, 10),
- })}
`;
- }
-
- return new Handlebars.SafeString(finalString);
-});
diff --git a/assets/javascripts/discourse/helpers/wizard-char-counter.js.es6 b/assets/javascripts/discourse/helpers/wizard-char-counter.js.es6
new file mode 100644
index 00000000..1e194314
--- /dev/null
+++ b/assets/javascripts/discourse/helpers/wizard-char-counter.js.es6
@@ -0,0 +1,25 @@
+import { registerUnbound } from "discourse-common/lib/helpers";
+import I18n from "I18n";
+import Handlebars from "handlebars";
+
+export default registerUnbound(
+ "wizard-char-counter",
+ function (body, maxLength) {
+ let bodyLength = body ? body.length : 0;
+ let finalString;
+
+ if (maxLength) {
+ let isOverMax = bodyLength > maxLength ? "true" : "false";
+ finalString = `${bodyLength} / ${I18n.t(
+ "wizard.x_characters",
+ { count: parseInt(maxLength, 10) }
+ )}
`;
+ } else {
+ finalString = `${I18n.t("wizard.x_characters", {
+ count: parseInt(bodyLength, 10),
+ })}
`;
+ }
+
+ return new Handlebars.SafeString(finalString);
+ }
+);
diff --git a/assets/javascripts/discourse/models/custom-wizard-field.js.es6 b/assets/javascripts/discourse/models/custom-wizard-field.js.es6
index a03c7c9e..2afe79d9 100644
--- a/assets/javascripts/discourse/models/custom-wizard-field.js.es6
+++ b/assets/javascripts/discourse/models/custom-wizard-field.js.es6
@@ -72,7 +72,7 @@ export default EmberObject.extend(ValidState, {
valid = true;
}
- this.setValid(valid);
+ this.setValid(Boolean(valid));
return valid;
},
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs
index 3b776215..0f798714 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs
@@ -1,11 +1,11 @@
-{{input
- type=inputType
+
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs
index 9cce87bc..79180dc4 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs
@@ -1,5 +1,6 @@
{{custom-wizard-category-selector
categories=categories
+ class=fieldClass
whitelist=field.content
onChange=(action (mut categories))
tabindex=field.tabindex
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs
index 053e0218..0ceeb11b 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs
@@ -1 +1,7 @@
-{{input type="checkbox" id=field.id checked=field.value tabindex=field.tabindex}}
+
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs
index 51964a1b..2c966d24 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs
@@ -2,6 +2,7 @@
field=field
composer=composer
wizard=wizard
+ fieldClass=fieldClass
groupsMentioned=(action "groupsMentioned")
cannotSeeMention=(action "cannotSeeMention")
importQuote=(action "importQuote")
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs
index 6873f9bd..75a5b2b1 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs
@@ -1,5 +1,6 @@
{{custom-wizard-group-selector
groups=site.groups
+ class=fieldClass
field=field
whitelist=field.content
value=field.value
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs
index f5d6543c..3049ab08 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs
@@ -1 +1,9 @@
-{{input type="number" step="0.01" id=field.id value=field.value tabindex=field.tabindex}}
+
+
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs
index 90679ae7..17f68b92 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs
@@ -1,5 +1,6 @@
{{custom-wizard-tag-chooser
tags=field.value
+ class=fieldClass
tabindex=field.tabindex
tagGroups=field.tag_groups
everyTag=true
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs
index 08733d3f..ed3f4f37 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs
@@ -1 +1,8 @@
-{{input id=field.id value=field.value class=fieldClass placeholder=field.translatedPlaceholder tabindex=field.tabindex autocomplete=autocomplete}}
+
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs
index dda299bc..1d43813e 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs
@@ -1 +1,7 @@
-{{textarea id=field.id value=field.value class=fieldClass placeholder=field.translatedPlaceholder tabindex=field.tabindex}}
+
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-url.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-url.hbs
index c7e1a508..5d1c4574 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field-url.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-url.hbs
@@ -1 +1,6 @@
-{{input type="text" id=field.id value=field.value tabindex=field.tabindex}}
+
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field.hbs
index efda8629..a95f9fef 100644
--- a/assets/javascripts/discourse/templates/components/custom-wizard-field.hbs
+++ b/assets/javascripts/discourse/templates/components/custom-wizard-field.hbs
@@ -20,7 +20,7 @@
{{#if field.char_counter}}
{{#if textType}}
- {{char-counter field.value field.max_length}}
+ {{wizard-char-counter field.value field.max_length}}
{{/if}}
{{/if}}
diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs
index 106c61ee..8763d3a5 100644
--- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs
+++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs
@@ -716,7 +716,7 @@
property="name"
onUpdate=(action "mappedFieldUpdated")
options=(hash
- textSelection="key,value"
+ textSelection="key,value,output"
wizardFieldSelection=true
userFieldSelection="key,value"
context="action"
diff --git a/assets/stylesheets/common/wizard/field.scss b/assets/stylesheets/common/wizard/field.scss
index f710632b..71f12d84 100644
--- a/assets/stylesheets/common/wizard/field.scss
+++ b/assets/stylesheets/common/wizard/field.scss
@@ -32,13 +32,8 @@ body.custom-wizard {
}
}
- &.invalid {
- textarea,
- input[type="text"],
- input[type="checkbox"],
- .select-kit {
- outline: 4px solid var(--danger);
- }
+ &.invalid .wizard-focusable {
+ outline: 4px solid var(--danger);
}
}
diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb
index 9d26c82e..4e18ad01 100644
--- a/lib/custom_wizard/mapper.rb
+++ b/lib/custom_wizard/mapper.rb
@@ -44,7 +44,7 @@ class CustomWizard::Mapper
def initialize(params)
@inputs = params[:inputs] || {}
- @data = params[:data] || {}
+ @data = params[:data] ? params[:data].with_indifferent_access : {}
@user = params[:user]
@opts = params[:opts] || {}
end
@@ -267,7 +267,12 @@ class CustomWizard::Mapper
return nil if data.nil?
k = keys.shift
result = data[k]
- keys.empty? ? result : self.recurse(result, keys)
+
+ if keys.empty?
+ result.is_a?(Hash) ? "" : result
+ else
+ self.recurse(result, keys)
+ end
end
def bool(value)
diff --git a/lib/custom_wizard/submission.rb b/lib/custom_wizard/submission.rb
index 38cad982..ae616b0b 100644
--- a/lib/custom_wizard/submission.rb
+++ b/lib/custom_wizard/submission.rb
@@ -84,6 +84,10 @@ class CustomWizard::Submission
data
end
+ def submitted?
+ !!submitted_at
+ end
+
def self.get(wizard)
data = PluginStore.get("#{wizard.id}_#{KEY}", wizard.actor_id).last
new(wizard, data)
diff --git a/lib/custom_wizard/wizard.rb b/lib/custom_wizard/wizard.rb
index 4ed4037d..3d62cf25 100644
--- a/lib/custom_wizard/wizard.rb
+++ b/lib/custom_wizard/wizard.rb
@@ -176,6 +176,7 @@ class CustomWizard::Wizard
def unfinished?
return nil unless actor_id
+ return false if last_submission&.submitted?
most_recent = CustomWizard::UserHistory.where(
actor_id: actor_id,
@@ -194,6 +195,7 @@ class CustomWizard::Wizard
def completed?
return nil unless actor_id
+ return true if last_submission&.submitted?
history = CustomWizard::UserHistory.where(
actor_id: actor_id,
@@ -282,6 +284,10 @@ class CustomWizard::Wizard
@submissions ||= CustomWizard::Submission.list(self).submissions
end
+ def last_submission
+ @last_submission ||= submissions&.last
+ end
+
def current_submission
@current_submission ||= begin
if submissions.present?
diff --git a/spec/components/custom_wizard/mapper_spec.rb b/spec/components/custom_wizard/mapper_spec.rb
index f460cc01..510632a9 100644
--- a/spec/components/custom_wizard/mapper_spec.rb
+++ b/spec/components/custom_wizard/mapper_spec.rb
@@ -58,6 +58,11 @@ describe CustomWizard::Mapper do
"step_1_field_3" => "Value"
}
}
+ let(:template_params_object) {
+ {
+ "step_1_field_1": get_wizard_fixture("field/upload")
+ }
+ }
def create_template_mapper(data, user)
CustomWizard::Mapper.new(
@@ -448,6 +453,40 @@ describe CustomWizard::Mapper do
expect(result).to eq(template)
end
+ it "handles correct object variable references" do
+ template = <<-LIQUID.strip
+ {%- if "w{step_1_field_1.id}" == "step_2_field_7" -%}
+ Correct
+ {%- else -%}
+ Incorrect
+ {%-endif-%}
+ LIQUID
+ mapper = create_template_mapper(template_params_object, user1)
+ result = mapper.interpolate(
+ template.dup,
+ template: true,
+ wizard: true
+ )
+ expect(result).to eq("Correct")
+ end
+
+ it "handles incorrect object variable references" do
+ template = <<-LIQUID.strip
+ {%- if "w{step_1_field_1}" == "step_2_field_7" -%}
+ Correct
+ {%- else -%}
+ Incorrect
+ {%-endif-%}
+ LIQUID
+ mapper = create_template_mapper(template_params_object, user1)
+ result = mapper.interpolate(
+ template.dup,
+ template: true,
+ wizard: true
+ )
+ expect(result).to eq("Incorrect")
+ end
+
context "custom filter: 'first_non_empty'" do
it "gives first non empty element from list" do
template = <<-LIQUID.strip
diff --git a/spec/components/custom_wizard/wizard_spec.rb b/spec/components/custom_wizard/wizard_spec.rb
index 591eee8c..17151077 100644
--- a/spec/components/custom_wizard/wizard_spec.rb
+++ b/spec/components/custom_wizard/wizard_spec.rb
@@ -7,6 +7,7 @@ describe CustomWizard::Wizard do
let(:template_json) { get_wizard_fixture("wizard") }
let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
let(:guests_permitted_json) { get_wizard_fixture("wizard/guests_permitted") }
+ let(:step_json) { get_wizard_fixture("step/step") }
before do
Group.refresh_automatic_group!(:trust_level_3)
@@ -75,6 +76,28 @@ describe CustomWizard::Wizard do
expect(@wizard.start).to eq('step_2')
end
+ it "determines the user's current step if steps are added" do
+ append_steps
+ progress_step('step_1')
+ progress_step('step_2')
+ progress_step("step_3")
+
+ fourth_step = step_json.dup
+ fourth_step['id'] = "step_4"
+ template = template_json.dup
+ template['steps'] << fourth_step
+
+ CustomWizard::Template.save(template, skip_jobs: true)
+
+ wizard = CustomWizard::Wizard.new(template, user)
+ template['steps'].each do |step_template|
+ wizard.append_step(step_template['id'])
+ end
+
+ expect(wizard.steps.size).to eq(4)
+ expect(wizard.start).to eq(nil)
+ end
+
it "creates a step updater" do
expect(
@wizard.create_updater('step_1', step_1_field_1: "Text input")