Discourse Macro Helpers + Minor Fix to Admin User View
This commit is contained in:
parent
89152116c6
commit
5eaae063f0
|
@ -78,9 +78,7 @@ Discourse.AdminUsersListController = Ember.ArrayController.extend(Discourse.Pres
|
|||
|
||||
@property hasSelection
|
||||
**/
|
||||
hasSelection: function() {
|
||||
return this.get('selectedCount') > 0;
|
||||
}.property('selectedCount'),
|
||||
hasSelection: Em.computed.gt('selectedCount', 0),
|
||||
|
||||
/**
|
||||
Refresh the current list of users.
|
||||
|
|
|
@ -98,19 +98,14 @@ Discourse.AdminUser = Discourse.User.extend({
|
|||
this.set('trustLevel.id', this.get('originalTrustLevel'));
|
||||
},
|
||||
|
||||
isBanned: (function() {
|
||||
return this.get('is_banned') === true;
|
||||
}).property('is_banned'),
|
||||
isBanned: Em.computed.equal('is_banned', true),
|
||||
canBan: Em.computed.not('staff'),
|
||||
|
||||
canBan: (function() {
|
||||
return !this.get('admin') && !this.get('moderator');
|
||||
}).property('admin', 'moderator'),
|
||||
|
||||
banDuration: (function() {
|
||||
banDuration: function() {
|
||||
var banned_at = moment(this.banned_at);
|
||||
var banned_till = moment(this.banned_till);
|
||||
return banned_at.format('L') + " - " + banned_till.format('L');
|
||||
}).property('banned_till', 'banned_at'),
|
||||
}.property('banned_till', 'banned_at'),
|
||||
|
||||
ban: function() {
|
||||
var duration = parseInt(window.prompt(I18n.t('admin.user.ban_duration')), 10);
|
||||
|
|
|
@ -16,11 +16,6 @@ Discourse.AdminUserRoute = Discourse.Route.extend(Discourse.ModelReady, {
|
|||
return Discourse.AdminUser.find(Em.get(params, 'username').toLowerCase());
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set('model', model);
|
||||
model.setOriginalTrustLevel();
|
||||
},
|
||||
|
||||
renderTemplate: function() {
|
||||
this.render({into: 'admin/templates/admin'});
|
||||
},
|
||||
|
@ -28,6 +23,7 @@ Discourse.AdminUserRoute = Discourse.Route.extend(Discourse.ModelReady, {
|
|||
modelReady: function(controller, adminUser) {
|
||||
adminUser.loadDetails();
|
||||
controller.set('model', adminUser);
|
||||
adminUser.setOriginalTrustLevel();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -12,6 +12,49 @@ Discourse.computed = {
|
|||
return Ember.computed(function() {
|
||||
return this.get(p1) === this.get(p2);
|
||||
}).property(p1, p2);
|
||||
},
|
||||
|
||||
/**
|
||||
Uses an Ember String `fmt` call to format a string. See:
|
||||
http://emberjs.com/api/classes/Ember.String.html#method_fmt
|
||||
|
||||
@method fmt
|
||||
@params {String} properties* to format
|
||||
@params {String} format the format string
|
||||
@return {Function} computedProperty function
|
||||
**/
|
||||
fmt: function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
var format = args.pop();
|
||||
var computed = Ember.computed(function() {
|
||||
var context = this;
|
||||
return format.fmt.apply(format, args.map(function (a) {
|
||||
return context.get(a);
|
||||
}));
|
||||
})
|
||||
return computed.property.apply(computed, args);
|
||||
},
|
||||
|
||||
/**
|
||||
Creates a URL using Discourse.getURL. It takes a fmt string just like
|
||||
fmt does.
|
||||
|
||||
@method url
|
||||
@params {String} properties* to format
|
||||
@params {String} format the format string for the URL
|
||||
@return {Function} computedProperty function returning a URL
|
||||
**/
|
||||
url: function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
var format = args.pop();
|
||||
var computed = Ember.computed(function() {
|
||||
var context = this;
|
||||
return Discourse.getURL(format.fmt.apply(format, args.map(function (a) {
|
||||
return context.get(a);
|
||||
})));
|
||||
})
|
||||
return computed.property.apply(computed, args);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -25,8 +25,7 @@ Discourse.ListCategoriesController = Discourse.ObjectController.extend({
|
|||
}.property('categories.@each'),
|
||||
|
||||
canEdit: function() {
|
||||
var u = Discourse.User.current();
|
||||
return u && u.staff;
|
||||
Discourse.User.current('staff');
|
||||
}.property(),
|
||||
|
||||
// clear a pinned topic
|
||||
|
|
|
@ -198,8 +198,6 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
Discourse.URL.routeTo(this.get('lastPostUrl'));
|
||||
},
|
||||
|
||||
|
||||
|
||||
replyAsNewTopic: function(post) {
|
||||
// TODO shut down topic draft cleanly if it exists ...
|
||||
var composerController = this.get('controllers.composer');
|
||||
|
|
|
@ -21,13 +21,7 @@ Discourse.Post = Discourse.Model.extend({
|
|||
return Discourse.Utilities.postUrl(this.get('topic.slug') || this.get('topic_slug'), this.get('topic_id'), this.get('post_number'));
|
||||
}.property('post_number', 'topic_id', 'topic.slug'),
|
||||
|
||||
originalPostUrl: function() {
|
||||
return Discourse.getURL("/t/") + (this.get('topic_id')) + "/" + (this.get('reply_to_post_number'));
|
||||
}.property('reply_to_post_number'),
|
||||
|
||||
usernameUrl: function() {
|
||||
return Discourse.getURL("/users/" + this.get('username'));
|
||||
}.property('username'),
|
||||
usernameUrl: Discourse.computed.url('username', '/users/%@'),
|
||||
|
||||
showUserReplyTab: function() {
|
||||
return this.get('reply_to_user') && (
|
||||
|
@ -36,15 +30,9 @@ Discourse.Post = Discourse.Model.extend({
|
|||
);
|
||||
}.property('reply_to_user', 'reply_to_post_number', 'post_number'),
|
||||
|
||||
byTopicCreator: function() {
|
||||
return this.get('topic.details.created_by.id') === this.get('user_id');
|
||||
}.property('topic.details.created_by.id', 'user_id'),
|
||||
|
||||
byTopicCreator: Discourse.computed.propertyEqual('topic.details.created_by.id', 'user_id'),
|
||||
hasHistory: Em.computed.gt('version', 1),
|
||||
|
||||
postElementId: function() {
|
||||
return "post_" + (this.get('post_number'));
|
||||
}.property('post_number'),
|
||||
postElementId: Discourse.computed.fmt('post_number', 'post_%@'),
|
||||
|
||||
// The class for the read icon of the post. It starts with read-icon then adds 'seen' or
|
||||
// 'last-read' if the post has been seen or is the highest post number seen so far respectively.
|
||||
|
|
|
@ -132,7 +132,6 @@ Discourse.Topic = Discourse.Model.extend({
|
|||
archetypeObject: function() {
|
||||
return Discourse.Site.instance().get('archetypes').findProperty('id', this.get('archetype'));
|
||||
}.property('archetype'),
|
||||
|
||||
isPrivateMessage: Em.computed.equal('archetype', 'private_message'),
|
||||
|
||||
toggleStatus: function(property) {
|
||||
|
@ -225,7 +224,6 @@ Discourse.Topic = Discourse.Model.extend({
|
|||
@method clearPin
|
||||
**/
|
||||
clearPin: function() {
|
||||
|
||||
var topic = this;
|
||||
|
||||
// Clear the pin optimistically from the object
|
||||
|
@ -241,29 +239,27 @@ Discourse.Topic = Discourse.Model.extend({
|
|||
|
||||
// Is the reply to a post directly below it?
|
||||
isReplyDirectlyBelow: function(post) {
|
||||
var postBelow, posts;
|
||||
posts = this.get('postStream.posts');
|
||||
var posts = this.get('postStream.posts');
|
||||
if (!posts) return;
|
||||
|
||||
postBelow = posts[posts.indexOf(post) + 1];
|
||||
var postBelow = posts[posts.indexOf(post) + 1];
|
||||
|
||||
// If the post directly below's reply_to_post_number is our post number, it's
|
||||
// considered directly below.
|
||||
return postBelow && postBelow.get('reply_to_post_number') === post.get('post_number');
|
||||
},
|
||||
|
||||
hasExcerpt: function() {
|
||||
return this.get('pinned') && this.get('excerpt') && this.get('excerpt').length > 0;
|
||||
}.property('pinned', 'excerpt'),
|
||||
excerptNotEmpty: Em.computed.notEmpty('excerpt'),
|
||||
hasExcerpt: Em.computed.and('pinned', 'excerptNotEmpty'),
|
||||
|
||||
excerptTruncated: function() {
|
||||
var e = this.get('excerpt');
|
||||
return( e && e.substr(e.length - 8,8) === '…' );
|
||||
}.property('excerpt'),
|
||||
|
||||
canClearPin: function() {
|
||||
return this.get('pinned') && (this.get('last_read_post_number') === this.get('highest_post_number'));
|
||||
}.property('pinned', 'last_read_post_number', 'highest_post_number')
|
||||
readLastPost: Discourse.computed.propertyEqual('last_read_post_number', 'highest_post_number'),
|
||||
canCleanPin: Em.computed.and('pinned', 'readLastPost')
|
||||
|
||||
});
|
||||
|
||||
Discourse.Topic.reopenClass({
|
||||
|
|
|
@ -8,15 +8,23 @@
|
|||
**/
|
||||
Discourse.User = Discourse.Model.extend({
|
||||
|
||||
/**
|
||||
Is this user a member of staff?
|
||||
|
||||
@property staff
|
||||
@type {Boolean}
|
||||
**/
|
||||
staff: Em.computed.or('admin', 'moderator'),
|
||||
|
||||
/**
|
||||
Large version of this user's avatar.
|
||||
|
||||
@property avatarLarge
|
||||
@type {String}
|
||||
**/
|
||||
avatarLarge: (function() {
|
||||
avatarLarge: function() {
|
||||
return Discourse.Utilities.avatarUrl(this.get('username'), 'large', this.get('avatar_template'));
|
||||
}).property('username'),
|
||||
}.property('username'),
|
||||
|
||||
/**
|
||||
Small version of this user's avatar.
|
||||
|
@ -39,11 +47,10 @@ Discourse.User = Discourse.Model.extend({
|
|||
@type {String}
|
||||
**/
|
||||
websiteName: function() {
|
||||
return this.get('website').split("/")[2];
|
||||
}.property('website'),
|
||||
var website = this.get('website');
|
||||
if (Em.isEmpty(website)) { return; }
|
||||
|
||||
hasWebsite: function() {
|
||||
return this.present('website');
|
||||
return this.get('website').split("/")[2];
|
||||
}.property('website'),
|
||||
|
||||
statusIcon: function() {
|
||||
|
@ -65,9 +72,7 @@ Discourse.User = Discourse.Model.extend({
|
|||
@property path
|
||||
@type {String}
|
||||
**/
|
||||
path: function() {
|
||||
return Discourse.getURL("/users/") + (this.get('username_lower'));
|
||||
}.property('username'),
|
||||
path: Discourse.computed.url('username_lower', "/users/%@"),
|
||||
|
||||
/**
|
||||
Path to this user's administration
|
||||
|
@ -75,9 +80,7 @@ Discourse.User = Discourse.Model.extend({
|
|||
@property adminPath
|
||||
@type {String}
|
||||
**/
|
||||
adminPath: function() {
|
||||
return Discourse.getURL("/admin/users/") + (this.get('username_lower'));
|
||||
}.property('username'),
|
||||
adminPath: Discourse.computed.url('username_lower', "/admin/users/%@"),
|
||||
|
||||
/**
|
||||
This user's username in lowercase.
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
</ul>
|
||||
<div class='show'>
|
||||
<dl>
|
||||
{{#if hasWebsite}}
|
||||
{{#if websiteName}}
|
||||
<dt>{{i18n user.website}}:</dt><dd><a {{bindAttr href="website"}} target="_blank">{{websiteName}}</a></dd>
|
||||
{{/if}}
|
||||
{{#if created_at}}
|
||||
|
|
|
@ -192,15 +192,15 @@ class PostsController < ApplicationController
|
|||
|
||||
def create_params
|
||||
permitted = [
|
||||
:raw,
|
||||
:topic_id,
|
||||
:title,
|
||||
:archetype,
|
||||
:category,
|
||||
:target_usernames,
|
||||
:reply_to_post_number,
|
||||
:image_sizes,
|
||||
:auto_close_days
|
||||
:raw,
|
||||
:topic_id,
|
||||
:title,
|
||||
:archetype,
|
||||
:category,
|
||||
:target_usernames,
|
||||
:reply_to_post_number,
|
||||
:image_sizes,
|
||||
:auto_close_days
|
||||
]
|
||||
|
||||
if api_key_valid?
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
module("Discourse.Computed");
|
||||
|
||||
var testClass = Em.Object.extend({
|
||||
same: Discourse.computed.propertyEqual('cookies', 'biscuits'),
|
||||
exclaimyUsername: Discourse.computed.fmt('username', "!!! %@ !!!"),
|
||||
multiple: Discourse.computed.fmt('username', 'mood', "%@ is %@"),
|
||||
userUrl: Discourse.computed.url('username', "/users/%@")
|
||||
});
|
||||
|
||||
test("propertyEqual", function() {
|
||||
var t = testClass.create({
|
||||
cookies: 10,
|
||||
biscuits: 10
|
||||
});
|
||||
|
||||
ok(t.get('same'), "it is true when the properties are the same");
|
||||
|
||||
t.set('biscuits', 9);
|
||||
ok(!t.get('same'), "it isn't true when one property is different");
|
||||
});
|
||||
|
||||
|
||||
test("fmt", function() {
|
||||
var t = testClass.create({
|
||||
username: 'eviltrout',
|
||||
mood: "happy"
|
||||
});
|
||||
|
||||
equal(t.get('exclaimyUsername'), '!!! eviltrout !!!', "it inserts the string");
|
||||
equal(t.get('multiple'), "eviltrout is happy");
|
||||
|
||||
t.set('username', 'codinghorror');
|
||||
equal(t.get('multiple'), "codinghorror is happy", "supports changing proerties");
|
||||
t.set('mood', 'ecstatic');
|
||||
equal(t.get('multiple'), "codinghorror is ecstatic", "supports changing another property");
|
||||
});
|
||||
|
||||
|
||||
test("url without a prefix", function() {
|
||||
var t = testClass.create({ username: 'eviltrout' });
|
||||
equal(t.get('userUrl'), "/users/eviltrout");
|
||||
|
||||
});
|
||||
|
||||
test("url with a prefix", function() {
|
||||
Discourse.BaseUri = "/prefixed/";
|
||||
var t = testClass.create({ username: 'eviltrout' });
|
||||
equal(t.get('userUrl'), "/prefixed/users/eviltrout");
|
||||
|
||||
});
|
|
@ -80,5 +80,6 @@ Discourse.Router.map(function() {
|
|||
QUnit.testStart(function() {
|
||||
// Allow our tests to change site settings and have them reset before the next test
|
||||
Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal);
|
||||
Discourse.BaseUri = "/";
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue