2020-03-21 18:30:11 +01:00
|
|
|
import { default as computed } from 'discourse-common/utils/decorators';
|
2020-04-05 03:37:09 +02:00
|
|
|
import { dasherize } from "@ember/string";
|
2019-09-11 10:30:38 +02:00
|
|
|
|
2017-09-25 16:47:40 +02:00
|
|
|
export default {
|
|
|
|
name: 'custom-routes',
|
|
|
|
|
2019-07-26 10:59:21 +02:00
|
|
|
initialize(app) {
|
2017-11-02 02:41:26 +01:00
|
|
|
if (window.location.pathname.indexOf('/w/') < 0) return;
|
2020-03-31 05:14:49 +02:00
|
|
|
|
|
|
|
const EmberObject = requirejs('@ember/object').default;
|
2017-09-29 13:27:03 +02:00
|
|
|
const Router = requirejs('wizard/router').default;
|
2017-10-13 15:02:34 +02:00
|
|
|
const ApplicationRoute = requirejs('wizard/routes/application').default;
|
2017-09-29 13:27:03 +02:00
|
|
|
const ajax = requirejs('wizard/lib/ajax').ajax;
|
|
|
|
const StepModel = requirejs('wizard/models/step').default;
|
2018-05-09 07:06:43 +02:00
|
|
|
const CustomWizard = requirejs('discourse/plugins/discourse-custom-wizard/wizard/models/custom').default;
|
2017-10-05 02:36:46 +02:00
|
|
|
const WizardStep = requirejs('wizard/components/wizard-step').default;
|
2018-01-30 14:19:32 +01:00
|
|
|
const WizardField = requirejs('wizard/components/wizard-field').default;
|
2017-10-05 02:36:46 +02:00
|
|
|
const getUrl = requirejs('discourse-common/lib/get-url').default;
|
2017-10-09 07:52:09 +02:00
|
|
|
const FieldModel = requirejs('wizard/models/wizard-field').default;
|
2017-11-23 10:03:19 +01:00
|
|
|
const autocomplete = requirejs('discourse/lib/autocomplete').default;
|
2018-03-05 02:52:15 +01:00
|
|
|
const cook = requirejs('discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite').cook;
|
2019-07-26 10:59:21 +02:00
|
|
|
const Singleton = requirejs("discourse/mixins/singleton").default;
|
2019-09-11 10:30:38 +02:00
|
|
|
const WizardFieldDropdown = requirejs('wizard/components/wizard-field-dropdown').default;
|
2019-11-14 08:28:26 +01:00
|
|
|
const Store = requirejs("discourse/models/store").default;
|
2019-11-20 13:08:04 +01:00
|
|
|
const registerRawHelpers = requirejs("discourse-common/lib/raw-handlebars-helpers").registerRawHelpers;
|
|
|
|
const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars").default;
|
2020-03-31 05:14:49 +02:00
|
|
|
const Site = requirejs("discourse/models/site").default;
|
|
|
|
const RestAdapter = requirejs("discourse/adapters/rest").default;
|
2019-11-14 08:28:26 +01:00
|
|
|
|
2020-03-31 05:14:49 +02:00
|
|
|
Discourse.Model = EmberObject.extend();
|
2019-11-14 08:28:26 +01:00
|
|
|
Discourse.__container__ = app.__container__;
|
|
|
|
Discourse.getURLWithCDN = getUrl;
|
|
|
|
Discourse.getURL = getUrl;
|
2019-11-20 13:08:04 +01:00
|
|
|
|
|
|
|
registerRawHelpers(RawHandlebars, Handlebars);
|
2019-09-11 10:30:38 +02:00
|
|
|
|
2018-11-19 22:10:33 +01:00
|
|
|
// IE11 Polyfill - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Polyfill
|
|
|
|
if (!Object.entries)
|
|
|
|
Object.entries = function( obj ){
|
|
|
|
var ownProps = Object.keys( obj ),
|
|
|
|
i = ownProps.length,
|
|
|
|
resArray = new Array(i); // preallocate the Array
|
|
|
|
while (i--)
|
|
|
|
resArray[i] = [ownProps[i], obj[ownProps[i]]];
|
|
|
|
|
|
|
|
return resArray;
|
|
|
|
};
|
|
|
|
|
2017-11-23 10:03:19 +01:00
|
|
|
$.fn.autocomplete = autocomplete;
|
|
|
|
|
2019-07-26 10:59:21 +02:00
|
|
|
const targets = ["controller", "component", "route", "model", "adapter"];
|
|
|
|
|
|
|
|
const siteSettings = Wizard.SiteSettings;
|
|
|
|
app.register("site-settings:main", siteSettings, { instantiate: false });
|
|
|
|
targets.forEach(t => app.inject(t, "siteSettings", "site-settings:main"));
|
2019-11-14 08:28:26 +01:00
|
|
|
|
|
|
|
app.register("service:store", Store);
|
|
|
|
targets.forEach(t => app.inject(t, "store", "service:store"));
|
2019-11-20 13:08:04 +01:00
|
|
|
targets.forEach(t => app.inject(t, "appEvents", "service:app-events"));
|
|
|
|
|
2020-03-31 05:14:49 +02:00
|
|
|
app.register("adapter:rest", RestAdapter);
|
2019-11-14 08:28:26 +01:00
|
|
|
|
2020-03-31 05:14:49 +02:00
|
|
|
const site = Site.current();
|
|
|
|
app.register("site:main", site, { instantiate: false });
|
|
|
|
targets.forEach(t => app.inject(t, "site", "site:main"));
|
|
|
|
|
|
|
|
site.set('can_create_tag', false);
|
|
|
|
|
2017-10-13 15:02:34 +02:00
|
|
|
Router.reopen({
|
|
|
|
rootURL: getUrl('/w/')
|
|
|
|
});
|
|
|
|
|
2017-09-25 16:47:40 +02:00
|
|
|
Router.map(function() {
|
2017-10-13 15:02:34 +02:00
|
|
|
this.route('custom', { path: '/:wizard_id' }, function() {
|
2017-10-22 05:37:58 +02:00
|
|
|
this.route('steps');
|
2017-09-25 16:47:40 +02:00
|
|
|
this.route('step', { path: '/steps/:step_id' });
|
|
|
|
});
|
|
|
|
});
|
2017-09-29 13:27:03 +02:00
|
|
|
|
2017-10-13 15:02:34 +02:00
|
|
|
ApplicationRoute.reopen({
|
|
|
|
redirect() {
|
|
|
|
this.transitionTo('custom');
|
2017-10-15 05:58:22 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
model() {}
|
2017-09-29 13:27:03 +02:00
|
|
|
});
|
2017-10-05 02:36:46 +02:00
|
|
|
|
|
|
|
WizardStep.reopen({
|
2017-11-15 08:36:44 +01:00
|
|
|
classNameBindings: ['step.id'],
|
|
|
|
|
2018-02-04 10:23:28 +01:00
|
|
|
animateInvalidFields() {
|
|
|
|
Ember.run.scheduleOnce('afterRender', () => {
|
2019-07-31 09:42:50 +02:00
|
|
|
$('.invalid input[type=text], .invalid textarea, .invalid input[type=checkbox], .invalid .select-kit').wiggle(2, 100);
|
2018-02-04 10:23:28 +01:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2018-02-01 06:11:23 +01:00
|
|
|
ensureStartsAtTop: function() {
|
|
|
|
window.scrollTo(0,0);
|
|
|
|
}.observes('step.id'),
|
|
|
|
|
2017-11-01 05:21:14 +01:00
|
|
|
showQuitButton: function() {
|
|
|
|
const index = this.get('step.index');
|
|
|
|
const required = this.get('wizard.required');
|
|
|
|
return index === 0 && !required;
|
|
|
|
}.property('step.index', 'wizard.required'),
|
|
|
|
|
2019-06-19 06:32:03 +02:00
|
|
|
cookedTitle: function() {
|
|
|
|
return cook(this.get('step.title'));
|
|
|
|
}.property('step.title'),
|
|
|
|
|
2018-03-05 02:52:15 +01:00
|
|
|
cookedDescription: function() {
|
|
|
|
return cook(this.get('step.description'));
|
|
|
|
}.property('step.description'),
|
|
|
|
|
2017-10-06 04:59:02 +02:00
|
|
|
bannerImage: function() {
|
|
|
|
const src = this.get('step.banner');
|
|
|
|
if (!src) return;
|
2018-05-24 07:34:58 +02:00
|
|
|
return getUrl(src);
|
2017-10-06 04:59:02 +02:00
|
|
|
}.property('step.banner'),
|
|
|
|
|
2017-10-13 15:02:34 +02:00
|
|
|
handleMessage: function() {
|
|
|
|
const message = this.get('step.message');
|
|
|
|
this.sendAction('showMessage', message);
|
|
|
|
}.observes('step.message'),
|
|
|
|
|
2017-10-05 02:36:46 +02:00
|
|
|
advance() {
|
|
|
|
this.set('saving', true);
|
|
|
|
this.get('step').save()
|
|
|
|
.then(response => {
|
|
|
|
if (this.get('finalStep')) {
|
2018-05-09 07:06:43 +02:00
|
|
|
CustomWizard.finished(response);
|
2017-10-05 02:36:46 +02:00
|
|
|
} else {
|
|
|
|
this.sendAction('goNext', response);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(() => this.animateInvalidFields())
|
|
|
|
.finally(() => this.set('saving', false));
|
|
|
|
},
|
2019-11-20 13:08:04 +01:00
|
|
|
|
|
|
|
keyPress(key) {
|
|
|
|
},
|
2017-10-05 02:36:46 +02:00
|
|
|
|
|
|
|
actions: {
|
|
|
|
quit() {
|
2017-11-03 14:24:09 +01:00
|
|
|
this.get('wizard').skip();
|
|
|
|
},
|
|
|
|
|
|
|
|
done() {
|
|
|
|
this.set('finalStep', true);
|
|
|
|
this.send('nextStep');
|
2017-10-13 15:02:34 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
showMessage(message) {
|
|
|
|
this.sendAction('showMessage', message);
|
2017-10-05 02:36:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2017-10-09 07:52:09 +02:00
|
|
|
|
2017-10-13 15:02:34 +02:00
|
|
|
StepModel.reopen({
|
|
|
|
save() {
|
|
|
|
const wizardId = this.get('wizardId');
|
|
|
|
const fields = {};
|
2018-05-24 07:34:58 +02:00
|
|
|
|
|
|
|
this.get('fields').forEach(f => {
|
|
|
|
if (f.type !== 'text-only') {
|
|
|
|
fields[f.id] = f.value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-10-13 15:02:34 +02:00
|
|
|
return ajax({
|
|
|
|
url: `/w/${wizardId}/steps/${this.get('id')}`,
|
|
|
|
type: 'PUT',
|
|
|
|
data: { fields }
|
|
|
|
}).catch(response => {
|
|
|
|
if (response && response.responseJSON && response.responseJSON.errors) {
|
|
|
|
let wizardErrors = [];
|
|
|
|
response.responseJSON.errors.forEach(err => {
|
|
|
|
if (err.field === wizardId) {
|
|
|
|
wizardErrors.push(err.description);
|
|
|
|
} else if (err.field) {
|
|
|
|
this.fieldError(err.field, err.description);
|
|
|
|
} else if (err) {
|
|
|
|
wizardErrors.push(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (wizardErrors.length) {
|
|
|
|
this.handleWizardError(wizardErrors.join('\n'));
|
|
|
|
}
|
|
|
|
throw response;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (response && response.responseText) {
|
|
|
|
const responseText = response.responseText;
|
|
|
|
const start = responseText.indexOf('>') + 1;
|
|
|
|
const end = responseText.indexOf('plugins');
|
|
|
|
const message = responseText.substring(start, end);
|
|
|
|
this.handleWizardError(message);
|
|
|
|
throw message;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
handleWizardError(message) {
|
|
|
|
this.set('message', {
|
|
|
|
state: 'error',
|
|
|
|
text: message
|
|
|
|
});
|
|
|
|
Ember.run.later(() => this.set('message', null), 6000);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-01-30 14:19:32 +01:00
|
|
|
WizardField.reopen({
|
2018-02-10 08:04:31 +01:00
|
|
|
classNameBindings: ['field.id'],
|
|
|
|
|
2018-03-05 02:52:15 +01:00
|
|
|
cookedDescription: function() {
|
|
|
|
return cook(this.get('field.description'));
|
|
|
|
}.property('field.description'),
|
|
|
|
|
2018-01-30 14:19:32 +01:00
|
|
|
inputComponentName: function() {
|
|
|
|
const type = this.get('field.type');
|
|
|
|
const id = this.get('field.id');
|
2020-03-23 19:40:11 +01:00
|
|
|
if (['text-only'].includes(type)) return false;
|
2020-04-05 03:37:09 +02:00
|
|
|
return (type === 'component') ? dasherize(id) : `wizard-field-${type}`;
|
2018-01-30 14:19:32 +01:00
|
|
|
}.property('field.type', 'field.id')
|
|
|
|
});
|
|
|
|
|
2019-07-31 08:57:25 +02:00
|
|
|
const StandardFieldValidation = [
|
|
|
|
'text',
|
2020-03-23 19:40:11 +01:00
|
|
|
'number',
|
2019-07-31 08:57:25 +02:00
|
|
|
'textarea',
|
|
|
|
'dropdown',
|
|
|
|
'tag',
|
|
|
|
'image',
|
|
|
|
'user-selector',
|
|
|
|
'text-only',
|
2020-03-21 18:30:11 +01:00
|
|
|
'composer',
|
2020-03-24 11:45:28 +01:00
|
|
|
'category',
|
2020-03-21 18:30:11 +01:00
|
|
|
'group'
|
2019-07-31 08:57:25 +02:00
|
|
|
];
|
2018-02-04 07:34:32 +01:00
|
|
|
|
2017-10-09 07:52:09 +02:00
|
|
|
FieldModel.reopen({
|
2018-02-04 07:34:32 +01:00
|
|
|
hasCustomCheck: false,
|
|
|
|
|
|
|
|
customCheck() {
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
2017-10-09 07:52:09 +02:00
|
|
|
check() {
|
|
|
|
let valid = this.get('valid');
|
|
|
|
|
|
|
|
if (!this.get('required')) {
|
|
|
|
this.setValid(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-04 07:34:32 +01:00
|
|
|
const hasCustomCheck = this.get('hasCustomCheck');
|
|
|
|
if (hasCustomCheck) {
|
|
|
|
valid = this.customCheck();
|
|
|
|
} else {
|
2017-10-09 07:52:09 +02:00
|
|
|
const val = this.get('value');
|
2018-02-04 07:34:32 +01:00
|
|
|
const type = this.get('type');
|
2020-03-31 06:53:00 +02:00
|
|
|
|
2018-02-04 07:34:32 +01:00
|
|
|
if (type === 'checkbox') {
|
|
|
|
valid = val;
|
2019-09-11 13:58:57 +02:00
|
|
|
} else if (type === 'upload') {
|
|
|
|
valid = val && val.id > 0;
|
2018-05-16 09:19:03 +02:00
|
|
|
} else if (StandardFieldValidation.indexOf(type) > -1) {
|
2020-03-24 11:45:28 +01:00
|
|
|
valid = val && val.toString().length > 0;
|
2020-03-23 19:40:11 +01:00
|
|
|
} else if (type === 'url') {
|
2020-03-31 06:53:00 +02:00
|
|
|
valid = true;
|
2018-02-04 07:34:32 +01:00
|
|
|
}
|
2017-10-09 07:52:09 +02:00
|
|
|
}
|
|
|
|
|
2019-07-31 09:42:50 +02:00
|
|
|
|
2018-02-04 07:34:32 +01:00
|
|
|
this.setValid(valid);
|
|
|
|
|
2017-10-09 07:52:09 +02:00
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
});
|
2017-09-25 16:47:40 +02:00
|
|
|
}
|
|
|
|
};
|