Switch Admin Settings Lists to Select2.js
- and use jquery.sortable to allow sorting - support for autocompletion
This commit is contained in:
parent
68600f1dce
commit
eb884f9928
|
@ -2,81 +2,41 @@
|
||||||
Provide a nice GUI for a pipe-delimited list in the site settings.
|
Provide a nice GUI for a pipe-delimited list in the site settings.
|
||||||
|
|
||||||
@param settingValue is a reference to SiteSetting.value.
|
@param settingValue is a reference to SiteSetting.value.
|
||||||
|
@param choices is a reference to SiteSetting.choices
|
||||||
|
|
||||||
@class Discourse.ListSettingComponent
|
@class Discourse.ListSettingComponent
|
||||||
@extends Ember.Component
|
@extends Ember.Component
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
|
|
||||||
Discourse.ListSettingComponent = Ember.Component.extend({
|
Discourse.ListSettingComponent = Ember.Component.extend({
|
||||||
layoutName: 'components/list-setting',
|
tagName: 'div',
|
||||||
|
|
||||||
init: function() {
|
didInsertElement: function(){
|
||||||
this._super();
|
this.$("input").select2({
|
||||||
this.on("focusOut", this.uncacheValue);
|
multiple: false,
|
||||||
this.set('children', []);
|
separator: "|",
|
||||||
|
tokenSeparators: [",", " ", "|"],
|
||||||
|
tags : this.get("choices") || [],
|
||||||
|
width: 'off'
|
||||||
|
}).on("change", function(obj) {
|
||||||
|
this.set("settingValue", obj.val.join("|"));
|
||||||
|
this.refreshSortables();
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
this.refreshSortables();
|
||||||
},
|
},
|
||||||
|
|
||||||
canAddNew: true,
|
refreshOnReset: function() {
|
||||||
|
this.$("input").select2("val", this.get("settingValue").split("|"));
|
||||||
|
}.observes("settingValue"),
|
||||||
|
|
||||||
readValues: function() {
|
refreshSortables: function() {
|
||||||
return this.get('settingValue').split('|');
|
this.$("ul.select2-choices").sortable().on('sortupdate', function() {
|
||||||
}.property('settingValue'),
|
this.$("input").select2("onSortEnd");
|
||||||
|
}.bind(this));
|
||||||
/**
|
|
||||||
Transfer the debounced value into the settingValue parameter.
|
|
||||||
|
|
||||||
This will cause a redraw of the child textboxes.
|
|
||||||
|
|
||||||
@param newFocus {Number|undefined} Which list index to focus on next, or undefined to not refocus
|
|
||||||
**/
|
|
||||||
uncacheValue: function(newFocus) {
|
|
||||||
var oldValue = this.get('settingValue'),
|
|
||||||
newValue = this.get('settingValueCached'),
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
if (newValue !== undefined && newValue !== oldValue) {
|
|
||||||
this.set('settingValue', newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newFocus !== undefined && newFocus > 0) {
|
|
||||||
Em.run.schedule('afterRender', function() {
|
|
||||||
var children = self.get('children');
|
|
||||||
if (newFocus < children.length) {
|
|
||||||
$(children[newFocus].get('element')).focus();
|
|
||||||
} else if (newFocus === children.length) {
|
|
||||||
$(self.get('element')).children().children('.list-add-value').focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setItemValue: function(index, item) {
|
|
||||||
var values = this.get('readValues');
|
|
||||||
values[index] = item;
|
|
||||||
|
|
||||||
// Remove blank items
|
|
||||||
values = values.filter(function(s) { return s !== ''; });
|
|
||||||
this.setProperties({
|
|
||||||
settingValueCached: values.join('|'),
|
|
||||||
canAddNew: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
addNewItem: function() {
|
|
||||||
var newValue = this.get('settingValue') + '|';
|
|
||||||
this.setProperties({
|
|
||||||
settingValue: newValue,
|
|
||||||
settingValueCached: newValue,
|
|
||||||
canAddNew: false
|
|
||||||
});
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
Em.run.schedule('afterRender', function() {
|
|
||||||
var children = self.get('children');
|
|
||||||
$(children[children.length - 1].get('element')).focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
One item in a ListSetting.
|
|
||||||
|
|
||||||
@param parent is the ListSettingComponent.
|
|
||||||
|
|
||||||
@class Discourse.ListSettingItemComponent
|
|
||||||
@extends Ember.Component, Ember.TextSupport
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.ListSettingItemComponent = Ember.Component.extend(Ember.TextSupport, {
|
|
||||||
classNames: ['ember-text-field'],
|
|
||||||
tagName: "input",
|
|
||||||
attributeBindings: ['type', 'value', 'size', 'pattern'],
|
|
||||||
|
|
||||||
_initialize: function() {
|
|
||||||
// _parentView is the #each
|
|
||||||
// parent is the ListSettingComponent
|
|
||||||
this.setProperties({
|
|
||||||
value: this.get('_parentView.content'),
|
|
||||||
index: this.get('_parentView.contentIndex')
|
|
||||||
});
|
|
||||||
this.get('parent').get('children')[this.get('index')] = this;
|
|
||||||
}.on('init'),
|
|
||||||
|
|
||||||
markTab: function(e) {
|
|
||||||
var keyCode = e.keyCode || e.which;
|
|
||||||
|
|
||||||
if (keyCode === 9) {
|
|
||||||
this.set('nextIndex', this.get('index') + (e.shiftKey ? -1 : 1));
|
|
||||||
}
|
|
||||||
}.on('keyDown'),
|
|
||||||
|
|
||||||
reloadList: function() {
|
|
||||||
var nextIndex = this.get('nextIndex');
|
|
||||||
this.set('nextIndex', undefined); // one use only
|
|
||||||
this.get('parent').uncacheValue(nextIndex);
|
|
||||||
}.on('focusOut'),
|
|
||||||
|
|
||||||
_elementValueDidChange: function() {
|
|
||||||
this._super();
|
|
||||||
this.get('parent').setItemValue(this.get('index'), this.get('value'));
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -2,7 +2,7 @@
|
||||||
<h3>{{unbound setting}}</h3>
|
<h3>{{unbound setting}}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{list-setting settingValue=value}}
|
{{list-setting settingValue=value choices=choices}}
|
||||||
<div class='desc'>{{unbound description}}</div>
|
<div class='desc'>{{unbound description}}</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if dirty}}
|
{{#if dirty}}
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
<div class="ac-wrap clearfix input-setting-list">
|
<div class="input-setting-list">
|
||||||
{{#each readValues}}
|
<input type="text" value="{{unbound settingValue}}">
|
||||||
{{list-setting-item parent=view action=update classNames="list-input-item"}}
|
|
||||||
{{/each}}
|
|
||||||
{{#if canAddNew}}
|
|
||||||
<button class="btn no-text list-add-value" {{action addNewItem}}><i class="fa fa-plus"></i></button>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -205,30 +205,29 @@
|
||||||
-webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
|
-webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
|
||||||
transition: border linear 0.2s, box-shadow linear 0.2s;
|
transition: border linear 0.2s, box-shadow linear 0.2s;
|
||||||
|
|
||||||
.list-input-item {
|
li.select2-search-choice {
|
||||||
width: 90px;
|
cursor: pointer;
|
||||||
margin: 2px 1px;
|
.select2-search-choice-close {
|
||||||
background-color: $secondary;
|
content: "x"
|
||||||
border: 1px solid scale-color-diff();
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: inset 0 1px 1px rgba(51, 51, 51, 0.3);
|
|
||||||
-webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
|
|
||||||
transition: border linear 0.2s, box-shadow linear 0.2s;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: $tertiary;
|
|
||||||
outline: 0;
|
|
||||||
box-shadow: inset 0 1px 1px rgba(51, 51, 51, 0.3), 0 0 8px $tertiary;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.list-add-value {
|
li.sortable-placeholder {
|
||||||
margin: 0px 3px;
|
padding: 3px 5px 3px 18px;
|
||||||
padding: 4px 10px;
|
margin: 3px 0px 3px 5px;
|
||||||
color: $tertiary;
|
position: relative;
|
||||||
|
line-height: 13px;
|
||||||
|
cursor: default;
|
||||||
|
border: 1px dashed #AAA;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-clip: padding-box;
|
||||||
|
-moz-user-select: none;
|
||||||
|
background-color: none;
|
||||||
|
width: 3em;
|
||||||
|
height: 1em;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.desc {
|
.desc {
|
||||||
padding-top: 3px;
|
padding-top: 3px;
|
||||||
|
|
Loading…
Reference in New Issue