0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-09 11:52:54 +01:00
Dieser Commit ist enthalten in:
Angus McLeod 2017-10-17 15:18:53 +08:00
Ursprung 897cc0b60e
Commit 5220b069f6
18 geänderte Dateien mit 304 neuen und 261 gelöschten Zeilen

Datei anzeigen

@ -1,9 +1,26 @@
import { on, observes } from 'ember-addons/ember-computed-decorators';
import { on, observes, default as computed } from 'ember-addons/ember-computed-decorators';
const PROFILE_FIELDS = [
'name',
'email',
'username',
'title',
'date_of_birth',
'muted_usernames',
'theme_key',
'locale',
'bio_raw',
'location',
'website',
'dismissed_banner_key',
'profile_background',
'card_background'
];
export default Ember.Component.extend({
classNames: 'wizard-custom-action',
types: ['create_topic', 'update_profile', 'send_message'],
profileFields: ['name', 'username', 'email'],
profileFields: PROFILE_FIELDS,
createTopic: Ember.computed.equal('action.type', 'create_topic'),
updateProfile: Ember.computed.equal('action.type', 'update_profile'),
sendMessage: Ember.computed.equal('action.type', 'send_message'),
@ -11,6 +28,32 @@ export default Ember.Component.extend({
@on('init')
@observes('action')
setup() {
this.set('existingId', this.get('action.id'));
if (!this.get('isNew')) this.set('existingId', this.get('action.id'));
},
@computed('steps')
wizardFields(steps) {
let fields = [];
steps.forEach((s) => {
let stepFields = s.fields.map((f) => `${f.id} (${s.id})`);
fields.push(...stepFields);
});
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

@ -7,7 +7,7 @@ export default Ember.Component.extend({
@on('init')
@observes('field')
setup() {
this.set('existingId', this.get('field.id'));
if (!this.get('isNew')) this.set('existingId', this.get('field.id'));
},
@computed('field.type')

Datei anzeigen

@ -1,101 +1,6 @@
import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
classNames: 'wizard-custom-step',
currentField: null,
currentAction: null,
@on('init')
@observes('step')
setCurrent() {
this.set('existingId', this.get('step.id'));
const fields = this.get('step.fields') || [];
const actions = this.get('step.actions') || [];
this.set('currentField', fields[0]);
this.set('currentAction', actions[0]);
},
@computed('step.fields.@each.id', 'currentField')
fieldLinks(fields, current) {
if (!fields) return;
return fields.map((f) => {
if (f) {
const id = f.get('id');
const label = f.get('label');
let link = { id, label: label || id || 'new' };
let classes = 'btn';
if (current && f.get('id') === current.get('id')) {
classes += ' btn-primary';
};
link['classes'] = classes;
return link;
}
});
},
@computed('step.actions.@each.id', 'currentAction')
actionLinks(actions, current) {
if (!actions) return;
return actions.map((a) => {
if (a) {
const id = a.get('id');
const label = a.get('label');
let link = { id, label: label || id || 'new' };
let classes = 'btn';
if (current && a.get('id') === current.get('id')) {
classes += ' btn-primary';
};
link['classes'] = classes;
return link;
}
});
},
actions: {
addField() {
const fields = this.get('step.fields');
const field = Ember.Object.create();
fields.pushObject(field);
this.set('currentField', field);
},
addAction() {
const actions = this.get('step.actions');
const action = Ember.Object.create();
actions.pushObject(action);
this.set('currentAction', action);
},
removeField(fieldId) {
const fields = this.get('step.fields');
fields.removeObject(fields.findBy('id', fieldId));
this.set('currentField', fields[fields.length - 1]);
},
removeAction(actionId) {
const actions = this.get('step.actions');
actions.removeObject(actions.findBy('id', actionId));
this.set('currentAction', actions[actions.length - 1]);
},
changeField(fieldId) {
const fields = this.get('step.fields');
this.set('currentField', fields.findBy('id', fieldId));
},
changeAction(actionId) {
const actions = this.get('step.actions');
this.set('currentAction', actions.findBy('id', actionId));
}
}
disableId: Ember.computed.not('step.isNew')
});

Datei anzeigen

@ -0,0 +1,80 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
classNames: 'wizard-links',
items: Ember.A(),
didInsertElement() {
this.applySortable();
},
applySortable() {
this.$("ul").sortable({tolerance: 'pointer'}).on('sortupdate', (e, ui) => {
const itemId = ui.item.data('id');
const index = ui.item.index();
Ember.run.bind(this, this.updateItemOrder(itemId, index));
});
},
updateItemOrder(itemId, newIndex) {
const items = this.get('items');
const item = items.findBy('id', itemId);
items.removeObject(item);
items.insertAt(newIndex, item);
Ember.run.scheduleOnce('afterRender', this, () => this.applySortable());
},
@computed('type')
header: (type) => `admin.wizard.${type}.header`,
@computed('items.@each.id', 'current')
links(items, current) {
if (!items) return;
return items.map((item) => {
if (item) {
const id = item.get('id');
const label = item.get('label') || item.get('title');
let link = { id, label: label || id };
let classes = 'btn';
if (current && item.get('id') === current.get('id')) {
classes += ' btn-primary';
};
link['classes'] = classes;
return link;
}
});
},
actions: {
add() {
const items = this.get('items');
const newId = `step_${items.length + 1}`;
const type = this.get('type');
let params = { id: newId, isNew: true };
if (type === 'step') {
params['fields'] = Ember.A();
params['actions'] = Ember.A();
};
const newItem = Ember.Object.create(params);
items.pushObject(newItem);
this.set('current', newItem);
},
change(itemId) {
const items = this.get('items');
this.set('current', items.findBy('id', itemId));
},
remove(itemId) {
const items = this.get('items');
items.removeObject(items.findBy('id', itemId));
this.set('current', items[items.length - 1]);
}
}
});

Datei anzeigen

@ -1,27 +1,6 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
@computed('model.steps.@each.id', 'currentStep')
stepLinks(steps, currentStep) {
return steps.map((s) => {
if (s) {
const id = s.get('id');
const title = s.get('title');
let link = { id, title: title || id || 'new' };
let classes = 'btn';
if (currentStep && id === currentStep.get('id')) {
classes += ' btn-primary';
};
link['classes'] = classes;
return link;
}
});
},
@computed('model.id', 'model.name')
wizardUrl(wizardId) {
return window.location.origin + '/w/' + Ember.String.dasherize(wizardId);
@ -52,27 +31,6 @@ export default Ember.Controller.extend({
this.get('model').remove().then(() => {
this.send("refreshAllWizards");
});
},
addStep() {
const steps = this.get('model.steps');
const step = Ember.Object.create({
fields: Ember.A(),
actions: Ember.A()
});
steps.pushObject(step);
this.set('currentStep', step);
},
removeStep(stepId) {
const steps = this.get('model.steps');
steps.removeObject(steps.findBy('id', stepId));
this.set('currentStep', steps[steps.length - 1]);
},
changeStep(stepId) {
const steps = this.get('model.steps');
this.set('currentStep', steps.findBy('id', stepId));
}
}
});

Datei anzeigen

@ -58,17 +58,9 @@
<a href="{{wizardUrl}}" target="_blank">{{wizardUrl}}</a>
</div>
<div class="wizard-links">
<div class="wizard-header">{{i18n 'admin.wizard.step.header'}}</div>
{{#each stepLinks as |s|}}
{{d-button action="changeStep" actionParam=s.id translatedLabel=s.title class=s.classes}}
{{d-button action="removeStep" actionParam=s.id icon='times' class='remove'}}
{{/each}}
{{d-button action='addStep' label='admin.wizard.add' icon='plus'}}
</div>
{{wizard-links type="step" current=currentStep items=model.steps}}
{{#if currentStep}}
{{wizard-custom-step step=currentStep fieldTypes=model.fieldTypes}}
{{wizard-custom-step step=currentStep steps=model.steps fieldTypes=model.fieldTypes}}
{{/if}}
<div class='buttons'>

Datei anzeigen

@ -1,6 +1,6 @@
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.id"}}</h3>
<h3>{{i18n "admin.wizard.id"}}</h3>
</div>
<div class="setting-value">
{{input value=action.id placeholderKey='admin.wizard.id_placeholder' disabled=existingId}}
@ -16,7 +16,6 @@
</div>
</div>
{{#if createTopic}}
<div class="setting">
<div class="setting-label">
@ -29,19 +28,28 @@
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.create_topic.title"}}</h3>
<h3>{{i18n "admin.wizard.action.title"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.title content=stepFields nameProperty="label"}}
{{combo-box value=action.title content=wizardFields nameProperty="label" none='admin.wizard.action.none'}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.create_topic.post"}}</h3>
<h3>{{i18n "admin.wizard.action.post"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.post content=stepFields nameProperty="label"}}
{{combo-box value=action.post content=wizardFields nameProperty="label" none='admin.wizard.action.none'}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.create_topic.featured_link"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.featured_link content=wizardFields none='admin.wizard.action.none'}}
</div>
</div>
{{/if}}
@ -49,20 +57,22 @@
{{#if sendMessage}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.send_message.title"}}</h3>
<h3>{{i18n "admin.wizard.action.title"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.title content=stepFields nameProperty="label"}}
{{combo-box value=action.title content=wizardFields none='admin.wizard.action.none'}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.send_message.post"}}</h3>
<h3>{{i18n "admin.wizard.action.post"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.post content=stepFields nameProperty="label"}}
{{combo-box value=action.post content=wizardFields none='admin.wizard.action.none'}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.send_message.recipient"}}</h3>
@ -77,20 +87,14 @@
{{/if}}
{{#if updateProfile}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.source"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.source content=stepFields nameProperty="label"}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.profile_field"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.profile_field content=profileFields}}
</div>
<div class="setting full">
{{#each profileUpdates as |pu|}}
<span class='custom-input'>
{{combo-box value=pu.wizard_field content=wizardFields none='admin.wizard.action.update_profile.wizard_field'}}
{{combo-box value=pu.profile_field content=profileFields none='admin.wizard.action.update_profile.profile_field'}}
</span>
{{d-button action='removeProfileUpdate' actionParam=f icon='times'}}
{{/each}}
<div>{{d-button action='addProfileUpdate' label='admin.wizard.add' icon='plus'}}</div>
</div>
{{/if}}

Datei anzeigen

@ -3,7 +3,7 @@
<h3>{{i18n 'admin.wizard.id'}}</h3>
</div>
<div class="setting-value">
{{input name="id" value=step.id placeholderKey="admin.wizard.id_placeholder" disabled=existingId}}
{{input name="id" value=step.id placeholderKey="admin.wizard.id_placeholder" disabled=disableId}}
</div>
</div>
@ -43,28 +43,12 @@
</div>
</div>
<div class="wizard-links">
<div class="wizard-header medium">{{i18n 'admin.wizard.field.header'}}</div>
{{#each fieldLinks as |f|}}
{{d-button action="changeField" actionParam=f.id translatedLabel=f.label class=f.classes}}
{{d-button action='removeField' actionParam=f.id icon='times' class='remove'}}
{{/each}}
{{d-button action='addField' label='admin.wizard.add' icon='plus'}}
</div>
{{wizard-links type="field" current=currentField itesm=step.fields}}
{{#if currentField}}
{{wizard-custom-field field=currentField types=fieldTypes removeField="removeField"}}
{{/if}}
<div class="wizard-links">
<div class="wizard-header medium">{{i18n 'admin.wizard.action.header'}}</div>
{{#each actionLinks as |a|}}
{{d-button action="changeAction" actionParam=a.id translatedLabel=a.label class=a.classes}}
{{d-button action='removeAction' actionParam=a.id icon='times' class='remove'}}
{{/each}}
{{d-button action='addAction' label='admin.wizard.add' icon='plus'}}
</div>
{{wizard-links type="action" current=currentAction items=step.actions}}
{{#if currentAction}}
{{wizard-custom-action action=currentAction stepFields=step.fields removeAction="removeAction"}}
{{wizard-custom-action action=currentAction steps=steps removeAction="removeAction"}}
{{/if}}

Datei anzeigen

@ -0,0 +1,12 @@
<div class="wizard-links {{type}}">
<div class="wizard-header medium">{{i18n header}}</div>
<ul>
{{#each links as |l|}}
<li data-id='{{l.id}}'>
{{d-button action="change" actionParam=l.id translatedLabel=l.label class=l.classes}}
{{d-button action='remove' actionParam=l.id icon='times' class='remove'}}
</li>
{{/each}}
</ul>
{{d-button action='add' label='admin.wizard.add' icon='plus'}}
</div>

Datei anzeigen

@ -3,6 +3,16 @@
.wizard-step-description {
line-height: 1.7;
ul {
margin: 0;
padding: 0;
list-style: none;
}
i {
margin-right: 7px;
}
}
.wizard-column .wizard-step-banner {
@ -35,6 +45,31 @@
}
}
.step-message {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 0;
line-height: 0;
text-align: center;
transition: all .2s;
&.success {
height: 60px;
line-height: 60px;
background-color: #009900;
color: #ffffff;
}
&.error {
height: 60px;
line-height: 60px;
background-color: #e45735;
color: #ffffff;
}
}
.p-list-box {
max-width: 550px;
position: relative;

Datei anzeigen

@ -73,8 +73,27 @@
.wizard-links {
margin-bottom: 20px;
.remove {
ul {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
li {
display: inline-block;
margin-bottom: 7px;
margin-right: 7px;
}
}
.sortable-placeholder {
height: 30px;
width: 100px;
display: inline-block;
vertical-align: top;
background-color: $primary-low;
margin-right: 10px;
margin-left: 3px;
}
}
@ -89,31 +108,6 @@
background-color: dark-light-diff($primary, $secondary, 96%, -65%);
}
.step-message {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 0;
line-height: 0;
text-align: center;
transition: all .2s;
&.success {
height: 60px;
line-height: 60px;
background-color: $success;
color: $secondary;
}
&.error {
height: 60px;
line-height: 60px;
background-color: $danger;
color: $secondary;
}
}
.wizard-dropdown-choices {
padding: 15px 15px 0 15px;
margin-bottom: 20px;

Datei anzeigen

@ -61,21 +61,21 @@ en:
min_length_placeholder: "Minimum length in characters"
action:
header: "Actions"
send_message:
label: "Send Message"
include: "Include Fields"
title: "Title"
post: "Post"
none: "Select a field"
send_message:
label: "Send Message"
recipient: "Recipient"
create_topic:
label: "Create Topic"
title: "Title"
post: "Post"
category: "Category"
featured_link: "Featured Link"
update_profile:
label: "Update Profile"
field: "Profile Field"
save_input:
label: "Save Input"
wizard_field: "Wizard Field"
profile_field: "Profile Field"
wizard_js:
wizard:

Datei anzeigen

@ -1,10 +1,14 @@
class CustomWizard::WizardController < ::ApplicationController
def set_layout
File.expand_path('../../views/layouts/custom_wizard.html.erb', __FILE__)
prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'views'))
layout 'wizard'
helper_method :wizard_page_title
def wizard_page_title
wizard = PluginStore.get('custom_wizard', params[:wizard_id].underscore)
wizard['name'] || wizard['id']
end
def index
puts "USING PROPER CONTROLLER"
respond_to do |format|
format.json do
wizard = CustomWizard::Builder.new(current_user, params[:wizard_id].underscore).build

Datei anzeigen

@ -9,7 +9,8 @@ class CustomWizard::Builder
id: wizard_id,
save_submissions: data['save_submissions'],
multiple_submissions: data['multiple_submissions'],
background: data["background"]
background: data["background"],
name: data["name"]
)
end
@ -120,24 +121,37 @@ class CustomWizard::Builder
if s['actions'] && s['actions'].length
s['actions'].each do |a|
if a['type'] === 'create_topic'
creator = PostCreator.new(user,
title: input[a['title']],
raw: input[a['post']],
category: a['category_id'],
skip_validations: true)
title = input[a['title']]
post = input[a['post']]
if title && post
params = {
title: title,
raw: post,
skip_validations: true
}
params[:category] = a['category_id'] if a['category_id']
params[:featured_link] = input[a['featured_link']] if input[a['featured_link']]
creator = PostCreator.new(user, params)
post = creator.create
if creator.errors.present?
updater.errors.add(:create_topic, creator.errors.full_messages.join(" "))
else
updater.result = { topic_id: post.topic.id }
end
end
end
if a['type'] === 'send_message'
title = input[a['title']]
post = input[a['post']]
if title && post
creator = PostCreator.new(user,
title: input[a['title']],
raw: input[a['post']],
title: title,
raw: post,
archetype: Archetype.private_message,
target_usernames: a['username'])
@ -150,6 +164,15 @@ class CustomWizard::Builder
end
end
end
if a['type'] === 'update_profile' && a['profile_updates'].length
updater = UserUpdater.new(user, user)
attributes = a['profile_updates'].map do |pu|
{ pu['profile_field'].to_sym => input[pu['wizard_field']] }
end
updater.update(attributes)
end
end
end
if @wizard.save_submissions && updater.errors.empty?

Datei anzeigen

@ -6,13 +6,14 @@ require_dependency 'wizard/builder'
class CustomWizard::Wizard
attr_reader :steps, :user
attr_accessor :id, :background, :save_submissions, :multiple_submissions
attr_accessor :id, :name, :background, :save_submissions, :multiple_submissions
def initialize(user, attrs = {})
@steps = []
@user = user
@first_step = nil
@id = attrs[:id] if attrs[:id]
@name = attrs[:name] if attrs[:name]
@save_submissions = attrs[:save_submissions] if attrs[:save_submissions]
@multiple_submissions = attrs[:multiple_submissions] if attrs[:multiple_submissions]
@background = attrs[:background] if attrs[:background]

Datei anzeigen

@ -30,16 +30,24 @@ end
object.id
end
def include_id?
object.respond_to?(:id)
end
def background
object.background
end
def include_background?
object.respond_to?(:background)
end
def completed
object.completed?
end
def include_completed?
object.completed? && !object.multiple_submissions && !scope.current_user.admin?
object.completed? && !object.respond_to?(:multiple_submissions) && !scope.current_user.admin?
end
def include_start?

Datei anzeigen

@ -6,16 +6,16 @@
register_asset 'stylesheets/wizard_custom_admin.scss'
config = Rails.application.config
config.assets.paths << Rails.root.join("plugins", "discourse-custom-wizard", "assets", "javascripts")
config.assets.paths << Rails.root.join("plugins", "discourse-custom-wizard", "assets", "stylesheets", "wizard")
config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'javascripts')
config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'stylesheets', 'wizard')
after_initialize do
UserHistory.actions[:custom_wizard_step] = 100
require_dependency "application_controller"
require_dependency 'application_controller'
module ::CustomWizard
class Engine < ::Rails::Engine
engine_name "custom_wizard"
engine_name 'custom_wizard'
isolate_namespace CustomWizard
end
end

Datei anzeigen

@ -17,7 +17,7 @@
<meta name="discourse-base-uri" content="<%= Discourse.base_uri %>">
<%= render partial: "layouts/head" %>
<title><%= t 'wizard.custom_title' %></title>
<title><%= wizard_page_title %></title>
</head>
<body class='custom-wizard'>