Version bump
This commit is contained in:
commit
8f77b478e4
@ -46,6 +46,7 @@
|
||||
"expandSelectBox":true,
|
||||
"collapseSelectBox":true,
|
||||
"selectBoxSelectRow":true,
|
||||
"selectBoxSelectNoneRow":true,
|
||||
"selectBoxFillInFilter":true,
|
||||
"asyncTestDiscourse":true,
|
||||
"fixture":true,
|
||||
|
||||
2
Gemfile
2
Gemfile
@ -172,6 +172,8 @@ gem 'memory_profiler', require: false, platform: :mri
|
||||
|
||||
gem 'cppjieba_rb', require: false
|
||||
|
||||
gem 'lograge', require: false
|
||||
gem 'logstash-logger', require: false
|
||||
gem 'logster'
|
||||
|
||||
gem 'sassc', require: false
|
||||
|
||||
21
Gemfile.lock
21
Gemfile.lock
@ -150,7 +150,15 @@ GEM
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
ruby_dep (~> 1.2)
|
||||
logster (1.2.7)
|
||||
lograge (0.7.1)
|
||||
actionpack (>= 4, < 5.2)
|
||||
activesupport (>= 4, < 5.2)
|
||||
railties (>= 4, < 5.2)
|
||||
request_store (~> 1.0)
|
||||
logstash-event (1.2.02)
|
||||
logstash-logger (0.25.1)
|
||||
logstash-event (~> 1.2)
|
||||
logster (1.2.8)
|
||||
loofah (2.1.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
@ -233,7 +241,7 @@ GEM
|
||||
openid-redis-store (0.0.2)
|
||||
redis
|
||||
ruby-openid
|
||||
parallel (1.11.2)
|
||||
parallel (1.12.0)
|
||||
parser (2.4.0.0)
|
||||
ast (~> 2.2)
|
||||
pg (0.20.0)
|
||||
@ -290,6 +298,7 @@ GEM
|
||||
redis (3.3.5)
|
||||
redis-namespace (1.5.3)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
request_store (1.3.2)
|
||||
rinku (2.0.2)
|
||||
rspec (3.6.0)
|
||||
rspec-core (~> 3.6.0)
|
||||
@ -316,11 +325,11 @@ GEM
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-support (3.6.0)
|
||||
rtlit (0.0.5)
|
||||
rubocop (0.49.1)
|
||||
rubocop (0.51.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.3.3.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
rainbow (>= 2.2.2, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-ll (2.1.2)
|
||||
@ -328,7 +337,7 @@ GEM
|
||||
ast
|
||||
ruby-openid (2.7.0)
|
||||
ruby-prof (0.16.2)
|
||||
ruby-progressbar (1.8.1)
|
||||
ruby-progressbar (1.9.0)
|
||||
ruby-readability (0.7.0)
|
||||
guess_html_encoding (>= 0.0.4)
|
||||
nokogiri (>= 1.6.0)
|
||||
@ -431,6 +440,8 @@ DEPENDENCIES
|
||||
htmlentities
|
||||
http_accept_language (~> 2.0.5)
|
||||
listen
|
||||
lograge
|
||||
logstash-logger
|
||||
logster
|
||||
lru_redux
|
||||
mail
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import loadScript from 'discourse/lib/load-script';
|
||||
import { observes } from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
const LOAD_ASYNC = !Ember.Test;
|
||||
const LOAD_ASYNC = !Ember.testing;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
mode: 'css',
|
||||
classNames: ['ace-wrapper'],
|
||||
_editor: null,
|
||||
_skipContentChangeEvent: null,
|
||||
disabled: false,
|
||||
|
||||
@observes('editorId')
|
||||
editorIdChanged() {
|
||||
@ -30,6 +31,24 @@ export default Ember.Component.extend({
|
||||
}
|
||||
},
|
||||
|
||||
@observes('disabled')
|
||||
disabledStateChanged() {
|
||||
this.changeDisabledState();
|
||||
},
|
||||
|
||||
changeDisabledState() {
|
||||
const editor = this._editor;
|
||||
if (editor) {
|
||||
const disabled = this.get('disabled');
|
||||
editor.setOptions({
|
||||
readOnly: disabled,
|
||||
highlightActiveLine: !disabled,
|
||||
highlightGutterLine: !disabled
|
||||
});
|
||||
editor.container.parentNode.setAttribute("data-disabled", disabled);
|
||||
}
|
||||
},
|
||||
|
||||
_destroyEditor: function() {
|
||||
if (this._editor) {
|
||||
this._editor.destroy();
|
||||
@ -76,6 +95,7 @@ export default Ember.Component.extend({
|
||||
|
||||
this.$().data('editor', editor);
|
||||
this._editor = editor;
|
||||
this.changeDisabledState();
|
||||
|
||||
$(window).off('ace:resize').on('ace:resize', ()=>{
|
||||
this.appEvents.trigger('ace:resize');
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['flag-counts'],
|
||||
|
||||
@computed('details.flag_type_id')
|
||||
title(id) {
|
||||
return I18n.t(`admin.flags.summary.action_type_${id}`, { count: 1 });
|
||||
}
|
||||
});
|
||||
@ -50,5 +50,3 @@ export default Ember.Component.extend({
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
function postActionTitle([id, nameKey]) {
|
||||
let title = I18n.t(`admin.flags.short_names.${nameKey}`, { defaultValue: null });
|
||||
|
||||
// TODO: We can remove this once other translations have been updated
|
||||
if (!title) {
|
||||
return I18n.t(`admin.flags.summary.action_type_${id}`, { count: 1 });
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
export default Ember.Helper.helper(postActionTitle);
|
||||
@ -1,5 +1,6 @@
|
||||
export default Discourse.Route.extend({
|
||||
redirect() {
|
||||
this.replaceWith('adminFlags.postsActive');
|
||||
let segment = this.siteSettings.flags_default_topics ? 'topics' : 'postsActive';
|
||||
this.replaceWith(`adminFlags.${segment}`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -26,9 +26,7 @@
|
||||
{{combo-box name="badge_type_id"
|
||||
value=buffered.badge_type_id
|
||||
content=badgeTypes
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"
|
||||
disabled=readOnly}}
|
||||
isDisabled=readOnly}}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@ -36,8 +34,7 @@
|
||||
{{combo-box name="badge_grouping_id"
|
||||
value=buffered.badge_grouping_id
|
||||
content=badgeGroupings
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.displayName"}}
|
||||
nameProperty="name"}}
|
||||
<button {{action "editGroupings"}} class='btn'>{{d-icon 'pencil'}}</button>
|
||||
</div>
|
||||
|
||||
@ -63,7 +60,7 @@
|
||||
{{#if siteSettings.enable_badge_sql}}
|
||||
<div>
|
||||
<label for="query">{{i18n 'admin.badges.query'}}</label>
|
||||
{{textarea name="query" value=buffered.query disabled=readOnly}}
|
||||
{{ace-editor content=buffered.query mode="sql" disabled=readOnly}}
|
||||
</div>
|
||||
|
||||
{{#if hasQuery}}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{{#if editing}}
|
||||
{{#admin-form-row label="admin.user_fields.type"}}
|
||||
{{combo-box content=fieldTypes valueAttribute="id" value=buffered.field_type}}
|
||||
{{combo-box content=fieldTypes value=buffered.field_type}}
|
||||
{{/admin-form-row}}
|
||||
|
||||
{{#admin-form-row label="admin.user_fields.name"}}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
{{input value=buffered.path_whitelist placeholder="/blog/.*" enter="save" class="path-whitelist"}}
|
||||
</td>
|
||||
<td>
|
||||
{{category-select-box value=categoryId class="small"}}
|
||||
{{category-chooser value=categoryId class="small"}}
|
||||
</td>
|
||||
<td>
|
||||
{{d-button icon="check" action="save" class="btn-primary" disabled=cantSave}}
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
<span class='type-name'>{{title}}</span>
|
||||
<span class='type-count'>x{{details.count}}</span>
|
||||
@ -73,7 +73,7 @@
|
||||
{{#each flaggedPost.post_actions as |postAction|}}
|
||||
{{#flag-user user=postAction.user date=postAction.created_at}}
|
||||
<div class='flagger-flag-type'>
|
||||
{{i18n (concat "admin.flags.summary.action_type_" postAction.post_action_type_id) count=1}}
|
||||
{{post-action-title postAction.post_action_type_id postAction.name_key}}
|
||||
</div>
|
||||
{{/flag-user}}
|
||||
{{/each}}
|
||||
|
||||
@ -36,8 +36,7 @@
|
||||
|
||||
<h3>{{i18n "admin.customize.theme.color_scheme"}}</h3>
|
||||
<p>{{i18n "admin.customize.theme.color_scheme_select"}}</p>
|
||||
<p>{{select-box content=colorSchemes
|
||||
textKey="name"
|
||||
<p>{{combo-box content=colorSchemes
|
||||
filterable=true
|
||||
value=colorSchemeId
|
||||
icon="paint-brush"}}
|
||||
@ -123,11 +122,8 @@
|
||||
</ul>
|
||||
{{/unless}}
|
||||
{{#if selectableChildThemes}}
|
||||
<p>{{combo-box content=selectableChildThemes
|
||||
nameProperty="name"
|
||||
value=selectedChildThemeId
|
||||
valueAttribute="id"}}
|
||||
|
||||
<p>
|
||||
{{combo-box content=selectableChildThemes value=selectedChildThemeId}}
|
||||
{{#d-button action="addChildTheme" icon="plus"}}{{i18n "admin.customize.theme.add"}}{{/d-button}}
|
||||
</p>
|
||||
{{/if}}
|
||||
|
||||
@ -19,7 +19,10 @@
|
||||
</td>
|
||||
<td>
|
||||
{{#each ft.flag_counts as |fc|}}
|
||||
{{flag-counts details=fc}}
|
||||
<div class='flag-counts'>
|
||||
<span class='type-name'>{{post-action-title fc.post_action_type_id fc.name_key}}</span>
|
||||
<span class='type-count'>x{{fc.count}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</td>
|
||||
<td class='flagged-topic-users'>
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
{{#admin-nav}}
|
||||
{{nav-item route='adminFlags.postsActive' label='admin.flags.active_posts'}}
|
||||
{{nav-item route='adminFlags.topics' label='admin.flags.topics'}}
|
||||
{{#if siteSettings.flags_default_topics}}
|
||||
{{nav-item route='adminFlags.topics' label='admin.flags.topics'}}
|
||||
{{nav-item route='adminFlags.postsActive' label='admin.flags.active_posts'}}
|
||||
{{else}}
|
||||
{{nav-item route='adminFlags.postsActive' label='admin.flags.active_posts'}}
|
||||
{{nav-item route='adminFlags.topics' label='admin.flags.topics'}}
|
||||
{{/if}}
|
||||
|
||||
{{nav-item route='adminFlags.postsOld' label='admin.flags.old_posts' class='right'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class='control'>
|
||||
{{combo-box content=groups valueAttribute="id" value=groupId none="admin.groups.bulk_select"}}
|
||||
{{combo-box filterable=true content=groups value=groupId none="admin.groups.bulk_select"}}
|
||||
</div>
|
||||
|
||||
<div class='control'>
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{i18n "admin.logs.staff_actions.filter"}} {{combo-box content=userHistoryActions nameProperty="name" value=filterActionId none="admin.logs.staff_actions.all"}}
|
||||
{{i18n "admin.logs.staff_actions.filter"}} {{combo-box content=userHistoryActions value=filterActionId none="admin.logs.staff_actions.all"}}
|
||||
{{/if}}
|
||||
|
||||
<div class="pull-right">
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
{{#d-modal-body title="admin.customize.colors.select_base.title"}}
|
||||
{{i18n "admin.customize.colors.select_base.description"}}
|
||||
{{combo-box content=model
|
||||
nameProperty="name"
|
||||
value=selectedBaseThemeId
|
||||
valueAttribute="base_scheme_id"}}
|
||||
{{/d-modal-body}}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
{{future-date-input
|
||||
class="suspend-until"
|
||||
label="admin.user.suspend_duration"
|
||||
includeForever=true
|
||||
includeFarFuture=true
|
||||
input=suspendUntil}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
{{i18n 'admin.dashboard.reports.start_date'}} {{date-picker-past value=startDate defaultDate=startDate}}
|
||||
{{i18n 'admin.dashboard.reports.end_date'}} {{date-picker-past value=endDate defaultDate=endDate}}
|
||||
{{#if showCategoryOptions}}
|
||||
{{combo-box valueAttribute="value" content=categoryOptions value=categoryId}}
|
||||
{{combo-box filterable=true valueAttribute="value" content=categoryOptions value=categoryId}}
|
||||
{{/if}}
|
||||
{{#if showGroupOptions}}
|
||||
{{combo-box valueAttribute="value" content=groupOptions value=groupId}}
|
||||
{{combo-box filterable=true valueAttribute="value" content=groupOptions value=groupId}}
|
||||
{{/if}}
|
||||
{{d-button action="refreshReport" class="btn-primary" label="admin.dashboard.reports.refresh_report" icon="refresh"}}
|
||||
{{d-button action="exportCsv" label="admin.export_csv.button_text" icon="download"}}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<form class="form-horizontal">
|
||||
<div>
|
||||
<label>{{i18n 'admin.badges.badge'}}</label>
|
||||
{{combo-box valueAttribute="id" value=selectedBadgeId content=grantableBadges nameProperty="name"}}
|
||||
{{combo-box filterable=true value=selectedBadgeId content=grantableBadges}}
|
||||
</div>
|
||||
<label>
|
||||
<label>{{i18n 'admin.badges.reason'}}</label>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<section class="details {{unless model.active 'not-activated'}}">
|
||||
|
||||
<div class='user-controls'>
|
||||
{{#if model.canViewProfile}}
|
||||
{{#link-to 'user' model class="btn"}}
|
||||
@ -379,7 +378,7 @@
|
||||
<div class='controls'>
|
||||
{{#if model.customGroups}}
|
||||
{{i18n 'admin.groups.primary'}}
|
||||
{{combo-box content=model.customGroups value=model.primary_group_id nameProperty="name" none="admin.groups.no_primary"}}
|
||||
{{combo-box content=model.customGroups value=model.primary_group_id none="admin.groups.no_primary"}}
|
||||
{{/if}}
|
||||
{{#if primaryGroupDirty}}
|
||||
{{d-button icon="check" class="ok" action="savePrimaryGroup"}}
|
||||
|
||||
@ -6,15 +6,13 @@
|
||||
{{/if}}
|
||||
|
||||
<div class="admin-title">
|
||||
<div class="pull-left">
|
||||
<h2>{{title}}</h2>
|
||||
</div>
|
||||
<h2>{{title}}</h2>
|
||||
</div>
|
||||
<div class='username controls'>
|
||||
{{text-field value=listFilter placeholder=searchHint}}
|
||||
{{#unless showEmails}}
|
||||
<div class="pull-right">
|
||||
<button {{action "showEmails"}} class="btn">{{i18n 'admin.users.show_emails'}}</button>
|
||||
<button {{action "showEmails"}} class="show-emails btn">{{i18n 'admin.users.show_emails'}}</button>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
@ -28,7 +26,7 @@
|
||||
{{/if}}
|
||||
<th> </th>
|
||||
<th>{{i18n 'username'}}</th>
|
||||
<th>{{i18n 'email'}}</th>
|
||||
<th class='email-heading'>{{i18n 'email'}}</th>
|
||||
<th>{{i18n 'admin.users.last_emailed'}}</th>
|
||||
{{admin-directory-toggle field="seen" i18nKey='last_seen' order=order ascending=ascending}}
|
||||
{{admin-directory-toggle field="topics_viewed" i18nKey="admin.user.topics_entered" order=order ascending=ascending}}
|
||||
|
||||
@ -16,8 +16,6 @@
|
||||
<label for='content-type'>{{i18n 'admin.web_hooks.content_type'}}</label>
|
||||
{{combo-box content=contentTypes
|
||||
name="content-type"
|
||||
nameProperty="name"
|
||||
valueAttribute="id"
|
||||
value=model.content_type}}
|
||||
</div>
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
//= require ./ember-addons/ember-computed-decorators
|
||||
//= require ./ember-addons/fmt
|
||||
//= require_tree ./discourse-common
|
||||
//= require_tree ./select-box-kit
|
||||
//= require ./discourse
|
||||
//= require ./deprecated
|
||||
|
||||
|
||||
@ -1,146 +0,0 @@
|
||||
import { bufferedRender } from 'discourse-common/lib/buffered-render';
|
||||
import { on, observes } from 'ember-addons/ember-computed-decorators';
|
||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||
|
||||
export default Ember.Component.extend(bufferedRender({
|
||||
tagName: 'select',
|
||||
attributeBindings: ['tabindex', 'disabled'],
|
||||
classNames: ['combobox'],
|
||||
valueAttribute: 'id',
|
||||
nameProperty: 'name',
|
||||
|
||||
buildBuffer(buffer) {
|
||||
const nameProperty = this.get('nameProperty');
|
||||
const none = this.get('none');
|
||||
let noneValue = null;
|
||||
|
||||
// Add none option if required
|
||||
if (typeof none === "string") {
|
||||
buffer.push('<option value="">' + I18n.t(none) + "</option>");
|
||||
} else if (typeof none === "object") {
|
||||
noneValue = Em.get(none, this.get('valueAttribute'));
|
||||
buffer.push(`<option value="${noneValue}">${Em.get(none, nameProperty)}</option>`);
|
||||
}
|
||||
|
||||
let selected = this.get('value');
|
||||
if (!Em.isNone(selected)) { selected = selected.toString(); }
|
||||
|
||||
let selectedFound = false;
|
||||
let firstVal = undefined;
|
||||
const content = this.get('content');
|
||||
|
||||
if (content) {
|
||||
let first = true;
|
||||
content.forEach(o => {
|
||||
let val = o[this.get('valueAttribute')];
|
||||
if (typeof val === "undefined") { val = o; }
|
||||
if (!Em.isNone(val)) { val = val.toString(); }
|
||||
|
||||
const selectedText = (val === selected) ? "selected" : "";
|
||||
const name = Handlebars.Utils.escapeExpression(Ember.get(o, nameProperty) || o);
|
||||
|
||||
if (val === selected) {
|
||||
selectedFound = true;
|
||||
}
|
||||
if (first) {
|
||||
firstVal = val;
|
||||
first = false;
|
||||
}
|
||||
buffer.push(`<option ${selectedText} value="${val}">${name}</option>`);
|
||||
});
|
||||
}
|
||||
|
||||
if (!selectedFound && !noneValue) {
|
||||
if (none) {
|
||||
this.set('value', null);
|
||||
} else {
|
||||
this.set('value', firstVal);
|
||||
}
|
||||
}
|
||||
|
||||
Ember.run.scheduleOnce('afterRender', this, this._updateSelect2);
|
||||
},
|
||||
|
||||
@observes('value')
|
||||
valueChanged() {
|
||||
const $combo = this.$(),
|
||||
val = this.get('value');
|
||||
|
||||
if (val !== undefined && val !== null) {
|
||||
$combo.select2('val', val.toString());
|
||||
} else {
|
||||
$combo.select2('val', null);
|
||||
}
|
||||
},
|
||||
|
||||
@observes('content.[]')
|
||||
_rerenderOnChange() {
|
||||
this.rerenderBuffer();
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
// Workaround for https://github.com/emberjs/ember.js/issues/9813
|
||||
// Can be removed when fixed. Without it, the wrong option is selected
|
||||
this.$('option').each((i, o) => o.selected = !!$(o).attr('selected'));
|
||||
|
||||
// observer for item names changing (optional)
|
||||
if (this.get('nameChanges')) {
|
||||
this.addObserver('content.@each.' + this.get('nameProperty'), this.rerenderBuffer);
|
||||
}
|
||||
|
||||
const $elem = this.$();
|
||||
const caps = this.capabilities;
|
||||
const minimumResultsForSearch = this.get('minimumResultsForSearch') || ((caps && caps.isIOS) ? -1 : 5);
|
||||
|
||||
if (!this.get("selectionTemplate") && this.get("selectionIcon")) {
|
||||
this.selectionTemplate = (item) => {
|
||||
let name = Em.get(item, 'text');
|
||||
name = Handlebars.escapeExpression(name);
|
||||
return iconHTML(this.get('selectionIcon')) + name;
|
||||
};
|
||||
}
|
||||
|
||||
const options = {
|
||||
minimumResultsForSearch,
|
||||
width: this.get('width') || 'resolve',
|
||||
allowClear: true
|
||||
};
|
||||
|
||||
if (this.comboTemplate) {
|
||||
options.formatResult = this.comboTemplate.bind(this);
|
||||
}
|
||||
|
||||
if (this.selectionTemplate) {
|
||||
options.formatSelection = this.selectionTemplate.bind(this);
|
||||
}
|
||||
|
||||
$elem.select2(options);
|
||||
|
||||
const castInteger = this.get('castInteger');
|
||||
$elem.on("change", e => {
|
||||
let val = $(e.target).val();
|
||||
if (val && val.length && castInteger) {
|
||||
val = parseInt(val, 10);
|
||||
}
|
||||
Ember.run(() => this.set('value', val));
|
||||
});
|
||||
|
||||
Ember.run.scheduleOnce('afterRender', this, this._triggerChange);
|
||||
},
|
||||
|
||||
_updateSelect2() {
|
||||
this.$().trigger('change.select2');
|
||||
},
|
||||
|
||||
_triggerChange() {
|
||||
this.$().trigger('change');
|
||||
},
|
||||
|
||||
@on('willDestroyElement')
|
||||
_destroyDropdown() {
|
||||
this.$().select2('destroy');
|
||||
}
|
||||
|
||||
}));
|
||||
@ -1,6 +1,8 @@
|
||||
import showModal from 'discourse/lib/show-modal';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['bulk-select-container'],
|
||||
|
||||
actions: {
|
||||
showBulkActions() {
|
||||
const controller = showModal('topic-bulk-actions', {
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
classNames: ["categories-admin-dropdown"],
|
||||
|
||||
icon: `${iconHTML('bars')}${iconHTML('caret-down')}`.htmlSafe(),
|
||||
|
||||
generatedHeadertext: null,
|
||||
|
||||
@computed
|
||||
content() {
|
||||
const items = [
|
||||
{
|
||||
id: "create",
|
||||
text: I18n.t("category.create"),
|
||||
description: I18n.t("category.create_long"),
|
||||
icon: "plus"
|
||||
}
|
||||
];
|
||||
|
||||
const includeReorder = this.get("siteSettings.fixed_category_positions");
|
||||
if (includeReorder) {
|
||||
items.push({
|
||||
id: "reorder",
|
||||
text: I18n.t("categories.reorder.title"),
|
||||
description: I18n.t("categories.reorder.title_long"),
|
||||
icon: "random"
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
|
||||
actionNames: {
|
||||
create: "createCategory",
|
||||
reorder: "reorderCategories"
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.sendAction(`actionNames.${this.get("value")}`);
|
||||
this.set("value", null);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,88 +0,0 @@
|
||||
import Combobox from 'discourse-common/components/combo-box';
|
||||
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { observes, on } from 'ember-addons/ember-computed-decorators';
|
||||
import PermissionType from 'discourse/models/permission-type';
|
||||
import Category from 'discourse/models/category';
|
||||
|
||||
export default Combobox.extend({
|
||||
classNames: ['combobox category-combobox'],
|
||||
dataAttributes: ['id', 'description_text'],
|
||||
overrideWidths: true,
|
||||
castInteger: true,
|
||||
|
||||
@computed("scopedCategoryId", "categories")
|
||||
content(scopedCategoryId, categories) {
|
||||
// Always scope to the parent of a category, if present
|
||||
if (scopedCategoryId) {
|
||||
const scopedCat = Category.findById(scopedCategoryId);
|
||||
scopedCategoryId = scopedCat.get('parent_category_id') || scopedCat.get('id');
|
||||
}
|
||||
|
||||
const excludeCategoryId = this.get('excludeCategoryId');
|
||||
|
||||
return categories.filter(c => {
|
||||
const categoryId = c.get('id');
|
||||
if (scopedCategoryId && categoryId !== scopedCategoryId && c.get('parent_category_id') !== scopedCategoryId) { return false; }
|
||||
if (c.get('isUncategorizedCategory') || excludeCategoryId === categoryId) { return false; }
|
||||
return c.get('permission') === PermissionType.FULL;
|
||||
});
|
||||
},
|
||||
|
||||
@on("init")
|
||||
@observes("site.sortedCategories")
|
||||
_updateCategories() {
|
||||
if (!this.get('categories')) {
|
||||
const categories = Discourse.SiteSettings.fixed_category_positions_on_create ?
|
||||
Category.list() :
|
||||
Category.listByActivity();
|
||||
this.set('categories', categories);
|
||||
}
|
||||
},
|
||||
|
||||
@computed("rootNone", "rootNoneLabel")
|
||||
none(rootNone, rootNoneLabel) {
|
||||
if (this.siteSettings.allow_uncategorized_topics || this.get('allowUncategorized')) {
|
||||
if (rootNone) {
|
||||
return rootNoneLabel || "category.none";
|
||||
} else {
|
||||
return Category.findUncategorized();
|
||||
}
|
||||
} else {
|
||||
return 'category.choose';
|
||||
}
|
||||
},
|
||||
|
||||
comboTemplate(item) {
|
||||
let category;
|
||||
|
||||
// If we have no id, but text with the uncategorized name, we can use that badge.
|
||||
if (Ember.isEmpty(item.id)) {
|
||||
const uncat = Category.findUncategorized();
|
||||
if (uncat && uncat.get('name') === item.text) {
|
||||
category = uncat;
|
||||
}
|
||||
} else {
|
||||
category = Category.findById(parseInt(item.id,10));
|
||||
}
|
||||
|
||||
if (!category) return item.text;
|
||||
let result = categoryBadgeHTML(category, {link: false, allowUncategorized: true, hideParent: true});
|
||||
const parentCategoryId = category.get('parent_category_id');
|
||||
|
||||
if (parentCategoryId) {
|
||||
result = categoryBadgeHTML(Category.findById(parentCategoryId), {link: false}) + " " + result;
|
||||
}
|
||||
|
||||
result += ` <span class='topic-count'>× ${category.get('topic_count')}</span>`;
|
||||
|
||||
const description = category.get('description');
|
||||
// TODO wtf how can this be null?;
|
||||
if (description && description !== 'null') {
|
||||
result += `<div class="category-desc">${description.substr(0, 200)}${description.length > 200 ? '…' : ''}</div>`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,28 +0,0 @@
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["category-notifications-button"],
|
||||
|
||||
hidden: Ember.computed.or("category.deleted", "site.isMobileDevice"),
|
||||
|
||||
i18nPrefix: "category.notifications",
|
||||
|
||||
value: Em.computed.alias("category.notification_level"),
|
||||
|
||||
@computed("value")
|
||||
icon() {
|
||||
return `${this._super()}${iconHTML("caret-down")}`.htmlSafe();
|
||||
},
|
||||
|
||||
generatedHeadertext: null,
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.get("category").setNotification(this.get("value"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,162 +0,0 @@
|
||||
import SelectBoxComponent from "discourse/components/select-box";
|
||||
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
||||
import { observes, on } from "ember-addons/ember-computed-decorators";
|
||||
import PermissionType from "discourse/models/permission-type";
|
||||
import Category from "discourse/models/category";
|
||||
|
||||
export default SelectBoxComponent.extend({
|
||||
classNames: ["category-select-box"],
|
||||
|
||||
selectBoxRowComponent: "category-select-box/category-select-box-row",
|
||||
|
||||
textKey: "name",
|
||||
|
||||
filterable: true,
|
||||
|
||||
castInteger: true,
|
||||
|
||||
clearable: true,
|
||||
|
||||
allowUncategorized: null,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
if (!Ember.isNone(this.get("categories"))) {
|
||||
this.set("content", this.get("categories"));
|
||||
this._scopeCategories();
|
||||
}
|
||||
|
||||
if (Ember.isNone(this.get("value"))) {
|
||||
if (this.siteSettings.allow_uncategorized_topics && this.get("allowUncategorized") !== false) {
|
||||
this.set("value", Category.findUncategorized().id);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
filterFunction: function(content) {
|
||||
const _matchFunction = (filter, text) => {
|
||||
return text.toLowerCase().indexOf(filter) > -1;
|
||||
};
|
||||
|
||||
return (selectBox) => {
|
||||
const filter = selectBox.get("filter").toLowerCase();
|
||||
return _.filter(content, (c) => {
|
||||
const category = Category.findById(c[selectBox.get("idKey")]);
|
||||
const text = c[selectBox.get("textKey")];
|
||||
if (category && category.get("parentCategory")) {
|
||||
const categoryName = category.get("parentCategory.name");
|
||||
return _matchFunction(filter, text) || _matchFunction(filter, categoryName);
|
||||
} else {
|
||||
return _matchFunction(filter, text);
|
||||
}
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
@on("init")
|
||||
@observes("selectedContent")
|
||||
_setHeaderText: function() {
|
||||
let headerText;
|
||||
|
||||
if (Ember.isNone(this.get("selectedContent"))) {
|
||||
if (this.siteSettings.allow_uncategorized_topics) {
|
||||
headerText = Ember.get(Category.findUncategorized(), this.get("textKey"));
|
||||
} else {
|
||||
headerText = I18n.t("category.choose").htmlSafe();
|
||||
}
|
||||
} else {
|
||||
headerText = this.get("selectedContent.text");
|
||||
}
|
||||
|
||||
this.set("headerText", headerText);
|
||||
},
|
||||
|
||||
templateForRow: function() {
|
||||
return (rowComponent) => this.rowContentTemplate(rowComponent.get("content"));
|
||||
}.property(),
|
||||
|
||||
@observes("scopedCategoryId", "categories")
|
||||
_scopeCategories() {
|
||||
let scopedCategoryId = this.get("scopedCategoryId");
|
||||
const categories = this.get("categories");
|
||||
|
||||
// Always scope to the parent of a category, if present
|
||||
if (scopedCategoryId) {
|
||||
const scopedCat = Category.findById(scopedCategoryId);
|
||||
scopedCategoryId = scopedCat.get("parent_category_id") || scopedCat.get("id");
|
||||
}
|
||||
|
||||
const excludeCategoryId = this.get("excludeCategoryId");
|
||||
|
||||
const filteredCategories = categories.filter(c => {
|
||||
const categoryId = c.get("id");
|
||||
if (scopedCategoryId && categoryId !== scopedCategoryId && c.get("parent_category_id") !== scopedCategoryId) { return false; }
|
||||
if (excludeCategoryId === categoryId) { return false; }
|
||||
if (this.get("allowUncategorized") === false && c.get("isUncategorizedCategory")) { return false; }
|
||||
if (this.get("allowUncategorized") !== true) {
|
||||
if (!this.siteSettings.allow_uncategorized_topics && c.get("isUncategorizedCategory")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return c.get("permission") === PermissionType.FULL;
|
||||
});
|
||||
|
||||
this.set("content", filteredCategories);
|
||||
},
|
||||
|
||||
@on("didRender")
|
||||
_bindComposerResizing() {
|
||||
this.appEvents.on("composer:resized", this, this.applyDirection);
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
_unbindComposerResizing() {
|
||||
this.appEvents.off("composer:resized");
|
||||
},
|
||||
|
||||
@on("init")
|
||||
@observes("site.sortedCategories")
|
||||
_updateCategories() {
|
||||
if (!this.get("categories")) {
|
||||
const categories = Discourse.SiteSettings.fixed_category_positions_on_create ?
|
||||
Category.list() :
|
||||
Category.listByActivity();
|
||||
this.set("categories", categories);
|
||||
}
|
||||
},
|
||||
|
||||
rowContentTemplate(item) {
|
||||
let category;
|
||||
|
||||
// If we have no id, but text with the uncategorized name, we can use that badge.
|
||||
if (Ember.isEmpty(item.id)) {
|
||||
const uncat = Category.findUncategorized();
|
||||
if (uncat && uncat.get("name") === item.text) {
|
||||
category = uncat;
|
||||
}
|
||||
} else {
|
||||
category = Category.findById(parseInt(item.id,10));
|
||||
}
|
||||
|
||||
if (!category) return item.text;
|
||||
let result = categoryBadgeHTML(category, {link: false, allowUncategorized: true, hideParent: true});
|
||||
const parentCategoryId = category.get("parent_category_id");
|
||||
|
||||
if (parentCategoryId) {
|
||||
result = `<div class="category-status">${categoryBadgeHTML(Category.findById(parentCategoryId), {link: false})} ${result}`;
|
||||
} else {
|
||||
result = `<div class="category-status">${result}`;
|
||||
}
|
||||
|
||||
result += ` <span class="topic-count">× ${category.get("topic_count")}</span></div>`;
|
||||
|
||||
const description = category.get("description");
|
||||
// TODO wtf how can this be null?;
|
||||
if (description && description !== "null") {
|
||||
result += `<div class="category-desc">${description.substr(0, 200)}${description.length > 200 ? '…' : ''}</div>`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
@ -1,13 +0,0 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import SelectBoxRowComponent from "discourse/components/select-box/select-box-row";
|
||||
import Category from "discourse/models/category";
|
||||
|
||||
export default SelectBoxRowComponent.extend({
|
||||
classNameBindings: ["isUncategorized"],
|
||||
|
||||
@computed("content")
|
||||
isUncategorized(content) {
|
||||
const category = Category.findById(content.id);
|
||||
return category.get("isUncategorizedCategory");
|
||||
}
|
||||
});
|
||||
@ -101,24 +101,6 @@ class Toolbar {
|
||||
perform: e => e.applyList(i => !i ? "1. " : `${parseInt(i) + 1}. `, 'list_item')
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'heading',
|
||||
group: 'extras',
|
||||
icon: 'header',
|
||||
label: getButtonLabel('composer.heading_label', 'H'),
|
||||
shortcut: 'Alt+1',
|
||||
perform: e => e.applyList('## ', 'heading_text')
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'rule',
|
||||
group: 'extras',
|
||||
icon: 'minus',
|
||||
shortcut: 'Alt+R',
|
||||
title: 'composer.hr_title',
|
||||
perform: e => e.addText("\n\n----------\n")
|
||||
});
|
||||
|
||||
if (site.mobileView) {
|
||||
this.groups.push({group: 'mobileExtras', buttons: []});
|
||||
}
|
||||
@ -233,7 +215,7 @@ export default Ember.Component.extend({
|
||||
const shortcuts = this.get('toolbar.shortcuts');
|
||||
|
||||
// for some reason I am having trouble bubbling this so hack it in
|
||||
mouseTrap.bind(['ctrl+shift+s','command+shift+s'], (event) =>{
|
||||
mouseTrap.bind(['ctrl+alt+f'], (event) =>{
|
||||
this.appEvents.trigger('header:keyboard-trigger', {type: 'search', event});
|
||||
return true;
|
||||
});
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import SelectBoxComponent from "discourse/components/select-box";
|
||||
|
||||
export default SelectBoxComponent.extend({
|
||||
classNames: ["dropdown-select-box"],
|
||||
wrapper: false,
|
||||
verticalOffset: 3,
|
||||
collectionHeight: "auto",
|
||||
fullWidthOnMobile: true,
|
||||
selectBoxHeaderComponent: "dropdown-select-box/dropdown-header",
|
||||
|
||||
@computed
|
||||
templateForRow: function() {
|
||||
return (rowComponent) => {
|
||||
let template = "";
|
||||
const content = rowComponent.get("content");
|
||||
|
||||
const icon = rowComponent.icon();
|
||||
if (icon) {
|
||||
template += `<div class="icons">${icon}</div>`;
|
||||
}
|
||||
|
||||
template += `
|
||||
<div class="texts">
|
||||
<span class="title">${Handlebars.escapeExpression(Ember.get(content, this.get("textKey")))}</span>
|
||||
<span class="desc">${Handlebars.escapeExpression(content.description)}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return template;
|
||||
};
|
||||
}
|
||||
});
|
||||
@ -1,7 +0,0 @@
|
||||
import SelectBoxHeaderComponent from "discourse/components/select-box/select-box-header";
|
||||
|
||||
export default SelectBoxHeaderComponent.extend({
|
||||
layoutName: "components/dropdown-select-box/dropdown-header",
|
||||
|
||||
classNames: ["dropdown-header"]
|
||||
});
|
||||
@ -20,6 +20,8 @@ export default buildCategoryPanel('security', {
|
||||
permission: PermissionType.create({ id: parseInt(id) })
|
||||
});
|
||||
}
|
||||
|
||||
this.set('selectedGroup', this.get('category.availableGroups.firstObject'));
|
||||
},
|
||||
|
||||
removePermission(permission) {
|
||||
|
||||
@ -2,6 +2,7 @@ import { MAX_MESSAGE_LENGTH } from 'discourse/models/post-action-type';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['flag-action-type'],
|
||||
|
||||
@computed('flag.name_key')
|
||||
customPlaceholder(nameKey) {
|
||||
|
||||
@ -1,207 +0,0 @@
|
||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
||||
import Combobox from 'discourse-common/components/combo-box';
|
||||
import { CLOSE_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer';
|
||||
|
||||
const LATER_TODAY = 'later_today';
|
||||
const TOMORROW = 'tomorrow';
|
||||
const LATER_THIS_WEEK = 'later_this_week';
|
||||
const THIS_WEEKEND = 'this_weekend';
|
||||
const NEXT_WEEK = 'next_week';
|
||||
const TWO_WEEKS = 'two_weeks';
|
||||
const NEXT_MONTH = 'next_month';
|
||||
const FOREVER = 'forever';
|
||||
|
||||
export const PICK_DATE_AND_TIME = 'pick_date_and_time';
|
||||
export const SET_BASED_ON_LAST_POST = 'set_based_on_last_post';
|
||||
|
||||
export const FORMAT = 'YYYY-MM-DD HH:mm';
|
||||
|
||||
export default Combobox.extend({
|
||||
classNames: ['future-date-input-selector'],
|
||||
isCustom: Ember.computed.equal("value", PICK_DATE_AND_TIME),
|
||||
|
||||
@computed()
|
||||
content() {
|
||||
const selections = [];
|
||||
const now = moment();
|
||||
const canScheduleToday = (24 - now.hour()) > 6;
|
||||
const day = now.day();
|
||||
|
||||
if (canScheduleToday) {
|
||||
selections.push({
|
||||
id: LATER_TODAY,
|
||||
name: I18n.t('topic.auto_update_input.later_today')
|
||||
});
|
||||
}
|
||||
|
||||
selections.push({
|
||||
id: TOMORROW,
|
||||
name: I18n.t('topic.auto_update_input.tomorrow')
|
||||
});
|
||||
|
||||
if (!canScheduleToday && day < 4) {
|
||||
selections.push({
|
||||
id: LATER_THIS_WEEK,
|
||||
name: I18n.t('topic.auto_update_input.later_this_week')
|
||||
});
|
||||
}
|
||||
|
||||
if (day < 5 && this.get('includeWeekend')) {
|
||||
selections.push({
|
||||
id: THIS_WEEKEND,
|
||||
name: I18n.t('topic.auto_update_input.this_weekend')
|
||||
});
|
||||
}
|
||||
|
||||
if (day !== 7) {
|
||||
selections.push({
|
||||
id: NEXT_WEEK,
|
||||
name: I18n.t('topic.auto_update_input.next_week')
|
||||
});
|
||||
}
|
||||
|
||||
selections.push({
|
||||
id: TWO_WEEKS,
|
||||
name: I18n.t('topic.auto_update_input.two_weeks')
|
||||
});
|
||||
|
||||
if (moment().endOf('month').date() !== now.date()) {
|
||||
selections.push({
|
||||
id: NEXT_MONTH,
|
||||
name: I18n.t('topic.auto_update_input.next_month')
|
||||
});
|
||||
}
|
||||
|
||||
if (this.get('includeForever')) {
|
||||
selections.push({
|
||||
id: FOREVER,
|
||||
name: I18n.t('topic.auto_update_input.forever')
|
||||
});
|
||||
}
|
||||
|
||||
selections.push({
|
||||
id: PICK_DATE_AND_TIME,
|
||||
name: I18n.t('topic.auto_update_input.pick_date_and_time')
|
||||
});
|
||||
|
||||
if (this.get('statusType') === CLOSE_STATUS_TYPE) {
|
||||
selections.push({
|
||||
id: SET_BASED_ON_LAST_POST,
|
||||
name: I18n.t('topic.auto_update_input.set_based_on_last_post')
|
||||
});
|
||||
}
|
||||
|
||||
return selections;
|
||||
},
|
||||
|
||||
@observes('value')
|
||||
_updateInput() {
|
||||
if (this.get('isCustom')) return;
|
||||
let input = null;
|
||||
const { time } = this.get('updateAt');
|
||||
|
||||
if (time && !Ember.isEmpty(this.get('value'))) {
|
||||
input = time.format(FORMAT);
|
||||
}
|
||||
|
||||
this.set('input', input);
|
||||
},
|
||||
|
||||
@computed('value')
|
||||
updateAt(value) {
|
||||
return this._updateAt(value);
|
||||
},
|
||||
|
||||
comboTemplate(state) {
|
||||
return this._format(state);
|
||||
},
|
||||
|
||||
selectionTemplate(state) {
|
||||
return this._format(state);
|
||||
},
|
||||
|
||||
_format(state) {
|
||||
let { time, icon } = this._updateAt(state.id);
|
||||
let icons;
|
||||
|
||||
if (icon) {
|
||||
icons = icon.split(',').map(i => iconHTML(i)).join(" ");
|
||||
}
|
||||
|
||||
if (time) {
|
||||
if (state.id === LATER_TODAY) {
|
||||
time = time.format('h a');
|
||||
} else if (state.id === NEXT_MONTH || state.id === TWO_WEEKS) {
|
||||
time = time.format('MMM D');
|
||||
} else {
|
||||
time = time.format('ddd, h a');
|
||||
}
|
||||
}
|
||||
|
||||
let output = "";
|
||||
|
||||
if (!Ember.isEmpty(icons)) {
|
||||
output += `<span class='future-date-input-selector-icons'>${icons}</span>`;
|
||||
}
|
||||
|
||||
output += `<span>${state.text}</span>`;
|
||||
|
||||
if (time && state.id !== FOREVER) {
|
||||
output += `<span class='future-date-input-selector-datetime'>${time}</span>`;
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
_updateAt(selection) {
|
||||
let time = moment();
|
||||
let icon;
|
||||
const timeOfDay = this.get('statusType') !== CLOSE_STATUS_TYPE ? 8 : 18;
|
||||
|
||||
switch(selection) {
|
||||
case LATER_TODAY:
|
||||
time = time.hour(18).minute(0);
|
||||
icon = 'moon-o';
|
||||
break;
|
||||
case TOMORROW:
|
||||
time = time.add(1, 'day').hour(timeOfDay).minute(0);
|
||||
icon = 'sun-o';
|
||||
break;
|
||||
case LATER_THIS_WEEK:
|
||||
time = time.add(2, 'day').hour(timeOfDay).minute(0);
|
||||
icon = 'briefcase';
|
||||
break;
|
||||
case THIS_WEEKEND:
|
||||
time = time.day(6).hour(timeOfDay).minute(0);
|
||||
icon = 'bed';
|
||||
break;
|
||||
case NEXT_WEEK:
|
||||
time = time.add(1, 'week').day(1).hour(timeOfDay).minute(0);
|
||||
icon = 'briefcase';
|
||||
break;
|
||||
case TWO_WEEKS:
|
||||
time = time.add(2, 'week').hour(timeOfDay).minute(0);
|
||||
icon = 'briefcase';
|
||||
break;
|
||||
case NEXT_MONTH:
|
||||
time = time.add(1, 'month').startOf('month').hour(timeOfDay).minute(0);
|
||||
icon = 'briefcase';
|
||||
break;
|
||||
case FOREVER:
|
||||
time = time.add(1000, 'year').hour(timeOfDay).minute(0);
|
||||
icon = 'gavel';
|
||||
break;
|
||||
case PICK_DATE_AND_TIME:
|
||||
time = null;
|
||||
icon = 'calendar-plus-o';
|
||||
break;
|
||||
case SET_BASED_ON_LAST_POST:
|
||||
time = null;
|
||||
icon = 'clock-o';
|
||||
break;
|
||||
}
|
||||
|
||||
return { time, icon };
|
||||
},
|
||||
});
|
||||
@ -1,9 +1,7 @@
|
||||
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
||||
import {
|
||||
FORMAT,
|
||||
PICK_DATE_AND_TIME,
|
||||
SET_BASED_ON_LAST_POST
|
||||
} from "discourse/components/future-date-input-selector";
|
||||
} from "select-box-kit/components/future-date-input-selector";
|
||||
|
||||
import { PUBLISH_TO_CATEGORY_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer';
|
||||
|
||||
@ -11,8 +9,8 @@ export default Ember.Component.extend({
|
||||
selection: null,
|
||||
date: null,
|
||||
time: null,
|
||||
isCustom: Ember.computed.equal('selection', PICK_DATE_AND_TIME),
|
||||
isBasedOnLastPost: Ember.computed.equal('selection', SET_BASED_ON_LAST_POST),
|
||||
isCustom: Ember.computed.equal('selection', 'pick_date_and_time'),
|
||||
isBasedOnLastPost: Ember.computed.equal('selection', 'set_based_on_last_post'),
|
||||
displayLabel: null,
|
||||
|
||||
init() {
|
||||
@ -22,9 +20,9 @@ export default Ember.Component.extend({
|
||||
|
||||
if (input) {
|
||||
if (this.get('basedOnLastPost')) {
|
||||
this.set('selection', SET_BASED_ON_LAST_POST);
|
||||
this.set('selection', 'set_based_on_last_post');
|
||||
} else {
|
||||
this.set('selection', PICK_DATE_AND_TIME);
|
||||
this.set('selection', 'pick_date_and_time');
|
||||
const datetime = moment(input);
|
||||
this.set('date', datetime.toDate());
|
||||
this.set('time', datetime.format("HH:mm"));
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["group-notifications-button"],
|
||||
|
||||
value: Em.computed.alias("group.group_user.notification_level"),
|
||||
|
||||
i18nPrefix: "groups.notifications",
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.get("group").setNotification(this.get("value"), this.get("user.id"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,68 +0,0 @@
|
||||
import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { buttonDetails } from "discourse/lib/notification-levels";
|
||||
import { allLevels } from "discourse/lib/notification-levels";
|
||||
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
classNames: ["notifications-button"],
|
||||
|
||||
i18nPrefix: "",
|
||||
i18nPostfix: "",
|
||||
textKey: "key",
|
||||
showFullTitle: true,
|
||||
fullWidthOnMobile: true,
|
||||
content: allLevels,
|
||||
|
||||
value: Em.computed.alias("notificationLevel"),
|
||||
|
||||
@computed("selectedDetails")
|
||||
icon(details) {
|
||||
return iconHTML(details.icon, {class: details.key}).htmlSafe();
|
||||
},
|
||||
|
||||
@computed("selectedDetails.key", "i18nPrefix")
|
||||
selectedTitle(key, prefix) {
|
||||
return I18n.t(`${prefix}.${key}.title`);
|
||||
},
|
||||
|
||||
@computed("value")
|
||||
selectedDetails(value) {
|
||||
return buttonDetails(value);
|
||||
},
|
||||
|
||||
@computed("selectedTitle", "showFullTitle")
|
||||
generatedHeadertext(selectedTitle, showFullTitle) {
|
||||
return showFullTitle ? selectedTitle : null;
|
||||
},
|
||||
|
||||
@computed
|
||||
titleForRow: function() {
|
||||
return (rowComponent) => {
|
||||
const notificationLevel = rowComponent.get(`content.${this.get("idKey")}`);
|
||||
const details = buttonDetails(notificationLevel);
|
||||
return I18n.t(`${this.get("i18nPrefix")}.${details.key}.title`);
|
||||
};
|
||||
},
|
||||
|
||||
@computed
|
||||
templateForRow: function() {
|
||||
return (rowComponent) => {
|
||||
const content = rowComponent.get("content");
|
||||
const start = `${this.get("i18nPrefix")}.${content.key}${this.get("i18nPostfix")}`;
|
||||
const title = I18n.t(`${start}.title`);
|
||||
const description = I18n.t(`${start}.description`);
|
||||
|
||||
return `
|
||||
<div class="icons">
|
||||
<span class="selection-indicator"></span>
|
||||
${iconHTML(content.icon, { class: content.key.dasherize() })}
|
||||
</div>
|
||||
<div class="texts">
|
||||
<span class="title">${Handlebars.escapeExpression(title)}</span>
|
||||
<span class="desc">${Handlebars.escapeExpression(description)}</span>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
}
|
||||
});
|
||||
@ -1,73 +0,0 @@
|
||||
import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { observes } from "ember-addons/ember-computed-decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
classNames: ["pinned-options"],
|
||||
|
||||
@computed("topic.pinned")
|
||||
value(pinned) {
|
||||
return pinned ? "pinned" : "unpinned";
|
||||
},
|
||||
|
||||
@observes("topic.pinned")
|
||||
_pinnedChanged() {
|
||||
this.set("value", this.get("topic.pinned") ? "pinned" : "unpinned");
|
||||
},
|
||||
|
||||
@computed("topic.pinned_globally")
|
||||
content(pinnedGlobally) {
|
||||
const globally = pinnedGlobally ? "_globally" : "";
|
||||
|
||||
return [
|
||||
{
|
||||
id: "pinned",
|
||||
text: I18n.t("topic_statuses.pinned" + globally + ".title"),
|
||||
description: I18n.t('topic_statuses.pinned' + globally + '.help'),
|
||||
icon: "thumb-tack"
|
||||
},
|
||||
{
|
||||
id: "unpinned",
|
||||
text: I18n.t("topic_statuses.unpinned.title"),
|
||||
icon: "thumb-tack",
|
||||
description: I18n.t('topic_statuses.unpinned.help'),
|
||||
iconClass: "unpinned"
|
||||
}
|
||||
];
|
||||
},
|
||||
|
||||
@computed("topic.pinned", "topic.pinned_globally")
|
||||
icon(pinned, pinnedGlobally) {
|
||||
const globally = pinnedGlobally ? "_globally" : "";
|
||||
const state = pinned ? `pinned${globally}` : "unpinned";
|
||||
|
||||
return iconHTML(
|
||||
"thumb-tack",
|
||||
{ class: (state === "unpinned" ? "unpinned" : null) }
|
||||
);
|
||||
},
|
||||
|
||||
@computed("topic.pinned", "topic.pinned_globally")
|
||||
generatedHeadertext(pinned, pinnedGlobally) {
|
||||
const globally = pinnedGlobally ? "_globally" : "";
|
||||
const state = pinned ? `pinned${globally}` : "unpinned";
|
||||
const title = I18n.t(`topic_statuses.${state}.title`);
|
||||
|
||||
return `${title}${iconHTML("caret-down")}`.htmlSafe();
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
const topic = this.get("topic");
|
||||
|
||||
if (this.get("value") === "unpinned") {
|
||||
topic.clearPin();
|
||||
} else {
|
||||
topic.rePin();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,485 +0,0 @@
|
||||
import { on, observes } from "ember-addons/ember-computed-decorators";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
layoutName: "components/select-box",
|
||||
classNames: "select-box",
|
||||
classNameBindings: ["expanded:is-expanded", "hidden:is-hidden"],
|
||||
|
||||
expanded: false,
|
||||
focused: false,
|
||||
filterFocused: false,
|
||||
renderBody: false,
|
||||
wrapper: true,
|
||||
hidden: false,
|
||||
tabindex: 0,
|
||||
scrollableParentSelector: ".modal-body",
|
||||
|
||||
caretUpIcon: "caret-up",
|
||||
caretDownIcon: "caret-down",
|
||||
headerText: I18n.t("select_box.default_header_text"),
|
||||
dynamicHeaderText: true,
|
||||
icon: null,
|
||||
clearable: false,
|
||||
|
||||
value: null,
|
||||
highlightedValue: null,
|
||||
selectedContent: null,
|
||||
noContentLabel: I18n.t("select_box.no_content"),
|
||||
clearSelectionLabel: null,
|
||||
|
||||
idKey: "id",
|
||||
textKey: "text",
|
||||
iconKey: "icon",
|
||||
|
||||
filterable: false,
|
||||
filter: "",
|
||||
filterPlaceholder: I18n.t("select_box.filter_placeholder"),
|
||||
filterIcon: "search",
|
||||
|
||||
selectBoxRowComponent: "select-box/select-box-row",
|
||||
selectBoxFilterComponent: "select-box/select-box-filter",
|
||||
selectBoxHeaderComponent: "select-box/select-box-header",
|
||||
selectBoxCollectionComponent: "select-box/select-box-collection",
|
||||
|
||||
collectionHeight: 200,
|
||||
verticalOffset: 0,
|
||||
horizontalOffset: 0,
|
||||
fullWidthOnMobile: false,
|
||||
|
||||
castInteger: false,
|
||||
|
||||
click(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
filterFunction: function(content) {
|
||||
return (selectBox) => {
|
||||
const filter = selectBox.get("filter").toLowerCase();
|
||||
return _.filter(content, (c) => {
|
||||
return c[selectBox.get("textKey")].toLowerCase().indexOf(filter) > -1;
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
@computed("textKey")
|
||||
titleForRow(textKey) {
|
||||
return (rowComponent) => {
|
||||
return rowComponent.get(`content.${textKey}`);
|
||||
};
|
||||
},
|
||||
|
||||
@computed("idKey")
|
||||
idForRow(idKey) {
|
||||
return (rowComponent) => {
|
||||
return rowComponent.get(`content.${idKey}`);
|
||||
};
|
||||
},
|
||||
|
||||
@computed
|
||||
shouldHighlightRow: function() {
|
||||
return (rowComponent) => {
|
||||
const id = this._castInteger(rowComponent.get(`content.${this.get("idKey")}`));
|
||||
return id === this.get("highlightedValue");
|
||||
};
|
||||
},
|
||||
|
||||
@computed("value", "idKey")
|
||||
shouldSelectRow(value, idKey) {
|
||||
return (rowComponent) => {
|
||||
const id = this._castInteger(rowComponent.get(`content.${idKey}`));
|
||||
return id === value;
|
||||
};
|
||||
},
|
||||
|
||||
@computed
|
||||
templateForRow: function() {
|
||||
return (rowComponent) => {
|
||||
let template = "";
|
||||
|
||||
const icon = rowComponent.icon();
|
||||
if (icon) {
|
||||
template += icon;
|
||||
}
|
||||
|
||||
const text = rowComponent.get(`content.${this.get("textKey")}`);
|
||||
template += `<p class="text">${Handlebars.escapeExpression(text)}</p>`;
|
||||
|
||||
return template;
|
||||
};
|
||||
},
|
||||
|
||||
applyDirection() {
|
||||
this.$().removeClass("is-above is-below is-left-aligned is-right-aligned");
|
||||
let options = { left: "auto", bottom: "auto", left: "auto", top: "auto" };
|
||||
const headerHeight = this.$(".select-box-header").outerHeight(false);
|
||||
const filterHeight = this.$(".select-box-filter").outerHeight(false);
|
||||
const bodyHeight = this.$(".select-box-body").outerHeight(false);
|
||||
const windowWidth = $(window).width();
|
||||
const windowHeight = $(window).height();
|
||||
const boundingRect = this.$()[0].getBoundingClientRect();
|
||||
const offsetTop = boundingRect.top;
|
||||
|
||||
if (this.get("fullWidthOnMobile") && this.site.isMobileDevice) {
|
||||
const margin = 10;
|
||||
const relativeLeft = this.$().offset().left - $(window).scrollLeft();
|
||||
options.left = margin - relativeLeft;
|
||||
options.width = windowWidth - margin * 2;
|
||||
options.maxWidth = options.minWidth = "unset";
|
||||
} else {
|
||||
const offsetLeft = boundingRect.left;
|
||||
const bodyWidth = this.$(".select-box-body").outerWidth(false);
|
||||
const hasRightSpace = (windowWidth - (this.get("horizontalOffset") + offsetLeft + filterHeight + bodyWidth) > 0);
|
||||
|
||||
if (hasRightSpace) {
|
||||
this.$().addClass("is-left-aligned");
|
||||
options.left = this.get("horizontalOffset");
|
||||
} else {
|
||||
this.$().addClass("is-right-aligned");
|
||||
options.right = this.get("horizontalOffset");
|
||||
}
|
||||
}
|
||||
|
||||
const componentHeight = this.get("verticalOffset") + bodyHeight + headerHeight;
|
||||
const hasBelowSpace = windowHeight - offsetTop - componentHeight > 0;
|
||||
if (hasBelowSpace) {
|
||||
this.$().addClass("is-below");
|
||||
options.top = headerHeight + this.get("verticalOffset");
|
||||
} else {
|
||||
this.$().addClass("is-above");
|
||||
options.bottom = headerHeight + this.get("verticalOffset");
|
||||
}
|
||||
|
||||
this.$(".select-box-body").css(options);
|
||||
},
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
const content = this.getWithDefault("content", []);
|
||||
this.set("content", content);
|
||||
|
||||
if (this.site.isMobileDevice) {
|
||||
this.set("filterable", false);
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
value: this._castInteger(this.get("value")),
|
||||
componentId: this.elementId
|
||||
});
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
_removeDocumentListeners: function() {
|
||||
$(document).off("click.select-box");
|
||||
$(window).off("resize.select-box");
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
_unbindEvents: function() {
|
||||
this.$(".select-box-offscreen").off(
|
||||
"focusin.select-box",
|
||||
"focusout.select-box",
|
||||
"keydown.select-box"
|
||||
);
|
||||
this.$(".filter-query").off("focusin.select-box", "focusout.select-box");
|
||||
},
|
||||
|
||||
@on("didRender")
|
||||
_configureSelectBoxDOM: function() {
|
||||
if (this.get("scrollableParent").length === 1) {
|
||||
this._removeFixedPosition();
|
||||
}
|
||||
|
||||
const computedWidth = this.$().outerWidth(false);
|
||||
const computedHeight = this.$().outerHeight(false);
|
||||
|
||||
this.$(".select-box-filter").css("height", computedHeight);
|
||||
|
||||
if (this.get("expanded")) {
|
||||
if (this.get("scrollableParent").length === 1) {
|
||||
this._applyFixedPosition(computedWidth, computedHeight);
|
||||
}
|
||||
|
||||
this.$(".select-box-collection").css("max-height", this.get("collectionHeight"));
|
||||
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this.applyDirection();
|
||||
if (this.get("wrapper")) {
|
||||
this._positionSelectBoxWrapper();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.get("wrapper")) {
|
||||
this.$(".select-box-wrapper").hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
keyDown(event) {
|
||||
const keyCode = event.keyCode || event.which;
|
||||
|
||||
if (this.get("expanded")) {
|
||||
if ((keyCode === 13 || keyCode === 9) && Ember.isPresent(this.get("highlightedValue"))) {
|
||||
event.preventDefault();
|
||||
this.send("onSelectRow", this.get("highlightedContent"));
|
||||
}
|
||||
|
||||
if (keyCode === 9) {
|
||||
this.set("expanded", false);
|
||||
}
|
||||
|
||||
if (keyCode === 27) {
|
||||
this.set("expanded", false);
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (keyCode === 38) {
|
||||
event.preventDefault();
|
||||
const self = this;
|
||||
Ember.run.throttle(self, this._handleUpArrow, 50);
|
||||
}
|
||||
|
||||
if (keyCode === 40) {
|
||||
event.preventDefault();
|
||||
const self = this;
|
||||
Ember.run.throttle(self, this._handleDownArrow, 50);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@on("didRender")
|
||||
_setupDocumentListeners: function() {
|
||||
$(document).off("click.select-box");
|
||||
|
||||
$(document)
|
||||
.on("click.select-box", (event) => {
|
||||
if (this.isDestroying || this.isDestroyed) { return; }
|
||||
|
||||
const $element = this.$();
|
||||
const $target = $(event.target);
|
||||
|
||||
if (!$target.closest($element).length) {
|
||||
this.set("expanded", false);
|
||||
}
|
||||
});
|
||||
|
||||
$(window).on("resize.select-box", () => this.set("expanded", false) );
|
||||
},
|
||||
|
||||
@on("didInsertElement")
|
||||
_bindEvents: function() {
|
||||
this.$(".select-box-offscreen")
|
||||
.on("focusin.select-box", () => this.set("focused", true) )
|
||||
.on("focusout.select-box", () => this.set("focused", false) );
|
||||
|
||||
this.$(".filter-query")
|
||||
.on("focusin.select-box", () => this.set("filterFocused", true) )
|
||||
.on("focusout.select-box", () => this.set("filterFocused", false) );
|
||||
|
||||
this.$(".select-box-offscreen").on("keydown.select-box", (event) => {
|
||||
const keyCode = event.keyCode || event.which;
|
||||
|
||||
if (keyCode === 13 || keyCode === 40) {
|
||||
this.setProperties({ expanded: true, focused: false });
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (keyCode >= 65 && keyCode <= 90) {
|
||||
this.setProperties({ expanded: true, focused: false });
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this.$(".filter-query").focus().val(String.fromCharCode(keyCode));
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@observes("expanded")
|
||||
_expandedChanged: function() {
|
||||
if (this.get("expanded")) {
|
||||
this.setProperties({ highlightedValue: null, renderBody: true, focused: false });
|
||||
|
||||
if (this.get("filterable")) {
|
||||
Ember.run.schedule("afterRender", () => this.$(".filter-query").focus());
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@computed("value", "content.[]", "idKey")
|
||||
selectedContent(value, content, idKey) {
|
||||
if (Ember.isNone(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return content.find((c) => {
|
||||
return this._castInteger(Ember.get(c, idKey)) === value;
|
||||
});
|
||||
},
|
||||
|
||||
@computed("highlightedValue", "content.[]", "idKey")
|
||||
highlightedContent(highlightedValue, content, idKey) {
|
||||
if (Ember.isNone(highlightedValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return content.find((c) => {
|
||||
return this._castInteger(Ember.get(c, idKey)) === highlightedValue;
|
||||
});
|
||||
},
|
||||
|
||||
@computed("headerText", "selectedContent", "textKey")
|
||||
selectedTitle(headerText, selectedContent, textKey) {
|
||||
if (Ember.isNone(selectedContent)) {
|
||||
return headerText;
|
||||
}
|
||||
|
||||
return selectedContent[textKey];
|
||||
},
|
||||
|
||||
@computed("headerText", "dynamicHeaderText", "selectedContent", "textKey", "clearSelectionLabel")
|
||||
generatedHeadertext(headerText, dynamic, selectedContent, textKey, clearSelectionLabel) {
|
||||
if (dynamic && !Ember.isNone(selectedContent)) {
|
||||
return selectedContent[textKey];
|
||||
}
|
||||
|
||||
if (dynamic && Ember.isNone(selectedContent) && !Ember.isNone(clearSelectionLabel)) {
|
||||
return I18n.t(clearSelectionLabel);
|
||||
}
|
||||
|
||||
return headerText;
|
||||
},
|
||||
|
||||
@computed("content.[]", "filter", "idKey")
|
||||
filteredContent(content, filter, idKey) {
|
||||
let filteredContent;
|
||||
|
||||
if (Ember.isEmpty(filter)) {
|
||||
filteredContent = content;
|
||||
} else {
|
||||
filteredContent = this.filterFunction(content)(this);
|
||||
|
||||
if (!Ember.isEmpty(filteredContent)) {
|
||||
this.set("highlightedValue", filteredContent[0][idKey]);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredContent;
|
||||
},
|
||||
|
||||
@computed("scrollableParentSelector")
|
||||
scrollableParent(scrollableParentSelector) {
|
||||
return this.$().parents(scrollableParentSelector).first();
|
||||
},
|
||||
|
||||
actions: {
|
||||
onToggle() {
|
||||
this.toggleProperty("expanded");
|
||||
},
|
||||
|
||||
onFilterChange(filter) {
|
||||
this.set("filter", filter);
|
||||
},
|
||||
|
||||
onHoverRow(content) {
|
||||
const id = this._castInteger(Ember.get(content, this.get("idKey")));
|
||||
this.set("highlightedValue", id);
|
||||
},
|
||||
|
||||
onSelectRow(content) {
|
||||
this.setProperties({
|
||||
value: this._castInteger(Ember.get(content, this.get("idKey"))),
|
||||
expanded: false
|
||||
});
|
||||
},
|
||||
|
||||
onClearSelection() {
|
||||
this.setProperties({ value: null, expanded: false });
|
||||
}
|
||||
},
|
||||
|
||||
_positionSelectBoxWrapper() {
|
||||
const headerHeight = this.$(".select-box-header").outerHeight(false);
|
||||
|
||||
this.$(".select-box-wrapper").css({
|
||||
width: this.$().width(),
|
||||
display: "block",
|
||||
height: headerHeight + this.$(".select-box-body").outerHeight(false)
|
||||
});
|
||||
},
|
||||
|
||||
_castInteger(id) {
|
||||
if (this.get("castInteger") === true && Ember.isPresent(id)) {
|
||||
return parseInt(id, 10);
|
||||
}
|
||||
|
||||
return id;
|
||||
},
|
||||
|
||||
_applyFixedPosition(width, height) {
|
||||
const $placeholder = $(`<div class='select-box-fixed-placeholder-${this.get("componentId")}' style='vertical-align: middle; height: ${height}px; width: ${width}px; line-height: ${height}px;display:inline-block'></div>`);
|
||||
|
||||
this.$()
|
||||
.before($placeholder)
|
||||
.css({
|
||||
width,
|
||||
position: "fixed",
|
||||
"margin-top": -this.get("scrollableParent").scrollTop(),
|
||||
"margin-left": -width
|
||||
});
|
||||
|
||||
this.get("scrollableParent").on("scroll.select-box", () => this.set("expanded", false) );
|
||||
},
|
||||
|
||||
_removeFixedPosition() {
|
||||
$(`.select-box-fixed-placeholder-${this.get("componentId")}`).remove();
|
||||
this.$().css({
|
||||
top: "auto",
|
||||
left: "auto",
|
||||
"margin-left": "auto",
|
||||
"margin-top": "auto",
|
||||
position: "relative"
|
||||
});
|
||||
|
||||
this.get("scrollableParent").off("scroll.select-box");
|
||||
},
|
||||
|
||||
_handleDownArrow() {
|
||||
this._handleArrow("down");
|
||||
},
|
||||
|
||||
_handleUpArrow() {
|
||||
this._handleArrow("up");
|
||||
},
|
||||
|
||||
_handleArrow(direction) {
|
||||
const content = this.get("filteredContent");
|
||||
const idKey = this.get("idKey");
|
||||
const selectedContent = content.findBy(idKey, this.get("highlightedValue"));
|
||||
const currentIndex = content.indexOf(selectedContent);
|
||||
|
||||
if (direction === "down") {
|
||||
if (currentIndex < 0) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[0], idKey)));
|
||||
} else if(currentIndex + 1 < content.length) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[currentIndex + 1], idKey)));
|
||||
}
|
||||
} else {
|
||||
if (currentIndex <= 0) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[0], idKey)));
|
||||
} else if(currentIndex - 1 < content.length) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[currentIndex - 1], idKey)));
|
||||
}
|
||||
}
|
||||
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
const $highlightedRow = this.$(".select-box-row.is-highlighted");
|
||||
|
||||
if ($highlightedRow.length === 0) { return; }
|
||||
|
||||
const $collection = this.$(".select-box-collection");
|
||||
const rowOffset = $highlightedRow.offset();
|
||||
const bodyOffset = $collection.offset();
|
||||
$collection.scrollTop(rowOffset.top - bodyOffset.top);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,9 +0,0 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: "select-box-collection",
|
||||
|
||||
actions: {
|
||||
onClearSelection() {
|
||||
this.sendAction("onClearSelection");
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: "select-box-filter",
|
||||
|
||||
classNameBindings: ["focused:is-focused"]
|
||||
});
|
||||
@ -1,24 +0,0 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: "select-box-header",
|
||||
|
||||
classNameBindings: ["focused:is-focused"],
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super();
|
||||
|
||||
this._setCaretIcon();
|
||||
},
|
||||
|
||||
click(event) {
|
||||
this.sendAction("onToggle");
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
_setCaretIcon() {
|
||||
if(this.get("expanded")) {
|
||||
this.set("caretIcon", this.get("caretUpIcon"));
|
||||
} else {
|
||||
this.set("caretIcon", this.get("caretDownIcon"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,47 +0,0 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
layoutName: "components/select-box/select-box-row",
|
||||
|
||||
classNames: "select-box-row",
|
||||
|
||||
tagName: "li",
|
||||
|
||||
attributeBindings: ["title", "id:data-id"],
|
||||
|
||||
classNameBindings: ["isHighlighted:is-highlighted", "isSelected:is-selected"],
|
||||
|
||||
@computed("titleForRow")
|
||||
title(titleForRow) { return titleForRow(this); },
|
||||
|
||||
@computed("idForRow")
|
||||
id(idForRow) { return idForRow(this); },
|
||||
|
||||
@computed("templateForRow")
|
||||
template(templateForRow) { return templateForRow(this); },
|
||||
|
||||
@computed("shouldHighlightRow", "highlightedValue")
|
||||
isHighlighted(shouldHighlightRow) { return shouldHighlightRow(this); },
|
||||
|
||||
@computed("shouldSelectRow", "value")
|
||||
isSelected(shouldSelectRow) { return shouldSelectRow(this); },
|
||||
|
||||
icon() {
|
||||
if (this.get("content.icon")) {
|
||||
const iconName = this.get("content.icon");
|
||||
const iconClass = this.get("content.iconClass");
|
||||
return iconHTML(iconName, { class: iconClass });
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
mouseEnter() {
|
||||
this.sendAction("onHover", this.get("content"));
|
||||
},
|
||||
|
||||
click() {
|
||||
this.sendAction("onSelect", this.get("content"));
|
||||
}
|
||||
});
|
||||
@ -1,24 +0,0 @@
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["tag-notifications-button"],
|
||||
|
||||
i18nPrefix: "tagging.notifications",
|
||||
|
||||
@computed("value")
|
||||
icon() {
|
||||
return `${this._super()}${iconHTML("caret-down")}`.htmlSafe();
|
||||
},
|
||||
|
||||
generatedHeadertext: null,
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.sendAction("action", this.get("value"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,78 +0,0 @@
|
||||
import { observes } from 'ember-addons/ember-computed-decorators';
|
||||
import SelectBoxComponent from "discourse/components/select-box";
|
||||
|
||||
export default SelectBoxComponent.extend({
|
||||
textKey: "name",
|
||||
|
||||
headerText: I18n.t("topic.controls"),
|
||||
|
||||
dynamicHeaderText: false,
|
||||
|
||||
collectionHeight: 300,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
this._createContent();
|
||||
},
|
||||
|
||||
_createContent() {
|
||||
const content = [];
|
||||
const topic = this.get('topic');
|
||||
const details = topic.get('details');
|
||||
|
||||
if (details.get('can_invite_to')) {
|
||||
content.push({ id: 'invite', icon: 'users', name: I18n.t('topic.invite_reply.title') });
|
||||
}
|
||||
|
||||
if (topic.get('bookmarked')) {
|
||||
content.push({ id: 'bookmark', icon: 'bookmark', name: I18n.t('bookmarked.clear_bookmarks') });
|
||||
} else {
|
||||
content.push({ id: 'bookmark', icon: 'bookmark', name: I18n.t('bookmarked.title') });
|
||||
}
|
||||
|
||||
content.push({ id: 'share', icon: 'link', name: I18n.t('topic.share.title') });
|
||||
|
||||
if (details.get('can_flag_topic')) {
|
||||
content.push({ id: 'flag', icon: 'flag', name: I18n.t('topic.flag_topic.title') });
|
||||
}
|
||||
|
||||
this.set('content', content);
|
||||
},
|
||||
|
||||
@observes('value')
|
||||
_valueChanged() {
|
||||
this._super();
|
||||
|
||||
const value = this.get('value');
|
||||
const topic = this.get('topic');
|
||||
|
||||
// In case it's not a valid topic
|
||||
if (!topic.get('id')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const refresh = () => {
|
||||
this._createContent();
|
||||
this.set('value', null);
|
||||
};
|
||||
|
||||
switch(value) {
|
||||
case 'invite':
|
||||
this.attrs.showInvite();
|
||||
refresh();
|
||||
break;
|
||||
case 'bookmark':
|
||||
topic.toggleBookmark().then(() => refresh());
|
||||
break;
|
||||
case 'share':
|
||||
this.appEvents.trigger('share:url', topic.get('shareUrl'), $('#topic-footer-buttons'));
|
||||
refresh();
|
||||
break;
|
||||
case 'flag':
|
||||
this.attrs.showFlagTopic();
|
||||
refresh();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,9 +0,0 @@
|
||||
export default Ember.Component.extend({
|
||||
layoutName: "components/topic-notifications-button",
|
||||
|
||||
classNames: ["topic-notifications-button"],
|
||||
|
||||
showFullTitle: true,
|
||||
|
||||
appendReason: true,
|
||||
});
|
||||
@ -1,52 +0,0 @@
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
import { on } from "ember-addons/ember-computed-decorators";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { topicLevels, buttonDetails } from "discourse/lib/notification-levels";
|
||||
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["topic-notifications-options"],
|
||||
|
||||
content: topicLevels,
|
||||
|
||||
i18nPrefix: "topic.notifications",
|
||||
|
||||
value: Ember.computed.alias("topic.details.notification_level"),
|
||||
|
||||
@on("didInsertElement")
|
||||
_bindGlobalLevelChanged() {
|
||||
this.appEvents.on("topic-notifications-button:changed", (msg) => {
|
||||
if (msg.type === "notification") {
|
||||
if (this.get("value") !== msg.id) {
|
||||
this.get("topic.details").updateNotifications(msg.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
_unbindGlobalLevelChanged() {
|
||||
this.appEvents.off("topic-notifications-button:changed");
|
||||
},
|
||||
|
||||
@computed("value", "showFullTitle")
|
||||
generatedHeadertext(value, showFullTitle) {
|
||||
if (showFullTitle) {
|
||||
const details = buttonDetails(value);
|
||||
return I18n.t(`topic.notifications.${details.key}.title`);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
const notificationLevelId = Ember.get(content, this.get("idKey"));
|
||||
|
||||
if (notificationLevelId !== this.get("value")) {
|
||||
this.get("topic.details").updateNotifications(notificationLevelId);
|
||||
}
|
||||
|
||||
this._super(content);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,3 +1,5 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['user-stat']
|
||||
classNames: ['user-stat'],
|
||||
type: 'number',
|
||||
isNumber: Ember.computed.equal('type', 'number')
|
||||
});
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['top-sub-section']
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li'
|
||||
});
|
||||
@ -0,0 +1,13 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
// should be kept in sync with 'UserSummary::MAX_SUMMARY_RESULTS'
|
||||
const MAX_SUMMARY_RESULTS = 6;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: '',
|
||||
|
||||
@computed('items.length')
|
||||
hasMore(length) {
|
||||
return length >= MAX_SUMMARY_RESULTS;
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li'
|
||||
});
|
||||
@ -25,9 +25,9 @@ export default Ember.Controller.extend(BadgeSelectController, {
|
||||
return username ? userCount : modelCount;
|
||||
},
|
||||
|
||||
@computed("model.has_title_badges")
|
||||
canSelectTitle(hasTitleBadges) {
|
||||
return this.siteSettings.enable_badges && hasTitleBadges;
|
||||
@computed("model.allow_title", "model.has_badge", "model")
|
||||
canSelectTitle(hasTitleBadges, hasBadge) {
|
||||
return this.siteSettings.enable_badges && hasTitleBadges && hasBadge;
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ActionSummary from 'discourse/models/action-summary';
|
||||
import { MAX_MESSAGE_LENGTH } from 'discourse/models/post-action-type';
|
||||
@ -54,19 +53,17 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
||||
return flagsAvailable;
|
||||
} else {
|
||||
// flagging topic
|
||||
const self = this,
|
||||
lookup = Em.Object.create();
|
||||
|
||||
_.each(this.get("model.actions_summary"),function(a) {
|
||||
a.flagTopic = self.get('model');
|
||||
a.actionType = self.site.topicFlagTypeById(a.id);
|
||||
const actionSummary = ActionSummary.create(a);
|
||||
lookup.set(a.actionType.get('name_key'), actionSummary);
|
||||
let lookup = Em.Object.create();
|
||||
let model = this.get('model');
|
||||
model.get('actions_summary').forEach(a => {
|
||||
a.flagTopic = model;
|
||||
a.actionType = this.site.topicFlagTypeById(a.id);
|
||||
lookup.set(a.actionType.get('name_key'), ActionSummary.create(a));
|
||||
});
|
||||
this.set('topicActionByName', lookup);
|
||||
|
||||
return this.site.get('topic_flag_types').filter(function(item) {
|
||||
return _.any(self.get("model.actions_summary"), function(a) {
|
||||
return this.site.get('topic_flag_types').filter(item => {
|
||||
return _.any(this.get("model.actions_summary"), a => {
|
||||
return (a.id === item.get('id') && a.can_act);
|
||||
});
|
||||
});
|
||||
@ -97,13 +94,18 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
||||
return !flagTopic && !isCustomFlag && this.currentUser.get('staff');
|
||||
},
|
||||
|
||||
submitText: function(){
|
||||
if (this.get('selected.is_custom_flag')) {
|
||||
return iconHTML('envelope') + (I18n.t(this.get('flagTopic') ? "flagging_topic.notify_action" : "flagging.notify_action"));
|
||||
} else {
|
||||
return iconHTML('flag') + (I18n.t(this.get('flagTopic') ? "flagging_topic.action" : "flagging.action"));
|
||||
@computed('selected.is_custom_flag')
|
||||
submitIcon(isCustomFlag) {
|
||||
return isCustomFlag ? "envelope" : "flag";
|
||||
},
|
||||
|
||||
@computed('selected.is_custom_flag', 'flagTopic')
|
||||
submitLabel(isCustomFlag, flagTopic) {
|
||||
if (isCustomFlag) {
|
||||
return flagTopic ? "flagging_topic.notify_action" : "flagging.notify_action";
|
||||
}
|
||||
}.property('selected.is_custom_flag'),
|
||||
return flagTopic ? "flagging_topic.action" : "flagging.action";
|
||||
},
|
||||
|
||||
actions: {
|
||||
deleteSpammer() {
|
||||
|
||||
@ -13,7 +13,7 @@ export default Ember.Controller.extend(PreferencesTabController, {
|
||||
'dynamic_favicon',
|
||||
'enable_quoting',
|
||||
'disable_jump_reply',
|
||||
'automatically_unpin_topics'
|
||||
'automatically_unpin_topics',
|
||||
];
|
||||
|
||||
if (makeDefault) {
|
||||
|
||||
@ -10,7 +10,8 @@ export default Ember.Controller.extend(PreferencesTabController, {
|
||||
'new_topic_duration_minutes',
|
||||
'auto_track_topics_after_msecs',
|
||||
'notification_level_when_replying',
|
||||
'like_notification_frequency'
|
||||
'like_notification_frequency',
|
||||
'allow_private_messages',
|
||||
],
|
||||
|
||||
@computed("model.watchedCategories", "model.trackedCategories", "model.mutedCategories")
|
||||
|
||||
@ -231,7 +231,11 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
|
||||
},
|
||||
|
||||
removeAllowedUser(user) {
|
||||
return this.get('model.details').removeAllowedUser(user);
|
||||
return this.get('model.details').removeAllowedUser(user).then(() => {
|
||||
if (this.currentUser.id === user.id) {
|
||||
this.transitionToRoute("userPrivateMessages", user);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeAllowedGroup(group) {
|
||||
@ -536,7 +540,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
|
||||
},
|
||||
|
||||
expandHidden(post) {
|
||||
post.expandHidden();
|
||||
return post.expandHidden();
|
||||
},
|
||||
|
||||
toggleVisibility() {
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
// should be kept in sync with 'UserSummary::MAX_SUMMARY_RESULTS'
|
||||
const MAX_SUMMARY_RESULTS = 6;
|
||||
// should be kept in sync with 'UserSummary::MAX_BADGES'
|
||||
const MAX_BADGES = 6;
|
||||
|
||||
@ -9,12 +7,6 @@ export default Ember.Controller.extend({
|
||||
userController: Ember.inject.controller('user'),
|
||||
user: Ember.computed.alias('userController.model'),
|
||||
|
||||
@computed("model.topics.length")
|
||||
moreTopics(topicsLength) { return topicsLength >= MAX_SUMMARY_RESULTS; },
|
||||
|
||||
@computed("model.replies.length")
|
||||
moreReplies(repliesLength) { return repliesLength >= MAX_SUMMARY_RESULTS; },
|
||||
|
||||
@computed("model.badges.length")
|
||||
moreBadges(badgesLength) { return badgesLength >= MAX_BADGES; },
|
||||
});
|
||||
|
||||
@ -33,7 +33,7 @@ export default {
|
||||
}
|
||||
|
||||
bus.subscribe(`/notification/${user.get('id')}`, data => {
|
||||
const store = container.lookup('store:main');
|
||||
const store = container.lookup('service:store');
|
||||
|
||||
const oldUnread = user.get('unread_notifications');
|
||||
const oldPM = user.get('unread_private_messages');
|
||||
|
||||
@ -6,8 +6,7 @@ const bindings = {
|
||||
'!': {postAction: 'showFlags'},
|
||||
'#': {handler: 'goToPost', anonymous: true},
|
||||
'/': {handler: 'toggleSearch', anonymous: true},
|
||||
'ctrl+shift+s': {handler: 'toggleSearch', anonymous: true},
|
||||
'command+shift+s': {handler: 'toggleSearch', anonymous: true},
|
||||
'ctrl+alt+f': {handler: 'toggleSearch', anonymous: true},
|
||||
'=': {handler: 'toggleHamburgerMenu', anonymous: true},
|
||||
'?': {handler: 'showHelpModal', anonymous: true},
|
||||
'.': {click: '.alert.alert-info.clickable', anonymous: true}, // show incoming/updated topics
|
||||
|
||||
@ -441,7 +441,7 @@ class PluginApi {
|
||||
* will issue a request to `/mice.json`
|
||||
**/
|
||||
addStorePluralization(thing, plural) {
|
||||
this.container.lookup("store:main").addPluralization(thing, plural);
|
||||
this.container.lookup("service:store").addPluralization(thing, plural);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -147,7 +147,7 @@ function positioningWorkaround($fixedElement) {
|
||||
|
||||
fixedElement.style.top = '0px';
|
||||
|
||||
composingTopic = $('#reply-control .category-select-box').length > 0;
|
||||
composingTopic = $('#reply-control .category-chooser').length > 0;
|
||||
|
||||
const height = calcHeight(composingTopic);
|
||||
fixedElement.style.height = height + "px";
|
||||
|
||||
@ -127,6 +127,7 @@ export default function transformPost(currentUser, site, post, prevPost, nextPos
|
||||
postAtts.allowedGroups = details.allowed_groups;
|
||||
postAtts.allowedUsers = details.allowed_users;
|
||||
postAtts.canRemoveAllowedUsers = details.can_remove_allowed_users;
|
||||
postAtts.canRemoveSelfId = details.can_remove_self_id;
|
||||
postAtts.canInvite = details.can_invite_to;
|
||||
}
|
||||
|
||||
|
||||
@ -122,7 +122,7 @@ NavItem.reopenClass({
|
||||
_.merge(args, extra);
|
||||
});
|
||||
|
||||
const store = Discourse.__container__.lookup('store:main');
|
||||
const store = Discourse.__container__.lookup('service:store');
|
||||
return store.createRecord('nav-item', args);
|
||||
},
|
||||
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import RestModel from 'discourse/models/rest';
|
||||
|
||||
const PostActionType = RestModel.extend({
|
||||
notCustomFlag: Em.computed.not('is_custom_flag')
|
||||
});
|
||||
|
||||
export const MAX_MESSAGE_LENGTH = 500;
|
||||
|
||||
export default PostActionType;
|
||||
export default RestModel.extend({
|
||||
notCustomFlag: Em.computed.not('is_custom_flag')
|
||||
});
|
||||
|
||||
@ -84,7 +84,7 @@ RestModel.reopenClass({
|
||||
if (!args.store) {
|
||||
const container = Discourse.__container__;
|
||||
// Ember.warn('Use `store.createRecord` to create records instead of `.create()`');
|
||||
args.store = container.lookup('store:main');
|
||||
args.store = container.lookup('service:store');
|
||||
}
|
||||
|
||||
args.__munge = this.munge;
|
||||
|
||||
@ -94,7 +94,7 @@ Site.reopenClass(Singleton, {
|
||||
|
||||
// The current singleton will retrieve its attributes from the `PreloadStore`.
|
||||
createCurrent() {
|
||||
const store = Discourse.__container__.lookup('store:main');
|
||||
const store = Discourse.__container__.lookup('service:store');
|
||||
return store.createRecord('site', PreloadStore.get('site'));
|
||||
},
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ TopicList.reopenClass({
|
||||
},
|
||||
|
||||
find(filter, params) {
|
||||
const store = Discourse.__container__.lookup('store:main');
|
||||
const store = Discourse.__container__.lookup('service:store');
|
||||
return store.findFiltered('topicList', {filter, params});
|
||||
},
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import UserBadge from 'discourse/models/user-badge';
|
||||
import UserActionStat from 'discourse/models/user-action-stat';
|
||||
import UserAction from 'discourse/models/user-action';
|
||||
import Group from 'discourse/models/group';
|
||||
import Topic from 'discourse/models/topic';
|
||||
import { emojiUnescape } from 'discourse/lib/text';
|
||||
import PreloadStore from 'preload-store';
|
||||
import { defaultHomepage } from 'discourse/lib/utilities';
|
||||
@ -248,7 +247,8 @@ const User = RestModel.extend({
|
||||
'notification_level_when_replying',
|
||||
'like_notification_frequency',
|
||||
'include_tl0_in_digests',
|
||||
'theme_key'
|
||||
'theme_key',
|
||||
'allow_private_messages',
|
||||
];
|
||||
|
||||
if (fields) {
|
||||
@ -492,38 +492,39 @@ const User = RestModel.extend({
|
||||
},
|
||||
|
||||
summary() {
|
||||
return ajax(userPath(`${this.get("username_lower")}/summary.json`))
|
||||
.then(json => {
|
||||
const summary = json["user_summary"];
|
||||
const topicMap = {};
|
||||
const badgeMap = {};
|
||||
let { store } = this;
|
||||
|
||||
json.topics.forEach(t => topicMap[t.id] = Topic.create(t));
|
||||
Badge.createFromJson(json).forEach(b => badgeMap[b.id] = b );
|
||||
return ajax(userPath(`${this.get("username_lower")}/summary.json`)).then(json => {
|
||||
const summary = json.user_summary;
|
||||
const topicMap = {};
|
||||
const badgeMap = {};
|
||||
|
||||
summary.topics = summary.topic_ids.map(id => topicMap[id]);
|
||||
json.topics.forEach(t => topicMap[t.id] = store.createRecord('topic', t));
|
||||
Badge.createFromJson(json).forEach(b => badgeMap[b.id] = b );
|
||||
|
||||
summary.replies.forEach(r => {
|
||||
r.topic = topicMap[r.topic_id];
|
||||
r.url = r.topic.urlForPostNumber(r.post_number);
|
||||
r.createdAt = new Date(r.created_at);
|
||||
});
|
||||
summary.topics = summary.topic_ids.map(id => topicMap[id]);
|
||||
|
||||
summary.links.forEach(l => {
|
||||
l.topic = topicMap[l.topic_id];
|
||||
l.post_url = l.topic.urlForPostNumber(l.post_number);
|
||||
});
|
||||
summary.replies.forEach(r => {
|
||||
r.topic = topicMap[r.topic_id];
|
||||
r.url = r.topic.urlForPostNumber(r.post_number);
|
||||
r.createdAt = new Date(r.created_at);
|
||||
});
|
||||
|
||||
if (summary.badges) {
|
||||
summary.badges = summary.badges.map(ub => {
|
||||
const badge = badgeMap[ub.badge_id];
|
||||
badge.count = ub.count;
|
||||
return badge;
|
||||
});
|
||||
}
|
||||
summary.links.forEach(l => {
|
||||
l.topic = topicMap[l.topic_id];
|
||||
l.post_url = l.topic.urlForPostNumber(l.post_number);
|
||||
});
|
||||
|
||||
return summary;
|
||||
});
|
||||
if (summary.badges) {
|
||||
summary.badges = summary.badges.map(ub => {
|
||||
const badge = badgeMap[ub.badge_id];
|
||||
badge.count = ub.count;
|
||||
return badge;
|
||||
});
|
||||
}
|
||||
|
||||
return summary;
|
||||
});
|
||||
},
|
||||
|
||||
canManageGroup(group) {
|
||||
@ -543,7 +544,7 @@ User.reopenClass(Singleton, {
|
||||
createCurrent() {
|
||||
const userJson = PreloadStore.get('currentUser');
|
||||
if (userJson) {
|
||||
const store = Discourse.__container__.lookup('store:main');
|
||||
const store = Discourse.__container__.lookup('service:store');
|
||||
return store.createRecord('user', userJson);
|
||||
}
|
||||
return null;
|
||||
|
||||
@ -8,17 +8,7 @@ import SearchService from 'discourse/services/search';
|
||||
import { startTracking, default as TopicTrackingState } from 'discourse/models/topic-tracking-state';
|
||||
import ScreenTrack from 'discourse/lib/screen-track';
|
||||
|
||||
function inject() {
|
||||
const app = arguments[0],
|
||||
name = arguments[1],
|
||||
singletonName = Ember.String.underscore(name).replace(/_/g, '-') + ':main';
|
||||
|
||||
Array.prototype.slice.call(arguments, 2).forEach(dest => app.inject(dest, name, singletonName));
|
||||
}
|
||||
|
||||
function injectAll(app, name) {
|
||||
inject(app, name, 'controller', 'component', 'route', 'model', 'adapter');
|
||||
}
|
||||
const ALL_TARGETS = ['controller', 'component', 'route', 'model', 'adapter'];
|
||||
|
||||
export default {
|
||||
name: "inject-discourse-objects",
|
||||
@ -26,51 +16,62 @@ export default {
|
||||
initialize(container, app) {
|
||||
const appEvents = AppEvents.create();
|
||||
app.register('app-events:main', appEvents, { instantiate: false });
|
||||
injectAll(app, 'appEvents');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'appEvents', 'app-events:main'));
|
||||
DiscourseURL.appEvents = appEvents;
|
||||
|
||||
// backwards compatibility: remove when plugins have updated
|
||||
app.register('store:main', Store);
|
||||
inject(app, 'store', 'route', 'controller', 'service');
|
||||
|
||||
app.register('service:store', Store);
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'store', 'service:store'));
|
||||
|
||||
const messageBus = window.MessageBus;
|
||||
app.register('message-bus:main', messageBus, { instantiate: false });
|
||||
injectAll(app, 'messageBus');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'messageBus', 'message-bus:main'));
|
||||
|
||||
const currentUser = Discourse.User.current();
|
||||
app.register('current-user:main', currentUser, { instantiate: false });
|
||||
|
||||
const topicTrackingState = TopicTrackingState.create({ messageBus, currentUser });
|
||||
app.register('topic-tracking-state:main', topicTrackingState, { instantiate: false });
|
||||
injectAll(app, 'topicTrackingState');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'topicTrackingState', 'topic-tracking-state:main'));
|
||||
|
||||
const site = Discourse.Site.current();
|
||||
app.register('site:main', site, { instantiate: false });
|
||||
injectAll(app, 'site');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'site', 'site:main'));
|
||||
|
||||
const siteSettings = Discourse.SiteSettings;
|
||||
app.register('site-settings:main', siteSettings, { instantiate: false });
|
||||
injectAll(app, 'siteSettings');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'siteSettings', 'site-settings:main'));
|
||||
|
||||
app.register('search-service:main', SearchService);
|
||||
injectAll(app, 'searchService');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'searchService', 'search-service:main'));
|
||||
|
||||
const session = Session.current();
|
||||
app.register('session:main', session, { instantiate: false });
|
||||
injectAll(app, 'session');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'session', 'session:main'));
|
||||
|
||||
const screenTrack = new ScreenTrack(
|
||||
topicTrackingState,
|
||||
siteSettings,
|
||||
session,
|
||||
currentUser
|
||||
);
|
||||
|
||||
const screenTrack = new ScreenTrack(topicTrackingState, siteSettings, session, currentUser);
|
||||
app.register('screen-track:main', screenTrack, { instantiate: false });
|
||||
inject(app, 'screenTrack', 'component', 'route');
|
||||
['component', 'route'].forEach(t => app.inject(t, 'screenTrack', 'screen-track:main'));
|
||||
|
||||
if (currentUser) {
|
||||
inject(app, 'currentUser', 'component', 'route', 'controller');
|
||||
['component', 'route', 'controller'].forEach(t => {
|
||||
app.inject(t, 'currentUser', 'current-user:main');
|
||||
});
|
||||
}
|
||||
|
||||
app.register('location:discourse-location', DiscourseLocation);
|
||||
|
||||
const keyValueStore = new KeyValueStore("discourse_");
|
||||
app.register('key-value-store:main', keyValueStore, { instantiate: false });
|
||||
injectAll(app, 'keyValueStore');
|
||||
ALL_TARGETS.forEach(t => app.inject(t, 'keyValueStore', 'key-value-store:main'));
|
||||
|
||||
startTracking(topicTrackingState);
|
||||
}
|
||||
|
||||
@ -2,12 +2,13 @@ import { ajax } from 'discourse/lib/ajax';
|
||||
import { translateResults, getSearchKey, isValidSearchTerm } from "discourse/lib/search";
|
||||
import PreloadStore from 'preload-store';
|
||||
import { getTransient, setTransient } from 'discourse/lib/page-tracker';
|
||||
import { escapeExpression } from 'discourse/lib/utilities';
|
||||
|
||||
export default Discourse.Route.extend({
|
||||
queryParams: { q: {}, expanded: false, context_id: {}, context: {}, skip_context: {} },
|
||||
|
||||
titleToken() {
|
||||
return I18n.t('search.results_page');
|
||||
return I18n.t('search.results_page', { term: escapeExpression(this.controllerFor("full-page-search").get('searchTerm')) });
|
||||
},
|
||||
|
||||
model(params) {
|
||||
|
||||
@ -9,17 +9,13 @@
|
||||
{{badge-card badge=model size="large" count=userBadges.grant_count}}
|
||||
<div class='badge-grant-info {{if hiddenSetTitle '' 'hidden'}}'>
|
||||
<div>
|
||||
{{#if model.allow_title}}
|
||||
{{#if canSelectTitle}}
|
||||
<div class='grant-info-item'>
|
||||
{{i18n 'badges.allow_title'}}
|
||||
{{#if userBadges}}
|
||||
{{#if model.allow_title}}
|
||||
{{d-button
|
||||
{{d-button
|
||||
class='btn btn-small pad-left no-text'
|
||||
action='toggleSetUserTitle'
|
||||
icon='pencil'}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if model.multiple_grant}}
|
||||
@ -29,10 +25,13 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class='badge-set-title {{if hiddenSetTitle 'hidden' ''}}'>
|
||||
{{badge-title selectableUserBadges=selectableUserBadges user=user}}
|
||||
<button class='btn btn-default close-btn' {{action "toggleSetUserTitle"}}>{{i18n 'close'}}</button>
|
||||
</div>
|
||||
|
||||
{{#if canSelectTitle}}
|
||||
<div class='badge-set-title {{if hiddenSetTitle 'hidden' ''}}'>
|
||||
{{badge-title selectableUserBadges=selectableUserBadges user=user}}
|
||||
<button class='btn btn-default close-btn' {{action "toggleSetUserTitle"}}>{{i18n 'close'}}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if userBadges}}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<div class="control-group">
|
||||
<label class="control-label"></label>
|
||||
<div class="controls">
|
||||
{{combo-box valueAttribute="id" value=selectedUserBadgeId nameProperty="badge.name" content=selectableUserBadges}}
|
||||
{{combo-box value=selectedUserBadgeId nameProperty="badge.name" content=selectableUserBadges}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
<button
|
||||
class="btn {{if text 'btn-icon-text' 'no-text btn-icon'}}"
|
||||
aria-label="{{selectedTitle}}"
|
||||
type="button"
|
||||
title="{{selectedTitle}}">
|
||||
|
||||
{{{icon}}}
|
||||
|
||||
{{#if text}}
|
||||
<span class="d-button-label">{{{text}}}</span>
|
||||
{{/if}}
|
||||
</button>
|
||||
@ -19,8 +19,8 @@
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<label>{{i18n 'category.parent'}}</label>
|
||||
{{category-select-box
|
||||
clearSelectionLabel="category.none"
|
||||
{{category-chooser
|
||||
none="category.none"
|
||||
value=category.parent_category_id
|
||||
categories=parentCategories
|
||||
allowUncategorized=false}}
|
||||
|
||||
@ -61,11 +61,13 @@
|
||||
<section class="field">
|
||||
<label>
|
||||
{{i18n "category.sort_order"}}
|
||||
{{combo-box valueAttribute="value" content=availableSorts value=category.sort_order none="category.sort_options.default"}}
|
||||
{{#unless isDefaultSortOrder}}
|
||||
{{combo-box valueAttribute="value" content=sortAscendingOptions value=category.sort_ascending none="category.sort_options.default"}}
|
||||
{{/unless}}
|
||||
</label>
|
||||
<div class="controls">
|
||||
{{combo-box valueAttribute="value" content=availableSorts value=category.sort_order none="category.sort_options.default"}}
|
||||
{{#unless isDefaultSortOrder}}
|
||||
{{combo-box valueAttribute="value" content=sortAscendingOptions value=category.sort_ascending none="category.sort_options.default"}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="field num-featured-topics-fields">
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
{{else if publishToCategory}}
|
||||
<div class="control-group">
|
||||
<label>{{i18n 'topic.topic_status_update.publish_to'}}</label>
|
||||
{{category-select-box
|
||||
{{category-chooser
|
||||
value=topicTimer.category_id
|
||||
excludeCategoryId=excludeCategoryId}}
|
||||
</div>
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
{{#if isNotifyUser}}
|
||||
<h3>{{formattedName}}</h3>
|
||||
<div class='controls'>
|
||||
<label class='radio'><input type='radio' id="radio_{{unbound flag.name_key}}" {{action "changePostActionType" flag}} name='post_action_type_index'> <span class='description'>{{{flag.description}}}</span></label>
|
||||
{{#if showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div class="custom-message-length {{customMessageLengthClasses}}">{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound flag.name_key}}" {{action "changePostActionType" flag}} name='post_action_type_index'>
|
||||
|
||||
<div class='flag-action-type-details'>
|
||||
<span class='description'>{{{flag.description}}}</span>
|
||||
{{#if showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div class="custom-message-length {{customMessageLengthClasses}}">{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{{#if staffFlagsAvailable}}
|
||||
<hr>
|
||||
@ -14,14 +20,17 @@
|
||||
{{else}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound flag.name_key}}" {{action "changePostActionType" flag}} name='post_action_type_index'> <strong>{{formattedName}}</strong>
|
||||
{{#if showDescription}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/if}}
|
||||
<input type='radio' id="radio_{{unbound flag.name_key}}" {{action "changePostActionType" flag}} name='post_action_type_index'>
|
||||
<div class='flag-action-type-details'>
|
||||
<strong>{{formattedName}}</strong>
|
||||
{{#if showDescription}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/if}}
|
||||
{{#if showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div class="custom-message-length {{customMessageLengthClasses}}">{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</label>
|
||||
{{#if showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div class="custom-message-length {{customMessageLengthClasses}}">{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
<div class="future-date-input">
|
||||
<div class="control-group">
|
||||
<label>{{displayLabel}}</label>
|
||||
|
||||
{{future-date-input-selector
|
||||
valueAttribute="id"
|
||||
minimumResultsForSearch=-1
|
||||
statusType=statusType
|
||||
value=selection
|
||||
input=input
|
||||
includeWeekend=includeWeekend
|
||||
includeForever=includeForever
|
||||
width="50%"
|
||||
includeFarFuture=includeFarFuture
|
||||
none="topic.auto_update_input.none"}}
|
||||
</div>
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
<span class="edit-title">
|
||||
{{text-field value=buffered.title maxlength=siteSettings.max_topic_title_length}}
|
||||
</span>
|
||||
{{category-select-box value=buffered.category_id}}
|
||||
{{category-chooser value=buffered.category_id}}
|
||||
{{else}}
|
||||
<span class='post-title'>
|
||||
{{i18n "queue.topic"}}
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
<input
|
||||
class="select-box-offscreen"
|
||||
type="text"
|
||||
aria-haspopup="true"
|
||||
role="button"
|
||||
aria-labelledby="select-box-input-{{componentId}}"
|
||||
tabindex={{tabindex}}
|
||||
/>
|
||||
|
||||
{{component selectBoxHeaderComponent
|
||||
text=generatedHeadertext
|
||||
selectedTitle=selectedTitle
|
||||
focused=focused
|
||||
caretUpIcon=caretUpIcon
|
||||
caretDownIcon=caretDownIcon
|
||||
onToggle=(action "onToggle")
|
||||
icon=icon
|
||||
expanded=expanded
|
||||
value=value
|
||||
}}
|
||||
|
||||
<div class="select-box-body">
|
||||
{{#if renderBody}}
|
||||
{{#if filterable}}
|
||||
{{component selectBoxFilterComponent
|
||||
onFilterChange=(action "onFilterChange")
|
||||
icon=filterIcon
|
||||
focused=filterFocused
|
||||
placeholder=filterPlaceholder
|
||||
tabindex=tabindex
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{component selectBoxCollectionComponent
|
||||
clearSelectionLabel=clearSelectionLabel
|
||||
filteredContent=filteredContent
|
||||
selectBoxRowComponent=selectBoxRowComponent
|
||||
templateForRow=templateForRow
|
||||
shouldHighlightRow=shouldHighlightRow
|
||||
shouldSelectRow=shouldSelectRow
|
||||
titleForRow=titleForRow
|
||||
idForRow=idForRow
|
||||
onSelectRow=(action "onSelectRow")
|
||||
onHoverRow=(action "onHoverRow")
|
||||
onClearSelection=(action "onClearSelection")
|
||||
noContentLabel=noContentLabel
|
||||
highlightedValue=highlightedValue
|
||||
value=value
|
||||
}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if wrapper}}
|
||||
<div class="select-box-wrapper"></div>
|
||||
{{/if}}
|
||||
@ -1,28 +0,0 @@
|
||||
<ul class="collection">
|
||||
{{#if clearSelectionLabel}}
|
||||
<li {{action "onClearSelection" on="click"}} class="select-box-row clear-selection">
|
||||
{{i18n clearSelectionLabel}}
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#each filteredContent as |content|}}
|
||||
{{component selectBoxRowComponent
|
||||
content=content
|
||||
templateForRow=templateForRow
|
||||
idForRow=idForRow
|
||||
titleForRow=titleForRow
|
||||
shouldHighlightRow=shouldHighlightRow
|
||||
shouldSelectRow=shouldSelectRow
|
||||
highlightedValue=highlightedValue
|
||||
onSelect=onSelectRow
|
||||
onHover=onHoverRow
|
||||
value=value
|
||||
}}
|
||||
{{else}}
|
||||
{{#if noContentLabel}}
|
||||
<li class="select-box-row no-content">
|
||||
{{noContentLabel}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@ -1,9 +0,0 @@
|
||||
{{#if icon}}
|
||||
{{d-icon icon class="icon"}}
|
||||
{{/if}}
|
||||
|
||||
<span class="current-selection" title={{selectedTitle}}>
|
||||
{{text}}
|
||||
</span>
|
||||
|
||||
{{d-icon caretIcon class="caret-icon"}}
|
||||
@ -1 +0,0 @@
|
||||
{{{template}}}
|
||||
@ -1,5 +1,11 @@
|
||||
<span class='value'>
|
||||
{{#if icon}}{{d-icon icon}}{{/if}}
|
||||
{{number value}}
|
||||
{{#if isNumber}}
|
||||
{{number value}}
|
||||
{{else}}
|
||||
{{value}}
|
||||
{{/if}}
|
||||
</span>
|
||||
<span class='label'>
|
||||
{{#if icon}}{{d-icon icon}}{{/if}}
|
||||
{{{i18n label count=value}}}
|
||||
</span>
|
||||
<span class='label'>{{{i18n label count=value}}}</span>
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
<h3 class='stats-title'>{{i18n (concat "user.summary." title)}}</h3>
|
||||
{{yield}}
|
||||
@ -0,0 +1,9 @@
|
||||
<span class='topic-info'>
|
||||
{{format-date createdAt format="tiny" noTitle="true"}}
|
||||
{{#if likes}}
|
||||
·
|
||||
{{d-icon 'heart'}} <span class='like-count'>{{number likes}}</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
<br>
|
||||
<a href="{{unbound url}}">{{{topic.fancyTitle}}}</a>
|
||||
@ -0,0 +1,16 @@
|
||||
{{#if items}}
|
||||
<ul>
|
||||
{{#each items as |item|}}
|
||||
{{yield item}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{#if hasMore}}
|
||||
<p>
|
||||
{{#link-to (concat "userActivity." type) user class="more"}}
|
||||
{{i18n (concat "user.summary.more_" type)}}
|
||||
{{/link-to}}
|
||||
</p>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<p>{{i18n (concat "user.summary.no_" type)}}</p>
|
||||
{{/if}}
|
||||
@ -0,0 +1,4 @@
|
||||
{{#user-info user=user}}
|
||||
{{d-icon icon}}
|
||||
<span class={{countClass}}>{{number user.count}}</span>
|
||||
{{/user-info}}
|
||||
@ -0,0 +1,9 @@
|
||||
{{#if users}}
|
||||
<ul>
|
||||
{{#each users as |user|}}
|
||||
{{yield user}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p>{{i18n (concat "user.summary." none)}}</p>
|
||||
{{/if}}
|
||||
@ -72,7 +72,7 @@
|
||||
|
||||
{{#if model.showCategoryChooser}}
|
||||
<div class="category-input">
|
||||
{{category-select-box value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}}
|
||||
{{category-chooser value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}}
|
||||
{{popup-input-tip validation=categoryValidation}}
|
||||
</div>
|
||||
{{#if model.archetype.hasOptions}}
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
<span class='desc'>
|
||||
{{i18n "search.sort_by"}}
|
||||
</span>
|
||||
{{combo-box value=sortOrder content=sortOrders castInteger="true"}}
|
||||
{{combo-box value=sortOrder content=sortOrders castInteger=true}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<p>{{i18n "topics.bulk.choose_new_category"}}</p>
|
||||
|
||||
<p>{{category-select-box value=newCategoryId}}</p>
|
||||
<p>{{category-chooser value=newCategoryId}}</p>
|
||||
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{d-button action="changeCategory" label="topics.bulk.change_category"}}
|
||||
|
||||
@ -18,7 +18,8 @@
|
||||
action=(action "createFlag")
|
||||
disabled=submitDisabled
|
||||
title="flagging.submit_tooltip"
|
||||
translatedLabel=submitText}}
|
||||
icon=submitIcon
|
||||
label=submitLabel}}
|
||||
|
||||
{{#if canSendWarning}}
|
||||
{{d-button
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
||||
<label>{{i18n 'categories.category'}}</label>
|
||||
{{category-select-box value=categoryId class="small"}}
|
||||
{{category-chooser value=categoryId class="small"}}
|
||||
</form>
|
||||
{{/d-modal-body}}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user