mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
ES6: Migrated and deprecated a bunch of views
This commit is contained in:
parent
c88bff5e0c
commit
580a1bf8b0
64 changed files with 206 additions and 382 deletions
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}} </span>
|
||||
{{/if}}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class='username controls'>
|
||||
{{textField value=username placeholderKey="username"}}
|
||||
{{text-field value=username placeholderKey="username"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
var deprecatedViewHelpers = {
|
||||
inputTip: 'input-tip',
|
||||
pagedown: 'pagedown-editor'
|
||||
pagedown: 'pagedown-editor',
|
||||
textField: 'text-field',
|
||||
userSelector: 'user-selector'
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -1 +1 @@
|
|||
{{textField class="hex-input" value=hexValue maxlength="6"}}
|
||||
{{text-field class="hex-input" value=hexValue maxlength="6"}}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<label for='login-account-name'>{{i18n login.username}} </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}} </label>
|
||||
</td>
|
||||
<td>
|
||||
{{textField value=loginPassword type="password" id="login-account-password"}}
|
||||
{{text-field value=loginPassword type="password" id="login-account-password"}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"}}
|
||||
{{input-tip validation=nameValidation}}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<label for='login-account-name'>{{i18n login.username}} </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}} </label>
|
||||
</td>
|
||||
<td>
|
||||
{{textField value=loginPassword type="password" id="login-account-password"}}
|
||||
{{text-field value=loginPassword type="password" id="login-account-password"}}
|
||||
</td>
|
||||
<td>
|
||||
<a id="forgot-password-link" {{action showForgotPassword}}>{{i18n forgot_password.action}}</a>
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
{{#if showSearch}}
|
||||
<form>
|
||||
{{textField value=searchTerm placeholderKey="user.invited.search"}}
|
||||
{{text-field value=searchTerm placeholderKey="user.invited.search"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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')
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -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);
|
108
app/assets/javascripts/discourse/views/user-selector.js.es6
Normal file
108
app/assets/javascripts/discourse/views/user-selector.js.es6
Normal 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;
|
|
@ -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);
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
});
|
|
@ -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() {
|
||||
|
|
|
@ -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({});
|
||||
|
|
Loading…
Reference in a new issue