ES6: Migrated and deprecated a bunch of views

This commit is contained in:
Robin Ward 2014-06-10 11:54:38 -04:00
parent c88bff5e0c
commit 580a1bf8b0
64 changed files with 206 additions and 382 deletions

View file

@ -14,7 +14,7 @@
<div class="current-style color-scheme">
<div class="admin-container">
{{#with selectedItem}}
<h1>{{textField class="style-name" value=name}}</h1>
<h1>{{text-field class="style-name" value=name}}</h1>
<div class="controls">
<button {{action save}} {{bind-attr disabled="disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>

View file

@ -12,7 +12,7 @@
{{#if selectedItem}}
<div class='current-style'>
{{#with selectedItem}}
{{textField class="style-name" value=name}}
{{text-field class="style-name" value=name}}
<div class='admin-controls'>
<ul class="nav nav-pills">

View file

@ -11,10 +11,10 @@
<tr class="filters">
<td>{{i18n admin.email.logs.filters.title}}</td>
<td>{{textField value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
<td>{{textField value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
<td>{{textField value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
<td>{{textField value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
</tr>
{{#each model}}

View file

@ -17,7 +17,7 @@
<div class='span15 controls'>{{i18n admin.email.sending_test}}</div>
{{else}}
<div class='controls'>
{{textField value=testEmailAddress placeholderKey="admin.email.test_email_address"}}
{{text-field value=testEmailAddress placeholderKey="admin.email.test_email_address"}}
</div>
<div class='span10 controls'>
<button class='btn' {{action sendTestEmail}} {{bind-attr disabled="sendTestEmailDisabled"}}>{{i18n admin.email.send_test}}</button>

View file

@ -11,10 +11,10 @@
<tr class="filters">
<td>{{i18n admin.email.logs.filters.title}}</td>
<td>{{textField value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
<td>{{textField value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
<td>{{textField value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
<td>{{textField value=filter.reply_key placeholderKey="admin.email.logs.filters.reply_key_placeholder"}}</td>
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
<td>{{text-field value=filter.reply_key placeholderKey="admin.email.logs.filters.reply_key_placeholder"}}</td>
</tr>
{{#each model}}

View file

@ -11,10 +11,10 @@
<tr class="filters">
<td>{{i18n admin.email.logs.filters.title}}</td>
<td>{{textField value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
<td>{{textField value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
<td>{{textField value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
<td>{{textField value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
</tr>
{{#each model}}

View file

@ -1,13 +1,13 @@
{{#if automatic}}
<h3>{{name}}</h3>
{{else}}
{{textField value=name placeholderKey="admin.groups.name_placeholder"}}
{{text-field value=name placeholderKey="admin.groups.name_placeholder"}}
{{/if}}
<div class="control-group">
<label class="control-label">{{i18n admin.groups.group_members}}</label>
<div class="controls">
{{userSelector usernames=usernames id="group-users" placeholderKey="admin.groups.selector_placeholder" tabindex="1" disabled=automatic}}
{{user-selector usernames=usernames id="group-users" placeholderKey="admin.groups.selector_placeholder" tabindex="1" disabled=automatic}}
</div>
</div>
<div class="control-group">

View file

@ -1,6 +1,6 @@
<div class="col first ip_address">
{{#if editing}}
{{textField value=ip_address autofocus="autofocus"}}
{{text-field value=ip_address autofocus="autofocus"}}
{{else}}
<span {{action edit this}}>{{ip_address}}</span>
{{/if}}

View file

@ -1,12 +1,12 @@
<div class="modal-body">
<form>
{{i18n admin.user.suspend_duration}}
{{textField value=duration maxlength="5" autofocus="autofocus"}}
{{text-field value=duration maxlength="5" autofocus="autofocus"}}
{{i18n admin.user.suspend_duration_units}}<br/>
<br/>
{{{i18n admin.user.suspend_reason_label}}}<br/>
<br/>
{{textField value=reason class="span8"}}
{{text-field value=reason class="span8"}}
</form>
</div>
<div class="modal-footer">

View file

@ -6,7 +6,7 @@
</label>
</div>
<div class='controls'>
{{textField value=filter placeholderKey="type_to_filter"}}
{{text-field value=filter placeholderKey="type_to_filter"}}
<button {{action clearFilter}} class="btn">{{i18n admin.site_settings.clear_filter}}</button>
</div>
</div>

View file

@ -2,7 +2,7 @@
<h3>{{unbound settingName}}</h3>
</div>
<div class="setting-value">
{{textField value=value classNames="input-setting-string"}}
{{text-field value=value classNames="input-setting-string"}}
<div {{bind-attr class=":validation-error validationMessage::hidden"}}><i class='fa fa-times'></i> {{validationMessage}}</div>
<div class='desc'>{{unbound description}}</div>
</div>

View file

@ -37,7 +37,7 @@
<div class='field'>{{i18n user.title.title}}</div>
<div class='value'>
{{#if editingTitle}}
{{textField value=title autofocus="autofocus"}}
{{text-field value=title autofocus="autofocus"}}
{{else}}
<span {{action toggleTitleEdit}}>{{title}}&nbsp;</span>
{{/if}}

View file

@ -13,7 +13,7 @@
</ul>
</div>
<div class='username controls'>
{{textField value=username placeholderKey="username"}}
{{text-field value=username placeholderKey="username"}}
</div>
</div>

View file

@ -1,6 +1,8 @@
var deprecatedViewHelpers = {
inputTip: 'input-tip',
pagedown: 'pagedown-editor'
pagedown: 'pagedown-editor',
textField: 'text-field',
userSelector: 'user-selector'
};
export default {

View file

@ -1,4 +1,4 @@
var helpers = ['input-tip', 'pagedown-editor'];
var helpers = ['input-tip', 'pagedown-editor', 'text-field', 'user-selector'];
/**
Creates view helpers for some views. Many of these should probably be converted
@ -9,8 +9,8 @@ export default {
initialize: function(container) {
helpers.forEach(function(h) {
Ember.Handlebars.registerHelper(h, function(options) {
var helper = container.lookupFactory('view:' + h);
var hash = options.hash,
var helper = container.lookupFactory('view:' + h),
hash = options.hash,
types = options.hashTypes;
Discourse.Utilities.normalizeHash(hash, types);

View file

@ -1,6 +1,6 @@
<label for='choose-topic-title'>{{i18n choose_topic.title.search}}</label>
{{textField value=view.topicTitle placeholderKey="choose_topic.title.placeholder" id="choose-topic-title"}}
{{text-field value=view.topicTitle placeholderKey="choose_topic.title.placeholder" id="choose-topic-title"}}
{{#if view.loading}}
<p>{{i18n loading}}</p>

View file

@ -2,7 +2,7 @@
<div>
<i class="fa fa-clock-o"></i>
{{label}}
{{textField value=autoCloseTime}}
{{text-field value=autoCloseTime}}
{{i18n composer.auto_close_units}}
</div>
<div class="examples">

View file

@ -1 +1 @@
{{textField class="hex-input" value=hexValue maxlength="6"}}
{{text-field class="hex-input" value=hexValue maxlength="6"}}

View file

@ -1,4 +1,4 @@
<b>{{i18n admin.logs.screened_ips.form.label}}</b>
{{textField value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}}
{{text-field value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}}
{{combobox content=actionNames value=actionName}}
<button class="btn btn-small" {{action submit target="view"}} {{bind-attr disabled="formSubmitted"}}>{{i18n admin.logs.screened_ips.form.add}}</button>

View file

@ -16,7 +16,7 @@
{{#if canEdit}}
{{#if showEditReason}}
<div class="edit-reason-input">
{{textField value=editReason tabindex="5" id="edit-reason" maxlength="255" placeholderKey="composer.edit_reason_placeholder"}}
{{text-field value=editReason tabindex="5" id="edit-reason" maxlength="255" placeholderKey="composer.edit_reason_placeholder"}}
</div>
{{else}}
<a {{action displayEditReason}} class="display-edit-reason">{{i18n composer.show_edit_reason}}</a>
@ -27,18 +27,18 @@
{{#if model.canEditTitle}}
<div class='form-element clearfix'>
{{#if model.creatingPrivateMessage}}
{{userSelector topicId=controller.controllers.topic.model.id
excludeCurrentUser="true"
id="private-message-users"
include_groups="true"
class="span8"
placeholderKey="composer.users_placeholder"
tabindex="1"
usernames=model.targetUsernames}}
{{user-selector topicId=controller.controllers.topic.model.id
excludeCurrentUser="true"
id="private-message-users"
include_groups="true"
class="span8"
placeholderKey="composer.users_placeholder"
tabindex="1"
usernames=model.targetUsernames}}
{{/if}}
<div class="title-input">
{{textField value=model.title tabindex="2" id="reply-title" maxlength="255" placeholderKey="composer.title_placeholder"}}
{{text-field value=model.title tabindex="2" id="reply-title" maxlength="255" placeholderKey="composer.title_placeholder"}}
{{popupInputTip validation=view.titleValidation shownAt=view.showTitleTip}}
</div>

View file

@ -19,7 +19,7 @@
<label for='login-account-name'>{{i18n login.username}}&nbsp;</label>
</td>
<td>
{{textField value=loginName placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off"}}
{{text-field value=loginName placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off"}}
</td>
</tr>
<tr>
@ -27,7 +27,7 @@
<label for='login-account-password'>{{i18n login.password}}&nbsp;</label>
</td>
<td>
{{textField value=loginPassword type="password" id="login-account-password"}} &nbsp;
{{text-field value=loginPassword type="password" id="login-account-password"}} &nbsp;
</td>
</tr>
<tr>

View file

@ -6,7 +6,7 @@
<form>
<label>{{i18n topic.change_owner.label}}</label>
{{userSelector single=true usernames=new_user include_groups="false" placeholderKey="topic.change_owner.placeholder"}}
{{user-selector single=true usernames=new_user include_groups="false" placeholderKey="topic.change_owner.placeholder"}}
</form>
</div>

View file

@ -6,7 +6,7 @@
<tr class="input">
<td style="width:80px" class="label"><label for='new-account-name'>{{i18n user.name.title}}</label></td>
<td style="width:496px">
{{textField value=accountName id="new-account-name" autofocus="autofocus"}}
{{text-field value=accountName id="new-account-name" autofocus="autofocus"}}
&nbsp;{{input-tip validation=nameValidation}}
</td>
</tr>

View file

@ -18,7 +18,7 @@
<form>
<section class='field'>
<label>{{i18n category.name}}</label>
{{textField value=name placeholderKey="category.name_placeholder" maxlength="50"}}
{{text-field value=name placeholderKey="category.name_placeholder" maxlength="50"}}
</section>
<section class='field'>
@ -56,13 +56,13 @@
<div class='input-prepend input-append' style="margin-top: 10px;">
<span class='color-title'>{{i18n category.background_color}}:</span>
<span class='add-on'>#</span>{{textField value=color placeholderKey="category.color_placeholder" maxlength="6"}}
<span class='add-on'>#</span>{{text-field value=color placeholderKey="category.color_placeholder" maxlength="6"}}
{{colorPicker colors=backgroundColors usedColors=usedBackgroundColors value=color}}
</div>
<div class='input-prepend input-append'>
<span class='color-title'>{{i18n category.foreground_color}}:</span>
<span class='add-on'>#</span>{{textField value=text_color placeholderKey="category.color_placeholder" maxlength="6"}}
<span class='add-on'>#</span>{{text-field value=text_color placeholderKey="category.color_placeholder" maxlength="6"}}
{{colorPicker colors=foregroundColors value=text_color}}
</div>
</div>
@ -99,7 +99,7 @@
<div>
<i class="fa fa-clock-o"></i>
{{i18n category.auto_close_label}}
{{textField value=auto_close_hours}}
{{text-field value=auto_close_hours}}
{{i18n category.auto_close_units}}
</div>
</div>
@ -111,7 +111,7 @@
<div>
<i class="fa fa-envelope-o"></i>
{{i18n category.email_in}}
{{textField value=email_in}}
{{text-field value=email_in}}
</div>
<div>
<label class="checkbox-label">
@ -126,7 +126,7 @@
{{#if showPositionInput}}
<section class='field'>
<label>{{i18n category.position}}</label>
{{textField value=position class="position-input"}}
{{text-field value=position class="position-input"}}
</section>
{{else}}
<p>{{i18n category.position_disabled}}</p>

View file

@ -1,7 +1,7 @@
<form>
<div class="modal-body">
<label for='username-or-email'>{{i18n forgot_password.invite}}</label>
{{textField value=accountEmailOrUsername placeholderKey="login.email_placeholder" id="username-or-email" autocorrect="off" autocapitalize="off"}}
{{text-field value=accountEmailOrUsername placeholderKey="login.email_placeholder" id="username-or-email" autocorrect="off" autocapitalize="off"}}
</div>
<div class="modal-footer">
<button class='btn btn-large btn-primary' {{bind-attr disabled="submitDisabled"}} {{action submit}}>{{i18n forgot_password.reset}}</button>

View file

@ -11,7 +11,7 @@
{{else}}
<label>{{inviteInstructions}}</label>
{{textField value=email placeholderKey="topic.invite_reply.email_placeholder"}}
{{text-field value=email placeholderKey="topic.invite_reply.email_placeholder"}}
{{#if isAdmin}}
<label>{{i18n topic.automatically_add_to_groups}}</label>

View file

@ -10,7 +10,7 @@
{{i18n topic.invite_private.success}}
{{else}}
<label>{{i18n topic.invite_private.email_or_username}}</label>
{{userSelector 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 include_groups="true" placeholderKey="topic.invite_private.email_or_username_placeholder"}}
{{/if}}
</div>
<div class="modal-footer">

View file

@ -18,7 +18,7 @@
<label for='login-account-name'>{{i18n login.username}}&nbsp;</label>
</td>
<td>
{{textField value=loginName placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off" autofocus="autofocus"}}
{{text-field value=loginName placeholderKey="login.email_placeholder" id="login-account-name" autocorrect="off" autocapitalize="off" autofocus="autofocus"}}
</td>
<td></td>
</tr>
@ -27,7 +27,7 @@
<label for='login-account-password'>{{i18n login.password}}&nbsp;</label>
</td>
<td>
{{textField value=loginPassword type="password" id="login-account-password"}} &nbsp;
{{text-field value=loginPassword type="password" id="login-account-password"}} &nbsp;
</td>
<td>
<a id="forgot-password-link" {{action showForgotPassword}}>{{i18n forgot_password.action}}</a>

View file

@ -9,7 +9,7 @@
<form>
<label>{{i18n topic.split_topic.topic_name}}</label>
{{textField value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
<label>{{i18n categories.category}}</label>
{{categoryChooser value=categoryId}}

View file

@ -1,4 +1,4 @@
{{view Discourse.SearchTextField valueBinding="term" searchContextBinding="searchContext" id="search-term"}}
{{view 'search-text-field' value=term searchContext=searchContext id="search-term"}}
{{#unless loading}}
{{#unless noResults}}
{{#each resultType in content}}

View file

@ -20,7 +20,7 @@
{{else}}
{{categoryChooser valueAttribute="id" value=newCategoryId source=category_id}}
{{/if}}
{{textField id='edit-title' value=newTitle}}
{{text-field id='edit-title' value=newTitle}}
<button class='btn btn-primary btn-small no-text' {{action finishedEditingTopic}}><i class='fa fa-check'></i></button>
<button class='btn btn-small no-text' {{action cancelEditingTopic}}><i class='fa fa-times'></i></button>

View file

@ -25,7 +25,7 @@
<div class="control-group">
<label class="control-label">{{i18n user.email.title}}</label>
<div class="controls">
{{textField value=newEmail id="change_email" classNames="input-xxlarge"}}
{{text-field value=newEmail id="change_email" classNames="input-xxlarge"}}
</div>
<div class='instructions'>
{{#if taken}}

View file

@ -8,7 +8,7 @@
{{#if showSearch}}
<form>
{{textField value=searchTerm placeholderKey="user.invited.search"}}
{{text-field value=searchTerm placeholderKey="user.invited.search"}}
</form>
{{/if}}

View file

@ -26,7 +26,7 @@
<label class="control-label">{{i18n user.name.title}}</label>
<div class="controls">
{{#if can_edit_name}}
{{textField value=newNameInput classNames="input-xxlarge"}}
{{text-field value=newNameInput classNames="input-xxlarge"}}
{{else}}
<span class='static'>{{name}}</span>
{{/if}}

View file

@ -18,7 +18,7 @@
<div class="control-group">
<label class="control-label">{{i18n user.username.title}}</label>
<div class="controls">
{{textField value=newUsername id="change_username" classNames="input-xxlarge" maxlengthBinding="Discourse.SiteSettings.max_username_length"}}
{{text-field value=newUsername id="change_username" classNames="input-xxlarge" maxlengthBinding="Discourse.SiteSettings.max_username_length"}}
</div>
<div class='instructions'>
{{#if taken}}

View file

@ -176,8 +176,8 @@ Discourse.ComposerView = Discourse.View.extend(Ember.Evented, {
$LAB.script(assetPath('defer/html-sanitizer-bundle'));
Discourse.ComposerView.trigger("initWmdEditor");
var template = Discourse.UserSelector.templateFunction();
var template = this.container.lookupFactory('view:user-selector').templateFunction();
$wmdInput.data('init', true);
$wmdInput.autocomplete({
template: template,

View file

@ -6,7 +6,10 @@
@namespace Discourse
@module Discourse
**/
Discourse.SearchTextField = Discourse.TextField.extend({
import TextField from 'discourse/views/text-field';
export default TextField.extend({
/**
A dynamic placeholder for the search field based on our context
@ -27,7 +30,4 @@ Discourse.SearchTextField = Discourse.TextField.extend({
return I18n.t('search.placeholder');
}.property('searchContext')
});

View file

@ -6,7 +6,7 @@
@namespace Discourse
@module Discourse
**/
Discourse.TextField = Ember.TextField.extend({
export default Ember.TextField.extend({
attributeBindings: ['autocorrect', 'autocapitalize', 'autofocus'],
placeholder: function() {
@ -16,7 +16,4 @@ Discourse.TextField = Ember.TextField.extend({
return '';
}
}.property('placeholderKey')
});
Discourse.View.registerHelper('textField', Discourse.TextField);

View file

@ -0,0 +1,108 @@
import TextField from 'discourse/views/text-field';
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 Discourse.UserSearch.search({
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;

View file

@ -1,103 +0,0 @@
Discourse.UserSelector = Discourse.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: Discourse.UserSelector.templateFunction(),
disabled: this.get('disabled'),
single: this.get('single'),
allowAny: this.get('allowAny'),
dataSource: function(term) {
return Discourse.UserSearch.search({
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 };
}
});
}
});
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(", ");
}
});
Discourse.UserSelector.reopenClass({
// I really want to move this into a template file, but I need a handlebars template here, not an ember one
templateFunction: function() {
this.compiled = this.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 this.compiled;
}
});
Discourse.View.registerHelper('userSelector', Discourse.UserSelector);

View file

@ -19,6 +19,7 @@
//= require ./discourse/controllers/controller
//= require ./discourse/controllers/object_controller
//= require ./discourse/controllers/navigation/default
//= require ./discourse/views/text-field
//= require ./discourse/views/modal/modal_body_view
//= require ./discourse/views/modal/flag_view
//= require ./discourse/views/combobox_view

View file

@ -1,181 +0,0 @@
var controller, oldSearchTextField, oldSearchResultsTypeView, oldViews;
var SearchTextFieldStub = Ember.View.extend({
classNames: ["search-text-field-stub"],
template: Ember.Handlebars.compile("{{view.value}} {{view.searchContext}}")
});
var SearchResultsTypeViewStub = Ember.View.extend({
classNames: ["search-results-type-view-stub"],
template: Ember.Handlebars.compile("{{view.type}} {{view.content}}")
});
var setUpController = function(properties) {
Ember.run(function() {
controller.setProperties(properties);
});
};
var appendView = function() {
Ember.run(function() {
Ember.View.create({
container: Discourse.__container__,
controller: controller,
templateName: "search"
}).appendTo(fixture());
});
};
var resultsSectionSelector = "ul";
var resultsFilterSelector = ".filter";
var noResultsSelector = ".no-results";
var searchInProgressSelector = ".searching";
module("Template: search", {
setup: function() {
sinon.stub(I18n, "t").returnsArg(0);
oldSearchTextField = Discourse.SearchTextField;
Discourse.SearchTextField = SearchTextFieldStub;
oldSearchResultsTypeView = Discourse.SearchResultsTypeView;
Discourse.SearchResultsTypeView = SearchResultsTypeViewStub;
oldViews = Ember.View.views;
Ember.View.views = {};
controller = Ember.ArrayController.create();
},
teardown: function() {
I18n.t.restore();
Discourse.SearchTextField = oldSearchTextField;
Discourse.SearchResultsTypeView = oldSearchResultsTypeView;
Ember.View.views = oldViews;
}
});
test("contain search text field (correctly bound to contextual placeholder and search term values)", function() {
setUpController({
term: "term",
searchContext: "searchContext"
});
appendView();
var $searchTextField = fixture(".search-text-field-stub");
ok(exists($searchTextField), "the field exists");
equal($searchTextField.text(), "term searchContext", "the placeholder and search term values are correctly bound");
});
test("shows spinner icon instead of results area when loading", function() {
setUpController({
loading: true
});
appendView();
ok(exists(fixture(".search-text-field-stub")), "the search field is still shown, even when loading results");
ok(!exists(fixture(resultsSectionSelector)), "no results are shown");
ok(!exists(fixture(noResultsSelector)), "the 'no results' message is not shown");
var $searchInProgress = fixture(searchInProgressSelector);
ok(exists($searchInProgress), "the 'search in progress' message is shown");
ok(exists($searchInProgress.find(".fa-spinner")), "the 'search in progress' message contains a spinner icon");
});
test("shows 'no results' message when loading has finished and there are no results found", function() {
setUpController({
loading: false,
noResults: true
});
appendView();
ok(exists(fixture(".search-text-field-stub")), "the search field is shown to allow another search");
ok(!exists(fixture(resultsSectionSelector)), "no results are shown");
ok(!exists(fixture(searchInProgressSelector)), "the 'search in progress' message is not shown");
var $noResults = fixture(noResultsSelector);
ok(exists($noResults), "the 'no results' message is shown");
notEqual($noResults.text().indexOf("search.no_results"), -1, "the 'no results' message contains correct text");
});
test("shows only search text field when user starts typing a new search term, but there are not enough characters typed yet", function() {
setUpController({
loading: false,
noResults: false,
content: []
});
appendView();
ok(exists(fixture(".search-text-field-stub")), "search text field is shown");
ok(!exists(fixture(resultsSectionSelector)), "no results are shown");
ok(!exists(fixture(searchInProgressSelector)), "the 'search in progress' message is not shown");
ok(!exists(fixture(noResultsSelector)), "the 'no results' message is not shown");
});
test("correctly iterates through and displays search results when the search succeeds", function() {
setUpController({
loading: false,
noResults: false,
content: [
Ember.Object.create({
more: true,
name: "name_1",
results: "results_1",
type: "type_1"
}),
Ember.Object.create({
more: false,
name: "name_2",
results: "results_2",
type: "type_2"
})
]
});
appendView();
var $resultSections = fixture(resultsSectionSelector);
equal(count($resultSections), 2, "the number of sections in results is correct");
var $firstSection = $resultSections.eq(0);
var $filter = $firstSection.find(resultsFilterSelector);
notEqual($firstSection.text().indexOf("name_1"), -1, "the name of the first section is correct");
ok(exists($filter), "the 'show more' link in the first section exists");
notEqual($filter.text().indexOf("show_more"), -1, "the 'show more' link in the first section contains correct text");
equal($firstSection.find(".search-results-type-view-stub").text(), "type_1 results_1", "the results view in the first section is correctly rendered");
var $secondSection = $resultSections.eq(1);
notEqual($secondSection.text().indexOf("name_2"), -1, "the name of the second section is correct");
ok(!exists($secondSection.find(resultsFilterSelector)), "the 'show more' link in the second section does not exist");
equal($secondSection.find(".search-results-type-view-stub").text(), "type_2 results_2", "the results view in the second section is correctly rendered");
});
test("displays 'close more results' button when the search is in the more results mode", function() {
setUpController({
loading: false,
noResults: false,
showCancelFilter: true,
content: [
Ember.Object.create({
more: false
})
]
});
appendView();
var $firstSection = fixture(resultsSectionSelector).eq(0);
var $filter = $firstSection.find(resultsFilterSelector);
ok(exists($filter), "the 'close more results' button exists");
ok(exists($filter.find(".fa-times-circle")), "the 'close more results' contains correct icon");
});

View file

@ -6,13 +6,13 @@ var placeholderUsesKeyAndContext = function(key, context) {
deepEqual(placeholder.context, context, "correct parameters are passed to the message");
};
module("Discourse.SearchTextField", {
module("view:search-text-field", {
setup: function() {
sinon.stub(I18n, "t", function(key, context) {
return {key: key, context: context};
});
view = Discourse.SearchTextField.create();
view = viewClassFor('search-text-field').create();
},
teardown: function() {

View file

@ -1,5 +1,5 @@
var appendTextFieldWithProperties = function(properties) {
var view = Discourse.TextField.create(properties);
var view = viewClassFor('text-field').create(properties);
Ember.run(function() {
view.appendTo(fixture());
});
@ -13,7 +13,7 @@ var hasNoAttr = function($element, attrName) {
equal($element.attr(attrName), undefined, "'" + attrName + "' attribute is not rendered");
};
module("Discourse.TextField");
module("view:text-field");
test("renders correctly with no properties set", function() {
appendTextFieldWithProperties({});