Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-26 11:00:28 +01:00
Merge pull request #49 from paviliondev/add_date_time_inputs
Add date time inputs
Dieser Commit ist enthalten in:
Commit
f70170abf7
19 geänderte Dateien mit 156 neuen und 8 gelöschten Zeilen
|
@ -25,6 +25,11 @@ export default Component.extend(UndoChanges, {
|
||||||
showAdvanced: alias('field.type'),
|
showAdvanced: alias('field.type'),
|
||||||
messageUrl: 'https://thepavilion.io/t/2809',
|
messageUrl: 'https://thepavilion.io/t/2809',
|
||||||
|
|
||||||
|
@discourseComputed('field.type')
|
||||||
|
isDateTime(type) {
|
||||||
|
return ['date_time', 'date', 'time'].indexOf(type) > -1;
|
||||||
|
},
|
||||||
|
|
||||||
@discourseComputed('field.type')
|
@discourseComputed('field.type')
|
||||||
messageKey(type) {
|
messageKey(type) {
|
||||||
let key = 'type';
|
let key = 'type';
|
||||||
|
|
|
@ -110,6 +110,19 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isDateTime}}
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{{i18n 'admin.wizard.field.date_time_format.label'}}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input value=field.format class="medium"}}
|
||||||
|
<label>{{{i18n 'admin.wizard.field.date_time_format.instructions'}}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#if showPrefill}}
|
{{#if showPrefill}}
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
|
|
|
@ -89,6 +89,9 @@
|
||||||
//= require discourse/app/components/emoji-picker
|
//= require discourse/app/components/emoji-picker
|
||||||
//= require discourse/app/components/input-tip
|
//= require discourse/app/components/input-tip
|
||||||
//= require discourse/app/components/date-picker
|
//= require discourse/app/components/date-picker
|
||||||
|
//= require discourse/app/components/time-input
|
||||||
|
//= require discourse/app/components/date-input
|
||||||
|
//= require discourse/app/components/date-time-input
|
||||||
//= require discourse/app/components/text-field
|
//= require discourse/app/components/text-field
|
||||||
//= require discourse/app/components/d-textarea
|
//= require discourse/app/components/d-textarea
|
||||||
|
|
||||||
|
@ -96,6 +99,9 @@
|
||||||
//= require discourse/app/templates/components/d-button
|
//= require discourse/app/templates/components/d-button
|
||||||
//= require discourse/app/templates/components/d-editor
|
//= require discourse/app/templates/components/d-editor
|
||||||
//= require discourse/app/templates/components/date-picker
|
//= require discourse/app/templates/components/date-picker
|
||||||
|
//= require discourse/app/templates/components/date-input
|
||||||
|
//= require discourse/app/templates/components/time-input
|
||||||
|
//= require discourse/app/templates/components/date-time-input
|
||||||
//= require discourse/app/templates/components/emoji-picker
|
//= require discourse/app/templates/components/emoji-picker
|
||||||
//= require discourse/app/templates/components/popup-input-tip
|
//= require discourse/app/templates/components/popup-input-tip
|
||||||
//= require discourse/app/templates/category-tag-autocomplete
|
//= require discourse/app/templates/category-tag-autocomplete
|
||||||
|
|
15
assets/javascripts/wizard/components/wizard-field-date-time.js.es6
Normale Datei
15
assets/javascripts/wizard/components/wizard-field-date-time.js.es6
Normale Datei
|
@ -0,0 +1,15 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { observes } from 'discourse-common/utils/decorators';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
@observes('dateTime')
|
||||||
|
setValue() {
|
||||||
|
this.set('field.value', this.dateTime.format(this.field.format));
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onChange(value) {
|
||||||
|
this.set('dateTime', moment(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
15
assets/javascripts/wizard/components/wizard-field-date.js.es6
Normale Datei
15
assets/javascripts/wizard/components/wizard-field-date.js.es6
Normale Datei
|
@ -0,0 +1,15 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { observes } from 'discourse-common/utils/decorators';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
@observes('date')
|
||||||
|
setValue() {
|
||||||
|
this.set('field.value', this.date.format(this.field.format));
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onChange(value) {
|
||||||
|
this.set('date', moment(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
20
assets/javascripts/wizard/components/wizard-field-time.js.es6
Normale Datei
20
assets/javascripts/wizard/components/wizard-field-time.js.es6
Normale Datei
|
@ -0,0 +1,20 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { observes } from 'discourse-common/utils/decorators';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
@observes('time')
|
||||||
|
setValue() {
|
||||||
|
this.set('field.value', this.time.format(this.field.format));
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onChange(value) {
|
||||||
|
this.set('time',
|
||||||
|
moment({
|
||||||
|
hours: value.hours,
|
||||||
|
minutes: value.minutes
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -241,7 +241,10 @@ export default {
|
||||||
'text_only',
|
'text_only',
|
||||||
'composer',
|
'composer',
|
||||||
'category',
|
'category',
|
||||||
'group'
|
'group',
|
||||||
|
'date',
|
||||||
|
'time',
|
||||||
|
'date_time'
|
||||||
];
|
];
|
||||||
|
|
||||||
FieldModel.reopen({
|
FieldModel.reopen({
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
{{date-time-input
|
||||||
|
date=dateTime
|
||||||
|
onChange=(action "onChange")
|
||||||
|
}}
|
|
@ -1,4 +1,4 @@
|
||||||
{{date-picker
|
{{date-input
|
||||||
value=field.value
|
date=date
|
||||||
id=field.id
|
onChange=(action "onChange")
|
||||||
}}
|
}}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{{time-input
|
||||||
|
date=time
|
||||||
|
onChange=(action "onChange")
|
||||||
|
}}
|
|
@ -300,6 +300,27 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.date-picker {
|
||||||
|
font-size: 1.1487em;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px solid $primary;
|
||||||
|
transition: border-color 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pika-single.is-bound {
|
||||||
|
width: fit-content;
|
||||||
|
position: absolute !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-time-input .select-kit.combo-box .select-kit-header {
|
||||||
|
font-size: 1.1487em;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-date-time-input {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.step-message {
|
.step-message {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: all .2s;
|
transition: all .2s;
|
||||||
|
|
|
@ -150,6 +150,9 @@ en:
|
||||||
property: "Property"
|
property: "Property"
|
||||||
prefill: "Prefill"
|
prefill: "Prefill"
|
||||||
content: "Content"
|
content: "Content"
|
||||||
|
date_time_format:
|
||||||
|
label: "Format"
|
||||||
|
instructions: "<a href='https://momentjs.com/docs/#/displaying/format/' target='_blank'>Moment.js format</a>"
|
||||||
|
|
||||||
type:
|
type:
|
||||||
text: "Text"
|
text: "Text"
|
||||||
|
@ -166,6 +169,8 @@ en:
|
||||||
group: Group
|
group: Group
|
||||||
user_selector: User Selector
|
user_selector: User Selector
|
||||||
date: Date
|
date: Date
|
||||||
|
time: Time
|
||||||
|
date_time: Date & Time
|
||||||
|
|
||||||
connector:
|
connector:
|
||||||
and: "and"
|
and: "and"
|
||||||
|
|
|
@ -11,6 +11,8 @@ en:
|
||||||
required: "%{label} is required."
|
required: "%{label} is required."
|
||||||
not_url: "%{label} must be a valid url"
|
not_url: "%{label} must be a valid url"
|
||||||
invalid_file: "%{label} must be a %{types}"
|
invalid_file: "%{label} must be a %{types}"
|
||||||
|
invalid_date: "Invalid date"
|
||||||
|
invalid_time: "Invalid time"
|
||||||
|
|
||||||
none: "We couldn't find a wizard at that address."
|
none: "We couldn't find a wizard at that address."
|
||||||
no_skip: "Wizard can't be skipped"
|
no_skip: "Wizard can't be skipped"
|
||||||
|
|
|
@ -101,6 +101,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
:type,
|
:type,
|
||||||
:min_length,
|
:min_length,
|
||||||
:file_types,
|
:file_types,
|
||||||
|
:format,
|
||||||
:limit,
|
:limit,
|
||||||
:property,
|
:property,
|
||||||
prefill: mapped_params,
|
prefill: mapped_params,
|
||||||
|
|
|
@ -5,6 +5,7 @@ module CustomWizardFieldExtension
|
||||||
:key,
|
:key,
|
||||||
:min_length,
|
:min_length,
|
||||||
:file_types,
|
:file_types,
|
||||||
|
:format,
|
||||||
:limit,
|
:limit,
|
||||||
:property,
|
:property,
|
||||||
:content
|
:content
|
||||||
|
@ -17,6 +18,7 @@ module CustomWizardFieldExtension
|
||||||
@key = attrs[:key]
|
@key = attrs[:key]
|
||||||
@min_length = attrs[:min_length]
|
@min_length = attrs[:min_length]
|
||||||
@file_types = attrs[:file_types]
|
@file_types = attrs[:file_types]
|
||||||
|
@format = attrs[:format]
|
||||||
@limit = attrs[:limit]
|
@limit = attrs[:limit]
|
||||||
@property = attrs[:property]
|
@property = attrs[:property]
|
||||||
@content = attrs[:content]
|
@content = attrs[:content]
|
||||||
|
|
|
@ -232,6 +232,10 @@ class CustomWizard::Builder
|
||||||
params[:file_types] = field_template['file_types']
|
params[:file_types] = field_template['file_types']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if ['date', 'time', 'date_time'].include?(field_template['type'])
|
||||||
|
params[:format] = field_template['format']
|
||||||
|
end
|
||||||
|
|
||||||
if field_template['type'] === 'category' || field_template['type'] === 'tag'
|
if field_template['type'] === 'category' || field_template['type'] === 'tag'
|
||||||
params[:limit] = field_template['limit']
|
params[:limit] = field_template['limit']
|
||||||
end
|
end
|
||||||
|
@ -306,6 +310,7 @@ class CustomWizard::Builder
|
||||||
id = field['id'].to_s
|
id = field['id'].to_s
|
||||||
min_length = field['min_length'] if is_text_type(field)
|
min_length = field['min_length'] if is_text_type(field)
|
||||||
file_types = field['file_types']
|
file_types = field['file_types']
|
||||||
|
format = field['format']
|
||||||
|
|
||||||
if required && !value
|
if required && !value
|
||||||
updater.errors.add(id, I18n.t('wizard.field.required', label: label))
|
updater.errors.add(id, I18n.t('wizard.field.required', label: label))
|
||||||
|
@ -327,10 +332,14 @@ class CustomWizard::Builder
|
||||||
updater.errors.add(id, I18n.t('wizard.field.invalid_file', label: label, types: file_types))
|
updater.errors.add(id, I18n.t('wizard.field.invalid_file', label: label, types: file_types))
|
||||||
end
|
end
|
||||||
|
|
||||||
if type === 'date' && value.present? && !validate_date(value)
|
if ['date', 'date_time'].include?(type) && value.present? && !validate_date(value)
|
||||||
updater.errors.add(id, I18n.t('wizard.field.invalid_date'))
|
updater.errors.add(id, I18n.t('wizard.field.invalid_date'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if type === 'time' && value.present? && !validate_time(value)
|
||||||
|
updater.errors.add(id, I18n.t('wizard.field.invalid_time'))
|
||||||
|
end
|
||||||
|
|
||||||
CustomWizard::Builder.field_validators.each do |validator|
|
CustomWizard::Builder.field_validators.each do |validator|
|
||||||
if type === validator[:type]
|
if type === validator[:type]
|
||||||
validator[:block].call(field, updater, step_template)
|
validator[:block].call(field, updater, step_template)
|
||||||
|
@ -353,6 +362,15 @@ class CustomWizard::Builder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_time(value)
|
||||||
|
begin
|
||||||
|
Time.parse(value)
|
||||||
|
true
|
||||||
|
rescue ArgumentError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def is_text_type(field)
|
def is_text_type(field)
|
||||||
['text', 'textarea'].include? field['type']
|
['text', 'textarea'].include? field['type']
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,15 @@ class CustomWizard::Field
|
||||||
min_length: nil
|
min_length: nil
|
||||||
},
|
},
|
||||||
text_only: {},
|
text_only: {},
|
||||||
date: {},
|
date: {
|
||||||
|
format: "YYYY-MM-DD"
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
format: "HH:mm"
|
||||||
|
},
|
||||||
|
date_time: {
|
||||||
|
format: ""
|
||||||
|
},
|
||||||
number: {},
|
number: {},
|
||||||
checkbox: {},
|
checkbox: {},
|
||||||
url: {
|
url: {
|
||||||
|
|
|
@ -249,6 +249,7 @@ class CustomWizard::Mapper
|
||||||
end
|
end
|
||||||
|
|
||||||
def recurse(data, keys)
|
def recurse(data, keys)
|
||||||
|
return nil if data.nil?
|
||||||
k = keys.shift
|
k = keys.shift
|
||||||
result = data[k]
|
result = data[k]
|
||||||
keys.empty? ? result : self.recurse(result, keys)
|
keys.empty? ? result : self.recurse(result, keys)
|
||||||
|
|
|
@ -4,6 +4,7 @@ class CustomWizard::FieldSerializer < ::WizardFieldSerializer
|
||||||
|
|
||||||
attributes :image,
|
attributes :image,
|
||||||
:file_types,
|
:file_types,
|
||||||
|
:format,
|
||||||
:limit,
|
:limit,
|
||||||
:property,
|
:property,
|
||||||
:content
|
:content
|
||||||
|
@ -34,6 +35,10 @@ class CustomWizard::FieldSerializer < ::WizardFieldSerializer
|
||||||
object.file_types
|
object.file_types
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def format
|
||||||
|
object.format
|
||||||
|
end
|
||||||
|
|
||||||
def limit
|
def limit
|
||||||
object.limit
|
object.limit
|
||||||
end
|
end
|
||||||
|
|
Laden …
In neuem Issue referenzieren