mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
Refactor selector components for extensibility
This commit is contained in:
parent
a026a7c5ec
commit
a8acbc37a2
15 changed files with 118 additions and 182 deletions
|
@ -1,29 +1,13 @@
|
|||
var compiled;
|
||||
|
||||
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({
|
||||
export default Ember.Component.extend({
|
||||
placeholder: function(){
|
||||
return I18n.t(this.get("placeholderKey"));
|
||||
}.property("placeholderKey"),
|
||||
|
||||
didInsertElement: function() {
|
||||
_initializeAutocomplete: function() {
|
||||
var self = this;
|
||||
var selectedGroups;
|
||||
|
||||
var template = this.container.lookup('template:group-selector-autocomplete.raw');
|
||||
self.$('input').autocomplete({
|
||||
allowAny: false,
|
||||
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('view', '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',
|
||||
'pagedown-editor',
|
||||
'user-selector',
|
||||
'category-chooser',
|
||||
'combo-box',
|
||||
'choose-topic',
|
||||
|
|
|
@ -74,7 +74,7 @@ function organizeResults(r, options) {
|
|||
|
||||
export default function userSearch(options) {
|
||||
var term = options.term || "",
|
||||
includeGroups = !!options.include_groups,
|
||||
includeGroups = options.includeGroups,
|
||||
topicId = options.topicId;
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
{{render "composer-messages"}}
|
||||
|
||||
<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}}
|
||||
<div class='control-row reply-area'>
|
||||
|
@ -33,7 +33,7 @@
|
|||
{{user-selector topicId=controller.controllers.topic.model.id
|
||||
excludeCurrentUser="true"
|
||||
id="private-message-users"
|
||||
include_groups="true"
|
||||
includeGroups="true"
|
||||
class="span8"
|
||||
placeholderKey="composer.users_placeholder"
|
||||
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>
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
{{#if isAdmin}}
|
||||
<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}}
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{{i18n 'topic.invite_private.success'}}
|
||||
{{else}}
|
||||
<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}}
|
||||
</div>
|
||||
<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'));
|
||||
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.autocomplete({
|
||||
template: template,
|
||||
|
@ -181,7 +181,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
|||
return userSearch({
|
||||
term: term,
|
||||
topicId: self.get('controller.controllers.topic.model.id'),
|
||||
include_groups: true
|
||||
includeGroups: true
|
||||
});
|
||||
},
|
||||
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 a new issue