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

Working version

Dieser Commit ist enthalten in:
Angus McLeod 2017-10-17 21:17:53 +08:00
Ursprung 5220b069f6
Commit dc1cbfbfe4
13 geänderte Dateien mit 172 neuen und 148 gelöschten Zeilen

Datei anzeigen

@ -1,4 +1,4 @@
import { on, observes, default as computed } from 'ember-addons/ember-computed-decorators'; import { default as computed } from 'ember-addons/ember-computed-decorators';
const PROFILE_FIELDS = [ const PROFILE_FIELDS = [
'name', 'name',
@ -24,36 +24,20 @@ export default Ember.Component.extend({
createTopic: Ember.computed.equal('action.type', 'create_topic'), createTopic: Ember.computed.equal('action.type', 'create_topic'),
updateProfile: Ember.computed.equal('action.type', 'update_profile'), updateProfile: Ember.computed.equal('action.type', 'update_profile'),
sendMessage: Ember.computed.equal('action.type', 'send_message'), sendMessage: Ember.computed.equal('action.type', 'send_message'),
disableId: Ember.computed.not('action.isNew'),
@on('init')
@observes('action')
setup() {
if (!this.get('isNew')) this.set('existingId', this.get('action.id'));
},
@computed('steps') @computed('steps')
wizardFields(steps) { wizardFields(steps) {
let fields = []; let fields = [];
steps.forEach((s) => { steps.forEach((s) => {
let stepFields = s.fields.map((f) => `${f.id} (${s.id})`); let stepFields = s.fields.map((f) => {
return Ember.Object.create({
id: f.id,
label: `${f.id} (${s.id})`
});
});
fields.push(...stepFields); fields.push(...stepFields);
}); });
return fields; return fields;
},
@computed('action.profile_updates.[]')
profileUpdates: fields => fields,
actions: {
addProfileUpdate() {
if (!this.get('action.profile_updates')) {
this.set('action.profile_updates', Ember.A());
}
this.get('action.profile_updates').pushObject(Ember.Object.create());
},
removeProfileUpdate(f) {
this.get('action.profile_updates').removeObject(f);
}
} }
}); });

Datei anzeigen

@ -1,52 +1,17 @@
import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators'; import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({ export default Ember.Component.extend({
classNames: 'wizard-custom-field', classNames: 'wizard-custom-field',
isDropdown: Ember.computed.equal('field.type', 'dropdown'), isDropdown: Ember.computed.equal('field.type', 'dropdown'),
disableId: Ember.computed.not('field.isNew'),
@on('init')
@observes('field')
setup() {
if (!this.get('isNew')) this.set('existingId', this.get('field.id'));
},
@computed('field.type') @computed('field.type')
isInput: (type) => type === 'text' || type === 'textarea', isInput: (type) => type === 'text' || type === 'textarea',
@computed('field.choices.[]')
dropdownChoices: choices => choices,
@computed('field.choices_filters.[]')
presetFilters: filters => filters,
@computed() @computed()
presetChoices() { presetChoices() {
return [ return [
{ id: 'categories', name: I18n.t('admin.wizard.field.choices_preset.categories') } { id: 'categories', name: I18n.t('admin.wizard.field.choices_preset.categories') }
]; ];
},
actions: {
addFilter() {
if (!this.get('field.choices_filters')) {
this.set('field.choices_filters', Ember.A());
}
this.get('field.choices_filters').pushObject(Ember.Object.create());
},
removeFilter(f) {
this.get('field.choices_filters').removeObject(f);
},
addChoice() {
if (!this.get('field.choices')) {
this.set('field.choices', Ember.A());
}
this.get('field.choices').pushObject(Ember.Object.create());
},
removeChoice(c) {
this.get('field.choices').removeObject(c);
}
} }
}); });

Datei anzeigen

@ -0,0 +1,17 @@
export default Ember.Component.extend({
noneKey: 'admin.wizard.none',
noneValue: 'admin.wizard.none',
actions: {
add() {
if (!this.get('inputs')) {
this.set('inputs', Ember.A());
}
this.get('inputs').pushObject(Ember.Object.create());
},
remove(input) {
this.get('inputs').removeObject(input);
}
}
});

Datei anzeigen

@ -34,8 +34,9 @@ export default Ember.Component.extend({
return items.map((item) => { return items.map((item) => {
if (item) { if (item) {
const id = item.get('id'); const id = item.get('id');
const label = item.get('label') || item.get('title'); const type = this.get('type');
let link = { id, label: label || id }; const label = type === 'action' ? id : (item.get('label') || item.get('title') || id);
let link = { id, label };
let classes = 'btn'; let classes = 'btn';
if (current && item.get('id') === current.get('id')) { if (current && item.get('id') === current.get('id')) {
@ -52,8 +53,8 @@ export default Ember.Component.extend({
actions: { actions: {
add() { add() {
const items = this.get('items'); const items = this.get('items');
const newId = `step_${items.length + 1}`;
const type = this.get('type'); const type = this.get('type');
const newId = `${type}_${items.length + 1}`;
let params = { id: newId, isNew: true }; let params = { id: newId, isNew: true };
if (type === 'step') { if (type === 'step') {
@ -64,6 +65,7 @@ export default Ember.Component.extend({
const newItem = Ember.Object.create(params); const newItem = Ember.Object.create(params);
items.pushObject(newItem); items.pushObject(newItem);
this.set('current', newItem); this.set('current', newItem);
this.sendAction('isNew');
}, },
change(itemId) { change(itemId) {

Datei anzeigen

@ -62,6 +62,8 @@ const CustomWizard = Discourse.Model.extend({
} }
} }
delete f.isNew;
step['fields'].push(f); step['fields'].push(f);
}); });
} }
@ -76,6 +78,8 @@ const CustomWizard = Discourse.Model.extend({
a.set('id', id.underscore()); a.set('id', id.underscore());
delete a.isNew;
step['actions'].push(a); step['actions'].push(a);
}); });
@ -138,7 +142,8 @@ CustomWizard.reopenClass({
s.fields.forEach((f) => { s.fields.forEach((f) => {
Object.keys(f).forEach((key) => (f[key] === '') && delete f[key]); Object.keys(f).forEach((key) => (f[key] === '') && delete f[key]);
let field = Ember.Object.create(f); const fieldParams = { isNew: false };
let field = Ember.Object.create(Object.assign(f, fieldParams));
if (f.choices) { if (f.choices) {
let choices = Ember.A(); let choices = Ember.A();
@ -157,7 +162,9 @@ CustomWizard.reopenClass({
let actions = Ember.A(); let actions = Ember.A();
if (s.actions && s.actions.length) { if (s.actions && s.actions.length) {
s.actions.forEach((a) => { s.actions.forEach((a) => {
actions.pushObject(Ember.Object.create(a)); const actionParams = { isNew: false };
const action = Ember.Object.create(Object.assign(a, actionParams));
actions.pushObject(action);
}); });
} }
@ -168,7 +175,8 @@ CustomWizard.reopenClass({
description: s.description, description: s.description,
banner: s.banner, banner: s.banner,
fields, fields,
actions actions,
isNew: false
})); }));
}); });
}; };

Datei anzeigen

@ -3,7 +3,7 @@
<h3>{{i18n "admin.wizard.id"}}</h3> <h3>{{i18n "admin.wizard.id"}}</h3>
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{input value=action.id placeholderKey='admin.wizard.id_placeholder' disabled=existingId}} {{input value=action.id placeholderKey='admin.wizard.id_placeholder' disabled=disableId}}
</div> </div>
</div> </div>
@ -44,13 +44,9 @@
</div> </div>
</div> </div>
<div class="setting"> <div class="setting full">
<div class="setting-label"> <label>{{i18n "admin.wizard.action.create_topic.add_fields"}}</label>
<h3>{{i18n "admin.wizard.action.create_topic.featured_link"}}</h3> {{wizard-custom-input inputs=action.add_fields valueContent=wizardFields noneValue='admin.wizard.action.none'}}
</div>
<div class="setting-value">
{{combo-box value=action.featured_link content=wizardFields none='admin.wizard.action.none'}}
</div>
</div> </div>
{{/if}} {{/if}}
@ -60,7 +56,7 @@
<h3>{{i18n "admin.wizard.action.title"}}</h3> <h3>{{i18n "admin.wizard.action.title"}}</h3>
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{combo-box value=action.title content=wizardFields none='admin.wizard.action.none'}} {{combo-box value=action.title content=wizardFields nameProperty='label' none='admin.wizard.action.none'}}
</div> </div>
</div> </div>
@ -69,7 +65,7 @@
<h3>{{i18n "admin.wizard.action.post"}}</h3> <h3>{{i18n "admin.wizard.action.post"}}</h3>
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{combo-box value=action.post content=wizardFields none='admin.wizard.action.none'}} {{combo-box value=action.post content=wizardFields nameProperty='label' none='admin.wizard.action.none'}}
</div> </div>
</div> </div>
@ -88,13 +84,10 @@
{{#if updateProfile}} {{#if updateProfile}}
<div class="setting full"> <div class="setting full">
{{#each profileUpdates as |pu|}} {{wizard-custom-input inputs=action.profile_updates
<span class='custom-input'> valueContent=profileFields
{{combo-box value=pu.wizard_field content=wizardFields none='admin.wizard.action.update_profile.wizard_field'}} keyContent=wizardFields
{{combo-box value=pu.profile_field content=profileFields none='admin.wizard.action.update_profile.profile_field'}} noneKey='admin.wizard.action.none'
</span> noneValue='admin.wizard.action.none'}}
{{d-button action='removeProfileUpdate' actionParam=f icon='times'}}
{{/each}}
<div>{{d-button action='addProfileUpdate' label='admin.wizard.add' icon='plus'}}</div>
</div> </div>
{{/if}} {{/if}}

Datei anzeigen

@ -3,7 +3,7 @@
<h3>{{i18n 'admin.wizard.id'}}</h3> <h3>{{i18n 'admin.wizard.id'}}</h3>
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{input name="id" value=field.id placeholderKey="admin.wizard.id_placeholder" disabled=existingId}} {{input name="id" value=field.id placeholderKey="admin.wizard.id_placeholder" disabled=disableId}}
</div> </div>
</div> </div>
@ -83,27 +83,13 @@
</div> </div>
{{combo-box value=field.choices_preset content=presetChoices none='admin.wizard.field.choices_preset.none'}} {{combo-box value=field.choices_preset content=presetChoices none='admin.wizard.field.choices_preset.none'}}
<label>{{i18n 'admin.wizard.field.choices_preset.filter'}}</label> <label>{{i18n 'admin.wizard.field.choices_preset.filter'}}</label>
{{#each presetFilters as |f|}} {{wizard-custom-input inputs=field.choices_filters}}
<span class='custom-input'>
{{input type="text" value=f.key placeholder=(i18n 'admin.wizard.field.choices_preset.key')}}
{{input type="text" value=f.value placeholder=(i18n 'admin.wizard.field.choices_preset.value')}}
</span>
{{d-button action='removeFilter' actionParam=f icon='times'}}
{{/each}}
<div>{{d-button action='addFilter' label='admin.wizard.add' icon='plus'}}</div>
</div> </div>
<div class="setting full"> <div class="setting full">
<div class="wizard-header small"> <div class="wizard-header small">
{{i18n 'admin.wizard.field.choices_custom'}} {{i18n 'admin.wizard.field.choices_custom'}}
</div> </div>
{{#each dropdownChoices as |c|}} {{wizard-custom-input inputs=field.choices}}
<span class='custom-input'>
{{input type='text' value=c.value placeholder=(i18n 'admin.wizard.field.choice.value')}}
{{input type='text' value=c.label placeholder=(i18n 'admin.wizard.field.choice.label')}}
</span>
{{d-button action='removeChoice' actionParam=c icon='times'}}
{{/each}}
<div>{{d-button action='addChoice' label='admin.wizard.add' icon='plus'}}</div>
</div> </div>
</div> </div>
{{/if}} {{/if}}

Datei anzeigen

@ -0,0 +1,16 @@
{{#each inputs as |in|}}
<span class='custom-input'>
{{#if keyContent}}
{{combo-box value=in.key content=keyContent nameProperty="label" none=noneKey}}
{{else}}
{{input type="text" value=in.key placeholder=(i18n 'admin.wizard.key')}}
{{/if}}
{{#if valueContent}}
{{combo-box value=in.value content=valueContent nameProperty="label" none=noneValue}}
{{else}}
{{input type="text" value=in.value placeholder=(i18n 'admin.wizard.value')}}
{{/if}}
</span>
{{d-button action='remove' actionParam=in icon='times'}}
{{/each}}
<div>{{d-button action='add' label='admin.wizard.add' icon='plus'}}</div>

Datei anzeigen

@ -43,7 +43,7 @@
</div> </div>
</div> </div>
{{wizard-links type="field" current=currentField itesm=step.fields}} {{wizard-links type="field" current=currentField items=step.fields}}
{{#if currentField}} {{#if currentField}}
{{wizard-custom-field field=currentField types=fieldTypes removeField="removeField"}} {{wizard-custom-field field=currentField types=fieldTypes removeField="removeField"}}
{{/if}} {{/if}}

Datei anzeigen

@ -7,7 +7,7 @@ export default StepController.extend({
const next = this.get('step.next'); const next = this.get('step.next');
if (response.refresh_required) { if (response.refresh_required) {
const id = this.get('wizard.id'); const id = this.get('wizard.id');
document.location = getUrl(`/w/${id}/steps/${next}`); window.location.href = getUrl(`/w/${id}/steps/${next}`);
} else { } else {
this.transitionToRoute('custom.step', next); this.transitionToRoute('custom.step', next);
} }
@ -19,6 +19,14 @@ export default StepController.extend({
showMessage(message) { showMessage(message) {
this.set('stepMessage', message); this.set('stepMessage', message);
},
finished(result) {
let url = "/";
if (result.topic_id) {
url += `t/${result.topic_id}`;
}
window.location.href = getUrl(url);
} }
} }
}); });

Datei anzeigen

@ -1,6 +1,5 @@
import { findCustomWizard } from '../models/custom'; import { findCustomWizard } from '../models/custom';
import { ajax } from 'wizard/lib/ajax'; import { ajax } from 'wizard/lib/ajax';
import { getUrl } from 'discourse-common/lib/get-url';
export default Ember.Route.extend({ export default Ember.Route.extend({
model(params) { model(params) {
@ -25,13 +24,5 @@ export default Ember.Route.extend({
customWizard: true, customWizard: true,
logoUrl: Wizard.SiteSettings.logo_small_url logoUrl: Wizard.SiteSettings.logo_small_url
}); });
},
actions: {
finished(result) {
let url = "/";
if (result.topic_id) url += `t/${result.topic_id}`;
document.location.replace(getUrl(url));
}
} }
}); });

Datei anzeigen

@ -20,11 +20,13 @@ en:
add: "Add" add: "Add"
url: "Url" url: "Url"
key: "Key" key: "Key"
value: "Value"
id: "Id" id: "Id"
id_placeholder: "Underscored. Cannot be changed." id_placeholder: "Underscored. Cannot be changed."
key_placeholder: "Translation key" key_placeholder: "Translation key"
custom_text_placeholder: "Overrides translation" custom_text_placeholder: "Overrides translation"
type: "Type" type: "Type"
none: "Make a selection"
error: error:
name_required: "Wizards must have a name." name_required: "Wizards must have a name."
steps_required: "Wizards must have at least one step." steps_required: "Wizards must have at least one step."
@ -47,11 +49,8 @@ en:
choices_custom: "Custom" choices_custom: "Custom"
choices_preset: choices_preset:
label: "Preset" label: "Preset"
none: "Select a data type"
categories: "Categories" categories: "Categories"
filter: "Filter" filter: "Filter"
key: "Key"
value: "Value"
choice: choice:
value: "Value" value: "Value"
label: "Label" label: "Label"
@ -71,7 +70,7 @@ en:
create_topic: create_topic:
label: "Create Topic" label: "Create Topic"
category: "Category" category: "Category"
featured_link: "Featured Link" add_fields: "Add Fields"
update_profile: update_profile:
label: "Update Profile" label: "Update Profile"
wizard_field: "Wizard Field" wizard_field: "Wizard Field"
@ -80,3 +79,33 @@ en:
wizard_js: wizard_js:
wizard: wizard:
completed: "You have completed this wizard." completed: "You have completed this wizard."
location:
name:
title: "Name (optional)"
desc: "e.g. P. Sherman Dentist"
street:
title: "Number and Street"
desc: "e.g. 42 Wallaby Way"
postalcode:
title: "Postal Code (Zip)"
desc: "e.g. 2548"
city:
title: "City, Town or Village"
desc: "e.g. Sydney"
country_code:
title: "Country"
placeholder: "Select a Country"
query:
title: "Address"
desc: "e.g. 42 Wallaby Way, Sydney."
geo:
desc: "Locations provided by {{provider}}"
btn:
label: "Find Location"
results: "Locations"
no_results: "No results. Please double check the spelling."
show_map: "Show Map"
validation:
city: "Please enter a city or town."
countrycode: "Please enter a country."
geo_location: "Search and select a result."

Datei anzeigen

@ -12,6 +12,7 @@ class CustomWizard::Builder
background: data["background"], background: data["background"],
name: data["name"] name: data["name"]
) )
@submissions = Array.wrap(PluginStore.get("custom_wizard_submissions", wizard_id))
end end
def self.sorted_handlers def self.sorted_handlers
@ -49,10 +50,9 @@ class CustomWizard::Builder
params[:description] = f['description'] if f['description'] params[:description] = f['description'] if f['description']
params[:key] = f['key'] if f['key'] params[:key] = f['key'] if f['key']
submissions = Array.wrap(PluginStore.get("custom_wizard_submissions", @wizard.id)) if @submissions.last && @submissions.last['completed'] === false
if submissions.last && submissions.last['completed'] === false submission = @submissions.last
@submission = submissions.last params[:value] = submission[f['id']] if submission[f['id']]
params[:value] = @submission[f['id']] if @submission[f['id']]
end end
field = step.add_field(params) field = step.add_field(params)
@ -94,12 +94,13 @@ class CustomWizard::Builder
step.on_update do |updater| step.on_update do |updater|
@updater = updater @updater = updater
input = updater.fields submission = @submissions.last || {}
step_input = updater.fields || {}
user = @wizard.user user = @wizard.user
if s['fields'] && s['fields'].length if s['fields'] && s['fields'].length
s['fields'].each do |f| s['fields'].each do |f|
value = input[f['id']] value = step_input[f['id']]
min_length = f['min_length'] min_length = f['min_length']
if min_length && value.is_a?(String) && value.length < min_length.to_i if min_length && value.is_a?(String) && value.length < min_length.to_i
label = f['label'] || I18n.t("#{f['key']}.label") label = f['label'] || I18n.t("#{f['key']}.label")
@ -121,17 +122,43 @@ class CustomWizard::Builder
if s['actions'] && s['actions'].length if s['actions'] && s['actions'].length
s['actions'].each do |a| s['actions'].each do |a|
if a['type'] === 'create_topic' if a['type'] === 'create_topic'
title = input[a['title']] title = submission[a['title']]
post = input[a['post']] post = submission[a['post']]
if title && post if title
params = { params = {
title: title, title: title,
raw: post, raw: post,
skip_validations: true skip_validations: true
} }
params[:category] = a['category_id'] if a['category_id'] params[:category] = a['category_id'] if a['category_id']
params[:featured_link] = input[a['featured_link']] if input[a['featured_link']]
topic_custom_fields = {}
if a['add_fields']
a['add_fields'].each do |f|
value = submission[f['value']]
key = f['key']
if key.include?('custom_fields')
keyArr = key.split('.')
if keyArr.length === 3
custom_key = keyArr.last
type = keyArr.first
if type === 'topic'
topic_custom_fields[custom_key] = value
elsif type === 'post'
params[:custom_fields] ||= {}
params[:custom_fields][custom_key.to_sym] = value
end
end
else
params[key.to_sym] = value
end
end
end
creator = PostCreator.new(user, params) creator = PostCreator.new(user, params)
post = creator.create post = creator.create
@ -139,14 +166,20 @@ class CustomWizard::Builder
if creator.errors.present? if creator.errors.present?
updater.errors.add(:create_topic, creator.errors.full_messages.join(" ")) updater.errors.add(:create_topic, creator.errors.full_messages.join(" "))
else else
if topic_custom_fields.present?
topic_custom_fields.each do |k, v|
post.topic.custom_fields[k] = v
end
post.topic.save_custom_fields(true)
end
updater.result = { topic_id: post.topic.id } updater.result = { topic_id: post.topic.id }
end end
end end
end end
if a['type'] === 'send_message' if a['type'] === 'send_message'
title = input[a['title']] title = submission[a['title']]
post = input[a['post']] post = submission[a['post']]
if title && post if title && post
creator = PostCreator.new(user, creator = PostCreator.new(user,
@ -160,50 +193,42 @@ class CustomWizard::Builder
if creator.errors.present? if creator.errors.present?
updater.errors.add(:send_message, creator.errors.full_messages.join(" ")) updater.errors.add(:send_message, creator.errors.full_messages.join(" "))
else else
updater.result = { topic_id: post.topic.id } updater.result = { topic_id: post.topic_id }
end end
end end
end end
if a['type'] === 'update_profile' && a['profile_updates'].length if a['type'] === 'update_profile' && a['profile_updates'].length
updater = UserUpdater.new(user, user) user_updater = UserUpdater.new(user, user)
attributes = a['profile_updates'].map do |pu| attributes = {}
{ pu['profile_field'].to_sym => input[pu['wizard_field']] } a['profile_updates'].each do |pu|
attributes[pu['key'].to_sym] = submission[pu['value']]
end end
updater.update(attributes) user_updater.update(attributes) if attributes.present?
end end
end end
end end
if @wizard.save_submissions && updater.errors.empty? if @wizard.save_submissions && updater.errors.empty?
store_key = @wizard.id @submissions.pop(1) if submission && submission['completed'] === false
submissions = Array.wrap(PluginStore.get("custom_wizard_submissions", store_key))
submission = {}
if submissions.last && submissions.last['completed'] === false
submission = submissions.last
submissions.pop(1)
end
submission['user_id'] = @wizard.user.id submission['user_id'] = @wizard.user.id
submission['completed'] = updater.step.next.nil? submission['completed'] = updater.step.next.nil?
if input if step_input
input.each do |key, value| step_input.each do |key, value|
submission[key] = value submission[key] = value
end end
end end
submissions.push(submission) @submissions.push(submission)
PluginStore.set('custom_wizard_submissions', store_key, submissions) PluginStore.set('custom_wizard_submissions', @wizard.id, @submissions)
end end
end end
end end
end end
end end
puts "BUILDER: #{@wizard.respond_to?(:multiple_submissions)}"
@wizard @wizard
end end
end end