Refactor selector components for extensibility
This commit is contained in:
parent
a026a7c5ec
commit
a8acbc37a2
|
@ -1,29 +1,13 @@
|
||||||
var compiled;
|
export default Ember.Component.extend({
|
||||||
|
|
||||||
function templateFunction() {
|
|
||||||
compiled = compiled || Handlebars.compile(
|
|
||||||
"<div class='autocomplete'>" +
|
|
||||||
"<ul>" +
|
|
||||||
"{{#each options}}" +
|
|
||||||
"<li>" +
|
|
||||||
"<a href=''>{{this.name}}</a>" +
|
|
||||||
"</li>" +
|
|
||||||
"{{/each}}" +
|
|
||||||
"</ul>" +
|
|
||||||
"</div>"
|
|
||||||
);
|
|
||||||
return compiled;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Em.Component.extend({
|
|
||||||
placeholder: function(){
|
placeholder: function(){
|
||||||
return I18n.t(this.get("placeholderKey"));
|
return I18n.t(this.get("placeholderKey"));
|
||||||
}.property("placeholderKey"),
|
}.property("placeholderKey"),
|
||||||
|
|
||||||
didInsertElement: function() {
|
_initializeAutocomplete: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var selectedGroups;
|
var selectedGroups;
|
||||||
|
|
||||||
|
var template = this.container.lookup('template:group-selector-autocomplete.raw');
|
||||||
self.$('input').autocomplete({
|
self.$('input').autocomplete({
|
||||||
allowAny: false,
|
allowAny: false,
|
||||||
onChangeItems: function(items){
|
onChangeItems: function(items){
|
||||||
|
@ -45,7 +29,7 @@ export default Em.Component.extend({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
template: templateFunction()
|
template: template
|
||||||
});
|
});
|
||||||
}
|
}.on('didInsertElement')
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import TextField from 'discourse/components/text-field';
|
||||||
|
import userSearch from 'discourse/lib/user-search';
|
||||||
|
|
||||||
|
export default TextField.extend({
|
||||||
|
|
||||||
|
_initializeAutocomplete: function() {
|
||||||
|
var self = this,
|
||||||
|
selected = [],
|
||||||
|
currentUser = this.currentUser,
|
||||||
|
includeGroups = this.get('includeGroups') === 'true';
|
||||||
|
|
||||||
|
function excludedUsernames() {
|
||||||
|
if (currentUser && self.get('excludeCurrentUser')) {
|
||||||
|
return selected.concat([currentUser.get('username')]);
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
var template = this.container.lookup('template:user-selector-autocomplete.raw');
|
||||||
|
$(this.get('element')).val(this.get('usernames')).autocomplete({
|
||||||
|
template: template,
|
||||||
|
|
||||||
|
disabled: this.get('disabled'),
|
||||||
|
single: this.get('single'),
|
||||||
|
allowAny: this.get('allowAny'),
|
||||||
|
|
||||||
|
dataSource: function(term) {
|
||||||
|
return userSearch({
|
||||||
|
term: term,
|
||||||
|
topicId: self.get('topicId'),
|
||||||
|
exclude: excludedUsernames(),
|
||||||
|
includeGroups: includeGroups
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
transformComplete: function(v) {
|
||||||
|
if (v.username) {
|
||||||
|
return v.username;
|
||||||
|
} else {
|
||||||
|
var excludes = excludedUsernames();
|
||||||
|
return v.usernames.filter(function(item){
|
||||||
|
return excludes.indexOf(item) === -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onChangeItems: function(items) {
|
||||||
|
items = items.map(function(i) {
|
||||||
|
return i.username ? i.username : i;
|
||||||
|
});
|
||||||
|
self.set('usernames', items.join(","));
|
||||||
|
selected = items;
|
||||||
|
},
|
||||||
|
|
||||||
|
reverseTransform: function(i) {
|
||||||
|
return { username: i };
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}.on('didInsertElement')
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
import registerUnbound from 'discourse/helpers/register-unbound';
|
||||||
|
|
||||||
|
registerUnbound('max-usernames', function(usernames, params) {
|
||||||
|
var maxLength = parseInt(params.max) || 3;
|
||||||
|
if (usernames.length > maxLength){
|
||||||
|
return usernames.slice(0, maxLength).join(", ") + ", +" + (usernames.length - maxLength);
|
||||||
|
} else {
|
||||||
|
return usernames.join(", ");
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,43 +0,0 @@
|
||||||
var deprecatedViewHelpers = {
|
|
||||||
inputTip: 'input-tip',
|
|
||||||
pagedown: 'pagedown-editor',
|
|
||||||
textField: 'text-field',
|
|
||||||
userSelector: 'user-selector',
|
|
||||||
combobox: 'combo-box',
|
|
||||||
categoryChooser: 'category-chooser',
|
|
||||||
chooseTopic: 'choose-topic',
|
|
||||||
'discourse-activity-filter': 'activity-filter'
|
|
||||||
};
|
|
||||||
|
|
||||||
var renamedHelpers = {
|
|
||||||
icon: "fa-icon",
|
|
||||||
date: "format-date",
|
|
||||||
age: "format-age"
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'deprecations',
|
|
||||||
initialize: function(container) {
|
|
||||||
Ember.keys(deprecatedViewHelpers).forEach(function(old) {
|
|
||||||
var newName = deprecatedViewHelpers[old];
|
|
||||||
Ember.Handlebars.registerHelper(old, function(options) {
|
|
||||||
Em.warn("The `" + old +"` helper is deprecated. Use `" + newName + "` instead.");
|
|
||||||
var helper = container.lookupFactory('view:' + newName) || container.lookupFactory('component:' + newName);
|
|
||||||
var hash = options.hash,
|
|
||||||
types = options.hashTypes;
|
|
||||||
|
|
||||||
Discourse.Utilities.normalizeHash(hash, types);
|
|
||||||
return Ember.Handlebars.helpers.view.call(this, helper, options);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Ember.keys(renamedHelpers).forEach(function(old) {
|
|
||||||
var newName = renamedHelpers[old];
|
|
||||||
Ember.Handlebars.registerHelper(old, function() {
|
|
||||||
Em.warn("The `" + old +"` helper is deprecated. Use `" + newName + "` instead.");
|
|
||||||
var newHelper = container.lookupFactory('helper:' + newName);
|
|
||||||
return newHelper.apply(this, Array.prototype.slice.call(arguments));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -39,5 +39,9 @@ export default {
|
||||||
application.inject('route', 'session', 'session:main');
|
application.inject('route', 'session', 'session:main');
|
||||||
application.inject('view', 'session', 'session:main');
|
application.inject('view', 'session', 'session:main');
|
||||||
application.inject('model', 'session', 'session:main');
|
application.inject('model', 'session', 'session:main');
|
||||||
|
|
||||||
|
// Inject currentUser. Components only for now to prevent any breakage
|
||||||
|
application.register('current-user:main', Discourse.User.current(), { instantiate: false });
|
||||||
|
application.inject('component', 'currentUser', 'current-user:main');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
var helpers = ['input-tip',
|
var helpers = ['input-tip',
|
||||||
'pagedown-editor',
|
'pagedown-editor',
|
||||||
'user-selector',
|
|
||||||
'category-chooser',
|
'category-chooser',
|
||||||
'combo-box',
|
'combo-box',
|
||||||
'choose-topic',
|
'choose-topic',
|
||||||
|
|
|
@ -74,7 +74,7 @@ function organizeResults(r, options) {
|
||||||
|
|
||||||
export default function userSearch(options) {
|
export default function userSearch(options) {
|
||||||
var term = options.term || "",
|
var term = options.term || "",
|
||||||
includeGroups = !!options.include_groups,
|
includeGroups = options.includeGroups,
|
||||||
topicId = options.topicId;
|
topicId = options.topicId;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{{render "composer-messages"}}
|
{{render "composer-messages"}}
|
||||||
|
|
||||||
<div class='control'>
|
<div class='control'>
|
||||||
<a href='#' class='toggler' {{action "toggle" bubbles=false}} title='{{i18n 'composer.toggler'}}'></a>
|
<a href class='toggler' {{action "toggle" bubbles=false}} title='{{i18n 'composer.toggler'}}'></a>
|
||||||
|
|
||||||
{{#if model.viewOpen}}
|
{{#if model.viewOpen}}
|
||||||
<div class='control-row reply-area'>
|
<div class='control-row reply-area'>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
{{user-selector topicId=controller.controllers.topic.model.id
|
{{user-selector topicId=controller.controllers.topic.model.id
|
||||||
excludeCurrentUser="true"
|
excludeCurrentUser="true"
|
||||||
id="private-message-users"
|
id="private-message-users"
|
||||||
include_groups="true"
|
includeGroups="true"
|
||||||
class="span8"
|
class="span8"
|
||||||
placeholderKey="composer.users_placeholder"
|
placeholderKey="composer.users_placeholder"
|
||||||
tabindex="1"
|
tabindex="1"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div class='autocomplete'>
|
||||||
|
<ul>
|
||||||
|
{{#each options}}
|
||||||
|
<li><a href>{{this.name}}</a></li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<form>
|
<form>
|
||||||
<label>{{i18n 'topic.change_owner.label'}}</label>
|
<label>{{i18n 'topic.change_owner.label'}}</label>
|
||||||
{{user-selector single=true usernames=new_user include_groups="false" placeholderKey="topic.change_owner.placeholder"}}
|
{{user-selector single="true" usernames=new_user placeholderKey="topic.change_owner.placeholder"}}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
{{#if isAdmin}}
|
{{#if isAdmin}}
|
||||||
<label>{{{groupInstructions}}}</label>
|
<label>{{{groupInstructions}}}</label>
|
||||||
{{group-selector includeAuto=false groupFinder=groupFinder groupNames=groupNames placeholderKey="topic.invite_private.group_name"}}
|
{{group-selector groupFinder=groupFinder groupNames=groupNames placeholderKey="topic.invite_private.group_name"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
{{i18n 'topic.invite_private.success'}}
|
{{i18n 'topic.invite_private.success'}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<label>{{i18n 'topic.invite_private.email_or_username'}}</label>
|
<label>{{i18n 'topic.invite_private.email_or_username'}}</label>
|
||||||
{{user-selector single=true allowAny=true usernames=emailOrUsername include_groups="true" placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
{{user-selector single="true" allowAny=true usernames=emailOrUsername includeGroups="true" placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class='autocomplete'>
|
||||||
|
<ul>
|
||||||
|
{{#each options.users}}
|
||||||
|
<li>
|
||||||
|
<a href='#'>{{avatar this imageSize="tiny"}}
|
||||||
|
<span class='username'>{{this.username}}</span>
|
||||||
|
<span class='name'>{{this.name}}</span></a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
{{#if options.groups}}
|
||||||
|
{{#if options.users}}<hr>{{/if}}
|
||||||
|
{{#each options.groups}}
|
||||||
|
<li>
|
||||||
|
<a href=''><i class='icon-group'></i>
|
||||||
|
<span class='username'>{{this.name}}</span>
|
||||||
|
<span class='name'>{{max-usernames usernames max="3"}}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -173,7 +173,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
$LAB.script(assetPath('defer/html-sanitizer-bundle'));
|
$LAB.script(assetPath('defer/html-sanitizer-bundle'));
|
||||||
ComposerView.trigger("initWmdEditor");
|
ComposerView.trigger("initWmdEditor");
|
||||||
|
|
||||||
var template = this.container.lookupFactory('view:user-selector').templateFunction();
|
var template = this.container.lookup('template:user-selector-autocomplete.raw');
|
||||||
$wmdInput.data('init', true);
|
$wmdInput.data('init', true);
|
||||||
$wmdInput.autocomplete({
|
$wmdInput.autocomplete({
|
||||||
template: template,
|
template: template,
|
||||||
|
@ -181,7 +181,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
return userSearch({
|
return userSearch({
|
||||||
term: term,
|
term: term,
|
||||||
topicId: self.get('controller.controllers.topic.model.id'),
|
topicId: self.get('controller.controllers.topic.model.id'),
|
||||||
include_groups: true
|
includeGroups: true
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
key: "@",
|
key: "@",
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
import TextField from 'discourse/components/text-field';
|
|
||||||
import userSearch from 'discourse/lib/user-search';
|
|
||||||
|
|
||||||
var compiled;
|
|
||||||
function templateFunction() {
|
|
||||||
if (!compiled) {
|
|
||||||
Handlebars.registerHelper("showMax", function(context, block) {
|
|
||||||
var maxLength = parseInt(block.hash.max) || 3;
|
|
||||||
if (context.length > maxLength){
|
|
||||||
return context.slice(0, maxLength).join(", ") + ", +" + (context.length - maxLength);
|
|
||||||
} else {
|
|
||||||
return context.join(", ");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
compiled = Handlebars.compile(
|
|
||||||
"<div class='autocomplete'>" +
|
|
||||||
"<ul>" +
|
|
||||||
"{{#each options.users}}" +
|
|
||||||
"<li>" +
|
|
||||||
"<a href='#'>{{avatar this imageSize=\"tiny\"}} " +
|
|
||||||
"<span class='username'>{{this.username}}</span> " +
|
|
||||||
"<span class='name'>{{this.name}}</span></a>" +
|
|
||||||
"</li>" +
|
|
||||||
"{{/each}}" +
|
|
||||||
"{{#if options.groups}}" +
|
|
||||||
"{{#if options.users}}<hr>{{/if}}"+
|
|
||||||
"{{#each options.groups}}" +
|
|
||||||
"<li>" +
|
|
||||||
"<a href=''><i class='icon-group'></i>" +
|
|
||||||
"<span class='username'>{{this.name}}</span> " +
|
|
||||||
"<span class='name'>{{showMax this.usernames max=3}}</span>" +
|
|
||||||
"</a>" +
|
|
||||||
"</li>" +
|
|
||||||
"{{/each}}" +
|
|
||||||
"{{/if}}" +
|
|
||||||
"</ul>" +
|
|
||||||
"</div>");
|
|
||||||
}
|
|
||||||
return compiled;
|
|
||||||
}
|
|
||||||
|
|
||||||
var UserSelector = TextField.extend({
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
var userSelectorView = this,
|
|
||||||
selected = [];
|
|
||||||
|
|
||||||
function excludedUsernames() {
|
|
||||||
var exclude = selected;
|
|
||||||
if (userSelectorView.get('excludeCurrentUser')) {
|
|
||||||
exclude = exclude.concat([Discourse.User.currentProp('username')]);
|
|
||||||
}
|
|
||||||
return exclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(this.get('element')).val(this.get('usernames')).autocomplete({
|
|
||||||
template: templateFunction(),
|
|
||||||
|
|
||||||
disabled: this.get('disabled'),
|
|
||||||
single: this.get('single'),
|
|
||||||
allowAny: this.get('allowAny'),
|
|
||||||
|
|
||||||
dataSource: function(term) {
|
|
||||||
return userSearch({
|
|
||||||
term: term,
|
|
||||||
topicId: userSelectorView.get('topicId'),
|
|
||||||
exclude: excludedUsernames(),
|
|
||||||
include_groups: userSelectorView.get('include_groups')
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
transformComplete: function(v) {
|
|
||||||
if (v.username) {
|
|
||||||
return v.username;
|
|
||||||
} else {
|
|
||||||
var excludes = excludedUsernames();
|
|
||||||
return v.usernames.filter(function(item){
|
|
||||||
// include only, those not found in the exclude list
|
|
||||||
return excludes.indexOf(item) === -1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeItems: function(items) {
|
|
||||||
items = _.map(items, function(i) {
|
|
||||||
if (i.username) {
|
|
||||||
return i.username;
|
|
||||||
} else {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
userSelectorView.set('usernames', items.join(","));
|
|
||||||
selected = items;
|
|
||||||
},
|
|
||||||
|
|
||||||
reverseTransform: function(i) {
|
|
||||||
return { username: i };
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
UserSelector.reopenClass({ templateFunction: templateFunction });
|
|
||||||
|
|
||||||
export default UserSelector;
|
|
Loading…
Reference in New Issue