Version bump
This commit is contained in:
commit
cc4bfa7b45
@ -20,4 +20,5 @@ vendor/
|
||||
test/javascripts/helpers/
|
||||
test/javascripts/test_helper.js
|
||||
test/javascripts/test_helper.js
|
||||
app/assets/javascripts/ember-addons/
|
||||
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
"parseHTML",
|
||||
"deepEqual",
|
||||
"notEqual",
|
||||
"define",
|
||||
"require",
|
||||
"requirejs",
|
||||
"hasModule",
|
||||
|
||||
2
Gemfile
2
Gemfile
@ -42,7 +42,7 @@ gem 'active_model_serializers', '~> 0.8.3'
|
||||
gem 'onebox'
|
||||
|
||||
gem 'ember-rails'
|
||||
gem 'ember-source', '1.9.0.beta.4'
|
||||
gem 'ember-source', '1.11.3.1'
|
||||
gem 'handlebars-source', '2.0.0'
|
||||
gem 'barber'
|
||||
gem 'babel-transpiler'
|
||||
|
||||
37
Gemfile.lock
37
Gemfile.lock
@ -45,10 +45,9 @@ GEM
|
||||
babel-transpiler (0.6.0)
|
||||
babel-source (>= 4.0, < 5)
|
||||
execjs (~> 2.0)
|
||||
barber (0.5.0)
|
||||
ember-source
|
||||
execjs
|
||||
handlebars-source (>= 1.0.0.rc.4)
|
||||
barber (0.9.0)
|
||||
ember-source (>= 1.0, < 2)
|
||||
execjs (>= 1.2, < 3)
|
||||
better_errors (2.1.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubis (>= 2.6.6)
|
||||
@ -68,23 +67,23 @@ GEM
|
||||
docile (1.1.5)
|
||||
dotenv (1.0.2)
|
||||
email_reply_parser (0.5.8)
|
||||
ember-data-source (0.14)
|
||||
ember-source
|
||||
ember-rails (0.14.1)
|
||||
ember-data-source (1.0.0.beta.16.1)
|
||||
ember-source (~> 1.8)
|
||||
ember-handlebars-template (0.1.5)
|
||||
barber (>= 0.9.0)
|
||||
sprockets (>= 2.1, < 3.1)
|
||||
ember-rails (0.18.2)
|
||||
active_model_serializers
|
||||
barber (>= 0.4.1)
|
||||
ember-data-source
|
||||
ember-source
|
||||
execjs (>= 1.2)
|
||||
handlebars-source
|
||||
ember-data-source (>= 1.0.0.beta.5)
|
||||
ember-handlebars-template (>= 0.1.1, < 1.0)
|
||||
ember-source (>= 1.1.0)
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
ember-source (1.9.0.beta.4)
|
||||
handlebars-source (~> 2.0)
|
||||
ember-source (1.11.3.1)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.7)
|
||||
excon (0.44.4)
|
||||
execjs (2.4.0)
|
||||
execjs (2.5.2)
|
||||
exifr (1.1.3)
|
||||
fabrication (2.9.8)
|
||||
fakeweb (1.3.0)
|
||||
@ -220,7 +219,7 @@ GEM
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mini_portile (0.6.2)
|
||||
minitest (5.6.0)
|
||||
minitest (5.6.1)
|
||||
mocha (1.1.0)
|
||||
metaclass (~> 0.0.1)
|
||||
mock_redis (0.14.0)
|
||||
@ -271,7 +270,7 @@ GEM
|
||||
omniauth-twitter (1.0.1)
|
||||
multi_json (~> 1.3)
|
||||
omniauth-oauth (~> 1.0)
|
||||
onebox (1.5.16)
|
||||
onebox (1.5.18)
|
||||
moneta (~> 0.7)
|
||||
multi_json (~> 1.7)
|
||||
mustache (~> 0.99)
|
||||
@ -295,7 +294,7 @@ GEM
|
||||
qunit-rails (0.0.7)
|
||||
railties
|
||||
r2 (0.2.5)
|
||||
rack (1.5.2)
|
||||
rack (1.5.3)
|
||||
rack-mini-profiler (0.9.3)
|
||||
rack (>= 1.1.3)
|
||||
rack-openid (1.3.1)
|
||||
@ -467,7 +466,7 @@ DEPENDENCIES
|
||||
certified
|
||||
email_reply_parser
|
||||
ember-rails
|
||||
ember-source (= 1.9.0.beta.4)
|
||||
ember-source (= 1.11.3.1)
|
||||
eventmachine
|
||||
fabrication (= 2.9.8)
|
||||
fakeweb (~> 1.3.0)
|
||||
|
||||
2
Vagrantfile
vendored
2
Vagrantfile
vendored
@ -17,7 +17,7 @@ Vagrant.configure("2") do |config|
|
||||
|
||||
config.vm.provider :virtualbox do |v|
|
||||
# This setting gives the VM 1024MB of RAM instead of the default 384.
|
||||
v.customize ["modifyvm", :id, "--memory", [ENV['DISCOURSE_VM_MEM'].to_i, 2048].max]
|
||||
v.customize ["modifyvm", :id, "--memory", [ENV['DISCOURSE_VM_MEM'].to_i, 1024].max]
|
||||
|
||||
# Who has a single core cpu these days anyways?
|
||||
cpu_count = 2
|
||||
|
||||
@ -3,8 +3,8 @@ export default Ember.ObjectController.extend({
|
||||
savedIpAddress: null,
|
||||
|
||||
isRange: function() {
|
||||
return this.get("ip_address").indexOf("/") > 0;
|
||||
}.property("ip_address"),
|
||||
return this.get("model.ip_address").indexOf("/") > 0;
|
||||
}.property("model.ip_address"),
|
||||
|
||||
actions: {
|
||||
allow: function(record) {
|
||||
@ -19,14 +19,14 @@ export default Ember.ObjectController.extend({
|
||||
|
||||
edit: function() {
|
||||
if (!this.get('editing')) {
|
||||
this.savedIpAddress = this.get('ip_address');
|
||||
this.savedIpAddress = this.get('model.ip_address');
|
||||
}
|
||||
this.set('editing', true);
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
if (this.get('savedIpAddress') && this.get('editing')) {
|
||||
this.set('ip_address', this.get('savedIpAddress'));
|
||||
this.set('model.ip_address', this.get('savedIpAddress'));
|
||||
}
|
||||
this.set('editing', false);
|
||||
},
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Ember.ArrayController.extend(Presence, {
|
||||
export default Ember.ArrayController.extend({
|
||||
loading: false,
|
||||
|
||||
actions: {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Ember.ArrayController.extend(Presence, {
|
||||
export default Ember.ArrayController.extend({
|
||||
loading: false,
|
||||
itemController: 'admin-log-screened-ip-address',
|
||||
filter: null,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Ember.ArrayController.extend(Presence, {
|
||||
export default Ember.ArrayController.extend({
|
||||
loading: false,
|
||||
|
||||
show() {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Ember.ArrayController.extend(Presence, {
|
||||
export default Ember.ArrayController.extend({
|
||||
loading: false,
|
||||
filters: null,
|
||||
|
||||
|
||||
@ -1,11 +1,6 @@
|
||||
/**
|
||||
Represents an IP address that is watched for during account registration
|
||||
(and possibly other times), and an action is taken.
|
||||
|
||||
@class ScreenedIpAddress
|
||||
@extends Discourse.Model
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ScreenedIpAddress = Discourse.Model.extend({
|
||||
actionName: function() {
|
||||
@ -17,21 +12,9 @@ Discourse.ScreenedIpAddress = Discourse.Model.extend({
|
||||
}.property('action_name'),
|
||||
|
||||
actionIcon: function() {
|
||||
if (this.get('action_name') === 'block') {
|
||||
return this.get('blockIcon');
|
||||
} else {
|
||||
return this.get('doNothingIcon');
|
||||
}
|
||||
return (this.get('action_name') === 'block') ? 'ban' : 'check';
|
||||
}.property('action_name'),
|
||||
|
||||
blockIcon: function() {
|
||||
return 'fa-ban';
|
||||
}.property(),
|
||||
|
||||
doNothingIcon: function() {
|
||||
return 'fa-check';
|
||||
}.property(),
|
||||
|
||||
save: function() {
|
||||
return Discourse.ajax("/admin/logs/screened_ip_addresses" + (this.id ? '/' + this.id : '') + ".json", {
|
||||
type: this.id ? 'PUT' : 'POST',
|
||||
|
||||
@ -18,10 +18,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if showHtml}}
|
||||
{{{html_content}}}
|
||||
{{else}}
|
||||
<pre>{{{text_content}}}</pre>
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
@ -147,7 +147,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{loading-spinner condition=view.loading}}
|
||||
{{conditional-loading-spinner condition=view.loading}}
|
||||
{{else}}
|
||||
<p>{{i18n 'admin.flags.no_results'}}</p>
|
||||
{{/if}}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
</p>
|
||||
<br>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if model.length}}
|
||||
|
||||
<div class='table screened-emails'>
|
||||
@ -25,4 +25,4 @@
|
||||
{{else}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
{{screened-ip-address-form action="recordAdded"}}
|
||||
<br/>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if model.length}}
|
||||
|
||||
<div class='table admin-logs-table screened-ip-addresses'>
|
||||
@ -27,4 +27,4 @@
|
||||
{{else}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
<div class="col first ip_address">
|
||||
{{#if editing}}
|
||||
{{text-field value=ip_address autofocus="autofocus"}}
|
||||
{{text-field value=model.ip_address autofocus="autofocus"}}
|
||||
{{else}}
|
||||
<span {{action "edit" this}}>
|
||||
{{#if isRange}}
|
||||
<strong>{{ip_address}}</strong>
|
||||
<strong>{{model.ip_address}}</strong>
|
||||
{{else}}
|
||||
{{ip_address}}
|
||||
{{model.ip_address}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="col action">
|
||||
<i {{bind-attr class=":fa actionIcon"}}></i>
|
||||
{{actionName}}
|
||||
{{fa-icon model.actionIcon}}
|
||||
{{model.actionName}}
|
||||
</div>
|
||||
<div class="col match_count">{{match_count}}</div>
|
||||
<div class="col match_count">{{model.match_count}}</div>
|
||||
<div class="col last_match_at">
|
||||
{{#if last_match_at}}
|
||||
{{age-with-tooltip last_match_at}}
|
||||
{{#if model.last_match_at}}
|
||||
{{age-with-tooltip model.last_match_at}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="col created_at">{{age-with-tooltip created_at}}</div>
|
||||
<div class="col created_at">{{age-with-tooltip model.created_at}}</div>
|
||||
<div class="col actions">
|
||||
{{#unless editing}}
|
||||
<button class="btn btn-danger" {{action "destroy" this}}><i class="fa fa-trash-o"></i></button>
|
||||
<button class="btn" {{action "edit" this}}><i class="fa fa-pencil"></i></button>
|
||||
{{#if isBlocked}}
|
||||
<button class="btn" {{action "allow" this}}><i {{bind-attr class=":fa doNothingIcon"}}></i> {{i18n 'admin.logs.screened_ips.actions.do_nothing'}}</button>
|
||||
{{#if model.isBlocked}}
|
||||
<button class="btn" {{action "allow" this}}>{{fa-icon "check"}} {{i18n 'admin.logs.screened_ips.actions.do_nothing'}}</button>
|
||||
{{else}}
|
||||
<button class="btn" {{action "block" this}}><i {{bind-attr class=":fa blockIcon"}}></i> {{i18n 'admin.logs.screened_ips.actions.block'}}</button>
|
||||
<button class="btn" {{action "block" this}}>{{fa-icon "ban"}} {{i18n 'admin.logs.screened_ips.actions.block'}}</button>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<button class="btn" {{action "save" this}}>{{i18n 'admin.logs.save'}}</button>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
</p>
|
||||
<br>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if model.length}}
|
||||
<div class='table screened-urls'>
|
||||
<div class="heading-container">
|
||||
@ -21,4 +21,4 @@
|
||||
{{else}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="staff-action-logs-instructions" {{bind-attr class=":staff-action-logs-instructions showInstructions::invisible"}}>
|
||||
<div class="staff-action-logs-instructions {{unless showInstructions 'invisible'}}">
|
||||
{{i18n 'admin.logs.staff_actions.instructions'}}
|
||||
</div>
|
||||
|
||||
@ -48,11 +48,11 @@
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if model.length}}
|
||||
{{view "staff-action-logs-list" content=controller}}
|
||||
{{else}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
</div>
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#loading-spinner condition=refreshing}}
|
||||
{{#conditional-loading-spinner condition=refreshing}}
|
||||
<table class='table report'>
|
||||
<tr>
|
||||
<th>{{xaxis}}</th>
|
||||
@ -43,4 +43,4 @@
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
<div class='admin-container user-badges'>
|
||||
<h2>{{i18n 'admin.badges.grant_badge'}}</h2>
|
||||
<br>
|
||||
@ -67,4 +67,4 @@
|
||||
{{/each}}
|
||||
</table>
|
||||
</div>
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
@ -316,7 +316,7 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class='display-row' {{bind-attr class=":display-row blocked:highlight-danger"}}>
|
||||
<div {{bind-attr class=":display-row blocked:highlight-danger"}}>
|
||||
<div class='field'>{{i18n 'admin.user.blocked'}}</div>
|
||||
<div class='value'>{{blocked}}</div>
|
||||
<div class='controls'>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{{#if hasSelection}}
|
||||
<div id='selected-controls'>
|
||||
<button {{action "approveUsers"}} class='btn'>{{countI18n admin.users.approved_selected count=selectedCount}}</button>
|
||||
<button {{action "rejectUsers"}} class='btn btn-danger'>{{countI18n admin.users.reject_selected count=selectedCount}}</button>
|
||||
<button {{action "approveUsers"}} class='btn'>{{count-i18n key="admin.users.approved_selected" count=selectedCount}}</button>
|
||||
<button {{action "rejectUsers"}} class='btn btn-danger'>{{count-i18n key="admin.users.reject_selected" count=selectedCount}}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
{{#loading-spinner condition=refreshing}}
|
||||
{{#conditional-loading-spinner condition=refreshing}}
|
||||
{{#if model}}
|
||||
<table class='table'>
|
||||
<tr>
|
||||
@ -81,4 +81,4 @@
|
||||
{{else}}
|
||||
<p>{{i18n 'search.no_results'}}</p>
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
{{else}}
|
||||
<span {{bind-attr class=":icon versionCheck.critical_updates:critical-updates-available:updates-available"}}>
|
||||
{{#if versionCheck.behindByOneVersion}}
|
||||
{{fa-icon "smile-o"}}
|
||||
{{fa-icon "meh-o"}}
|
||||
{{else}}
|
||||
{{fa-icon "frown-o"}}
|
||||
{{/if}}
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
Discourse.ScreenedEmailsListView = Ember.ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 32,
|
||||
itemViewClass: Ember.ListItemView.extend({templateName: "admin/templates/logs/screened_emails_list_item"})
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
Discourse.ScreenedIpAddressesListView = Ember.ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 32,
|
||||
itemViewClass: Ember.ListItemView.extend({templateName: "admin/templates/logs/screened_ip_addresses_list_item"})
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
Discourse.ScreenedUrlsListView = Ember.ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 32,
|
||||
itemViewClass: Ember.ListItemView.extend({templateName: "admin/templates/logs/screened_urls_list_item"})
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
Discourse.StaffActionLogsListView = Ember.ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 75,
|
||||
itemViewClass: Ember.ListItemView.extend({templateName: "admin/templates/logs/staff_action_logs_list_item"})
|
||||
});
|
||||
@ -0,0 +1,8 @@
|
||||
import ListView from 'ember-addons/list-view';
|
||||
import ListItemView from 'ember-addons/list-item-view';
|
||||
|
||||
export default ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 32,
|
||||
itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/screened_emails_list_item"})
|
||||
});
|
||||
@ -0,0 +1,8 @@
|
||||
import ListView from 'ember-addons/list-view';
|
||||
import ListItemView from 'ember-addons/list-item-view';
|
||||
|
||||
export default ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 32,
|
||||
itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/screened_ip_addresses_list_item"})
|
||||
});
|
||||
@ -0,0 +1,8 @@
|
||||
import ListView from 'ember-addons/list-view';
|
||||
import ListItemView from 'ember-addons/list-item-view';
|
||||
|
||||
export default ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 32,
|
||||
itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/screened_urls_list_item"})
|
||||
});
|
||||
@ -0,0 +1,8 @@
|
||||
import ListView from 'ember-addons/list-view';
|
||||
import ListItemView from 'ember-addons/list-item-view';
|
||||
|
||||
export default ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 75,
|
||||
itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/staff_action_logs_list_item"})
|
||||
});
|
||||
@ -1,6 +1,11 @@
|
||||
/*global Favcount:true*/
|
||||
var DiscourseResolver = require('discourse/ember/resolver').default;
|
||||
|
||||
// Allow us to import Ember
|
||||
define('ember', ['exports'], function(__exports__) {
|
||||
__exports__["default"] = Ember;
|
||||
});
|
||||
|
||||
window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
||||
rootElement: '#main',
|
||||
_docTitle: document.title,
|
||||
|
||||
@ -15,21 +15,21 @@ export default Ember.Component.extend(StringBuffer, {
|
||||
if (this.get('isIndexStream')) {
|
||||
return !this.get('userActionType');
|
||||
}
|
||||
var content = this.get('content');
|
||||
const content = this.get('content');
|
||||
if (content) {
|
||||
return parseInt(this.get('userActionType'), 10) === parseInt(Em.get(content, 'action_type'), 10);
|
||||
}
|
||||
}.property('userActionType', 'indexStream'),
|
||||
}.property('userActionType', 'isIndexStream'),
|
||||
|
||||
activityCount: function() {
|
||||
return this.get('content.count') || this.get('count') || 0;
|
||||
}.property('content.count', 'count'),
|
||||
|
||||
typeKey: function() {
|
||||
var actionType = this.get('content.action_type');
|
||||
const actionType = this.get('content.action_type');
|
||||
if (actionType === Discourse.UserAction.TYPES.messages_received) { return ""; }
|
||||
|
||||
var result = Discourse.UserAction.TYPES_INVERTED[actionType];
|
||||
const result = Discourse.UserAction.TYPES_INVERTED[actionType];
|
||||
if (!result) { return ""; }
|
||||
|
||||
// We like our URLS to have hyphens, not underscores
|
||||
@ -44,9 +44,9 @@ export default Ember.Component.extend(StringBuffer, {
|
||||
return this.get('content.description') || I18n.t("user.filters.all");
|
||||
}.property('content.description'),
|
||||
|
||||
renderString: function(buffer) {
|
||||
renderString(buffer) {
|
||||
buffer.push("<a href='" + this.get('url') + "'>");
|
||||
var icon = this.get('icon');
|
||||
const icon = this.get('icon');
|
||||
if (icon) {
|
||||
buffer.push("<i class='glyph fa fa-" + icon + "'></i> ");
|
||||
}
|
||||
@ -20,7 +20,7 @@ export default Ember.Component.extend({
|
||||
}.observes("autoCloseTime", "limited"),
|
||||
|
||||
_isAutoCloseValid: function(autoCloseTime, limited) {
|
||||
var t = (autoCloseTime || "").trim();
|
||||
var t = (autoCloseTime || "").toString().trim();
|
||||
if (t.length === 0) {
|
||||
// "empty" is always valid
|
||||
return true;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import ComboboxView from 'discourse/views/combo-box';
|
||||
import ComboboxView from 'discourse/components/combo-box';
|
||||
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
|
||||
|
||||
export default ComboboxView.extend({
|
||||
@ -41,7 +41,7 @@ export default ComboboxView.extend({
|
||||
}
|
||||
}.property(),
|
||||
|
||||
template(item) {
|
||||
comboTemplate(item) {
|
||||
|
||||
let category;
|
||||
|
||||
@ -2,10 +2,7 @@ var get = Ember.get;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNameBindings: ['category::no-category', 'categories:has-drop','categoryStyle'],
|
||||
|
||||
categoryStyle: function(){
|
||||
return Discourse.SiteSettings.category_style;
|
||||
}.property(),
|
||||
categoryStyle: Discourse.computed.setting('category_style'),
|
||||
|
||||
tagName: 'li',
|
||||
|
||||
@ -50,11 +47,11 @@ export default Ember.Component.extend({
|
||||
if (color) {
|
||||
var style = "";
|
||||
if (color) { style += "background-color: #" + color + ";" }
|
||||
return style;
|
||||
return style.htmlSafe();
|
||||
}
|
||||
}
|
||||
|
||||
return "background-color: #eee;";
|
||||
return "background-color: #eee;".htmlSafe();
|
||||
}.property('category'),
|
||||
|
||||
badgeStyle: function() {
|
||||
@ -68,11 +65,11 @@ export default Ember.Component.extend({
|
||||
var style = "";
|
||||
if (color) { style += "background-color: #" + color + "; border-color: #" + color + ";"; }
|
||||
if (textColor) { style += "color: #" + textColor + "; "; }
|
||||
return style;
|
||||
return style.htmlSafe();
|
||||
}
|
||||
}
|
||||
|
||||
return "background-color: #eee; color: #333";
|
||||
return "background-color: #eee; color: #333".htmlSafe();
|
||||
}.property('category'),
|
||||
|
||||
clickEventName: function() {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
// This view handles rendering of a combobox
|
||||
export default Discourse.View.extend({
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'select',
|
||||
attributeBindings: ['tabindex'],
|
||||
classNames: ['combobox'],
|
||||
@ -65,7 +64,7 @@ export default Discourse.View.extend({
|
||||
o.selected = !!$(o).attr('selected');
|
||||
});
|
||||
|
||||
$elem.select2({formatResult: this.template, minimumResultsForSearch: 5, width: 'resolve'});
|
||||
$elem.select2({formatResult: this.comboTemplate, minimumResultsForSearch: 5, width: 'resolve'});
|
||||
|
||||
const castInteger = this.get('castInteger');
|
||||
$elem.on("change", function (e) {
|
||||
@ -9,7 +9,7 @@ export default Ember.Component.extend({
|
||||
if (this.get('condition')) {
|
||||
buffer.push('<div class="spinner ' + this.get('size') + '"}}></div>');
|
||||
} else {
|
||||
return this._super();
|
||||
return this._super(buffer);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
export default Ember.Component.extend(Discourse.StringBuffer, {
|
||||
tagName: 'span',
|
||||
rerenderTriggers: ['count', 'suffix'],
|
||||
|
||||
renderString: function(buffer) {
|
||||
buffer.push(I18n.t(this.get('key') + (this.get('suffix') || ''), { count: this.get('count') }));
|
||||
}
|
||||
});
|
||||
@ -26,7 +26,7 @@ export default Ember.Component.extend({
|
||||
if (label) { buffer.push(label); }
|
||||
} else {
|
||||
// If no label or icon is present, yield
|
||||
return this._super();
|
||||
return this._super(buffer);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
17
app/assets/javascripts/discourse/components/input-tip.js.es6
Normal file
17
app/assets/javascripts/discourse/components/input-tip.js.es6
Normal file
@ -0,0 +1,17 @@
|
||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
classNameBindings: [':tip', 'good', 'bad'],
|
||||
rerenderTriggers: ['validation'],
|
||||
|
||||
bad: Em.computed.alias('validation.failed'),
|
||||
good: Em.computed.not('bad'),
|
||||
|
||||
renderString(buffer) {
|
||||
const reason = this.get('validation.reason');
|
||||
if (reason) {
|
||||
buffer.push(iconHTML(this.get('good') ? 'check' : 'times') + ' ' + reason);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,22 +1,55 @@
|
||||
const INVITED_TYPE = 8;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['notification.read', 'notification.is_warning'],
|
||||
|
||||
scope: function() {
|
||||
return "notifications." + this.site.get("notificationLookup")[this.get("notification.notification_type")];
|
||||
}.property("notification.notification_type"),
|
||||
|
||||
url: function() {
|
||||
const it = this.get('notification');
|
||||
const badgeId = it.get("data.badge_id");
|
||||
if (badgeId) {
|
||||
const badgeName = it.get("data.badge_name");
|
||||
return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase());
|
||||
}
|
||||
|
||||
const topicId = it.get('topic_id');
|
||||
if (topicId) {
|
||||
return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number"));
|
||||
}
|
||||
|
||||
if (it.get('notification_type') === INVITED_TYPE) {
|
||||
return Discourse.getURL('/my/invited');
|
||||
}
|
||||
}.property("notification.data.{badge_id,badge_name}", "model.slug", "model.topic_id", "model.post_number"),
|
||||
|
||||
description: function() {
|
||||
const badgeName = this.get("notification.data.badge_name");
|
||||
if (badgeName) { return Handlebars.Utils.escapeExpression(badgeName); }
|
||||
|
||||
const title = this.get('notification.data.topic_title');
|
||||
return Ember.isEmpty(title) ? "" : Handlebars.Utils.escapeExpression(title);
|
||||
}.property("notification.data.{badge_name,topic_title}"),
|
||||
|
||||
_markRead: function(){
|
||||
var self = this;
|
||||
this.$('a').click(function(){
|
||||
self.set('notification.read', true);
|
||||
this.$('a').click(() => {
|
||||
this.set('notification.read', true);
|
||||
return true;
|
||||
});
|
||||
}.on('didInsertElement'),
|
||||
|
||||
render: function(buffer) {
|
||||
var notification = this.get('notification'),
|
||||
text = I18n.t(this.get('scope'), Em.getProperties(notification, 'description', 'username'));
|
||||
render(buffer) {
|
||||
const notification = this.get('notification');
|
||||
const description = this.get('description');
|
||||
const username = notification.get('data.display_username');
|
||||
const text = I18n.t(this.get('scope'), {description, username});
|
||||
|
||||
var url = notification.get('url');
|
||||
const url = this.get('url');
|
||||
if (url) {
|
||||
buffer.push('<a href="' + notification.get('url') + '">' + text + '</a>');
|
||||
buffer.push('<a href="' + url + '">' + text + '</a>');
|
||||
} else {
|
||||
buffer.push(text);
|
||||
}
|
||||
|
||||
@ -1,23 +1,14 @@
|
||||
/**
|
||||
This view extends the functionality of InputTipView with these extra features:
|
||||
* it can be dismissed
|
||||
* it bounces when it's shown
|
||||
* it's absolutely positioned beside the input element, with the help of
|
||||
extra css you'll need to write to line it up correctly.
|
||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
|
||||
@class PopupInputTipView
|
||||
@extends Discourse.View
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.PopupInputTipView = Discourse.View.extend({
|
||||
templateName: 'popup_input_tip',
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
classNameBindings: [':popup-tip', 'good', 'bad', 'shownAt::hide'],
|
||||
animateAttribute: null,
|
||||
bouncePixels: 6,
|
||||
bounceDelay: 100,
|
||||
rerenderTriggers: ['validation.reason'],
|
||||
|
||||
click: function() {
|
||||
click() {
|
||||
this.set('shownAt', false);
|
||||
},
|
||||
|
||||
@ -43,17 +34,23 @@ Discourse.PopupInputTipView = Discourse.View.extend({
|
||||
}
|
||||
}.observes('shownAt'),
|
||||
|
||||
bounceLeft: function($elem) {
|
||||
renderString(buffer) {
|
||||
const reason = this.get('validation.reason');
|
||||
if (!reason) { return; }
|
||||
|
||||
buffer.push("<span class='close'>" + iconHTML('times-circle') + "</span>");
|
||||
buffer.push(reason);
|
||||
},
|
||||
|
||||
bounceLeft($elem) {
|
||||
for( var i = 0; i < 5; i++ ) {
|
||||
$elem.animate({ left: '+=' + this.bouncePixels }, this.bounceDelay).animate({ left: '-=' + this.bouncePixels }, this.bounceDelay);
|
||||
}
|
||||
},
|
||||
|
||||
bounceRight: function($elem) {
|
||||
bounceRight($elem) {
|
||||
for( var i = 0; i < 5; i++ ) {
|
||||
$elem.animate({ right: '-=' + this.bouncePixels }, this.bounceDelay).animate({ right: '+=' + this.bouncePixels }, this.bounceDelay);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Discourse.View.registerHelper('popupInputTip', Discourse.PopupInputTipView);
|
||||
@ -1,11 +1,3 @@
|
||||
/**
|
||||
The controls for toggling the supression of deleted posts
|
||||
|
||||
@class ToggleDeletedComponent
|
||||
@extends Ember.Component
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default Ember.Component.extend({
|
||||
layoutName: 'components/toggle-deleted',
|
||||
tagName: 'section',
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['user-stat']
|
||||
});
|
||||
@ -4,9 +4,8 @@ export default Ember.Component.extend({
|
||||
}.observes("visible"),
|
||||
|
||||
render: function(buffer){
|
||||
if(!this.get("visible")){
|
||||
return;
|
||||
}
|
||||
if (this._state !== 'inDOM' && this._state !== 'preRender' && this._state !== 'inBuffer') { return; }
|
||||
if (!this.get("visible")) { return; }
|
||||
|
||||
return this._super(buffer);
|
||||
}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
faqOverriden: Ember.computed.gt('siteSettings.faq_url.length', 0),
|
||||
|
||||
contactInfo: function() {
|
||||
|
||||
@ -1,25 +1,19 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
/**
|
||||
Controller for showing a particular badge.
|
||||
|
||||
@class BadgesShowController
|
||||
@extends ObjectController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default ObjectController.extend({
|
||||
noMoreBadges: false,
|
||||
userBadges: null,
|
||||
needs: ["application"],
|
||||
|
||||
actions: {
|
||||
loadMore: function() {
|
||||
var self = this;
|
||||
var userBadges = this.get('userBadges');
|
||||
loadMore() {
|
||||
const self = this;
|
||||
const userBadges = this.get('userBadges');
|
||||
|
||||
Discourse.UserBadge.findByBadgeId(this.get('model.id'), {
|
||||
offset: userBadges.length
|
||||
}).then(function(userBadges) {
|
||||
self.get('userBadges').pushObjects(userBadges);
|
||||
}).then(function(result) {
|
||||
userBadges.pushObjects(result);
|
||||
if(userBadges.length === 0){
|
||||
self.set('noMoreBadges', true);
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
// Modal related to changing the ownership of posts
|
||||
export default ObjectController.extend(Discourse.SelectedPostsCount, ModalFunctionality, {
|
||||
export default ObjectController.extend(Presence, SelectedPostsCount, ModalFunctionality, {
|
||||
needs: ['topic'],
|
||||
|
||||
topicController: Em.computed.alias('controllers.topic'),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import DiscourseController from 'discourse/controllers/controller';
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
|
||||
export default DiscourseController.extend({
|
||||
export default Ember.ObjectController.extend(Presence, {
|
||||
needs: ['modal', 'topic', 'composer-messages', 'application'],
|
||||
|
||||
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY),
|
||||
@ -10,6 +10,14 @@ export default DiscourseController.extend({
|
||||
editReason: null,
|
||||
maxTitleLength: Discourse.computed.setting('max_topic_title_length'),
|
||||
scopedCategoryId: null,
|
||||
similarTopics: null,
|
||||
similarTopicsMessage: null,
|
||||
lastSimilaritySearch: null,
|
||||
|
||||
topic: null,
|
||||
|
||||
// TODO: Remove this, very bad
|
||||
view: null,
|
||||
|
||||
_initializeSimilar: function() {
|
||||
this.set('similarTopics', []);
|
||||
@ -183,7 +191,7 @@ export default DiscourseController.extend({
|
||||
// for now handle a very narrow use case
|
||||
// if we are replying to a topic AND not on the topic pop the window up
|
||||
if (!force && composer.get('replyingToTopic')) {
|
||||
const topic = this.get('topic');
|
||||
const topic = this.get('model.topic');
|
||||
if (!topic || topic.get('id') !== composer.get('topic.id'))
|
||||
{
|
||||
const message = I18n.t("composer.posting_not_on_topic");
|
||||
@ -226,7 +234,6 @@ export default DiscourseController.extend({
|
||||
imageSizes: this.get('view').imageSizes(),
|
||||
editReason: this.get("editReason")
|
||||
}).then(function(result) {
|
||||
|
||||
if (result.responseJson.action === "enqueued") {
|
||||
self.send('postWasEnqueued', result.responseJson);
|
||||
self.destroyDraft();
|
||||
@ -285,7 +292,7 @@ export default DiscourseController.extend({
|
||||
// Checks to see if a reply has been typed.
|
||||
// This is signaled by a keyUp event in a view.
|
||||
checkReplyLength() {
|
||||
if (this.present('model.reply')) {
|
||||
if (!Ember.isEmpty('model.reply')) {
|
||||
// Notify the composer messages controller that a reply has been typed. Some
|
||||
// messages only appear after typing.
|
||||
this.get('controllers.composer-messages').typedReply();
|
||||
@ -441,6 +448,23 @@ export default DiscourseController.extend({
|
||||
|
||||
if (opts.topicCategoryId) {
|
||||
this.set('model.categoryId', opts.topicCategoryId);
|
||||
} else if (opts.topicCategory) {
|
||||
const splitCategory = opts.topicCategory.split("/");
|
||||
let category;
|
||||
|
||||
if (!splitCategory[1]) {
|
||||
category = this.site.get('categories').findProperty('nameLower', splitCategory[0].toLowerCase());
|
||||
} else {
|
||||
const categories = Discourse.Category.list();
|
||||
const mainCategory = categories.findProperty('nameLower', splitCategory[0].toLowerCase());
|
||||
category = categories.find(function(item) {
|
||||
return item && item.get('nameLower') === splitCategory[1].toLowerCase() && item.get('parent_category_id') === mainCategory.id;
|
||||
});
|
||||
}
|
||||
|
||||
if (category) {
|
||||
this.set('model.categoryId', category.get('id'));
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.topicBody) {
|
||||
@ -452,7 +476,7 @@ export default DiscourseController.extend({
|
||||
|
||||
// View a new reply we've made
|
||||
viewNewReply() {
|
||||
Discourse.URL.routeTo(this.get('createdPost.url'));
|
||||
Discourse.URL.routeTo(this.get('model.createdPost.url'));
|
||||
this.close();
|
||||
return false;
|
||||
},
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend({
|
||||
export default Ember.ObjectController.extend({
|
||||
needs: ['navigation/category', 'discovery/topics', 'application'],
|
||||
loading: false,
|
||||
|
||||
category: Em.computed.alias('controllers.navigation/category.category'),
|
||||
noSubcategories: Em.computed.alias('controllers.navigation/category.noSubcategories'),
|
||||
|
||||
loadedAllItems: Em.computed.not("controllers.discovery/topics.canLoadMore"),
|
||||
loadedAllItems: Em.computed.not("controllers.discovery/topics.model.canLoadMore"),
|
||||
|
||||
_showFooter: function() {
|
||||
this.set("controllers.application.showFooter", this.get("loadedAllItems"));
|
||||
|
||||
@ -3,7 +3,7 @@ import DiscoveryController from 'discourse/controllers/discovery';
|
||||
export default DiscoveryController.extend({
|
||||
needs: ['modal', 'discovery'],
|
||||
|
||||
withLogo: Em.computed.filterBy('categories', 'logo_url'),
|
||||
withLogo: Em.computed.filterBy('model.categories', 'logo_url'),
|
||||
showPostsColumn: Em.computed.empty('withLogo'),
|
||||
|
||||
actions: {
|
||||
@ -35,7 +35,7 @@ export default DiscoveryController.extend({
|
||||
}.property(),
|
||||
|
||||
latestTopicOnly: function() {
|
||||
return this.get('categories').find(function(c) { return c.get('featuredTopics.length') > 1; }) === undefined;
|
||||
}.property('categories.@each.featuredTopics.length')
|
||||
return this.get('model.categories').find(function(c) { return c.get('featuredTopics.length') > 1; }) === undefined;
|
||||
}.property('model.categories.@each.featuredTopics.length')
|
||||
|
||||
});
|
||||
|
||||
@ -13,6 +13,8 @@ var controllerOpts = {
|
||||
|
||||
order: 'default',
|
||||
ascending: false,
|
||||
expandGloballyPinned: false,
|
||||
expandAllPinned: false,
|
||||
|
||||
actions: {
|
||||
|
||||
@ -80,27 +82,28 @@ var controllerOpts = {
|
||||
}.property(),
|
||||
|
||||
isFilterPage: function(filter, filterType) {
|
||||
if (!filter) { return false; }
|
||||
return filter.match(new RegExp(filterType + '$', 'gi')) ? true : false;
|
||||
},
|
||||
|
||||
showDismissRead: function() {
|
||||
return this.isFilterPage(this.get('filter'), 'unread') && this.get('topics.length') > 0;
|
||||
}.property('filter', 'topics.length'),
|
||||
return this.isFilterPage(this.get('model.filter'), 'unread') && this.get('model.topics.length') > 0;
|
||||
}.property('model.filter', 'model.topics.length'),
|
||||
|
||||
showResetNew: function() {
|
||||
return this.get('filter') === 'new' && this.get('topics.length') > 0;
|
||||
}.property('filter', 'topics.length'),
|
||||
return this.get('model.filter') === 'new' && this.get('model.topics.length') > 0;
|
||||
}.property('model.filter', 'model.topics.length'),
|
||||
|
||||
showDismissAtTop: function() {
|
||||
return (this.isFilterPage(this.get('filter'), 'new') ||
|
||||
this.isFilterPage(this.get('filter'), 'unread')) &&
|
||||
this.get('topics.length') >= 30;
|
||||
}.property('filter', 'topics.length'),
|
||||
return (this.isFilterPage(this.get('model.filter'), 'new') ||
|
||||
this.isFilterPage(this.get('model.filter'), 'unread')) &&
|
||||
this.get('model.topics.length') >= 30;
|
||||
}.property('model.filter', 'model.topics.length'),
|
||||
|
||||
hasTopics: Em.computed.gt('topics.length', 0),
|
||||
allLoaded: Em.computed.empty('more_topics_url'),
|
||||
latest: Discourse.computed.endWith('filter', 'latest'),
|
||||
new: Discourse.computed.endWith('filter', 'new'),
|
||||
hasTopics: Em.computed.gt('model.topics.length', 0),
|
||||
allLoaded: Em.computed.empty('model.more_topics_url'),
|
||||
latest: Discourse.computed.endWith('model.filter', 'latest'),
|
||||
new: Discourse.computed.endWith('model.filter', 'new'),
|
||||
top: Em.computed.notEmpty('period'),
|
||||
yearly: Em.computed.equal('period', 'yearly'),
|
||||
monthly: Em.computed.equal('period', 'monthly'),
|
||||
@ -114,8 +117,8 @@ var controllerOpts = {
|
||||
if( category ) {
|
||||
return I18n.t('topics.bottom.category', {category: category.get('name')});
|
||||
} else {
|
||||
var split = this.get('filter').split('/');
|
||||
if (this.get('topics.length') === 0) {
|
||||
var split = (this.get('model.filter') || '').split('/');
|
||||
if (this.get('model.topics.length') === 0) {
|
||||
return I18n.t("topics.none." + split[0], {
|
||||
category: split[1]
|
||||
});
|
||||
@ -125,19 +128,19 @@ var controllerOpts = {
|
||||
});
|
||||
}
|
||||
}
|
||||
}.property('allLoaded', 'topics.length'),
|
||||
}.property('allLoaded', 'model.topics.length'),
|
||||
|
||||
footerEducation: function() {
|
||||
if (!this.get('allLoaded') || this.get('topics.length') > 0 || !Discourse.User.current()) { return; }
|
||||
if (!this.get('allLoaded') || this.get('model.topics.length') > 0 || !Discourse.User.current()) { return; }
|
||||
|
||||
var split = this.get('filter').split('/');
|
||||
var split = (this.get('model.filter') || '').split('/');
|
||||
|
||||
if (split[0] !== 'new' && split[0] !== 'unread') { return; }
|
||||
|
||||
return I18n.t("topics.none.educate." + split[0], {
|
||||
userPrefsUrl: Discourse.getURL("/users/") + (Discourse.User.currentProp("username_lower")) + "/preferences"
|
||||
});
|
||||
}.property('allLoaded', 'topics.length'),
|
||||
}.property('allLoaded', 'model.topics.length'),
|
||||
|
||||
loadMoreTopics() {
|
||||
return this.get('model').loadMore();
|
||||
|
||||
@ -9,20 +9,20 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
setAutoCloseTime: function() {
|
||||
var autoCloseTime = null;
|
||||
|
||||
if (this.get("details.auto_close_based_on_last_post")) {
|
||||
autoCloseTime = this.get("details.auto_close_hours");
|
||||
} else if (this.get("details.auto_close_at")) {
|
||||
var closeTime = new Date(this.get("details.auto_close_at"));
|
||||
if (this.get("model.details.auto_close_based_on_last_post")) {
|
||||
autoCloseTime = this.get("model.details.auto_close_hours");
|
||||
} else if (this.get("model.details.auto_close_at")) {
|
||||
var closeTime = new Date(this.get("model.details.auto_close_at"));
|
||||
if (closeTime > new Date()) {
|
||||
autoCloseTime = moment(closeTime).format("YYYY-MM-DD HH:mm");
|
||||
}
|
||||
}
|
||||
|
||||
this.set("auto_close_time", autoCloseTime);
|
||||
}.observes("details.{auto_close_at,auto_close_hours}"),
|
||||
this.set("model.auto_close_time", autoCloseTime);
|
||||
}.observes("model.details.{auto_close_at,auto_close_hours}"),
|
||||
|
||||
actions: {
|
||||
saveAutoClose: function() { this.setAutoClose(this.get("auto_close_time")); },
|
||||
saveAutoClose: function() { this.setAutoClose(this.get("model.auto_close_time")); },
|
||||
removeAutoClose: function() { this.setAutoClose(null); }
|
||||
},
|
||||
|
||||
@ -30,18 +30,18 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
var self = this;
|
||||
this.send('hideModal');
|
||||
Discourse.ajax({
|
||||
url: '/t/' + this.get('id') + '/autoclose',
|
||||
url: '/t/' + this.get('model.id') + '/autoclose',
|
||||
type: 'PUT',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
auto_close_time: time,
|
||||
auto_close_based_on_last_post: this.get("details.auto_close_based_on_last_post"),
|
||||
auto_close_based_on_last_post: this.get("model.details.auto_close_based_on_last_post"),
|
||||
}
|
||||
}).then(function(result){
|
||||
if (result.success) {
|
||||
self.send('closeModal');
|
||||
self.set('details.auto_close_at', result.auto_close_at);
|
||||
self.set('details.auto_close_hours', result.auto_close_hours);
|
||||
self.set('model.details.auto_close_at', result.auto_close_at);
|
||||
self.set('model.details.auto_close_hours', result.auto_close_hours);
|
||||
} else {
|
||||
bootbox.alert(I18n.t('composer.auto_close.error'), function() { self.send('reopenModal'); } );
|
||||
}
|
||||
|
||||
@ -11,14 +11,14 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
bannerCount: 0,
|
||||
|
||||
categoryLink: function() {
|
||||
return categoryLinkHTML(this.get("category"), { allowUncategorized: true });
|
||||
}.property("category"),
|
||||
return categoryLinkHTML(this.get("model.category"), { allowUncategorized: true });
|
||||
}.property("model.category"),
|
||||
|
||||
unPinMessage: function() {
|
||||
return this.get("pinned_globally") ?
|
||||
return this.get("model.pinned_globally") ?
|
||||
I18n.t("topic.feature_topic.unpin_globally") :
|
||||
I18n.t("topic.feature_topic.unpin", { categoryLink: this.get("categoryLink") });
|
||||
}.property("categoryLink", "pinned_globally"),
|
||||
}.property("categoryLink", "model.pinned_globally"),
|
||||
|
||||
pinMessage: function() {
|
||||
return I18n.t("topic.feature_topic.pin", { categoryLink: this.get("categoryLink") });
|
||||
@ -32,7 +32,7 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
this.set("loading", true);
|
||||
|
||||
return Discourse.ajax("/topics/feature_stats.json", {
|
||||
data: { category_id: this.get("category.id") }
|
||||
data: { category_id: this.get("model.category.id") }
|
||||
}).then(result => {
|
||||
if (result) {
|
||||
this.setProperties({
|
||||
|
||||
@ -7,22 +7,22 @@ export default ObjectController.extend({
|
||||
message: Em.computed.alias('controllers.flag.message'),
|
||||
|
||||
customPlaceholder: function(){
|
||||
return I18n.t("flagging.custom_placeholder_" + this.get('name_key'));
|
||||
}.property('name_key'),
|
||||
return I18n.t("flagging.custom_placeholder_" + this.get('model.name_key'));
|
||||
}.property('model.name_key'),
|
||||
|
||||
formattedName: function(){
|
||||
if (this.get("is_custom_flag")) {
|
||||
return this.get('name').replace("{{username}}", this.get('controllers.flag.username'));
|
||||
if (this.get("model.is_custom_flag")) {
|
||||
return this.get('model.name').replace("{{username}}", this.get('controllers.flag.model.username'));
|
||||
} else {
|
||||
return I18n.t("flagging.formatted_name." + this.get('name_key'));
|
||||
return I18n.t("flagging.formatted_name." + this.get('model.name_key'));
|
||||
}
|
||||
}.property('name', 'name_key', 'is_custom_flag'),
|
||||
}.property('model.name', 'model.name_key', 'model.is_custom_flag'),
|
||||
|
||||
selected: function() {
|
||||
return this.get('model') === this.get('controllers.flag.selected');
|
||||
}.property('controllers.flag.selected'),
|
||||
|
||||
showMessageInput: Em.computed.and('is_custom_flag', 'selected'),
|
||||
showMessageInput: Em.computed.and('model.is_custom_flag', 'selected'),
|
||||
showDescription: Em.computed.not('showMessageInput'),
|
||||
|
||||
customMessageLengthClasses: function() {
|
||||
|
||||
@ -2,8 +2,13 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(ModalFunctionality, {
|
||||
userDetails: null,
|
||||
selected: null,
|
||||
flagTopic: null,
|
||||
message: null,
|
||||
topicActionByName: null,
|
||||
|
||||
onShow: function() {
|
||||
onShow() {
|
||||
this.set('selected', null);
|
||||
},
|
||||
|
||||
@ -11,32 +16,31 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
if (!this.get('flagTopic')) {
|
||||
return this.get('model.flagsAvailable');
|
||||
} else {
|
||||
var self = this,
|
||||
const self = this,
|
||||
lookup = Em.Object.create();
|
||||
|
||||
_.each(this.get("actions_summary"),function(a) {
|
||||
var actionSummary;
|
||||
_.each(this.get("model.actions_summary"),function(a) {
|
||||
a.flagTopic = self.get('model');
|
||||
a.actionType = self.site.topicFlagTypeById(a.id);
|
||||
actionSummary = Discourse.ActionSummary.create(a);
|
||||
const actionSummary = Discourse.ActionSummary.create(a);
|
||||
lookup.set(a.actionType.get('name_key'), actionSummary);
|
||||
});
|
||||
this.set('topicActionByName', lookup);
|
||||
|
||||
return this.site.get('topic_flag_types').filter(function(item) {
|
||||
return _.any(self.get("actions_summary"), function(a) {
|
||||
return _.any(self.get("model.actions_summary"), function(a) {
|
||||
return (a.id === item.get('id') && a.can_act);
|
||||
});
|
||||
});
|
||||
}
|
||||
}.property('post', 'flagTopic', 'actions_summary.@each.can_act'),
|
||||
}.property('post', 'flagTopic', 'model.actions_summary.@each.can_act'),
|
||||
|
||||
submitEnabled: function() {
|
||||
var selected = this.get('selected');
|
||||
const selected = this.get('selected');
|
||||
if (!selected) return false;
|
||||
|
||||
if (selected.get('is_custom_flag')) {
|
||||
var len = this.get('message.length') || 0;
|
||||
const len = this.get('message.length') || 0;
|
||||
return len >= Discourse.SiteSettings.min_private_message_post_length &&
|
||||
len <= Discourse.PostActionType.MAX_MESSAGE_LENGTH;
|
||||
}
|
||||
@ -63,27 +67,29 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
}.property('selected.is_custom_flag'),
|
||||
|
||||
actions: {
|
||||
takeAction: function() {
|
||||
takeAction() {
|
||||
this.send('createFlag', {takeAction: true});
|
||||
this.set('hidden', true);
|
||||
this.set('model.hidden', true);
|
||||
},
|
||||
|
||||
createFlag: function(opts) {
|
||||
var self = this;
|
||||
var postAction; // an instance of ActionSummary
|
||||
createFlag(opts) {
|
||||
const self = this;
|
||||
let postAction; // an instance of ActionSummary
|
||||
if (!this.get('flagTopic')) {
|
||||
postAction = this.get('actionByName.' + this.get('selected.name_key'));
|
||||
postAction = this.get('model.actionByName.' + this.get('selected.name_key'));
|
||||
} else {
|
||||
postAction = this.get('topicActionByName.' + this.get('selected.name_key'));
|
||||
}
|
||||
var params = this.get('selected.is_custom_flag') ? {message: this.get('message')} : {};
|
||||
|
||||
if (opts) params = $.extend(params, opts);
|
||||
let params = this.get('selected.is_custom_flag') ? {message: this.get('message')} : {};
|
||||
if (opts) { params = $.extend(params, opts); }
|
||||
|
||||
this.send('hideModal');
|
||||
|
||||
postAction.act(this.get('model'), params).then(function() {
|
||||
self.send('closeModal');
|
||||
if (params.message) {
|
||||
self.set('message', '');
|
||||
}
|
||||
}, function(errors) {
|
||||
self.send('closeModal');
|
||||
if (errors && errors.responseText) {
|
||||
@ -94,7 +100,7 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
});
|
||||
},
|
||||
|
||||
changePostActionType: function(action) {
|
||||
changePostActionType(action) {
|
||||
this.set('selected', action);
|
||||
},
|
||||
},
|
||||
@ -112,12 +118,12 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||
usernameChanged: function() {
|
||||
this.set('userDetails', null);
|
||||
this.fetchUserDetails();
|
||||
}.observes('username'),
|
||||
}.observes('model.username'),
|
||||
|
||||
fetchUserDetails: function() {
|
||||
if( Discourse.User.currentProp('staff') && this.get('username') ) {
|
||||
var flagController = this;
|
||||
Discourse.AdminUser.find(this.get('username').toLowerCase()).then(function(user){
|
||||
if( Discourse.User.currentProp('staff') && this.get('model.username') ) {
|
||||
const flagController = this;
|
||||
Discourse.AdminUser.find(this.get('model.username').toLowerCase()).then(function(user){
|
||||
flagController.set('userDetails', user);
|
||||
});
|
||||
}
|
||||
|
||||
@ -41,10 +41,11 @@ const HeaderController = DiscourseController.extend({
|
||||
if (self.get("loadingNotifications")) { return; }
|
||||
|
||||
self.set("loadingNotifications", true);
|
||||
Discourse.NotificationContainer.loadRecent().then(function(result) {
|
||||
|
||||
this.store.find('notification', {recent: true}).then(function(notifications) {
|
||||
self.setProperties({
|
||||
'currentUser.unread_notifications': 0,
|
||||
notifications: result
|
||||
notifications
|
||||
});
|
||||
}).catch(function() {
|
||||
self.setProperties({
|
||||
@ -79,27 +80,18 @@ function addFlagProperty(prop) {
|
||||
_flagProperties.pushObject(prop);
|
||||
}
|
||||
|
||||
let _appliedFlagProps = false;
|
||||
HeaderController.reopenClass({
|
||||
create() {
|
||||
// We only want to change the class the first time it's created
|
||||
if (!_appliedFlagProps && _flagProperties.length) {
|
||||
_appliedFlagProps = true;
|
||||
|
||||
const args = _flagProperties.slice();
|
||||
args.push(function() {
|
||||
let sum = 0;
|
||||
_flagProperties.forEach((fp) => sum += (this.get(fp) || 0));
|
||||
return sum;
|
||||
});
|
||||
HeaderController.reopen({ flaggedPostsCount: Ember.computed.apply(this, args) });
|
||||
}
|
||||
return this._super.apply(this, Array.prototype.slice.call(arguments));
|
||||
}
|
||||
});
|
||||
function applyFlaggedProperties() {
|
||||
const args = _flagProperties.slice();
|
||||
args.push(function() {
|
||||
let sum = 0;
|
||||
_flagProperties.forEach((fp) => sum += (this.get(fp) || 0));
|
||||
return sum;
|
||||
});
|
||||
HeaderController.reopen({ flaggedPostsCount: Ember.computed.apply(this, args) });
|
||||
}
|
||||
|
||||
addFlagProperty('currentUser.site_flagged_posts_count');
|
||||
addFlagProperty('currentUser.post_queue_new_count');
|
||||
|
||||
export { addFlagProperty };
|
||||
export { addFlagProperty, applyFlaggedProperties };
|
||||
export default HeaderController;
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(ModalFunctionality, {
|
||||
export default ObjectController.extend(Presence, ModalFunctionality, {
|
||||
needs: ['user-invited'],
|
||||
|
||||
// If this isn't defined, it will proxy to the user model on the preferences
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
// Modal related to merging of topics
|
||||
export default ObjectController.extend(Discourse.SelectedPostsCount, ModalFunctionality, {
|
||||
export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, Presence, {
|
||||
needs: ['topic'],
|
||||
|
||||
topicController: Em.computed.alias('controllers.topic'),
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
const INVITED_TYPE = 8;
|
||||
|
||||
export default ObjectController.extend({
|
||||
|
||||
notificationUrl: function(it) {
|
||||
var badgeId = it.get("data.badge_id");
|
||||
if (badgeId) {
|
||||
var badgeName = it.get("data.badge_name");
|
||||
return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase());
|
||||
}
|
||||
|
||||
var topicId = it.get('topic_id');
|
||||
if (topicId) {
|
||||
return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number"));
|
||||
}
|
||||
|
||||
if (it.get('notification_type') === INVITED_TYPE) {
|
||||
return Discourse.getURL('/my/invited');
|
||||
}
|
||||
},
|
||||
|
||||
scope: function() {
|
||||
return "notifications." + this.site.get("notificationLookup")[this.get("notification_type")];
|
||||
}.property("notification_type"),
|
||||
|
||||
username: Em.computed.alias("data.display_username"),
|
||||
|
||||
url: function() {
|
||||
return this.notificationUrl(this);
|
||||
}.property("data.{badge_id,badge_name}", "slug", "topic_id", "post_number"),
|
||||
|
||||
description: function() {
|
||||
const badgeName = this.get("data.badge_name");
|
||||
if (badgeName) { return Handlebars.Utils.escapeExpression(badgeName); }
|
||||
return this.blank("data.topic_title") ? "" : Handlebars.Utils.escapeExpression(this.get("data.topic_title"));
|
||||
}.property("data.{badge_name,topic_title}")
|
||||
|
||||
});
|
||||
@ -1,6 +1,7 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend({
|
||||
export default ObjectController.extend(Presence, {
|
||||
taken: false,
|
||||
saving: false,
|
||||
error: false,
|
||||
|
||||
@ -43,7 +43,7 @@ export default DiscourseController.extend({
|
||||
if (this.get('buffer') === selectedText) return;
|
||||
|
||||
// we need to retrieve the post data from the posts collection in the topic controller
|
||||
const postStream = this.get('controllers.topic.postStream');
|
||||
const postStream = this.get('controllers.topic.model.postStream');
|
||||
this.set('post', postStream.findLoadedPost(postId));
|
||||
this.set('buffer', selectedText);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import Sharing from 'discourse/lib/sharing';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['topic'],
|
||||
title: Ember.computed.alias('controllers.topic.title'),
|
||||
title: Ember.computed.alias('controllers.topic.model.title'),
|
||||
|
||||
displayDate: function() {
|
||||
return Discourse.Formatter.longDateNoYear(new Date(this.get('date')));
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['site-map'],
|
||||
|
||||
unreadTotal: function() {
|
||||
return parseInt(this.get('unreadTopics'), 10) +
|
||||
parseInt(this.get('newTopics'), 10);
|
||||
}.property('unreadTopics', 'newTopics'),
|
||||
return parseInt(this.get('model.unreadTopics'), 10) +
|
||||
parseInt(this.get('model.newTopics'), 10);
|
||||
}.property('model.unreadTopics', 'model.newTopics'),
|
||||
|
||||
showTopicCount: Em.computed.not('currentUser')
|
||||
});
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import Presence from 'discourse/mixins/presence';
|
||||
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
// Modal related to auto closing of topics
|
||||
export default ObjectController.extend(Discourse.SelectedPostsCount, ModalFunctionality, {
|
||||
export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, Presence, {
|
||||
needs: ['topic'],
|
||||
|
||||
topicController: Em.computed.alias('controllers.topic'),
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
export default Em.ObjectController.extend({
|
||||
showLoginButton: Em.computed.equal('path', 'login'),
|
||||
export default Ember.Controller.extend({
|
||||
showLoginButton: Em.computed.equal('model.path', 'login'),
|
||||
|
||||
actions: {
|
||||
markFaqRead: function() {
|
||||
if (Discourse.User.current()) {
|
||||
if (this.currentUser) {
|
||||
Discourse.ajax("/users/read-faq", { method: "POST" });
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ import ObjectController from 'discourse/controllers/object';
|
||||
// This controller supports the admin menu on topics
|
||||
export default ObjectController.extend({
|
||||
menuVisible: false,
|
||||
showRecover: Em.computed.and('deleted', 'details.can_recover'),
|
||||
isFeatured: Em.computed.or("pinned_at", "isBanner"),
|
||||
showRecover: Em.computed.and('model.deleted', 'model.details.can_recover'),
|
||||
isFeatured: Em.computed.or("model.pinned_at", "model.isBanner"),
|
||||
|
||||
actions: {
|
||||
show: function() { this.set('menuVisible', true); },
|
||||
|
||||
@ -17,7 +17,7 @@ function entranceDate(dt, showTime) {
|
||||
);
|
||||
}
|
||||
|
||||
export default Ember.ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
position: null,
|
||||
|
||||
createdDate: function() {
|
||||
@ -51,11 +51,11 @@ export default Ember.ObjectController.extend({
|
||||
},
|
||||
|
||||
enterTop: function() {
|
||||
Discourse.URL.routeTo(this.get('url'));
|
||||
Discourse.URL.routeTo(this.get('model.url'));
|
||||
},
|
||||
|
||||
enterBottom: function() {
|
||||
Discourse.URL.routeTo(this.get('lastPostUrl'));
|
||||
Discourse.URL.routeTo(this.get('model.lastPostUrl'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
// Handles displaying of a topic as a list item
|
||||
export default ObjectController.extend({
|
||||
needs: ['discovery/topics'],
|
||||
|
||||
canStar: Em.computed.alias('controllers.discovery/topics.currentUser.id'),
|
||||
bulkSelectEnabled: Em.computed.alias('controllers.discovery/topics.bulkSelectEnabled'),
|
||||
showTopicPostBadges: Em.computed.not('controllers.discovery/topics.new'),
|
||||
|
||||
checked: function(key, value) {
|
||||
var selected = this.get('controllers.discovery/topics.selected'),
|
||||
topic = this.get('model');
|
||||
|
||||
if (arguments.length > 1) {
|
||||
if (value) {
|
||||
selected.addObject(topic);
|
||||
} else {
|
||||
selected.removeObject(topic);
|
||||
}
|
||||
}
|
||||
return selected.contains(topic);
|
||||
}.property('controllers.discovery/topics.selected.length'),
|
||||
|
||||
titleColSpan: function() {
|
||||
// Uncategorized pinned topics will span the title and category column in the topic list.
|
||||
return (!this.get('controllers.discovery/topics.hideCategory') &&
|
||||
this.get('model.isPinnedUncategorized') ? 2 : 1);
|
||||
}.property('controllers.discovery/topics.hideCategory', 'model.isPinnedUncategorized'),
|
||||
|
||||
hideCategory: function() {
|
||||
return this.get('controllers.discovery/topics.hideCategory') || this.get('titleColSpan') > 1;
|
||||
}.property('controllers.discovery/topics.hideCategory', 'titleColSpan'),
|
||||
|
||||
actions: {
|
||||
toggleStar: function() {
|
||||
this.get('model').toggleStar();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -24,11 +24,11 @@ export default Ember.ObjectController.extend({
|
||||
if (isNaN(postIndex) || postIndex < 1) {
|
||||
postIndex = 1;
|
||||
}
|
||||
if (postIndex > this.get('postStream.filteredPostsCount')) {
|
||||
postIndex = this.get('postStream.filteredPostsCount');
|
||||
if (postIndex > this.get('model.postStream.filteredPostsCount')) {
|
||||
postIndex = this.get('model.postStream.filteredPostsCount');
|
||||
}
|
||||
this.set('toPostIndex', postIndex);
|
||||
var stream = this.get('postStream'),
|
||||
var stream = this.get('model.postStream'),
|
||||
postId = stream.findPostIdForPostNumber(postIndex);
|
||||
|
||||
if (!postId) {
|
||||
@ -65,36 +65,36 @@ export default Ember.ObjectController.extend({
|
||||
},
|
||||
|
||||
streamPercentage: function() {
|
||||
if (!this.get('postStream.loaded')) { return 0; }
|
||||
if (this.get('postStream.highest_post_number') === 0) { return 0; }
|
||||
var perc = this.get('progressPosition') / this.get('postStream.filteredPostsCount');
|
||||
if (!this.get('model.postStream.loaded')) { return 0; }
|
||||
if (this.get('model.postStream.highest_post_number') === 0) { return 0; }
|
||||
var perc = this.get('progressPosition') / this.get('model.postStream.filteredPostsCount');
|
||||
return (perc > 1.0) ? 1.0 : perc;
|
||||
}.property('postStream.loaded', 'progressPosition', 'postStream.filteredPostsCount'),
|
||||
}.property('model.postStream.loaded', 'progressPosition', 'model.postStream.filteredPostsCount'),
|
||||
|
||||
jumpTopDisabled: function() {
|
||||
return this.get('progressPosition') <= 3;
|
||||
}.property('progressPosition'),
|
||||
|
||||
filteredPostCountChanged: function(){
|
||||
if(this.get('postStream.filteredPostsCount') < this.get('progressPosition')){
|
||||
this.set('progressPosition', this.get('postStream.filteredPostsCount'));
|
||||
if(this.get('model.postStream.filteredPostsCount') < this.get('progressPosition')){
|
||||
this.set('progressPosition', this.get('model.postStream.filteredPostsCount'));
|
||||
}
|
||||
}.observes('postStream.filteredPostsCount'),
|
||||
}.observes('model.postStream.filteredPostsCount'),
|
||||
|
||||
jumpBottomDisabled: function() {
|
||||
return this.get('progressPosition') >= this.get('postStream.filteredPostsCount') ||
|
||||
return this.get('progressPosition') >= this.get('model.postStream.filteredPostsCount') ||
|
||||
this.get('progressPosition') >= this.get('highest_post_number');
|
||||
}.property('postStream.filteredPostsCount', 'highest_post_number', 'progressPosition'),
|
||||
}.property('model.postStream.filteredPostsCount', 'highest_post_number', 'progressPosition'),
|
||||
|
||||
hideProgress: function() {
|
||||
if (!this.get('postStream.loaded')) return true;
|
||||
if (!this.get('currentPost')) return true;
|
||||
if (this.get('postStream.filteredPostsCount') < 2) return true;
|
||||
if (!this.get('model.postStream.loaded')) return true;
|
||||
if (!this.get('model.currentPost')) return true;
|
||||
if (this.get('model.postStream.filteredPostsCount') < 2) return true;
|
||||
return false;
|
||||
}.property('postStream.loaded', 'currentPost', 'postStream.filteredPostsCount'),
|
||||
}.property('model.postStream.loaded', 'model.currentPost', 'model.postStream.filteredPostsCount'),
|
||||
|
||||
hugeNumberOfPosts: function() {
|
||||
return (this.get('postStream.filteredPostsCount') >= Discourse.SiteSettings.short_progress_text_threshold);
|
||||
return (this.get('model.postStream.filteredPostsCount') >= Discourse.SiteSettings.short_progress_text_threshold);
|
||||
}.property('highest_post_number'),
|
||||
|
||||
jumpToBottomTitle: function() {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||
import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
|
||||
import { spinnerHTML } from 'discourse/helpers/loading-spinner';
|
||||
import Topic from 'discourse/models/topic';
|
||||
|
||||
export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedContent, {
|
||||
export default ObjectController.extend(SelectedPostsCount, BufferedContent, {
|
||||
multiSelect: false,
|
||||
needs: ['header', 'modal', 'composer', 'quote-button', 'search', 'topic-progress', 'application'],
|
||||
allPostsSelected: false,
|
||||
@ -12,6 +13,9 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
selectedReplies: null,
|
||||
queryParams: ['filter', 'username_filters', 'show_deleted'],
|
||||
searchHighlight: null,
|
||||
loadedAllPosts: false,
|
||||
enteredAt: null,
|
||||
firstPostExpanded: false,
|
||||
|
||||
maxTitleLength: Discourse.computed.setting('max_topic_title_length'),
|
||||
|
||||
@ -20,14 +24,14 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
}.observes('topic'),
|
||||
|
||||
_titleChanged: function() {
|
||||
const title = this.get('title');
|
||||
const title = this.get('model.title');
|
||||
if (!Ember.isEmpty(title)) {
|
||||
|
||||
// Note normally you don't have to trigger this, but topic titles can be updated
|
||||
// and are sometimes lazily loaded.
|
||||
this.send('refreshTitle');
|
||||
}
|
||||
}.observes('title', 'category'),
|
||||
}.observes('model.title', 'category'),
|
||||
|
||||
termChanged: function() {
|
||||
const dropdown = this.get('controllers.header.visibleDropdown');
|
||||
@ -47,47 +51,47 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
// semantics of loaded all posts are slightly diff at topic level,
|
||||
// it just means that we "once" loaded all posts, this means we don't
|
||||
// keep re-rendering the suggested topics when new posts zoom in
|
||||
let loaded = this.get('postStream.loadedAllPosts');
|
||||
let loaded = this.get('model.postStream.loadedAllPosts');
|
||||
|
||||
if (loaded) {
|
||||
this.set('loadedTopicId', this.get('model.id'));
|
||||
this.set('model.loadedTopicId', this.get('model.id'));
|
||||
} else {
|
||||
loaded = this.get('loadedTopicId') === this.get('model.id');
|
||||
loaded = this.get('model.loadedTopicId') === this.get('model.id');
|
||||
}
|
||||
|
||||
this.set('loadedAllPosts', loaded);
|
||||
|
||||
}.observes('postStream', 'postStream.loadedAllPosts'),
|
||||
}.observes('model.postStream', 'model.postStream.loadedAllPosts'),
|
||||
|
||||
show_deleted: function(key, value) {
|
||||
const postStream = this.get('postStream');
|
||||
const postStream = this.get('model.postStream');
|
||||
if (!postStream) { return; }
|
||||
|
||||
if (arguments.length > 1) {
|
||||
postStream.set('show_deleted', value);
|
||||
}
|
||||
return postStream.get('show_deleted') ? true : undefined;
|
||||
}.property('postStream.summary'),
|
||||
}.property('model.postStream.summary'),
|
||||
|
||||
filter: function(key, value) {
|
||||
const postStream = this.get('postStream');
|
||||
const postStream = this.get('model.postStream');
|
||||
if (!postStream) { return; }
|
||||
|
||||
if (arguments.length > 1) {
|
||||
postStream.set('summary', value === "summary");
|
||||
}
|
||||
return postStream.get('summary') ? "summary" : undefined;
|
||||
}.property('postStream.summary'),
|
||||
}.property('model.postStream.summary'),
|
||||
|
||||
username_filters: function(key, value) {
|
||||
const postStream = this.get('postStream');
|
||||
const postStream = this.get('model.postStream');
|
||||
if (!postStream) { return; }
|
||||
|
||||
if (arguments.length > 1) {
|
||||
postStream.set('streamFilters.username_filters', value);
|
||||
}
|
||||
return postStream.get('streamFilters.username_filters');
|
||||
}.property('postStream.streamFilters.username_filters'),
|
||||
}.property('model.postStream.streamFilters.username_filters'),
|
||||
|
||||
_clearSelected: function() {
|
||||
this.set('selectedPosts', []);
|
||||
@ -95,7 +99,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
}.on('init'),
|
||||
|
||||
_togglePinnedStates(property) {
|
||||
const value = this.get('pinned_at') ? false : true,
|
||||
const value = this.get('model.pinned_at') ? false : true,
|
||||
topic = this.get('content');
|
||||
|
||||
// optimistic update
|
||||
@ -189,7 +193,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
'class': 'btn-primary',
|
||||
callback() {
|
||||
Discourse.Post.deleteMany([post], [post]);
|
||||
self.get('postStream.posts').forEach(function (p) {
|
||||
self.get('model.postStream.posts').forEach(function (p) {
|
||||
if (p === post || p.get('reply_to_post_number') === post.get('post_number')) {
|
||||
p.setDeletedState(user);
|
||||
}
|
||||
@ -246,7 +250,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
},
|
||||
|
||||
selectAll() {
|
||||
const posts = this.get('postStream.posts'),
|
||||
const posts = this.get('model.postStream.posts'),
|
||||
selectedPosts = this.get('selectedPosts');
|
||||
if (posts) {
|
||||
selectedPosts.addObjects(posts);
|
||||
@ -261,11 +265,11 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
},
|
||||
|
||||
toggleParticipant(user) {
|
||||
this.get('postStream').toggleParticipant(Em.get(user, 'username'));
|
||||
this.get('model.postStream').toggleParticipant(Em.get(user, 'username'));
|
||||
},
|
||||
|
||||
editTopic() {
|
||||
if (!this.get('details.can_edit')) return false;
|
||||
if (!this.get('model.details.can_edit')) return false;
|
||||
|
||||
this.set('editingTopic', true);
|
||||
return false;
|
||||
@ -326,7 +330,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
|
||||
const selectedPosts = self.get('selectedPosts'),
|
||||
selectedReplies = self.get('selectedReplies'),
|
||||
postStream = self.get('postStream'),
|
||||
postStream = self.get('model.postStream'),
|
||||
toRemove = [];
|
||||
|
||||
Discourse.Post.deleteMany(selectedPosts, selectedReplies);
|
||||
@ -365,7 +369,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
},
|
||||
|
||||
togglePinned() {
|
||||
const value = this.get('pinned_at') ? false : true,
|
||||
const value = this.get('model.pinned_at') ? false : true,
|
||||
topic = this.get('content');
|
||||
|
||||
// optimistic update
|
||||
@ -403,7 +407,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
},
|
||||
|
||||
togglePinnedForUser() {
|
||||
if (this.get('pinned_at')) {
|
||||
if (this.get('model.pinned_at')) {
|
||||
if (this.get('pinned')) {
|
||||
this.get('content').clearPin();
|
||||
} else {
|
||||
@ -428,7 +432,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
return Em.isEmpty(quotedText) ? Discourse.Post.loadQuote(post.get('id')) : quotedText;
|
||||
}).then(function(q) {
|
||||
const postUrl = "" + location.protocol + "//" + location.host + post.get('url'),
|
||||
postLink = "[" + Handlebars.escapeExpression(self.get('title')) + "](" + postUrl + ")";
|
||||
postLink = "[" + Handlebars.escapeExpression(self.get('model.title')) + "](" + postUrl + ")";
|
||||
composerController.appendText(I18n.t("post.continue_discussion", { postLink: postLink }) + "\n\n" + q);
|
||||
});
|
||||
},
|
||||
@ -448,7 +452,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
retryLoading() {
|
||||
const self = this;
|
||||
self.set('retrying', true);
|
||||
this.get('postStream').refresh().then(function() {
|
||||
this.get('model.postStream').refresh().then(function() {
|
||||
self.set('retrying', false);
|
||||
}, function() {
|
||||
self.set('retrying', false);
|
||||
@ -491,12 +495,12 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
}.property(),
|
||||
|
||||
canMergeTopic: function() {
|
||||
if (!this.get('details.can_move_posts')) return false;
|
||||
if (!this.get('model.details.can_move_posts')) return false;
|
||||
return (this.get('selectedPostsCount') > 0);
|
||||
}.property('selectedPostsCount'),
|
||||
|
||||
canSplitTopic: function() {
|
||||
if (!this.get('details.can_move_posts')) return false;
|
||||
if (!this.get('model.details.can_move_posts')) return false;
|
||||
if (this.get('allPostsSelected')) return false;
|
||||
return (this.get('selectedPostsCount') > 0);
|
||||
}.property('selectedPostsCount'),
|
||||
@ -533,7 +537,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
return canDelete;
|
||||
}.property('selectedPostsCount'),
|
||||
|
||||
hasError: Ember.computed.or('notFoundHtml', 'message'),
|
||||
hasError: Ember.computed.or('model.notFoundHtml', 'model.message'),
|
||||
noErrorYet: Ember.computed.not('hasError'),
|
||||
|
||||
multiSelectChanged: function() {
|
||||
@ -564,8 +568,8 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
},
|
||||
|
||||
showStarButton: function() {
|
||||
return Discourse.User.current() && !this.get('isPrivateMessage');
|
||||
}.property('isPrivateMessage'),
|
||||
return Discourse.User.current() && !this.get('model.isPrivateMessage');
|
||||
}.property('model.isPrivateMessage'),
|
||||
|
||||
loadingHTML: function() {
|
||||
return spinnerHTML;
|
||||
@ -586,7 +590,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
this.unsubscribe();
|
||||
|
||||
const self = this;
|
||||
this.messageBus.subscribe("/topic/" + this.get('id'), function(data) {
|
||||
this.messageBus.subscribe("/topic/" + this.get('model.id'), function(data) {
|
||||
const topic = self.get('model');
|
||||
|
||||
if (data.notification_level_change) {
|
||||
@ -595,7 +599,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
return;
|
||||
}
|
||||
|
||||
const postStream = self.get('postStream');
|
||||
const postStream = self.get('model.postStream');
|
||||
switch (data.type) {
|
||||
case "revised":
|
||||
case "acted":
|
||||
@ -643,27 +647,24 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
return false;
|
||||
} else {
|
||||
selectedPosts.addObject(post);
|
||||
|
||||
// If the user manually selects all posts, all posts are selected
|
||||
if (selectedPosts.length === this.get('posts_count')) {
|
||||
this.set('allPostsSelected', true);
|
||||
}
|
||||
this.set('allPostsSelected', selectedPosts.length === this.get('model.posts_count'));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
// If our current post is changed, notify the router
|
||||
_currentPostChanged: function() {
|
||||
const currentPost = this.get('currentPost');
|
||||
const currentPost = this.get('model.currentPost');
|
||||
if (currentPost) {
|
||||
this.send('postChangedRoute', currentPost);
|
||||
}
|
||||
}.observes('currentPost'),
|
||||
}.observes('model.currentPost'),
|
||||
|
||||
readPosts(topicId, postNumbers) {
|
||||
const postStream = this.get('postStream');
|
||||
const postStream = this.get('model.postStream');
|
||||
|
||||
if(this.get('postStream.topic.id') === topicId){
|
||||
if (postStream.get('topic.id') === topicId){
|
||||
_.each(postStream.get('posts'), function(post){
|
||||
// optimise heavy loop
|
||||
// TODO identity map for postNumber
|
||||
@ -673,8 +674,8 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
});
|
||||
|
||||
const max = _.max(postNumbers);
|
||||
if(max > this.get('last_read_post_number')){
|
||||
this.set('last_read_post_number', max);
|
||||
if(max > this.get('model.last_read_post_number')){
|
||||
this.set('model.sast_read_post_number', max);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -683,10 +684,10 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
topVisibleChanged(post) {
|
||||
if (!post) { return; }
|
||||
|
||||
const postStream = this.get('postStream'),
|
||||
firstLoadedPost = postStream.get('firstLoadedPost');
|
||||
const postStream = this.get('model.postStream'),
|
||||
firstLoadedPost = postStream.get('firstLoadedPost');
|
||||
|
||||
this.set('currentPost', post.get('post_number'));
|
||||
this.set('model.currentPost', post.get('post_number'));
|
||||
|
||||
if (post.get('post_number') === 1) { return; }
|
||||
|
||||
@ -721,7 +722,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
bottomVisibleChanged(post) {
|
||||
if (!post) { return; }
|
||||
|
||||
const postStream = this.get('postStream'),
|
||||
const postStream = this.get('model.postStream'),
|
||||
lastLoadedPost = postStream.get('lastLoadedPost');
|
||||
|
||||
this.set('controllers.topic-progress.progressPosition', postStream.progressIndexOfPost(post));
|
||||
@ -732,7 +733,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||
},
|
||||
|
||||
_showFooter: function() {
|
||||
this.set("controllers.application.showFooter", this.get("postStream.loadedAllPosts"));
|
||||
}.observes("postStream.loadedAllPosts")
|
||||
this.set("controllers.application.showFooter", this.get("model.postStream.loadedAllPosts"));
|
||||
}.observes("model.postStream.loadedAllPosts")
|
||||
|
||||
});
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
export default Ember.ObjectController.extend({
|
||||
userActionType: null,
|
||||
needs: ["application"],
|
||||
|
||||
_showFooter: function() {
|
||||
var showFooter;
|
||||
if (this.get("userActionType")) {
|
||||
var stat = _.find(this.get("stats"), { action_type: this.get("userActionType") });
|
||||
showFooter = stat && stat.count <= this.get("stream.itemsLoaded");
|
||||
var stat = _.find(this.get("model.stats"), { action_type: this.get("userActionType") });
|
||||
showFooter = stat && stat.count <= this.get("model.stream.itemsLoaded");
|
||||
} else {
|
||||
showFooter = this.get("statsCountNonPM") <= this.get("stream.itemsLoaded");
|
||||
showFooter = this.get("model.statsCountNonPM") <= this.get("model.stream.itemsLoaded");
|
||||
}
|
||||
this.set("controllers.application.showFooter", showFooter);
|
||||
}.observes("userActionType", "stream.itemsLoaded")
|
||||
}.observes("userActionType", "model.stream.itemsLoaded")
|
||||
|
||||
});
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend({
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['topic', 'application'],
|
||||
visible: false,
|
||||
user: null,
|
||||
@ -13,7 +11,7 @@ export default ObjectController.extend({
|
||||
// If inside a topic
|
||||
topicPostCount: null,
|
||||
|
||||
postStream: Em.computed.alias('controllers.topic.postStream'),
|
||||
postStream: Em.computed.alias('controllers.topic.model.postStream'),
|
||||
enoughPostsForFiltering: Em.computed.gte('topicPostCount', 2),
|
||||
viewingTopic: Em.computed.match('controllers.application.currentPath', /^topic\./),
|
||||
viewingAdmin: Em.computed.match('controllers.application.currentPath', /^admin\./),
|
||||
@ -47,7 +45,7 @@ export default ObjectController.extend({
|
||||
|
||||
const currentUsername = this.get('username'),
|
||||
wasVisible = this.get('visible'),
|
||||
post = this.get('viewingTopic') && postId ? this.get('controllers.topic.postStream').findLoadedPost(postId) : null;
|
||||
post = this.get('viewingTopic') && postId ? this.get('postStream').findLoadedPost(postId) : null;
|
||||
|
||||
this.setProperties({ avatar: null, post: post, username: username });
|
||||
|
||||
@ -92,7 +90,7 @@ export default ObjectController.extend({
|
||||
|
||||
actions: {
|
||||
togglePosts(user) {
|
||||
const postStream = this.get('controllers.topic.postStream');
|
||||
const postStream = this.get('postStream');
|
||||
postStream.toggleParticipant(user.get('username'));
|
||||
this.close();
|
||||
},
|
||||
|
||||
@ -1,43 +1,21 @@
|
||||
|
||||
export default Ember.ArrayController.extend({
|
||||
needs: ['user-notifications', 'application'],
|
||||
loading: false,
|
||||
needs: ['application'],
|
||||
|
||||
_showFooter: function() {
|
||||
this.set("controllers.application.showFooter", !this.get("canLoadMore"));
|
||||
}.observes("canLoadMore"),
|
||||
this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
|
||||
}.observes("model.canLoadMore"),
|
||||
|
||||
showDismissButton: function() {
|
||||
return this.get('user').total_unread_notifications > 0;
|
||||
}.property('user'),
|
||||
showDismissButton: Ember.computed.gt('user.total_unread_notifications', 0),
|
||||
|
||||
actions: {
|
||||
resetNew: function() {
|
||||
var self = this;
|
||||
Discourse.NotificationContainer.resetNew().then(function() {
|
||||
self.get('controllers.user-notifications').setEach('read', true);
|
||||
Discourse.ajax('/notifications/mark-read', { method: 'PUT' }).then(() => {
|
||||
this.setEach('read', true);
|
||||
});
|
||||
},
|
||||
|
||||
loadMore: function() {
|
||||
if (this.get('canLoadMore') && !this.get('loading')) {
|
||||
this.set('loading', true);
|
||||
var self = this;
|
||||
Discourse.NotificationContainer.loadHistory(
|
||||
self.get('model.lastObject.created_at'),
|
||||
self.get('user.username')).then(function(result) {
|
||||
self.set('loading', false);
|
||||
var notifications = result.get('content');
|
||||
self.pushObjects(notifications);
|
||||
// Stop trying if it's the end
|
||||
if (notifications && (notifications.length === 0 || notifications.length < 60)) {
|
||||
self.set('canLoadMore', false);
|
||||
}
|
||||
}).catch(function(error) {
|
||||
self.set('loading', false);
|
||||
Em.Logger.error(error);
|
||||
});
|
||||
}
|
||||
this.get('model').loadMore();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -7,8 +7,8 @@ export default ObjectController.extend({
|
||||
showParticipants: false,
|
||||
|
||||
_showFooter: function() {
|
||||
this.set("controllers.application.showFooter", !this.get("canLoadMore"));
|
||||
}.observes("canLoadMore"),
|
||||
this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
|
||||
}.observes("model.canLoadMore"),
|
||||
|
||||
actions: {
|
||||
loadMore: function() {
|
||||
|
||||
@ -3,7 +3,9 @@ import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||
|
||||
export default ObjectController.extend(CanCheckEmails, {
|
||||
indexStream: false,
|
||||
needs: ['user-notifications', 'user_topics_list'],
|
||||
pmView: false,
|
||||
userActionType: null,
|
||||
needs: ['user-notifications', 'user-topics-list'],
|
||||
|
||||
viewingSelf: function() {
|
||||
return this.get('content.username') === Discourse.User.currentProp('username');
|
||||
@ -12,12 +14,16 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||
collapsedInfo: Em.computed.not('indexStream'),
|
||||
|
||||
websiteName: function() {
|
||||
var website = this.get('website');
|
||||
var website = this.get('model.website');
|
||||
if (Em.isEmpty(website)) { return; }
|
||||
return this.get('website').split("/")[2];
|
||||
}.property('website'),
|
||||
return website.split("/")[2];
|
||||
}.property('model.website'),
|
||||
|
||||
linkWebsite: Em.computed.not('isBasic'),
|
||||
linkWebsite: Em.computed.not('model.isBasic'),
|
||||
|
||||
removeNoFollow: function() {
|
||||
return this.get('model.trust_level') > 2 && !this.siteSettings.tl3_links_no_follow;
|
||||
}.property('model.trust_level'),
|
||||
|
||||
canSeePrivateMessages: Ember.computed.or('viewingSelf', 'currentUser.admin'),
|
||||
canSeeNotificationHistory: Em.computed.alias('canSeePrivateMessages'),
|
||||
@ -36,13 +42,13 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||
}.property(),
|
||||
|
||||
canDeleteUser: function() {
|
||||
return this.get('can_be_deleted') && this.get('can_delete_all_posts');
|
||||
}.property('can_be_deleted', 'can_delete_all_posts'),
|
||||
return this.get('model.can_be_deleted') && this.get('model.can_delete_all_posts');
|
||||
}.property('model.can_be_deleted', 'model.can_delete_all_posts'),
|
||||
|
||||
publicUserFields: function() {
|
||||
var siteUserFields = this.site.get('user_fields');
|
||||
if (!Ember.isEmpty(siteUserFields)) {
|
||||
var userFields = this.get('user_fields');
|
||||
var userFields = this.get('model.user_fields');
|
||||
return siteUserFields.filterProperty('show_on_profile', true).sortBy('id').map(function(uf) {
|
||||
var val = userFields ? userFields[uf.get('id').toString()] : null;
|
||||
if (Ember.isEmpty(val)) {
|
||||
@ -52,7 +58,7 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||
}
|
||||
}).compact();
|
||||
}
|
||||
}.property('user_fields.@each.value'),
|
||||
}.property('model.user_fields.@each.value'),
|
||||
|
||||
privateMessagesActive: Em.computed.equal('pmView', 'index'),
|
||||
privateMessagesMineActive: Em.computed.equal('pmView', 'mine'),
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
export default Ember.Handlebars.makeBoundHelper(function(value) {
|
||||
return ("border-color: #" + value).htmlSafe();
|
||||
});
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
/**
|
||||
Set up an i18n binding that will update as a count changes, complete with pluralization.
|
||||
|
||||
@method countI18n
|
||||
@for Handlebars
|
||||
**/
|
||||
Ember.Handlebars.registerHelper('countI18n', function(key, options) {
|
||||
var view = Discourse.View.extend(Discourse.StringBuffer, {
|
||||
tagName: 'span',
|
||||
rerenderTriggers: ['count', 'suffix'],
|
||||
|
||||
renderString: function(buffer) {
|
||||
buffer.push(I18n.t(key + (this.get('suffix') || ''), { count: this.get('count') }));
|
||||
}
|
||||
});
|
||||
return Ember.Handlebars.helpers.view.call(this, view, options);
|
||||
});
|
||||
@ -1,9 +1,11 @@
|
||||
Handlebars.registerHelper('custom-html', function(name, contextString, options) {
|
||||
var html = Discourse.HTML.getCustomHTML(name);
|
||||
Ember.HTMLBars._registerHelper('custom-html', function(params, hash, options, env) {
|
||||
const name = params[0];
|
||||
const html = Discourse.HTML.getCustomHTML(name);
|
||||
if (html) { return html; }
|
||||
|
||||
var container = (options || contextString).data.view.container;
|
||||
const contextString = params[1];
|
||||
const container = (env || contextString).data.view.container;
|
||||
if (container.lookup('template:' + name)) {
|
||||
return Ember.Handlebars.helpers.partial.apply(this, arguments);
|
||||
return env.helpers.partial.helperFunction.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import ConditionalLoadingSpinner from 'discourse/components/conditional-loading-spinner';
|
||||
|
||||
function renderSpinner(cssClass) {
|
||||
var html = "<div class='spinner";
|
||||
if (cssClass) { html += ' ' + cssClass; }
|
||||
@ -7,25 +5,9 @@ function renderSpinner(cssClass) {
|
||||
}
|
||||
var spinnerHTML = renderSpinner();
|
||||
|
||||
/**
|
||||
If you use it as a regular helper {{loading-spinner}} you'll just get the
|
||||
HTML for a spinner.
|
||||
|
||||
If you provide an `condition=xyz` parameter, it will be bound to that property
|
||||
and only show when it's truthy.
|
||||
|
||||
If you use the block form `{{#loading-spinner}} ... {{/loading-spinner}`,
|
||||
the contents will shown when the loading condition finishes.
|
||||
**/
|
||||
Handlebars.registerHelper('loading-spinner', function(options) {
|
||||
var hash = options.hash;
|
||||
if (hash && hash.condition) {
|
||||
var types = options.hashTypes;
|
||||
Discourse.Utilities.normalizeHash(hash, types);
|
||||
return Ember.Handlebars.helpers.view.call(this, ConditionalLoadingSpinner, options);
|
||||
} else {
|
||||
return new Handlebars.SafeString(renderSpinner((hash && hash.size) ? hash.size : undefined));
|
||||
}
|
||||
Ember.Handlebars.registerHelper('loading-spinner', function(params) {
|
||||
const hash = params.hash;
|
||||
return new Handlebars.SafeString(renderSpinner((hash && hash.size) ? hash.size : undefined));
|
||||
});
|
||||
|
||||
export { spinnerHTML, renderSpinner };
|
||||
|
||||
@ -99,7 +99,9 @@ function buildConnectorCache() {
|
||||
});
|
||||
}
|
||||
|
||||
export default function(connectionName, options) {
|
||||
Ember.HTMLBars._registerHelper('plugin-outlet', function(params, hash, options, env) {
|
||||
const connectionName = params[0];
|
||||
|
||||
if (!_connectorCache) { buildConnectorCache(); }
|
||||
|
||||
if (_connectorCache[connectionName]) {
|
||||
@ -110,9 +112,9 @@ export default function(connectionName, options) {
|
||||
const viewClass = (childViews.length > 1) ? Ember.ContainerView : childViews[0];
|
||||
|
||||
delete options.fn; // we don't need the default template since we have a connector
|
||||
Ember.Handlebars.helpers.view.call(this, viewClass, options);
|
||||
env.helpers.view.helperFunction.call(this, [viewClass], hash, options, env);
|
||||
|
||||
const cvs = options.data.view._childViews;
|
||||
const cvs = env.data.view._childViews;
|
||||
if (childViews.length > 1 && cvs && cvs.length) {
|
||||
const inserted = cvs[cvs.length-1];
|
||||
if (inserted) {
|
||||
@ -121,16 +123,5 @@ export default function(connectionName, options) {
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (options.fn) {
|
||||
// If a block is passed, render its content.
|
||||
return Ember.Handlebars.helpers.view.call(this,
|
||||
Ember.View.extend({
|
||||
isVirtual: true,
|
||||
tagName: '',
|
||||
template: function() {
|
||||
return options.hash.template;
|
||||
}.property()
|
||||
}),
|
||||
options);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -22,11 +22,14 @@ function resolveParams(ctx, options) {
|
||||
}
|
||||
|
||||
export default function registerUnbound(name, fn) {
|
||||
Handlebars.registerHelper(name, function(property, options) {
|
||||
const func = function(property, options) {
|
||||
if (options.types && options.types[0] === "ID") {
|
||||
property = get(this, property, options);
|
||||
}
|
||||
|
||||
return fn.call(this, property, resolveParams(this, options));
|
||||
});
|
||||
};
|
||||
|
||||
Handlebars.registerHelper(name, func);
|
||||
Ember.Handlebars.registerHelper(name, func);
|
||||
}
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { applyFlaggedProperties } from 'discourse/controllers/header';
|
||||
|
||||
export default {
|
||||
name: 'apply-flagged-properties',
|
||||
after: 'register-discourse-location',
|
||||
initialize: applyFlaggedProperties
|
||||
};
|
||||
@ -3,6 +3,7 @@ export default {
|
||||
after: "message-bus",
|
||||
|
||||
initialize(container) {
|
||||
|
||||
const banner = Em.Object.create(PreloadStore.get("banner")),
|
||||
site = container.lookup('site:main');
|
||||
|
||||
|
||||
@ -38,13 +38,13 @@ export default {
|
||||
app.register('session:main', Session.current(), { instantiate: false });
|
||||
injectAll(app, 'session');
|
||||
|
||||
app.register('store:main', Store);
|
||||
inject(app, 'store', 'route', 'controller');
|
||||
|
||||
app.register('current-user:main', Discourse.User.current(), { instantiate: false });
|
||||
inject(app, 'currentUser', 'component', 'route', 'controller');
|
||||
|
||||
app.register('message-bus:main', window.MessageBus, { instantiate: false });
|
||||
inject(app, 'messageBus', 'route', 'controller', 'view');
|
||||
|
||||
app.register('store:main', Store);
|
||||
inject(app, 'store', 'route', 'controller');
|
||||
}
|
||||
};
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import { mapRoutes } from 'discourse/router';
|
||||
|
||||
export default {
|
||||
name: "map-routes",
|
||||
after: 'inject-objects',
|
||||
|
||||
initialize(container, app) {
|
||||
app.register('router:main', mapRoutes());
|
||||
|
||||
// HACK to fix: https://github.com/emberjs/ember.js/issues/10310
|
||||
const originalBuildInstance = originalBuildInstance || Ember.Application.prototype.buildInstance;
|
||||
Ember.Application.prototype.buildInstance = function() {
|
||||
this.registry = this.buildRegistry();
|
||||
return originalBuildInstance.apply(this);
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -1,8 +1,10 @@
|
||||
import DiscourseLocation from 'discourse/lib/discourse-location';
|
||||
|
||||
export default {
|
||||
name: "register-discourse-location",
|
||||
after: 'inject-objects',
|
||||
|
||||
initialize: function(container, application) {
|
||||
application.register('location:discourse-location', Ember.DiscourseLocation);
|
||||
application.register('location:discourse-location', DiscourseLocation);
|
||||
}
|
||||
};
|
||||
|
||||
@ -19,12 +19,14 @@ export default {
|
||||
return "http://twitter.com/intent/tweet?url=" + encodeURIComponent(link) + "&text=" + encodeURIComponent(title);
|
||||
},
|
||||
shouldOpenInPopup: true,
|
||||
title: I18n.t('share.twitter'),
|
||||
popupHeight: 265
|
||||
});
|
||||
|
||||
Sharing.addSource({
|
||||
id: 'facebook',
|
||||
faIcon: 'fa-facebook-square',
|
||||
title: I18n.t('share.facebook'),
|
||||
generateUrl: function(link, title) {
|
||||
return "http://www.facebook.com/sharer.php?u=" + encodeURIComponent(link) + '&t=' + encodeURIComponent(title);
|
||||
},
|
||||
@ -34,6 +36,7 @@ export default {
|
||||
Sharing.addSource({
|
||||
id: 'google+',
|
||||
faIcon: 'fa-google-plus-square',
|
||||
title: I18n.t('share.google+'),
|
||||
generateUrl: function(link) {
|
||||
return "https://plus.google.com/share?url=" + encodeURIComponent(link);
|
||||
},
|
||||
@ -44,6 +47,7 @@ export default {
|
||||
Sharing.addSource({
|
||||
id: 'email',
|
||||
faIcon: 'fa-envelope-square',
|
||||
title: I18n.t('share.email'),
|
||||
generateUrl: function(link, title) {
|
||||
return "mailto:?to=&subject=" + encodeURIComponent('[' + Discourse.SiteSettings.title + '] ' + title) + "&body=" + encodeURIComponent(link);
|
||||
}
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
var helpers = ['input-tip',
|
||||
'category-chooser',
|
||||
'combo-box',
|
||||
'choose-topic',
|
||||
'activity-filter'];
|
||||
|
||||
/**
|
||||
Creates view helpers for some views. Many of these should probably be converted
|
||||
into components in the long term as it's a better fit.
|
||||
**/
|
||||
export default {
|
||||
name: 'view-hlpers',
|
||||
initialize: function(container) {
|
||||
helpers.forEach(function(h) {
|
||||
Ember.Handlebars.registerHelper(h, function(options) {
|
||||
var helper = container.lookupFactory('view:' + h),
|
||||
hash = options.hash,
|
||||
types = options.hashTypes;
|
||||
|
||||
Discourse.Utilities.normalizeHash(hash, types);
|
||||
return Ember.Handlebars.helpers.view.call(this, helper, options);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -1403,6 +1403,10 @@
|
||||
xPosition += 25;
|
||||
button.id = id + postfix;
|
||||
button.title = title;
|
||||
// we really should just use jquery here
|
||||
if (button.setAttribute) {
|
||||
button.setAttribute('aria-label', title);
|
||||
}
|
||||
if (textOp)
|
||||
button.textOp = textOp;
|
||||
setupButton(button, true);
|
||||
|
||||
@ -7,20 +7,33 @@ function extractError(error) {
|
||||
Ember.Logger.error(error);
|
||||
}
|
||||
|
||||
let parsedError;
|
||||
if (error.responseText) {
|
||||
if (error.jqXHR) {
|
||||
error = error.jqXHR;
|
||||
}
|
||||
|
||||
let parsedError, parsedJSON;
|
||||
|
||||
if (error.responseJSON) {
|
||||
parsedJSON = error.responseJSON;
|
||||
}
|
||||
|
||||
if (!parsedJSON && error.responseText) {
|
||||
try {
|
||||
const parsedJSON = $.parseJSON(error.responseText);
|
||||
if (parsedJSON.errors) {
|
||||
parsedError = parsedJSON.errors[0];
|
||||
} else if (parsedJSON.failed) {
|
||||
parsedError = parsedJSON.message;
|
||||
}
|
||||
parsedJSON = $.parseJSON(error.responseText);
|
||||
} catch(ex) {
|
||||
// in case the JSON doesn't parse
|
||||
Ember.Logger.error(ex.stack);
|
||||
}
|
||||
}
|
||||
|
||||
if (parsedJSON) {
|
||||
if (parsedJSON.errors && parsedJSON.errors.length > 0) {
|
||||
parsedError = parsedJSON.errors[0];
|
||||
} else if (parsedJSON.failed) {
|
||||
parsedError = parsedJSON.message;
|
||||
}
|
||||
}
|
||||
|
||||
return parsedError || I18n.t('generic_error');
|
||||
}
|
||||
|
||||
@ -28,11 +41,10 @@ export function throwAjaxError(undoCallback) {
|
||||
return function(error) {
|
||||
// If we provided an `undo` callback
|
||||
if (undoCallback) { undoCallback(error); }
|
||||
|
||||
throw extractError(error);
|
||||
};
|
||||
}
|
||||
|
||||
export function popupAjaxError(err) {
|
||||
bootbox.alert(extractError(err));
|
||||
export function popupAjaxError(error) {
|
||||
bootbox.alert(extractError(error));
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import CloakedCollectionView from 'discourse/views/cloaked-collection';
|
||||
|
||||
/**
|
||||
@module Discourse
|
||||
*/
|
||||
|
||||
var get = Ember.get, set = Ember.set;
|
||||
var popstateFired = false;
|
||||
var supportsHistoryState = window.history && 'state' in window.history;
|
||||
const get = Ember.get, set = Ember.set;
|
||||
let popstateFired = false;
|
||||
const supportsHistoryState = window.history && 'state' in window.history;
|
||||
|
||||
var popstateCallbacks = [];
|
||||
const popstateCallbacks = [];
|
||||
|
||||
/**
|
||||
`Ember.DiscourseLocation` implements the location API using the browser's
|
||||
@ -16,7 +18,7 @@ var popstateCallbacks = [];
|
||||
@namespace Discourse
|
||||
@extends Ember.Object
|
||||
*/
|
||||
Ember.DiscourseLocation = Ember.Object.extend({
|
||||
const DiscourseLocation = Ember.Object.extend({
|
||||
|
||||
init: function() {
|
||||
set(this, 'location', get(this, 'location') || window.location);
|
||||
@ -226,7 +228,7 @@ Ember.DiscourseLocation = Ember.Object.extend({
|
||||
eject itself when the popState occurs. This results in better back button
|
||||
behavior.
|
||||
**/
|
||||
Ember.CloakedCollectionView.reopen({
|
||||
CloakedCollectionView.reopen({
|
||||
_watchForPopState: function() {
|
||||
var self = this,
|
||||
cb = function() {
|
||||
@ -241,7 +243,7 @@ Ember.CloakedCollectionView.reopen({
|
||||
// topic_route deactivate
|
||||
$('.posts,#topic-title').hide();
|
||||
self.cleanUp();
|
||||
self.set('controller.postStream.loaded', false);
|
||||
self.set('controller.model.postStream.loaded', false);
|
||||
};
|
||||
this.set('_callback', cb);
|
||||
popstateCallbacks.addObject(cb);
|
||||
@ -252,3 +254,5 @@ Ember.CloakedCollectionView.reopen({
|
||||
this.set('_callback', null);
|
||||
}.on('willDestroyElement')
|
||||
});
|
||||
|
||||
export default DiscourseLocation;
|
||||
@ -22,6 +22,8 @@
|
||||
RawHandlebars.helpers.get = function(context, options){
|
||||
var firstContext = options.contexts[0];
|
||||
var val = firstContext[context];
|
||||
|
||||
if (val && val.isDescriptor) { return Em.get(firstContext, context); }
|
||||
val = val === undefined ? Em.get(firstContext, context): val;
|
||||
return val;
|
||||
};
|
||||
|
||||
@ -196,7 +196,7 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
|
||||
var selectedPostId = parseInt($('.topic-post.selected article.boxed').data('post-id'), 10);
|
||||
if (selectedPostId) {
|
||||
var topicController = container.lookup('controller:topic'),
|
||||
post = topicController.get('postStream.posts').findBy('id', selectedPostId);
|
||||
post = topicController.get('model.postStream.posts').findBy('id', selectedPostId);
|
||||
if (post) {
|
||||
topicController.send(action, post);
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ Discourse.URL = Ember.Object.createWithMixins({
|
||||
var container = Discourse.__container__,
|
||||
topicController = container.lookup('controller:topic'),
|
||||
opts = {},
|
||||
postStream = topicController.get('postStream');
|
||||
postStream = topicController.get('model.postStream');
|
||||
|
||||
if (newMatches[3]) opts.nearPost = newMatches[3];
|
||||
if (path.match(/last$/)) { opts.nearPost = topicController.get('highest_post_number'); }
|
||||
@ -295,7 +295,7 @@ Discourse.URL = Ember.Object.createWithMixins({
|
||||
**/
|
||||
router: function() {
|
||||
return Discourse.__container__.lookup('router:main');
|
||||
}.property(),
|
||||
}.property().volatile(),
|
||||
|
||||
/**
|
||||
@private
|
||||
|
||||
@ -15,7 +15,7 @@ export default {
|
||||
if (categoryFullSlug) {
|
||||
$('body').addClass('category-' + categoryFullSlug);
|
||||
}
|
||||
}.observes('categoryFullSlug'),
|
||||
}.observes('categoryFullSlug').on('init'),
|
||||
|
||||
_leaveView: function() { this._removeClasses(); }.on('willDestroyElement')
|
||||
};
|
||||
|
||||
@ -60,7 +60,7 @@ Discourse.Ajax = Em.Mixin.create({
|
||||
Ember.run(null, resolve, data);
|
||||
};
|
||||
|
||||
args.error = function(xhr, textStatus) {
|
||||
args.error = function(xhr, textStatus, errorThrown) {
|
||||
// note: for bad CSRF we don't loop an extra request right away.
|
||||
// this allows us to eliminate the possibility of having a loop.
|
||||
if (xhr.status === 403 && xhr.responseText === "['BAD CSRF']") {
|
||||
@ -74,7 +74,11 @@ Discourse.Ajax = Em.Mixin.create({
|
||||
xhr.jqTextStatus = textStatus;
|
||||
xhr.requestedUrl = url;
|
||||
|
||||
Ember.run(null, reject, xhr);
|
||||
Ember.run(null, reject, {
|
||||
jqXHR: xhr,
|
||||
textStatus: textStatus,
|
||||
errorThrown: errorThrown
|
||||
});
|
||||
};
|
||||
|
||||
// We default to JSON on GET. If we don't, sometimes if the server doesn't return the proper header
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export default Ember.Mixin.create({
|
||||
isOwnEmail: Discourse.computed.propertyEqual("id", "currentUser.id"),
|
||||
showEmailOnProfile: Discourse.computed.setting("show_email_on_profile"),
|
||||
isOwnEmail: Discourse.computed.propertyEqual("model.id", "currentUser.id"),
|
||||
showEmailOnProfile: Discourse.computed.setting("model.show_email_on_profile"),
|
||||
canStaffCheckEmails: Em.computed.and("showEmailOnProfile", "currentUser.staff"),
|
||||
canAdminCheckEmails: Em.computed.alias("currentUser.admin"),
|
||||
canCheckEmails: Em.computed.or("isOwnEmail", "canStaffCheckEmails", "canAdminCheckEmails"),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user