Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-09 20:02:54 +01:00
Schema handling updates
- support custom field types - move client schema to seperate helper - handle schema defaults properly
Dieser Commit ist enthalten in:
Ursprung
707f187455
Commit
d26744cf56
10 geänderte Dateien mit 295 neuen und 285 gelöschten Zeilen
|
@ -1,11 +1,12 @@
|
|||
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
|
||||
import { equal, empty, or } from "@ember/object/computed";
|
||||
import { generateName, selectKitContent, schema } from '../lib/wizard';
|
||||
import { generateName, selectKitContent } from '../lib/wizard';
|
||||
import wizardSchema from '../lib/wizard-schema';
|
||||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: 'wizard-custom-action',
|
||||
actionTypes: Object.keys(schema.action.types).map(t => ({ id: t, name: generateName(t) })),
|
||||
actionTypes: Object.keys(wizardSchema.action.types).map(t => ({ id: t, name: generateName(t) })),
|
||||
createTopic: equal('action.type', 'create_topic'),
|
||||
updateProfile: equal('action.type', 'update_profile'),
|
||||
sendMessage: equal('action.type', 'send_message'),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { default as discourseComputed, observes } from 'discourse-common/utils/decorators';
|
||||
import { equal, or } from "@ember/object/computed";
|
||||
import { selectKitContent, schema } from '../lib/wizard';
|
||||
import { selectKitContent } from '../lib/wizard';
|
||||
import { default as wizardSchema, setSchemaDefaults } from '../lib/wizard-schema';
|
||||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
|
@ -19,18 +20,15 @@ export default Component.extend({
|
|||
showMinLength: or('isText', 'isTextarea', 'isUrl', 'isComposer'),
|
||||
categoryPropertyTypes: selectKitContent(['id', 'slug']),
|
||||
|
||||
// clearMapped only clears mapped fields if the field type of a specific field
|
||||
// setTypeDefaults only set defaults if the field type of a specific field
|
||||
// changes, and not when switching between fields. Switching between fields also
|
||||
// changes the field.type property in this component
|
||||
|
||||
@observes('field.id', 'field.type')
|
||||
clearMapped(ctx, changed) {
|
||||
setTypeDefaults(ctx, changed) {
|
||||
if (this.field.id === this.bufferedFieldId) {
|
||||
schema.field.mapped.forEach(property => {
|
||||
this.set(`field.${property}`, null);
|
||||
});
|
||||
setSchemaDefaults(this.field, 'field');
|
||||
}
|
||||
|
||||
if (changed === 'field.type') {
|
||||
this.set('bufferedFieldId', this.field.id);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { default as discourseComputed, on, observes } from 'discourse-common/utils/decorators';
|
||||
import { generateName, schema } from '../lib/wizard';
|
||||
import { generateName } from '../lib/wizard';
|
||||
import { default as wizardSchema, setSchemaDefaults } from '../lib/wizard-schema';
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import { scheduleOnce, bind } from "@ember/runloop";
|
||||
import EmberObject from "@ember/object";
|
||||
|
@ -64,15 +65,6 @@ export default Component.extend({
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
setDefaults(object, params) {
|
||||
Object.keys(object).forEach(property => {
|
||||
if (object[property]) {
|
||||
params[property] = object[property];
|
||||
}
|
||||
});
|
||||
return params;
|
||||
},
|
||||
|
||||
actions: {
|
||||
add() {
|
||||
|
@ -89,19 +81,14 @@ export default Component.extend({
|
|||
isNew: true
|
||||
};
|
||||
|
||||
let objectArrays = schema[itemType].objectArrays;
|
||||
let objectArrays = wizardSchema[itemType].objectArrays;
|
||||
if (objectArrays) {
|
||||
Object.keys(objectArrays).forEach(objectType => {
|
||||
params[objectArrays[objectType].property] = A();
|
||||
});
|
||||
};
|
||||
|
||||
params = this.setDefaults(schema[itemType].basic, params);
|
||||
|
||||
let types = schema[itemType].types;
|
||||
if (types && params.type) {
|
||||
params = this.setDefaults(types[params.type], params);
|
||||
}
|
||||
setSchemaDefaults(params, itemType);
|
||||
|
||||
const newItem = EmberObject.create(params);
|
||||
items.pushObject(newItem);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { schema, listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||
import { listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||
import wizardSchema from '../lib/wizard-schema';
|
||||
import EmberObject from '@ember/object';
|
||||
import { A } from "@ember/array";
|
||||
|
||||
|
@ -15,7 +16,7 @@ function present(val) {
|
|||
}
|
||||
|
||||
function mapped(property, type) {
|
||||
return schema[type].mapped.indexOf(property) > -1;
|
||||
return wizardSchema[type].mapped.indexOf(property) > -1;
|
||||
}
|
||||
|
||||
function castCase(property, value) {
|
||||
|
@ -114,7 +115,7 @@ function buildBasicProperties(json, type, props) {
|
|||
|
||||
function hasAdvancedProperties(object, type) {
|
||||
return Object.keys(object).some(p => {
|
||||
return schema[type].advanced.indexOf(p) > -1 && present(object[p]);
|
||||
return wizardSchema[type].advanced.indexOf(p) > -1 && present(object[p]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -164,7 +165,7 @@ function buildProperties(json) {
|
|||
props.actions = buildObjectArray(json.actions, 'action');
|
||||
} else {
|
||||
listProperties('wizard').forEach(prop => {
|
||||
props[prop] = schema.wizard.basic[prop];
|
||||
props[prop] = wizardSchema.wizard.basic[prop];
|
||||
});
|
||||
}
|
||||
|
||||
|
|
218
assets/javascripts/discourse/lib/wizard-schema.js.es6
Normale Datei
218
assets/javascripts/discourse/lib/wizard-schema.js.es6
Normale Datei
|
@ -0,0 +1,218 @@
|
|||
import { set } from "@ember/object";
|
||||
|
||||
const wizard = {
|
||||
basic: {
|
||||
id: null,
|
||||
name: null,
|
||||
background: null,
|
||||
save_submissions: true,
|
||||
multiple_submissions: null,
|
||||
after_signup: null,
|
||||
after_time: null,
|
||||
after_time_scheduled: null,
|
||||
required: null,
|
||||
prompt_completion: null,
|
||||
restart_on_revisit: null,
|
||||
theme_id: null,
|
||||
permitted: null
|
||||
},
|
||||
mapped: [
|
||||
'permitted'
|
||||
],
|
||||
advanced: [
|
||||
'restart_on_revisit',
|
||||
],
|
||||
required: [
|
||||
'id',
|
||||
],
|
||||
dependent: {
|
||||
after_time: 'after_time_scheduled'
|
||||
},
|
||||
objectArrays: {
|
||||
step: {
|
||||
property: 'steps',
|
||||
required: false
|
||||
},
|
||||
action: {
|
||||
property: 'actions',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const step = {
|
||||
basic: {
|
||||
id: null,
|
||||
title: null,
|
||||
key: null,
|
||||
banner: null,
|
||||
raw_description: null,
|
||||
required_data: null,
|
||||
required_data_message: null,
|
||||
permitted_params: null
|
||||
},
|
||||
mapped: [
|
||||
'required_data',
|
||||
'permitted_params'
|
||||
],
|
||||
advanced: [
|
||||
'required_data',
|
||||
'permitted_params'
|
||||
],
|
||||
required: [
|
||||
'id'
|
||||
],
|
||||
dependent: {
|
||||
},
|
||||
objectArrays: {
|
||||
field: {
|
||||
property: 'fields',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const field = {
|
||||
basic: {
|
||||
id: null,
|
||||
label: null,
|
||||
image: null,
|
||||
description: null,
|
||||
required: null,
|
||||
key: null,
|
||||
type: null
|
||||
},
|
||||
types: {},
|
||||
mapped: [
|
||||
'prefill',
|
||||
'content'
|
||||
],
|
||||
advanced: [
|
||||
'property',
|
||||
'key'
|
||||
],
|
||||
required: [
|
||||
'id',
|
||||
'type'
|
||||
],
|
||||
dependent: {
|
||||
},
|
||||
objectArrays: {
|
||||
}
|
||||
}
|
||||
|
||||
const action = {
|
||||
basic: {
|
||||
id: null,
|
||||
run_after: 'wizard_completion',
|
||||
type: null
|
||||
},
|
||||
types: {
|
||||
create_topic: {
|
||||
title: null,
|
||||
post: null,
|
||||
post_builder: null,
|
||||
post_template: null,
|
||||
category: null,
|
||||
tags: null,
|
||||
custom_fields: null,
|
||||
skip_redirect: null
|
||||
},
|
||||
send_message: {
|
||||
title: null,
|
||||
post: null,
|
||||
post_builder: null,
|
||||
post_template: null,
|
||||
skip_redirect: null,
|
||||
custom_fields: null,
|
||||
required: null,
|
||||
recipient: null
|
||||
},
|
||||
open_composer: {
|
||||
title: null,
|
||||
post: null,
|
||||
post_builder: null,
|
||||
post_template: null,
|
||||
category: null,
|
||||
tags: null,
|
||||
custom_fields: null
|
||||
},
|
||||
update_profile: {
|
||||
profile_updates: null,
|
||||
custom_fields: null
|
||||
},
|
||||
add_to_group: {
|
||||
group: null
|
||||
},
|
||||
route_to: {
|
||||
url: null,
|
||||
code: null
|
||||
}
|
||||
},
|
||||
mapped: [
|
||||
'title',
|
||||
'category',
|
||||
'tags',
|
||||
'custom_fields',
|
||||
'required',
|
||||
'recipient',
|
||||
'profile_updates',
|
||||
'group'
|
||||
],
|
||||
advanced: [
|
||||
'code',
|
||||
'custom_fields',
|
||||
'skip_redirect',
|
||||
'required'
|
||||
],
|
||||
required: [
|
||||
'id',
|
||||
'type'
|
||||
],
|
||||
dependent: {
|
||||
},
|
||||
objectArrays: {
|
||||
}
|
||||
}
|
||||
|
||||
const wizardSchema = {
|
||||
wizard,
|
||||
step,
|
||||
field,
|
||||
action
|
||||
}
|
||||
|
||||
export function buildFieldTypes(types) {
|
||||
wizardSchema.field.types = types;
|
||||
}
|
||||
|
||||
if (Discourse.SiteSettings.wizard_apis_enabled) {
|
||||
wizardSchema.action.types.send_to_api = {
|
||||
api: null,
|
||||
api_endpoint: null,
|
||||
api_body: null
|
||||
}
|
||||
}
|
||||
|
||||
export function setSchemaDefaults(obj, objType) {
|
||||
let objSchema = wizardSchema[objType];
|
||||
let basicDefaults = objSchema.basic;
|
||||
|
||||
Object.keys(basicDefaults).forEach(property => {
|
||||
if (basicDefaults[property]) {
|
||||
set(obj, property, basicDefaults[property]);
|
||||
}
|
||||
});
|
||||
|
||||
if (objSchema.types && obj.type) {
|
||||
let typeDefaults = objSchema.types[obj.type];
|
||||
|
||||
Object.keys(typeDefaults).forEach(property => {
|
||||
if (typeDefaults.hasOwnProperty(property)) {
|
||||
set(obj, property, typeDefaults[property]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default wizardSchema;
|
|
@ -1,4 +1,5 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import wizardSchema from './wizard-schema';
|
||||
|
||||
function selectKitContent(content) {
|
||||
return content.map(i => ({id: i, name: i}));
|
||||
|
@ -48,248 +49,11 @@ const userProperties = [
|
|||
'trust_level'
|
||||
];
|
||||
|
||||
const wizardProperties = {
|
||||
basic: {
|
||||
id: null,
|
||||
name: null,
|
||||
background: null,
|
||||
save_submissions: true,
|
||||
multiple_submissions: null,
|
||||
after_signup: null,
|
||||
after_time: null,
|
||||
after_time_scheduled: null,
|
||||
required: null,
|
||||
prompt_completion: null,
|
||||
restart_on_revisit: null,
|
||||
theme_id: null,
|
||||
permitted: null
|
||||
},
|
||||
mapped: [
|
||||
'permitted'
|
||||
],
|
||||
advanced: [
|
||||
'restart_on_revisit',
|
||||
],
|
||||
required: [
|
||||
'id',
|
||||
],
|
||||
dependent: {
|
||||
after_time: 'after_time_scheduled'
|
||||
},
|
||||
objectArrays: {
|
||||
step: {
|
||||
property: 'steps',
|
||||
required: false
|
||||
},
|
||||
action: {
|
||||
property: 'actions',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const stepProperties = {
|
||||
basic: {
|
||||
id: null,
|
||||
title: null,
|
||||
key: null,
|
||||
banner: null,
|
||||
raw_description: null,
|
||||
required_data: null,
|
||||
required_data_message: null,
|
||||
permitted_params: null
|
||||
},
|
||||
mapped: [
|
||||
'required_data',
|
||||
'permitted_params'
|
||||
],
|
||||
advanced: [
|
||||
'required_data',
|
||||
'permitted_params'
|
||||
],
|
||||
required: [
|
||||
'id'
|
||||
],
|
||||
dependent: {
|
||||
},
|
||||
objectArrays: {
|
||||
field: {
|
||||
property: 'fields',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fieldProperties = {
|
||||
basic: {
|
||||
id: null,
|
||||
label: null,
|
||||
image: null,
|
||||
description: null,
|
||||
required: null,
|
||||
key: null,
|
||||
type: null
|
||||
},
|
||||
types: {
|
||||
text: {
|
||||
min_length: null
|
||||
},
|
||||
textarea: {
|
||||
min_length: null
|
||||
},
|
||||
composer: {
|
||||
min_length: null
|
||||
},
|
||||
text_only: {
|
||||
},
|
||||
number: {
|
||||
},
|
||||
checkbox: {
|
||||
},
|
||||
url: {
|
||||
min_length: null
|
||||
},
|
||||
upload: {
|
||||
file_types: '.jpg,.png'
|
||||
},
|
||||
dropdown: {
|
||||
prefill: null,
|
||||
content: null
|
||||
},
|
||||
tag: {
|
||||
limit: null,
|
||||
prefill: null,
|
||||
content: null
|
||||
},
|
||||
category: {
|
||||
limit: 1,
|
||||
property: 'id',
|
||||
prefill: null,
|
||||
content: null
|
||||
},
|
||||
group: {
|
||||
prefill: null,
|
||||
content: null
|
||||
},
|
||||
user_selector: {
|
||||
},
|
||||
event: {
|
||||
},
|
||||
location: {
|
||||
}
|
||||
},
|
||||
mapped: [
|
||||
'prefill',
|
||||
'content'
|
||||
],
|
||||
advanced: [
|
||||
'property',
|
||||
'key'
|
||||
],
|
||||
required: [
|
||||
'id',
|
||||
'type'
|
||||
],
|
||||
dependent: {
|
||||
},
|
||||
objectArrays: {
|
||||
}
|
||||
}
|
||||
|
||||
const actionProperties = {
|
||||
basic: {
|
||||
id: null,
|
||||
run_after: 'wizard_completion',
|
||||
type: null
|
||||
},
|
||||
types: {
|
||||
create_topic: {
|
||||
title: null,
|
||||
post: null,
|
||||
post_builder: null,
|
||||
post_template: null,
|
||||
category: null,
|
||||
tags: null,
|
||||
custom_fields: null,
|
||||
skip_redirect: null
|
||||
},
|
||||
send_message: {
|
||||
title: null,
|
||||
post: null,
|
||||
post_builder: null,
|
||||
post_template: null,
|
||||
skip_redirect: null,
|
||||
custom_fields: null,
|
||||
required: null,
|
||||
recipient: null
|
||||
},
|
||||
open_composer: {
|
||||
title: null,
|
||||
post: null,
|
||||
post_builder: null,
|
||||
post_template: null,
|
||||
category: null,
|
||||
tags: null,
|
||||
custom_fields: null
|
||||
},
|
||||
update_profile: {
|
||||
profile_updates: null,
|
||||
custom_fields: null
|
||||
},
|
||||
add_to_group: {
|
||||
group: null
|
||||
},
|
||||
route_to: {
|
||||
url: null,
|
||||
code: null
|
||||
}
|
||||
},
|
||||
mapped: [
|
||||
'title',
|
||||
'category',
|
||||
'tags',
|
||||
'custom_fields',
|
||||
'required',
|
||||
'recipient',
|
||||
'profile_updates',
|
||||
'group'
|
||||
],
|
||||
advanced: [
|
||||
'code',
|
||||
'custom_fields',
|
||||
'skip_redirect',
|
||||
'required'
|
||||
],
|
||||
required: [
|
||||
'id',
|
||||
'type'
|
||||
],
|
||||
dependent: {
|
||||
},
|
||||
objectArrays: {
|
||||
}
|
||||
}
|
||||
|
||||
if (Discourse.SiteSettings.wizard_apis_enabled) {
|
||||
actionProperties.types.send_to_api = {
|
||||
api: null,
|
||||
api_endpoint: null,
|
||||
api_body: null
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
wizard: wizardProperties,
|
||||
step: stepProperties,
|
||||
field: fieldProperties,
|
||||
action: actionProperties
|
||||
}
|
||||
|
||||
function listProperties(type, objectType = null) {
|
||||
let properties = Object.keys(schema[type].basic);
|
||||
let properties = Object.keys(wizardSchema[type].basic);
|
||||
|
||||
if (schema[type].types && objectType) {
|
||||
properties = properties.concat(Object.keys(schema[type].types[objectType]));
|
||||
if (wizardSchema[type].types && objectType) {
|
||||
properties = properties.concat(Object.keys(wizardSchema[type].types[objectType]));
|
||||
}
|
||||
|
||||
return properties;
|
||||
|
@ -328,7 +92,6 @@ export {
|
|||
generateId,
|
||||
camelCase,
|
||||
snakeCase,
|
||||
schema,
|
||||
userProperties,
|
||||
listProperties,
|
||||
wizardFieldList
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { ajax } from 'discourse/lib/ajax';
|
||||
import EmberObject from "@ember/object";
|
||||
import { buildProperties, present, mapped } from '../lib/wizard-json';
|
||||
import { schema, listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||
import { listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||
import wizardSchema from '../lib/wizard-schema';
|
||||
import { Promise } from "rsvp";
|
||||
|
||||
const CustomWizard = EmberObject.extend({
|
||||
|
@ -38,7 +39,7 @@ const CustomWizard = EmberObject.extend({
|
|||
buildJson(object, type, result = {}) {
|
||||
let objectType = object.type || null;
|
||||
|
||||
if (schema[type].types) {
|
||||
if (wizardSchema[type].types) {
|
||||
if (!objectType) {
|
||||
result.error = {
|
||||
type: 'required',
|
||||
|
@ -67,8 +68,8 @@ const CustomWizard = EmberObject.extend({
|
|||
};
|
||||
|
||||
if (!result.error) {
|
||||
for (let arrayObjectType of Object.keys(schema[type].objectArrays)) {
|
||||
let arraySchema = schema[type].objectArrays[arrayObjectType];
|
||||
for (let arrayObjectType of Object.keys(wizardSchema[type].objectArrays)) {
|
||||
let arraySchema = wizardSchema[type].objectArrays[arrayObjectType];
|
||||
let objectArray = object.get(arraySchema.property);
|
||||
|
||||
if (arraySchema.required && !present(objectArray)) {
|
||||
|
@ -98,14 +99,14 @@ const CustomWizard = EmberObject.extend({
|
|||
},
|
||||
|
||||
validateValue(property, value, object, type, result) {
|
||||
if (schema[type].required.indexOf(property) > -1 && !value) {
|
||||
if (wizardSchema[type].required.indexOf(property) > -1 && !value) {
|
||||
result.error = {
|
||||
type: 'required',
|
||||
params: { type, property }
|
||||
}
|
||||
}
|
||||
|
||||
let dependent = schema[type].dependent[property];
|
||||
let dependent = wizardSchema[type].dependent[property];
|
||||
if (dependent && value && !object[dependent]) {
|
||||
result.error = {
|
||||
type: 'dependent',
|
||||
|
|
|
@ -24,7 +24,7 @@ export default DiscourseRoute.extend({
|
|||
|
||||
controller.setProperties({
|
||||
wizardList: parentModel.wizard_list,
|
||||
fieldTypes: selectKitContent(parentModel.field_types),
|
||||
fieldTypes: selectKitContent(Object.keys(parentModel.field_types)),
|
||||
userFields: parentModel.userFields,
|
||||
apis: parentModel.apis,
|
||||
themes: parentModel.themes,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { userProperties, generateName } from '../lib/wizard';
|
||||
import { buildFieldTypes } from '../lib/wizard-schema';
|
||||
import { set } from "@ember/object";
|
||||
import { all } from "rsvp";
|
||||
import { ajax } from 'discourse/lib/ajax';
|
||||
|
@ -10,6 +11,8 @@ export default DiscourseRoute.extend({
|
|||
},
|
||||
|
||||
afterModel(model) {
|
||||
buildFieldTypes(model.field_types);
|
||||
|
||||
return all([
|
||||
this._getThemes(model),
|
||||
this._getApis(model),
|
||||
|
@ -63,12 +66,10 @@ export default DiscourseRoute.extend({
|
|||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
let props = {
|
||||
controller.setProperties({
|
||||
wizardList: model.wizard_list,
|
||||
wizardId: this.currentWizard()
|
||||
}
|
||||
|
||||
controller.setProperties(props);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
|
|
@ -1,15 +1,55 @@
|
|||
class CustomWizard::Field
|
||||
def self.types
|
||||
@types ||= ['text', 'textarea', 'composer', 'text_only', 'number', 'checkbox', 'url', 'upload', 'dropdown', 'tag', 'category', 'group', 'user_selector']
|
||||
@types ||= {
|
||||
text: {
|
||||
min_length: nil
|
||||
},
|
||||
textarea: {
|
||||
min_length: nil
|
||||
},
|
||||
composer: {
|
||||
min_length: nil
|
||||
},
|
||||
text_only: {},
|
||||
number: {},
|
||||
checkbox: {},
|
||||
url: {
|
||||
min_length: nil
|
||||
},
|
||||
upload: {
|
||||
file_types: '.jpg,.png'
|
||||
},
|
||||
dropdown: {
|
||||
prefill: nil,
|
||||
content: nil
|
||||
},
|
||||
tag: {
|
||||
limit: nil,
|
||||
prefill: nil,
|
||||
content: nil
|
||||
},
|
||||
category: {
|
||||
limit: 1,
|
||||
property: 'id',
|
||||
prefill: nil,
|
||||
content: nil
|
||||
},
|
||||
group: {
|
||||
prefill: nil,
|
||||
content: nil
|
||||
},
|
||||
user_selector: {}
|
||||
}
|
||||
end
|
||||
|
||||
def self.require_assets
|
||||
@require_assets ||= {}
|
||||
end
|
||||
|
||||
def self.add_assets(type, plugin = nil, asset_paths = [])
|
||||
def self.add_assets(type, plugin = nil, asset_paths = [], opts={})
|
||||
if type
|
||||
types.push(*type)
|
||||
types[type] ||= {}
|
||||
types[type] = opts[:type_opts] if opts[:type_opts].present?
|
||||
end
|
||||
|
||||
if plugin && asset_paths
|
||||
|
|
Laden …
In neuem Issue referenzieren