FEATURE: New "Dropdown" user field type

This commit is contained in:
Robin Ward
2015-07-28 12:29:40 -04:00
parent f22618050f
commit dc8a68fd29
18 changed files with 248 additions and 52 deletions

View File

@@ -10,6 +10,10 @@ export default Ember.Component.extend(bufferedProperty('userField'), {
return I18n.t('admin.user_fields.description');
}.property(),
bufferedFieldType: function() {
return UserField.fieldTypeById(this.get('buffered.field_type'));
}.property('buffered.field_type'),
_focusOnEdit: function() {
if (this.get('editing')) {
Ember.run.scheduleOnce('afterRender', this, '_focusName');
@@ -42,7 +46,14 @@ export default Ember.Component.extend(bufferedProperty('userField'), {
actions: {
save() {
const self = this;
const attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable', 'required', 'show_on_profile');
const buffered = this.get('buffered');
const attrs = buffered.getProperties('name',
'description',
'field_type',
'editable',
'required',
'show_on_profile',
'options');
this.get('userField').save(attrs).then(function(res) {
self.set('userField.id', res.user_field.id);

View File

@@ -3,11 +3,19 @@ export default Ember.Component.extend({
_setupCollection: function() {
const values = this.get('values');
this.set('collection', (values && values.length) ? values.split("\n") : []);
if (this.get('inputType') === "array") {
this.set('collection', values || []);
} else {
this.set('collection', (values && values.length) ? values.split("\n") : []);
}
}.on('init').observes('values'),
_collectionChanged: function() {
this.set('values', this.get('collection').join("\n"));
if (this.get('inputType') === "array") {
this.set('values', this.get('collection'));
} else {
this.set('values', this.get('collection').join("\n"));
}
}.observes('collection.@each'),
inputInvalid: Ember.computed.empty('newValue'),

View File

@@ -1,8 +1,9 @@
var UserField = Ember.Object.extend({
destroy: function() {
var self = this;
const UserField = Ember.Object.extend({
destroy() {
const self = this;
return new Ember.RSVP.Promise(function(resolve) {
var id = self.get('id');
const id = self.get('id');
if (id) {
return Discourse.ajax("/admin/customize/user_fields/" + id, { type: 'DELETE' }).then(function() {
resolve();
@@ -12,8 +13,8 @@ var UserField = Ember.Object.extend({
});
},
save: function(attrs) {
var id = this.get('id');
save(attrs) {
const id = this.get('id');
if (!id) {
return Discourse.ajax("/admin/customize/user_fields", {
type: "POST",
@@ -28,8 +29,12 @@ var UserField = Ember.Object.extend({
}
});
const UserFieldType = Ember.Object.extend({
name: Discourse.computed.i18n('id', 'admin.user_fields.field_types.%@')
});
UserField.reopenClass({
findAll: function() {
findAll() {
return Discourse.ajax("/admin/customize/user_fields").then(function(result) {
return result.user_fields.map(function(uf) {
return UserField.create(uf);
@@ -37,18 +42,19 @@ UserField.reopenClass({
});
},
fieldTypes: function() {
fieldTypes() {
if (!this._fieldTypes) {
this._fieldTypes = [
Ember.Object.create({id: 'text', name: I18n.t('admin.user_fields.field_types.text') }),
Ember.Object.create({id: 'confirm', name: I18n.t('admin.user_fields.field_types.confirm') })
UserFieldType.create({ id: 'text' }),
UserFieldType.create({ id: 'confirm' }),
UserFieldType.create({ id: 'dropdown', hasOptions: true })
];
}
return this._fieldTypes;
},
fieldTypeById: function(id) {
fieldTypeById(id) {
return this.fieldTypes().findBy('id', id);
}
});

View File

@@ -1,11 +1,11 @@
<div class='form-element-desc'>
<div class='form-element label-area'>
{{#if label}}
<label>{{i18n label}}</label>
{{else}}
&nbsp;
{{/if}}
</div>
<div class='form-element'>
<div class='form-element input-area'>
{{#if wrapLabel}}
<label>{{yield}}</label>
{{else}}

View File

@@ -11,6 +11,12 @@
{{input value=buffered.description class="user-field-desc"}}
{{/admin-form-row}}
{{#if bufferedFieldType.hasOptions}}
{{#admin-form-row label="admin.user_fields.options"}}
{{value-list values=buffered.options inputType="array"}}
{{/admin-form-row}}
{{/if}}
{{#admin-form-row wrapLabel="true"}}
{{input type="checkbox" checked=buffered.editable}} {{i18n 'admin.user_fields.editable.title'}}
{{/admin-form-row}}

View File

@@ -3,8 +3,9 @@ export default Ember.Component.extend({
attributeBindings: ['tabindex'],
classNames: ['combobox'],
valueAttribute: 'id',
nameProperty: 'name',
buildData(o) {
_buildData(o) {
let result = "";
if (this.resultAttributes) {
this.resultAttributes.forEach(function(a) {
@@ -14,19 +15,15 @@ export default Ember.Component.extend({
return result;
},
realNameProperty: function() {
return this.get('nameProperty') || 'name';
}.property('nameProperty'),
render(buffer) {
const nameProperty = this.get('realNameProperty'),
none = this.get('none');
const nameProperty = this.get('nameProperty');
const none = this.get('none');
// Add none option if required
if (typeof none === "string") {
buffer.push('<option value="">' + I18n.t(none) + "</option>");
} else if (typeof none === "object") {
buffer.push("<option value=\"\" " + this.buildData(none) + ">" + Em.get(none, nameProperty) + "</option>");
buffer.push("<option value=\"\" " + this._buildData(none) + ">" + Em.get(none, nameProperty) + "</option>");
}
let selected = this.get('value');
@@ -35,18 +32,20 @@ export default Ember.Component.extend({
if (this.get('content')) {
const self = this;
this.get('content').forEach(function(o) {
let val = o[self.get('valueAttribute')];
let val = o[self.get('valueAttribute')] || o;
if (!Em.isNone(val)) { val = val.toString(); }
const selectedText = (val === selected) ? "selected" : "";
buffer.push("<option " + selectedText + " value=\"" + val + "\" " + self.buildData(o) + ">" + Handlebars.Utils.escapeExpression(Em.get(o, nameProperty)) + "</option>");
const name = Ember.get(o, nameProperty) || o;
buffer.push("<option " + selectedText + " value=\"" + val + "\" " + self._buildData(o) + ">" + Handlebars.Utils.escapeExpression(name) + "</option>");
});
}
},
valueChanged: function() {
const $combo = this.$(),
val = this.get('value');
val = this.get('value');
if (val !== undefined && val !== null) {
$combo.select2('val', val.toString());
} else {
@@ -54,13 +53,11 @@ export default Ember.Component.extend({
}
}.observes('value'),
contentChanged: function() {
_rerenderOnChange: function() {
this.rerender();
}.observes('content.@each'),
_initializeCombo: function() {
const $elem = this.$(),
self = this;
// Workaround for https://github.com/emberjs/ember.js/issues/9813
// Can be removed when fixed. Without it, the wrong option is selected
@@ -70,12 +67,14 @@ export default Ember.Component.extend({
// observer for item names changing (optional)
if (this.get('nameChanges')) {
this.addObserver('content.@each.' + this.get('realNameProperty'), this.rerender);
this.addObserver('content.@each.' + this.get('nameProperty'), this.rerender);
}
const $elem = this.$();
$elem.select2({formatResult: this.comboTemplate, minimumResultsForSearch: 5, width: 'resolve'});
const castInteger = this.get('castInteger');
const self = this;
$elem.on("change", function (e) {
let val = $(e.target).val();
if (val && val.length && castInteger) {

View File

@@ -1,6 +1,10 @@
export default Ember.Component.extend({
classNameBindings: [':user-field', 'field.field_type'],
layoutName: function() {
return "components/user-fields/" + this.get('field.field_type');
}.property('field.field_type')
layoutName: Discourse.computed.fmt('field.field_type', 'components/user-fields/%@'),
noneLabel: function() {
if (!this.get('field.required')) {
return 'user_fields.none';
}
}.property('field.required')
});

View File

@@ -0,0 +1,6 @@
<label>{{{field.name}}}</label>
<div class='controls'>
{{combo-box content=field.options value=value none=noneLabel}}
{{#if field.required}}<span class='required'>*</span>{{/if}}
<p>{{{field.description}}}</p>
</div>

View File

@@ -1437,15 +1437,24 @@ tr.not-activated {
.form-element, .form-element-desc {
float: left;
width: 25%;
height: 30px;
min-height: 30px;
padding: 0.25em 0;
}
.form-element-desc label {
margin: 0.5em 1em 0 0;
text-align: right;
font-weight: bold;
&.input-area {
width: 75%;
input[type=text] {
width: 50%;
}
}
&.label-area {
width: 25%;
label {
margin: 0.5em 1em 0 0;
text-align: right;
font-weight: bold;
}
}
}
.controls {