0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-22 09:20:29 +01:00

Merge branch 'main' into admin-acceptance-tests

Dieser Commit ist enthalten in:
jumagura 2023-03-30 21:22:44 -04:00
Commit 0f59c9092f
27 geänderte Dateien mit 176 neuen und 64 gelöschten Zeilen

Datei anzeigen

@ -3,6 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators";
export default DateInput.extend({ export default DateInput.extend({
useNativePicker: false, useNativePicker: false,
classNameBindings: ["fieldClass"],
@discourseComputed() @discourseComputed()
placeholder() { placeholder() {

Datei anzeigen

@ -2,6 +2,8 @@ import DateTimeInput from "discourse/components/date-time-input";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default DateTimeInput.extend({ export default DateTimeInput.extend({
classNameBindings: ["fieldClass"],
@discourseComputed("timeFirst", "tabindex") @discourseComputed("timeFirst", "tabindex")
timeTabindex(timeFirst, tabindex) { timeTabindex(timeFirst, tabindex) {
return timeFirst ? tabindex : tabindex + 1; return timeFirst ? tabindex : tabindex + 1;

Datei anzeigen

@ -2,6 +2,8 @@ import Component from "@ember/component";
import { observes } from "discourse-common/utils/decorators"; import { observes } from "discourse-common/utils/decorators";
export default Component.extend({ export default Component.extend({
classNameBindings: ["fieldClass"],
@observes("time") @observes("time")
setValue() { setValue() {
this.set("field.value", this.time.format(this.field.format)); this.set("field.value", this.time.format(this.field.format));

Datei anzeigen

@ -4,7 +4,7 @@ import { computed } from "@ember/object";
export default Component.extend(UppyUploadMixin, { export default Component.extend(UppyUploadMixin, {
classNames: ["wizard-field-upload"], classNames: ["wizard-field-upload"],
classNameBindings: ["isImage"], classNameBindings: ["isImage", "fieldClass"],
uploading: false, uploading: false,
type: computed(function () { type: computed(function () {
return `wizard_${this.field.id}`; return `wizard_${this.field.id}`;

Datei anzeigen

@ -1,3 +1,5 @@
import Component from "@ember/component"; import Component from "@ember/component";
export default Component.extend({}); export default Component.extend({
classNameBindings: ["fieldClass"],
});

Datei anzeigen

@ -9,6 +9,7 @@ import CustomWizard, {
updateCachedWizard, updateCachedWizard,
} from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard"; } from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard";
import { alias, not } from "@ember/object/computed"; import { alias, not } from "@ember/object/computed";
import discourseLater from "discourse-common/lib/later";
const alreadyWarned = {}; const alreadyWarned = {};
@ -110,29 +111,22 @@ export default Component.extend({
}, },
autoFocus() { autoFocus() {
schedule("afterRender", () => { discourseLater(() => {
const $invalid = $( schedule("afterRender", () => {
".wizard-field.invalid:nth-of-type(1) .wizard-focusable" if ($(".invalid .wizard-focusable").length) {
); this.animateInvalidFields();
}
if ($invalid.length) { });
return $invalid.focus();
}
$(".wizard-focusable:first").focus();
}); });
}, },
animateInvalidFields() { animateInvalidFields() {
schedule("afterRender", () => { schedule("afterRender", () => {
let $element = $( let $invalid = $(".invalid .wizard-focusable");
".invalid input[type=text],.invalid textarea,.invalid input[type=checkbox],.invalid .select-kit" if ($invalid.length) {
);
if ($element.length) {
$([document.documentElement, document.body]).animate( $([document.documentElement, document.body]).animate(
{ {
scrollTop: $element.offset().top - 200, scrollTop: $invalid.offset().top - 200,
}, },
400 400
); );

Datei anzeigen

@ -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 = `<div class="body-length" data-length=${bodyLength} data-over-max=${isOverMax}>${bodyLength} / ${I18n.t(
"wizard.x_characters",
{ count: parseInt(maxLength, 10) }
)}</div>`;
} else {
finalString = `<div class="body-length">${I18n.t("wizard.x_characters", {
count: parseInt(bodyLength, 10),
})}</div>`;
}
return new Handlebars.SafeString(finalString);
});

Datei anzeigen

@ -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 = `<div class="body-length" data-length=${bodyLength} data-over-max=${isOverMax}>${bodyLength} / ${I18n.t(
"wizard.x_characters",
{ count: parseInt(maxLength, 10) }
)}</div>`;
} else {
finalString = `<div class="body-length">${I18n.t("wizard.x_characters", {
count: parseInt(bodyLength, 10),
})}</div>`;
}
return new Handlebars.SafeString(finalString);
}
);

Datei anzeigen

@ -72,7 +72,7 @@ export default EmberObject.extend(ValidState, {
valid = true; valid = true;
} }
this.setValid(valid); this.setValid(Boolean(valid));
return valid; return valid;
}, },

Datei anzeigen

@ -1,11 +1,11 @@
{{input <Input
type=inputType @type={{this.inputType}}
@value={{readonly this.value}}
class="date-picker" class="date-picker"
placeholder=placeholder placeholder={{this.placeholder}}
value=(readonly value) tabindex={{this.tabindex}}
input=(action "onChangeDate") {{on "input" (action "onChangeDate")}}
tabindex=tabindex
autocomplete="off" autocomplete="off"
}} />
<div class="picker-container"></div> <div class="picker-container"></div>

Datei anzeigen

@ -1,5 +1,6 @@
{{custom-wizard-category-selector {{custom-wizard-category-selector
categories=categories categories=categories
class=fieldClass
whitelist=field.content whitelist=field.content
onChange=(action (mut categories)) onChange=(action (mut categories))
tabindex=field.tabindex tabindex=field.tabindex

Datei anzeigen

@ -1 +1,7 @@
{{input type="checkbox" id=field.id checked=field.value tabindex=field.tabindex}} <Input
id={{this.field.id}}
@type="checkbox"
@checked={{this.field.value}}
tabindex={{this.field.tabindex}}
class={{this.fieldClass}}
/>

Datei anzeigen

@ -2,6 +2,7 @@
field=field field=field
composer=composer composer=composer
wizard=wizard wizard=wizard
fieldClass=fieldClass
groupsMentioned=(action "groupsMentioned") groupsMentioned=(action "groupsMentioned")
cannotSeeMention=(action "cannotSeeMention") cannotSeeMention=(action "cannotSeeMention")
importQuote=(action "importQuote") importQuote=(action "importQuote")

Datei anzeigen

@ -1,5 +1,6 @@
{{custom-wizard-group-selector {{custom-wizard-group-selector
groups=site.groups groups=site.groups
class=fieldClass
field=field field=field
whitelist=field.content whitelist=field.content
value=field.value value=field.value

Datei anzeigen

@ -1 +1,9 @@
{{input type="number" step="0.01" id=field.id value=field.value tabindex=field.tabindex}} <Input
id={{this.field.id}}
step="0.01"
@type="number"
@value={{this.field.value}}
tabindex={{this.field.tabindex}}
class={{this.fieldClass}}
/>

Datei anzeigen

@ -1,5 +1,6 @@
{{custom-wizard-tag-chooser {{custom-wizard-tag-chooser
tags=field.value tags=field.value
class=fieldClass
tabindex=field.tabindex tabindex=field.tabindex
tagGroups=field.tag_groups tagGroups=field.tag_groups
everyTag=true everyTag=true

Datei anzeigen

@ -1 +1,8 @@
{{input id=field.id value=field.value class=fieldClass placeholder=field.translatedPlaceholder tabindex=field.tabindex autocomplete=autocomplete}} <Input
id={{this.field.id}}
@value={{this.field.value}}
tabindex={{this.field.tabindex}}
class={{this.fieldClass}}
placeholder={{this.field.translatedPlaceholder}}
autocomplete={{this.autocomplete}}
/>

Datei anzeigen

@ -1 +1,7 @@
{{textarea id=field.id value=field.value class=fieldClass placeholder=field.translatedPlaceholder tabindex=field.tabindex}} <Textarea
id={{this.field.id}}
@value={{this.field.value}}
tabindex={{this.field.tabindex}}
class={{this.fieldClass}}
placeholder={{this.field.translatedPlaceholder}}
/>

Datei anzeigen

@ -1 +1,6 @@
{{input type="text" id=field.id value=field.value tabindex=field.tabindex}} <Input
id={{this.field.id}}
@value={{this.field.value}}
tabindex={{this.field.tabindex}}
class={{this.fieldClass}}
/>

Datei anzeigen

@ -20,7 +20,7 @@
{{#if field.char_counter}} {{#if field.char_counter}}
{{#if textType}} {{#if textType}}
{{char-counter field.value field.max_length}} {{wizard-char-counter field.value field.max_length}}
{{/if}} {{/if}}
{{/if}} {{/if}}

Datei anzeigen

@ -716,7 +716,7 @@
property="name" property="name"
onUpdate=(action "mappedFieldUpdated") onUpdate=(action "mappedFieldUpdated")
options=(hash options=(hash
textSelection="key,value" textSelection="key,value,output"
wizardFieldSelection=true wizardFieldSelection=true
userFieldSelection="key,value" userFieldSelection="key,value"
context="action" context="action"

Datei anzeigen

@ -32,13 +32,8 @@ body.custom-wizard {
} }
} }
&.invalid { &.invalid .wizard-focusable {
textarea, outline: 4px solid var(--danger);
input[type="text"],
input[type="checkbox"],
.select-kit {
outline: 4px solid var(--danger);
}
} }
} }

Datei anzeigen

@ -44,7 +44,7 @@ class CustomWizard::Mapper
def initialize(params) def initialize(params)
@inputs = params[:inputs] || {} @inputs = params[:inputs] || {}
@data = params[:data] || {} @data = params[:data] ? params[:data].with_indifferent_access : {}
@user = params[:user] @user = params[:user]
@opts = params[:opts] || {} @opts = params[:opts] || {}
end end
@ -267,7 +267,12 @@ class CustomWizard::Mapper
return nil if data.nil? return nil if data.nil?
k = keys.shift k = keys.shift
result = data[k] 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 end
def bool(value) def bool(value)

Datei anzeigen

@ -84,6 +84,10 @@ class CustomWizard::Submission
data data
end end
def submitted?
!!submitted_at
end
def self.get(wizard) def self.get(wizard)
data = PluginStore.get("#{wizard.id}_#{KEY}", wizard.actor_id).last data = PluginStore.get("#{wizard.id}_#{KEY}", wizard.actor_id).last
new(wizard, data) new(wizard, data)

Datei anzeigen

@ -176,6 +176,7 @@ class CustomWizard::Wizard
def unfinished? def unfinished?
return nil unless actor_id return nil unless actor_id
return false if last_submission&.submitted?
most_recent = CustomWizard::UserHistory.where( most_recent = CustomWizard::UserHistory.where(
actor_id: actor_id, actor_id: actor_id,
@ -194,6 +195,7 @@ class CustomWizard::Wizard
def completed? def completed?
return nil unless actor_id return nil unless actor_id
return true if last_submission&.submitted?
history = CustomWizard::UserHistory.where( history = CustomWizard::UserHistory.where(
actor_id: actor_id, actor_id: actor_id,
@ -282,6 +284,10 @@ class CustomWizard::Wizard
@submissions ||= CustomWizard::Submission.list(self).submissions @submissions ||= CustomWizard::Submission.list(self).submissions
end end
def last_submission
@last_submission ||= submissions&.last
end
def current_submission def current_submission
@current_submission ||= begin @current_submission ||= begin
if submissions.present? if submissions.present?

Datei anzeigen

@ -58,6 +58,11 @@ describe CustomWizard::Mapper do
"step_1_field_3" => "Value" "step_1_field_3" => "Value"
} }
} }
let(:template_params_object) {
{
"step_1_field_1": get_wizard_fixture("field/upload")
}
}
def create_template_mapper(data, user) def create_template_mapper(data, user)
CustomWizard::Mapper.new( CustomWizard::Mapper.new(
@ -448,6 +453,40 @@ describe CustomWizard::Mapper do
expect(result).to eq(template) expect(result).to eq(template)
end 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 context "custom filter: 'first_non_empty'" do
it "gives first non empty element from list" do it "gives first non empty element from list" do
template = <<-LIQUID.strip template = <<-LIQUID.strip

Datei anzeigen

@ -7,6 +7,7 @@ describe CustomWizard::Wizard do
let(:template_json) { get_wizard_fixture("wizard") } let(:template_json) { get_wizard_fixture("wizard") }
let(:permitted_json) { get_wizard_fixture("wizard/permitted") } let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
let(:guests_permitted_json) { get_wizard_fixture("wizard/guests_permitted") } let(:guests_permitted_json) { get_wizard_fixture("wizard/guests_permitted") }
let(:step_json) { get_wizard_fixture("step/step") }
before do before do
Group.refresh_automatic_group!(:trust_level_3) Group.refresh_automatic_group!(:trust_level_3)
@ -75,6 +76,28 @@ describe CustomWizard::Wizard do
expect(@wizard.start).to eq('step_2') expect(@wizard.start).to eq('step_2')
end 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 it "creates a step updater" do
expect( expect(
@wizard.create_updater('step_1', step_1_field_1: "Text input") @wizard.create_updater('step_1', step_1_field_1: "Text input")