Show topics as a list of topics on the User Stream.
This commit is contained in:
parent
3f5ea1ef79
commit
0317cf9608
|
@ -13,5 +13,3 @@
|
||||||
|
|
||||||
{{collection contentBinding="filteredContent" classNames="form-horizontal settings" itemViewClass="Discourse.SiteSettingView"}}
|
{{collection contentBinding="filteredContent" classNames="form-horizontal settings" itemViewClass="Discourse.SiteSettingView"}}
|
||||||
|
|
||||||
<!-- will remove as soon as I figure out what is going on -->
|
|
||||||
<p><small>Diagnostics: last_message_processed {{diags.last_message_processed}}</small></p>
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
{{#with view.content}}
|
<div class='span4 offset1'>
|
||||||
<div class='span4 offset1'>
|
<h3>{{unbound setting}}</h3>
|
||||||
<h3>{{unbound setting}}</h3>
|
</div>
|
||||||
</div>
|
<div class="span11">
|
||||||
<div class="span11">
|
<label>
|
||||||
<label>
|
{{view Ember.Checkbox checkedBinding="enabled" value="true"}}
|
||||||
{{view Ember.Checkbox checkedBinding="enabled" value="true"}}
|
{{unbound description}}
|
||||||
{{unbound description}}
|
</label>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
|
||||||
{{/with}}
|
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
{{#with view.content}}
|
<div class='span4 offset1'>
|
||||||
<div class='span4 offset1'>
|
<h3>{{unbound setting}}</h3>
|
||||||
<h3>{{unbound setting}}</h3>
|
</div>
|
||||||
|
<div class="span11">
|
||||||
|
{{combobox valueAttribute="value" content=validValues value=value none=allowsNone}}
|
||||||
|
<div class='desc'>{{unbound description}}</div>
|
||||||
|
</div>
|
||||||
|
{{#if dirty}}
|
||||||
|
<div class='span3'>
|
||||||
|
<button class='btn ok' {{action save this}}><i class='icon-ok'></i></button>
|
||||||
|
<button class='btn cancel' {{action cancel this}}><i class='icon-remove'></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="span11">
|
{{else}}
|
||||||
{{combobox valueAttribute="value" content=validValues value=value none=allowsNone}}
|
{{#if overridden}}
|
||||||
<div class='desc'>{{unbound description}}</div>
|
<button class='btn' href='#' {{action resetDefault this}}>{{i18n admin.site_settings.reset}}</button>
|
||||||
</div>
|
|
||||||
{{#if dirty}}
|
|
||||||
<div class='span3'>
|
|
||||||
<button class='btn ok' {{action save this}}><i class='icon-ok'></i></button>
|
|
||||||
<button class='btn cancel' {{action cancel this}}><i class='icon-remove'></i></button>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
{{#if overridden}}
|
|
||||||
<button class='btn' href='#' {{action resetDefault this}}>{{i18n admin.site_settings.reset}}</button>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/with}}
|
{{/if}}
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
{{#with view.content}}
|
<div class='span4 offset1'>
|
||||||
<div class='span4 offset1'>
|
<h3>{{unbound setting}}</h3>
|
||||||
<h3>{{unbound setting}}</h3>
|
</div>
|
||||||
|
<div class="span11">
|
||||||
|
{{textField value=value classNames="input-xxlarge"}}
|
||||||
|
<div class='desc'>{{unbound description}}</div>
|
||||||
|
</div>
|
||||||
|
{{#if dirty}}
|
||||||
|
<div class='span3'>
|
||||||
|
<button class='btn ok' {{action save this}}><i class='icon-ok'></i></button>
|
||||||
|
<button class='btn cancel' {{action cancel this}}><i class='icon-remove'></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="span11">
|
{{else}}
|
||||||
{{textField value=value classNames="input-xxlarge"}}
|
{{#if overridden}}
|
||||||
<div class='desc'>{{unbound description}}</div>
|
<button class='btn' href='#' {{action resetDefault this}}>{{i18n admin.site_settings.reset}}</button>
|
||||||
</div>
|
|
||||||
{{#if dirty}}
|
|
||||||
<div class='span3'>
|
|
||||||
<button class='btn ok' {{action save this}}><i class='icon-ok'></i></button>
|
|
||||||
<button class='btn cancel' {{action cancel this}}><i class='icon-remove'></i></button>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
{{#if overridden}}
|
|
||||||
<button class='btn' href='#' {{action resetDefault this}}>{{i18n admin.site_settings.reset}}</button>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/with}}
|
{{/if}}
|
||||||
|
|
|
@ -64,6 +64,9 @@ Discourse.URL = Em.Object.createWithMixins({
|
||||||
if (this.navigatedToListMore(oldPath, path)) { return; }
|
if (this.navigatedToListMore(oldPath, path)) { return; }
|
||||||
if (this.navigatedToHome(oldPath, path)) { return; }
|
if (this.navigatedToHome(oldPath, path)) { return; }
|
||||||
|
|
||||||
|
if (path.match(/^\/?users\/[^\/]+$/)) {
|
||||||
|
path += "/activity";
|
||||||
|
}
|
||||||
// Be wary of looking up the router. In this case, we have links in our
|
// Be wary of looking up the router. In this case, we have links in our
|
||||||
// HTML, say form compiled markdown posts, that need to be routed.
|
// HTML, say form compiled markdown posts, that need to be routed.
|
||||||
var router = this.get('router');
|
var router = this.get('router');
|
||||||
|
|
|
@ -87,7 +87,7 @@ Discourse.Utilities = {
|
||||||
},
|
},
|
||||||
|
|
||||||
userUrl: function(username) {
|
userUrl: function(username) {
|
||||||
return Discourse.getURL("/users/" + username);
|
return Discourse.getURL("/users/" + username.toLowerCase());
|
||||||
},
|
},
|
||||||
|
|
||||||
emailValid: function(email) {
|
emailValid: function(email) {
|
||||||
|
|
|
@ -24,6 +24,16 @@ Discourse.ListController = Discourse.Controller.extend({
|
||||||
});
|
});
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
|
createTopicText: function() {
|
||||||
|
if (this.get('category.name')) {
|
||||||
|
return I18n.t("topic.create_in", {
|
||||||
|
categoryName: this.get('category.name')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return I18n.t("topic.create");
|
||||||
|
}
|
||||||
|
}.property('category.name'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Refresh our current topic list
|
Refresh our current topic list
|
||||||
|
|
||||||
|
|
|
@ -81,11 +81,11 @@ Discourse.ListTopicsController = Discourse.ObjectController.extend({
|
||||||
}.property('allLoaded', 'topics.length'),
|
}.property('allLoaded', 'topics.length'),
|
||||||
|
|
||||||
loadMore: function() {
|
loadMore: function() {
|
||||||
this.set('loadingMore', true);
|
var topicList = this.get('model');
|
||||||
var listTopicsController = this;
|
return topicList.loadMoreTopics().then(function(moreUrl) {
|
||||||
return this.get('model').loadMoreTopics().then(function(hasMoreTopics) {
|
if (!Em.isEmpty(moreUrl)) {
|
||||||
listTopicsController.set('loadingMore', false);
|
Discourse.URL.replaceState(Discourse.getURL("/") + topicList.get('filter') + "/more");
|
||||||
return hasMoreTopics;
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,51 +1,3 @@
|
||||||
/**
|
|
||||||
The route for editing a user's "About Me" bio.
|
|
||||||
|
|
||||||
@class PreferencesAboutRoute
|
|
||||||
@extends Discourse.RestrictedUserRoute
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.PreferencesAboutRoute = Discourse.RestrictedUserRoute.extend({
|
|
||||||
model: function() {
|
|
||||||
return this.modelFor('user');
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTemplate: function() {
|
|
||||||
this.render({ into: 'user', outlet: 'userOutlet' });
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController: function(controller, model) {
|
|
||||||
controller.setProperties({ model: model, newBio: model.get('bio_raw') });
|
|
||||||
},
|
|
||||||
|
|
||||||
// A bit odd, but if we leave to /preferences we need to re-render that outlet
|
|
||||||
exit: function() {
|
|
||||||
this._super();
|
|
||||||
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
|
||||||
},
|
|
||||||
|
|
||||||
events: {
|
|
||||||
changeAbout: function() {
|
|
||||||
var route = this;
|
|
||||||
var controller = route.controllerFor('preferencesAbout');
|
|
||||||
|
|
||||||
controller.setProperties({ saving: true });
|
|
||||||
return controller.get('model').save().then(function() {
|
|
||||||
controller.set('saving', false);
|
|
||||||
route.transitionTo('user.index');
|
|
||||||
}, function() {
|
|
||||||
// model failed to save
|
|
||||||
controller.set('saving', false);
|
|
||||||
alert(I18n.t('generic_error'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This controller supports actions related to updating your "About Me" bio
|
This controller supports actions related to updating your "About Me" bio
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,3 @@
|
||||||
/**
|
|
||||||
The common route stuff for a user's preference
|
|
||||||
|
|
||||||
@class PreferencesRoute
|
|
||||||
@extends Discourse.RestrictedUserRoute
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.PreferencesRoute = Discourse.RestrictedUserRoute.extend({
|
|
||||||
model: function() {
|
|
||||||
return this.modelFor('user');
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTemplate: function() {
|
|
||||||
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This controller supports actions related to updating one's preferences
|
This controller supports actions related to updating one's preferences
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,3 @@
|
||||||
/**
|
|
||||||
The route for editing a user's email
|
|
||||||
|
|
||||||
@class PreferencesEmailRoute
|
|
||||||
@extends Discourse.RestrictedUserRoute
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.PreferencesEmailRoute = Discourse.RestrictedUserRoute.extend({
|
|
||||||
model: function() {
|
|
||||||
return this.modelFor('user');
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTemplate: function() {
|
|
||||||
this.render({ into: 'user', outlet: 'userOutlet' });
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController: function(controller, model) {
|
|
||||||
controller.setProperties({ model: model, newEmail: model.get('email') });
|
|
||||||
},
|
|
||||||
|
|
||||||
// A bit odd, but if we leave to /preferences we need to re-render that outlet
|
|
||||||
exit: function() {
|
|
||||||
this._super();
|
|
||||||
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This controller supports actions related to updating one's email address
|
This controller supports actions related to updating one's email address
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,3 @@
|
||||||
/**
|
|
||||||
The route for updating a user's username
|
|
||||||
|
|
||||||
@class PreferencesUsernameRoute
|
|
||||||
@extends Discourse.RestrictedUserRoute
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.PreferencesUsernameRoute = Discourse.RestrictedUserRoute.extend({
|
|
||||||
model: function() {
|
|
||||||
return this.modelFor('user');
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTemplate: function() {
|
|
||||||
return this.render({ into: 'user', outlet: 'userOutlet' });
|
|
||||||
},
|
|
||||||
|
|
||||||
// A bit odd, but if we leave to /preferences we need to re-render that outlet
|
|
||||||
exit: function() {
|
|
||||||
this._super();
|
|
||||||
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController: function(controller, user) {
|
|
||||||
controller.setProperties({ model: user, newUsername: user.get('username') });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This controller supports actions related to updating one's username
|
This controller supports actions related to updating one's username
|
||||||
|
|
||||||
|
|
|
@ -1,82 +1,3 @@
|
||||||
/**
|
|
||||||
The base route for showing an activity stream.
|
|
||||||
|
|
||||||
@class UserActivityRoute
|
|
||||||
@extends Discourse.Route
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.UserActivityRoute = Discourse.Route.extend({
|
|
||||||
renderTemplate: function() {
|
|
||||||
this.render('user_activity', {into: 'user', outlet: 'userOutlet' });
|
|
||||||
},
|
|
||||||
|
|
||||||
model: function() {
|
|
||||||
return this.modelFor('user');
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController: function(controller, user) {
|
|
||||||
this.controllerFor('userActivity').set('model', user);
|
|
||||||
|
|
||||||
var composerController = this.controllerFor('composer');
|
|
||||||
controller.set('model', user);
|
|
||||||
if (Discourse.User.current()) {
|
|
||||||
Discourse.Draft.get('new_private_message').then(function(data) {
|
|
||||||
if (data.draft) {
|
|
||||||
composerController.open({
|
|
||||||
draft: data.draft,
|
|
||||||
draftKey: 'new_private_message',
|
|
||||||
ignoreIfChanged: true,
|
|
||||||
draftSequence: data.draft_sequence
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Discourse.UserActivityIndexRoute = Discourse.Route.extend({
|
|
||||||
model: function() {
|
|
||||||
return this.modelFor('user').findStream(this.get('userActionType'));
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTemplate: function() {
|
|
||||||
this.render('user_stream', {into: 'user_activity', outlet: 'activity'});
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController: function() {
|
|
||||||
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Discourse.UserIndexRoute = Discourse.UserActivityRoute.extend({
|
|
||||||
renderTemplate: function() {
|
|
||||||
this._super();
|
|
||||||
this.render('user_stream', {into: 'user_activity', outlet: 'activity'});
|
|
||||||
},
|
|
||||||
|
|
||||||
model: function() {
|
|
||||||
return this.modelFor('user').findStream();
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController: function(controller, model) {
|
|
||||||
this.controllerFor('userActivity').set('model', this.modelFor('user'));
|
|
||||||
this.set('model', model);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Build all the filter routes
|
|
||||||
Object.keys(Discourse.UserAction.TYPES).forEach(function (userAction) {
|
|
||||||
Discourse["UserActivity" + userAction.classify() + "Route"] = Discourse.UserActivityIndexRoute.extend({
|
|
||||||
userActionType: Discourse.UserAction.TYPES[userAction]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// // Build the private message routes
|
|
||||||
Discourse.UserPrivateMessagesRoute = Discourse.UserActivityRoute.extend({});
|
|
||||||
Discourse.UserPrivateMessagesIndexRoute = Discourse.UserActivityMessagesReceivedRoute;
|
|
||||||
Discourse.UserPrivateMessagesSentRoute = Discourse.UserActivityMessagesSentRoute;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This controller supports all actions on a user's activity stream
|
This controller supports all actions on a user's activity stream
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
This mixin provides the ability to load more items for a view which is
|
||||||
|
scrolled to the bottom.
|
||||||
|
|
||||||
|
@class Discourse.LoadMore
|
||||||
|
@extends Ember.Mixin
|
||||||
|
@uses Discourse.Scrolling
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.LoadMore = Em.Mixin.create(Discourse.Scrolling, {
|
||||||
|
|
||||||
|
scrolled: function(e) {
|
||||||
|
var eyeline = this.get('eyeline');
|
||||||
|
if (eyeline) { eyeline.update(); }
|
||||||
|
},
|
||||||
|
|
||||||
|
loadMore: function() {
|
||||||
|
console.error('loadMore() not defined');
|
||||||
|
},
|
||||||
|
|
||||||
|
didInsertElement: function() {
|
||||||
|
this._super();
|
||||||
|
var eyeline = new Discourse.Eyeline(this.get('eyelineSelector'));
|
||||||
|
this.set('eyeline', eyeline);
|
||||||
|
|
||||||
|
var paginatedTopicListView = this;
|
||||||
|
eyeline.on('sawBottom', function() {
|
||||||
|
paginatedTopicListView.loadMore();
|
||||||
|
});
|
||||||
|
this.bindScrolling();
|
||||||
|
},
|
||||||
|
|
||||||
|
willRemoveElement: function() {
|
||||||
|
this._super();
|
||||||
|
this.unbindScrolling();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
|
@ -23,32 +23,37 @@ Discourse.TopicList = Discourse.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
loadMoreTopics: function() {
|
loadMoreTopics: function() {
|
||||||
var moreUrl, _this = this;
|
|
||||||
|
|
||||||
if (moreUrl = this.get('more_topics_url')) {
|
if (this.get('loadingMore')) { return Ember.RSVP.reject(); }
|
||||||
Discourse.URL.replaceState(Discourse.getURL("/") + (this.get('filter')) + "/more");
|
|
||||||
|
var moreUrl = this.get('more_topics_url');
|
||||||
|
if (moreUrl) {
|
||||||
|
|
||||||
|
var topicList = this;
|
||||||
|
this.set('loadingMore', true);
|
||||||
|
|
||||||
return Discourse.ajax({url: moreUrl}).then(function (result) {
|
return Discourse.ajax({url: moreUrl}).then(function (result) {
|
||||||
var newTopics, topics, topicsAdded = 0;
|
var topicsAdded = 0;
|
||||||
if (result) {
|
if (result) {
|
||||||
// the new topics loaded from the server
|
// the new topics loaded from the server
|
||||||
newTopics = Discourse.TopicList.topicsFrom(result);
|
var newTopics = Discourse.TopicList.topicsFrom(result);
|
||||||
topics = _this.get("topics");
|
var topics = topicList.get("topics");
|
||||||
|
|
||||||
_this.forEachNew(newTopics, function(t) {
|
topicList.forEachNew(newTopics, function(t) {
|
||||||
t.set('highlight', topicsAdded++ === 0);
|
t.set('highlight', topicsAdded++ === 0);
|
||||||
topics.pushObject(t);
|
topics.pushObject(t);
|
||||||
});
|
});
|
||||||
|
|
||||||
_this.set('more_topics_url', result.topic_list.more_topics_url);
|
topicList.set('more_topics_url', result.topic_list.more_topics_url);
|
||||||
Discourse.set('transient.topicsList', _this);
|
Discourse.set('transient.topicsList', topicList);
|
||||||
|
topicList.set('loadingMore', false);
|
||||||
|
|
||||||
|
return result.topic_list.more_topics_url;
|
||||||
}
|
}
|
||||||
return result.topic_list.more_topics_url;
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Return a promise indicating no more results
|
// Return a promise indicating no more results
|
||||||
return Ember.Deferred.promise(function (p) {
|
return Ember.RSVP.reject();
|
||||||
p.resolve(false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -109,6 +114,9 @@ Discourse.TopicList.reopenClass({
|
||||||
categories = this.extractByKey(result.categories, Discourse.Category);
|
categories = this.extractByKey(result.categories, Discourse.Category);
|
||||||
users = this.extractByKey(result.users, Discourse.User);
|
users = this.extractByKey(result.users, Discourse.User);
|
||||||
topics = Em.A();
|
topics = Em.A();
|
||||||
|
|
||||||
|
console.log(result.topic_list);
|
||||||
|
|
||||||
_.each(result.topic_list.topics,function(ft) {
|
_.each(result.topic_list.topics,function(ft) {
|
||||||
ft.category = categories[ft.category_id];
|
ft.category = categories[ft.category_id];
|
||||||
_.each(ft.posters,function(p) {
|
_.each(ft.posters,function(p) {
|
||||||
|
|
|
@ -264,6 +264,7 @@ Discourse.User = Discourse.Model.extend({
|
||||||
json.user.invited_by = Discourse.User.create(json.user.invited_by);
|
json.user.invited_by = Discourse.User.create(json.user.invited_by);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
user.setProperties(json.user);
|
user.setProperties(json.user);
|
||||||
return user;
|
return user;
|
||||||
});
|
});
|
||||||
|
|
|
@ -99,7 +99,11 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
}.property('target_username'),
|
}.property('target_username'),
|
||||||
|
|
||||||
targetUserUrl: Discourse.computed.url('target_username', '/users/%@'),
|
targetUserUrl: Discourse.computed.url('target_username', '/users/%@'),
|
||||||
userUrl: Discourse.computed.url('username', '/users/%@'),
|
usernameLower: function() {
|
||||||
|
return this.get('username').toLowerCase();
|
||||||
|
}.property('username'),
|
||||||
|
|
||||||
|
userUrl: Discourse.computed.url('usernameLower', '/users/%@'),
|
||||||
|
|
||||||
postUrl: function() {
|
postUrl: function() {
|
||||||
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('post_number'));
|
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('post_number'));
|
||||||
|
|
|
@ -18,7 +18,7 @@ Discourse.UserStream = Discourse.Model.extend({
|
||||||
|
|
||||||
findItems: function() {
|
findItems: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.get("loading")) { return; }
|
if(this.get("loading")) { return Ember.RSVP.reject(); }
|
||||||
this.set("loading",true);
|
this.set("loading",true);
|
||||||
|
|
||||||
var url = Discourse.getURL("/user_actions.json?offset=") + this.get('itemsLoaded') + "&username=" + (this.get('user.username_lower'));
|
var url = Discourse.getURL("/user_actions.json?offset=") + this.get('itemsLoaded') + "&username=" + (this.get('user.username_lower'));
|
||||||
|
|
|
@ -47,5 +47,3 @@ Discourse.FilteredListRoute = Discourse.Route.extend({
|
||||||
Discourse.ListController.filters.forEach(function(filter) {
|
Discourse.ListController.filters.forEach(function(filter) {
|
||||||
Discourse["List" + (filter.capitalize()) + "Route"] = Discourse.FilteredListRoute.extend({ filter: filter });
|
Discourse["List" + (filter.capitalize()) + "Route"] = Discourse.FilteredListRoute.extend({ filter: filter });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/**
|
||||||
|
The common route stuff for a user's preference
|
||||||
|
|
||||||
|
@class PreferencesRoute
|
||||||
|
@extends Discourse.RestrictedUserRoute
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PreferencesRoute = Discourse.RestrictedUserRoute.extend({
|
||||||
|
model: function() {
|
||||||
|
return this.modelFor('user');
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
The route for editing a user's "About Me" bio.
|
||||||
|
|
||||||
|
@class PreferencesAboutRoute
|
||||||
|
@extends Discourse.RestrictedUserRoute
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PreferencesAboutRoute = Discourse.RestrictedUserRoute.extend({
|
||||||
|
model: function() {
|
||||||
|
return this.modelFor('user');
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render({ into: 'user', outlet: 'userOutlet' });
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, model) {
|
||||||
|
controller.setProperties({ model: model, newBio: model.get('bio_raw') });
|
||||||
|
},
|
||||||
|
|
||||||
|
// A bit odd, but if we leave to /preferences we need to re-render that outlet
|
||||||
|
exit: function() {
|
||||||
|
this._super();
|
||||||
|
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
changeAbout: function() {
|
||||||
|
var route = this;
|
||||||
|
var controller = route.controllerFor('preferencesAbout');
|
||||||
|
|
||||||
|
controller.setProperties({ saving: true });
|
||||||
|
return controller.get('model').save().then(function() {
|
||||||
|
controller.set('saving', false);
|
||||||
|
route.transitionTo('user.index');
|
||||||
|
}, function() {
|
||||||
|
// model failed to save
|
||||||
|
controller.set('saving', false);
|
||||||
|
alert(I18n.t('generic_error'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
The route for editing a user's email
|
||||||
|
|
||||||
|
@class PreferencesEmailRoute
|
||||||
|
@extends Discourse.RestrictedUserRoute
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PreferencesEmailRoute = Discourse.RestrictedUserRoute.extend({
|
||||||
|
model: function() {
|
||||||
|
return this.modelFor('user');
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render({ into: 'user', outlet: 'userOutlet' });
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, model) {
|
||||||
|
controller.setProperties({ model: model, newEmail: model.get('email') });
|
||||||
|
},
|
||||||
|
|
||||||
|
// A bit odd, but if we leave to /preferences we need to re-render that outlet
|
||||||
|
exit: function() {
|
||||||
|
this._super();
|
||||||
|
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
The route for updating a user's username
|
||||||
|
|
||||||
|
@class PreferencesUsernameRoute
|
||||||
|
@extends Discourse.RestrictedUserRoute
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PreferencesUsernameRoute = Discourse.RestrictedUserRoute.extend({
|
||||||
|
model: function() {
|
||||||
|
return this.modelFor('user');
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplate: function() {
|
||||||
|
return this.render({ into: 'user', outlet: 'userOutlet' });
|
||||||
|
},
|
||||||
|
|
||||||
|
// A bit odd, but if we leave to /preferences we need to re-render that outlet
|
||||||
|
exit: function() {
|
||||||
|
this._super();
|
||||||
|
this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' });
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, user) {
|
||||||
|
controller.setProperties({ model: user, newUsername: user.get('username') });
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
This route shows who a user has invited
|
|
||||||
|
|
||||||
@class UserInvitedRoute
|
|
||||||
@extends Discourse.Route
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.UserInvitedRoute = Discourse.Route.extend({
|
|
||||||
|
|
||||||
renderTemplate: function() {
|
|
||||||
this.render({ into: 'user', outlet: 'userOutlet' });
|
|
||||||
},
|
|
||||||
|
|
||||||
model: function() {
|
|
||||||
return Discourse.InviteList.findInvitedBy(this.modelFor('user'));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
/**
|
|
||||||
Handles routes related to users.
|
|
||||||
|
|
||||||
@class UserRoute
|
|
||||||
@extends Discourse.Route
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.UserRoute = Discourse.Route.extend({
|
|
||||||
|
|
||||||
model: function(params) {
|
|
||||||
|
|
||||||
// If we're viewing the currently logged in user, return that object
|
|
||||||
// instead.
|
|
||||||
var currentUser = Discourse.User.current();
|
|
||||||
if (currentUser && (params.username.toLowerCase() === currentUser.get('username_lower'))) {
|
|
||||||
return currentUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Discourse.User.create({username: params.username});
|
|
||||||
},
|
|
||||||
|
|
||||||
afterModel: function() {
|
|
||||||
return this.modelFor('user').findDetails();
|
|
||||||
},
|
|
||||||
|
|
||||||
serialize: function(params) {
|
|
||||||
if (!params) return {};
|
|
||||||
return { username: Em.get(params, 'username').toLowerCase() };
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController: function(controller, user) {
|
|
||||||
controller.set('model', user);
|
|
||||||
|
|
||||||
// Add a search context
|
|
||||||
this.controllerFor('search').set('searchContext', user.get('searchContext'));
|
|
||||||
},
|
|
||||||
|
|
||||||
activate: function() {
|
|
||||||
this._super();
|
|
||||||
var user = this.modelFor('user');
|
|
||||||
Discourse.MessageBus.subscribe("/users/" + user.get('username_lower'), function(data) {
|
|
||||||
user.loadUserAction(data);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
deactivate: function() {
|
|
||||||
this._super();
|
|
||||||
Discourse.MessageBus.unsubscribe("/users/" + this.modelFor('user').get('username_lower'));
|
|
||||||
|
|
||||||
// Remove the search context
|
|
||||||
this.controllerFor('search').set('searchContext', null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/**
|
||||||
|
Handles routes related to users.
|
||||||
|
|
||||||
|
@class UserRoute
|
||||||
|
@extends Discourse.Route
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserRoute = Discourse.Route.extend({
|
||||||
|
|
||||||
|
model: function(params) {
|
||||||
|
|
||||||
|
// If we're viewing the currently logged in user, return that object
|
||||||
|
// instead.
|
||||||
|
var currentUser = Discourse.User.current();
|
||||||
|
if (currentUser && (params.username.toLowerCase() === currentUser.get('username_lower'))) {
|
||||||
|
return currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Discourse.User.create({username: params.username});
|
||||||
|
},
|
||||||
|
|
||||||
|
afterModel: function() {
|
||||||
|
return this.modelFor('user').findDetails();
|
||||||
|
},
|
||||||
|
|
||||||
|
serialize: function(params) {
|
||||||
|
if (!params) return {};
|
||||||
|
return { username: Em.get(params, 'username').toLowerCase() };
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, user) {
|
||||||
|
controller.set('model', user);
|
||||||
|
|
||||||
|
// Add a search context
|
||||||
|
this.controllerFor('search').set('searchContext', user.get('searchContext'));
|
||||||
|
},
|
||||||
|
|
||||||
|
activate: function() {
|
||||||
|
this._super();
|
||||||
|
var user = this.modelFor('user');
|
||||||
|
Discourse.MessageBus.subscribe("/users/" + user.get('username_lower'), function(data) {
|
||||||
|
user.loadUserAction(data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivate: function() {
|
||||||
|
this._super();
|
||||||
|
Discourse.MessageBus.unsubscribe("/users/" + this.modelFor('user').get('username_lower'));
|
||||||
|
|
||||||
|
// Remove the search context
|
||||||
|
this.controllerFor('search').set('searchContext', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
This route shows who a user has invited
|
||||||
|
|
||||||
|
@class UserInvitedRoute
|
||||||
|
@extends Discourse.Route
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserInvitedRoute = Discourse.Route.extend({
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render({ into: 'user', outlet: 'userOutlet' });
|
||||||
|
},
|
||||||
|
|
||||||
|
model: function() {
|
||||||
|
return Discourse.InviteList.findInvitedBy(this.modelFor('user'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
The base route for showing a user's activity
|
||||||
|
|
||||||
|
@class UserActivityRoute
|
||||||
|
@extends Discourse.Route
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserActivityRoute = Discourse.Route.extend({
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render('user_activity', {into: 'user', outlet: 'userOutlet' });
|
||||||
|
},
|
||||||
|
|
||||||
|
model: function() {
|
||||||
|
return this.modelFor('user');
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, user) {
|
||||||
|
this.controllerFor('userActivity').set('model', user);
|
||||||
|
|
||||||
|
var composerController = this.controllerFor('composer');
|
||||||
|
controller.set('model', user);
|
||||||
|
if (Discourse.User.current()) {
|
||||||
|
Discourse.Draft.get('new_private_message').then(function(data) {
|
||||||
|
if (data.draft) {
|
||||||
|
composerController.open({
|
||||||
|
draft: data.draft,
|
||||||
|
draftKey: 'new_private_message',
|
||||||
|
ignoreIfChanged: true,
|
||||||
|
draftSequence: data.draft_sequence
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Discourse.UserPrivateMessagesRoute = Discourse.UserActivityRoute.extend({});
|
||||||
|
|
||||||
|
/**
|
||||||
|
If we request /user/eviltrout without a sub route.
|
||||||
|
|
||||||
|
@class UserIndexRoute
|
||||||
|
@extends Discourse.Route
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserIndexRoute = Discourse.UserActivityRoute.extend({
|
||||||
|
redirect: function() {
|
||||||
|
this.transitionTo('userActivity', this.modelFor('user'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
The base route for showing an activity stream.
|
||||||
|
|
||||||
|
@class UserActivityStreamRoute
|
||||||
|
@extends Discourse.Route
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.UserActivityStreamRoute = Discourse.Route.extend({
|
||||||
|
model: function() {
|
||||||
|
return this.modelFor('user').findStream(this.get('userActionType'));
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render('user_stream', {into: 'user_activity', outlet: 'activity'});
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, model) {
|
||||||
|
controller.set('model', model);
|
||||||
|
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build all activity stream routes
|
||||||
|
['bookmarks', 'edits', 'likes_given', 'likes_received', 'replies', 'posts', 'index'].forEach(function (userAction) {
|
||||||
|
Discourse["UserActivity" + userAction.classify() + "Route"] = Discourse.UserActivityStreamRoute.extend({
|
||||||
|
userActionType: Discourse.UserAction.TYPES[userAction]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Discourse.UserPrivateMessagesIndexRoute = Discourse.UserActivityStreamRoute.extend({
|
||||||
|
userActionType: Discourse.UserAction.TYPES.messages_received
|
||||||
|
});
|
||||||
|
Discourse.UserPrivateMessagesSentRoute = Discourse.UserActivityStreamRoute.extend({
|
||||||
|
userActionType: Discourse.UserAction.TYPES.messages_sent
|
||||||
|
});
|
||||||
|
|
||||||
|
//Discourse.UserTopicsListView = Em.View.extend({ templateName: 'user/topics_list' });
|
||||||
|
Discourse.UserTopicListRoute = Discourse.Route.extend({
|
||||||
|
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render('paginated_topic_list', {into: 'user_activity', outlet: 'activity'});
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, model) {
|
||||||
|
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
|
||||||
|
controller.set('model', model);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Discourse.UserActivityTopicsRoute = Discourse.UserTopicListRoute.extend({
|
||||||
|
userActionType: Discourse.UserAction.TYPES.topics,
|
||||||
|
|
||||||
|
model: function() {
|
||||||
|
return Discourse.TopicList.find('topics/created-by/' + this.modelFor('user').get('username_lower'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Discourse.UserActivityFavoritesRoute = Discourse.UserTopicListRoute.extend({
|
||||||
|
userActionType: Discourse.UserAction.TYPES.favorites,
|
||||||
|
|
||||||
|
model: function() {
|
||||||
|
return Discourse.TopicList.find('favorited');
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,20 +1,18 @@
|
||||||
{{#with view.content}}
|
<div class='row'>
|
||||||
<div class='row'>
|
<div class='topic-meta-data span2'>
|
||||||
<div class='topic-meta-data span2'>
|
<div class='contents'>
|
||||||
<div class='contents'>
|
<div>
|
||||||
<div>
|
<a href='/users/{{unbound username}}'>{{avatar this imageSize="small"}}</a>
|
||||||
<a href='/users/{{unbound username}}'>{{avatar this imageSize="small"}}</a>
|
|
||||||
</div>
|
|
||||||
<h5 {{bindAttr class="staff new_user"}}><a href='{{unbound usernameUrl}}'>{{breakUp username}}</a></h5>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<h5 {{bindAttr class="staff new_user"}}><a href='{{unbound usernameUrl}}'>{{breakUp username}}</a></h5>
|
||||||
<div class='span11 topic-body'>
|
|
||||||
<div class="topic-meta-data-inside">
|
|
||||||
<div class='post-info post-date'>{{unboundAgeWithTooltip created_at}}</div>
|
|
||||||
{{#if view.previousPost}}<a href='{{unbound url}}' class="post-info arrow" title="{{i18n topic.jump_reply_up}}"><i class='icon icon-arrow-up'></i></a>{{/if}}
|
|
||||||
</div>
|
|
||||||
{{{unbound cooked}}}
|
|
||||||
{{#unless view.previousPost}}<a href='{{unbound url}}' class="arrow" title="{{i18n topic.jump_reply_down}}"><i class='icon icon-arrow-down'></i></a>{{/unless}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/with}}
|
<div class='span11 topic-body'>
|
||||||
|
<div class="topic-meta-data-inside">
|
||||||
|
<div class='post-info post-date'>{{unboundAgeWithTooltip created_at}}</div>
|
||||||
|
{{#if view.previousPost}}<a href='{{unbound url}}' class="post-info arrow" title="{{i18n topic.jump_reply_up}}"><i class='icon icon-arrow-up'></i></a>{{/if}}
|
||||||
|
</div>
|
||||||
|
{{{unbound cooked}}}
|
||||||
|
{{#unless view.previousPost}}<a href='{{unbound url}}' class="arrow" title="{{i18n topic.jump_reply_down}}"><i class='icon icon-arrow-down'></i></a>{{/unless}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<div id='list-controls'>
|
||||||
|
<div class="container">
|
||||||
|
<ul class="nav nav-pills" id='category-filter'>
|
||||||
|
{{each availableNavItems itemViewClass="Discourse.NavItemView"}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{#if canCreateTopic}}
|
||||||
|
<button class='btn btn-default' {{action createTopic}}><i class='icon icon-plus'></i>{{createTopicText}}</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if canEditCategory}}
|
||||||
|
<button class='btn btn-default' {{action editCategory category}}>{{i18n category.edit_long}}</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if canCreateCategory}}
|
||||||
|
<button class='btn btn-default' {{action createCategory}}><i class='icon icon-plus'></i>{{i18n category.create}}</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="full-width">
|
||||||
|
<div id='list-area'>
|
||||||
|
{{#if loading}}
|
||||||
|
<div class='contents loading'>
|
||||||
|
<table id='topic-list'>
|
||||||
|
<tr>
|
||||||
|
<td colspan='8'>
|
||||||
|
<div class='spinner'>{{i18n loading}}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{outlet listView}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<table id="topic-list">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{{i18n topic.title}}
|
||||||
|
</th>
|
||||||
|
<th>{{i18n category_title}}</th>
|
||||||
|
<th class='num posts'>{{i18n posts}}</th>
|
||||||
|
<th class='num likes'>{{i18n likes}}</th>
|
||||||
|
<th class='num views'>{{i18n views}}</th>
|
||||||
|
<th class='num activity' colspan='2'>{{i18n activity}}</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{#group}}
|
||||||
|
{{#collection contentBinding="view.topics" tagName="tbody" itemTagName="tr"}}
|
||||||
|
<td class='main-link'>
|
||||||
|
<a class='title' href="{{unbound lastReadUrl}}">{{{unbound fancy_title}}}</a>
|
||||||
|
{{#if unread}}
|
||||||
|
<a href="{{unbound lastReadUrl}}" class='badge unread badge-notification' title='{{i18n topic.unread_posts count="unread"}}'>{{unbound unread}}</a>
|
||||||
|
{{/if}}
|
||||||
|
{{#if new_posts}}
|
||||||
|
<a href="{{unbound lastReadUrl}}" class='badge new-posts badge-notification' title='{{i18n topic.new_posts count="new_posts"}}'>{{unbound new_posts}}</a>
|
||||||
|
{{/if}}
|
||||||
|
{{#if unseen}}
|
||||||
|
<a href="{{lastReadUrl}}" class='badge new-posts badge-notification' title='{{i18n topic.new}}'><i class='icon icon-asterisk'></i></a>
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
<td class='category'>
|
||||||
|
{{categoryLink category}}
|
||||||
|
</td>
|
||||||
|
<td class='num posts'><a href="{{lastReadUrl}}" class='badge-posts'>{{number posts_count numberKey="posts_long"}}</a></td>
|
||||||
|
|
||||||
|
<td class='num likes'>
|
||||||
|
{{#if like_count}}
|
||||||
|
<a href='{{url}}{{#if has_best_of}}?filter=best_of{{/if}}'>{{like_count}} <i class='icon-heart'></i></a>
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td {{bindAttr class=":num :views viewsHeat"}}>{{number views numberKey="views_long"}}</td>
|
||||||
|
{{#if bumped}}
|
||||||
|
<td class='num activity'>
|
||||||
|
<a href="{{url}}" {{{bindAttr class=":age ageCold"}}} title='{{i18n first_post}}: {{{unboundDate created_at}}}' >{{unboundAge created_at}}</a>
|
||||||
|
</td>
|
||||||
|
<td class='num activity last'>
|
||||||
|
<a href="{{lastPostUrl}}" class='age' title='{{i18n last_post}}: {{{unboundDate bumped_at}}}'>{{unboundAge bumped_at}}</a>
|
||||||
|
</td>
|
||||||
|
{{else}}
|
||||||
|
<td class='num activity'>
|
||||||
|
<a href="{{url}}" class='age' title='{{i18n first_post}}: {{{unboundDate created_at}}}'>{{unboundAge created_at}}</a>
|
||||||
|
</td>
|
||||||
|
<td class="activity"></td>
|
||||||
|
{{/if}}
|
||||||
|
{{/collection}}
|
||||||
|
{{/group}}
|
||||||
|
|
||||||
|
</table>
|
|
@ -5,7 +5,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{{#if canCreateTopic}}
|
{{#if canCreateTopic}}
|
||||||
<button class='btn btn-default' {{action createTopic}}><i class='icon icon-plus'></i>{{view.createTopicText}}</button>
|
<button class='btn btn-default' {{action createTopic}}><i class='icon icon-plus'></i>{{createTopicText}}</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if canEditCategory}}
|
{{#if canEditCategory}}
|
||||||
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="full-width">
|
<div class="full-width">
|
||||||
<div id='list-area'>
|
<div id='list-area'>
|
||||||
{{#if loading}}
|
{{#if loading}}
|
||||||
|
@ -39,7 +38,6 @@
|
||||||
{{outlet listView}}
|
{{outlet listView}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
{{#with view.content}}
|
<a href='{{unbound url}}'>
|
||||||
<a href='{{unbound url}}'>
|
<span class='badge-category' style="background-color: #{{unbound color}}; color: #{{unbound text_color}};">{{unbound title}}</span>
|
||||||
<span class='badge-category' style="background-color: #{{unbound color}}; color: #{{unbound text_color}};">{{unbound title}}</span>
|
</a>
|
||||||
</a>
|
|
||||||
{{/with}}
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
{{#with view.content}}
|
<a href='{{unbound url}}'>
|
||||||
<a href='{{unbound url}}'>
|
{{unbound title}}
|
||||||
{{unbound title}}
|
</a>
|
||||||
</a>
|
|
||||||
{{/with}}
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
{{#with view.content}}
|
<a href='{{unbound url}}'>
|
||||||
<a href='{{unbound url}}'>
|
{{avatar this usernamePath="title" imageSize="small"}}
|
||||||
{{avatar this usernamePath="title" imageSize="small"}}
|
{{unbound title}}
|
||||||
{{unbound title}}
|
</a>
|
||||||
</a>
|
|
||||||
{{/with}}
|
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
{{#with view.content}}
|
|
||||||
{{#group}}
|
|
||||||
<td class='main-link'>
|
|
||||||
<a class='title' href="{{unbound lastReadUrl}}">{{{unbound fancy_title}}}</a>
|
|
||||||
{{#if unread}}
|
|
||||||
<a href="{{unbound lastReadUrl}}" class='badge unread badge-notification' title='{{i18n topic.unread_posts count="unread"}}'>{{unbound unread}}</a>
|
|
||||||
{{/if}}
|
|
||||||
{{#if new_posts}}
|
|
||||||
<a href="{{unbound lastReadUrl}}" class='badge new-posts badge-notification' title='{{i18n topic.new_posts count="new_posts"}}'>{{unbound new_posts}}</a>
|
|
||||||
{{/if}}
|
|
||||||
{{#if unseen}}
|
|
||||||
<a href="{{lastReadUrl}}" class='badge new-posts badge-notification' title='{{i18n topic.new}}'><i class='icon icon-asterisk'></i></a>
|
|
||||||
{{/if}}
|
|
||||||
</td>
|
|
||||||
<td class='category'>
|
|
||||||
{{categoryLink category}}
|
|
||||||
</td>
|
|
||||||
<td class='num posts'><a href="{{lastReadUrl}}" class='badge-posts'>{{number posts_count numberKey="posts_long"}}</a></td>
|
|
||||||
|
|
||||||
<td class='num likes'>
|
|
||||||
{{#if like_count}}
|
|
||||||
<a href='{{url}}{{#if has_best_of}}?filter=best_of{{/if}}'>{{like_count}} <i class='icon-heart'></i></a>
|
|
||||||
{{/if}}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td {{bindAttr class=":num :views viewsHeat"}}>{{number views numberKey="views_long"}}</td>
|
|
||||||
|
|
||||||
{{#if bumped}}
|
|
||||||
<td class='num activity'>
|
|
||||||
<a href="{{url}}" {{{bindAttr class=":age ageCold"}}} title='{{i18n first_post}}: {{{unboundDate created_at}}}' >{{unboundAge created_at}}</a>
|
|
||||||
</td>
|
|
||||||
<td class='num activity last'>
|
|
||||||
<a href="{{lastPostUrl}}" class='age' title='{{i18n last_post}}: {{{unboundDate bumped_at}}}'>{{unboundAge bumped_at}}</a>
|
|
||||||
</td>
|
|
||||||
{{else}}
|
|
||||||
<td class='num activity'>
|
|
||||||
<a href="{{url}}" class='age' title='{{i18n first_post}}: {{{unboundDate created_at}}}'>{{unboundAge created_at}}</a>
|
|
||||||
</td>
|
|
||||||
<td class="activity"></td>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{/group}}
|
|
||||||
{{/with}}
|
|
|
@ -74,24 +74,9 @@
|
||||||
|
|
||||||
{{#if details.suggested_topics.length}}
|
{{#if details.suggested_topics.length}}
|
||||||
<div id='suggested-topics'>
|
<div id='suggested-topics'>
|
||||||
|
|
||||||
<h3>{{i18n suggested_topics.title}}</h3>
|
<h3>{{i18n suggested_topics.title}}</h3>
|
||||||
|
|
||||||
<div class='topics'>
|
<div class='topics'>
|
||||||
<table id="topic-list">
|
{{basicTopicList topics=details.suggested_topics}}
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
{{i18n topic.title}}
|
|
||||||
</th>
|
|
||||||
<th>{{i18n category_title}}</th>
|
|
||||||
<th class='num posts'>{{i18n posts}}</th>
|
|
||||||
<th class='num likes'>{{i18n likes}}</th>
|
|
||||||
<th class='num views'>{{i18n views}}</th>
|
|
||||||
<th class='num activity' colspan='2'>{{i18n activity}}</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{{each details.suggested_topics itemTagName="tr" itemViewClass="Discourse.SuggestedTopicView"}}
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<h3>{{{view.browseMoreMessage}}}</h3>
|
<h3>{{{view.browseMoreMessage}}}</h3>
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id='user-activity'>
|
||||||
{{outlet activity}}
|
{{outlet activity}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
{{#with view.content}}
|
<div {{bindAttr class=":item hidden deleted moderator_action"}}>
|
||||||
<div {{bindAttr class=":item hidden deleted moderator_action"}}>
|
<div class='clearfix info'>
|
||||||
<div class='clearfix info'>
|
<a href="{{unbound userUrl}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="large" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
||||||
<a href="{{unbound userUrl}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="large" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
<span class='time'>{{date path="created_at" leaveAgo="true"}}</span>
|
||||||
<span class='time'>{{date path="created_at" leaveAgo="true"}}</span>
|
<span class="title">
|
||||||
<span class="title">
|
<a href="{{unbound postUrl}}">{{unbound title}}</a>
|
||||||
<a href="{{unbound postUrl}}">{{unbound title}}</a>
|
</span>
|
||||||
</span>
|
<span class="type">{{unbound descriptionHtml}}</span>
|
||||||
<span class="type">{{unbound descriptionHtml}}</span>
|
|
||||||
</div>
|
|
||||||
<p class='excerpt'>
|
|
||||||
{{{unbound excerpt}}}
|
|
||||||
</p>
|
|
||||||
{{#each children}}
|
|
||||||
<div class='child-actions'>
|
|
||||||
<i class="icon {{unbound icon}}"></i>
|
|
||||||
{{#each items}}
|
|
||||||
<a href="{{unbound userUrl}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
</div>
|
||||||
{{/with}}
|
<p class='excerpt'>
|
||||||
|
{{{unbound excerpt}}}
|
||||||
|
</p>
|
||||||
|
{{#each children}}
|
||||||
|
<div class='child-actions'>
|
||||||
|
<i class="icon {{unbound icon}}"></i>
|
||||||
|
{{#each items}}
|
||||||
|
<a href="{{unbound userUrl}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
no
|
|
@ -10,6 +10,11 @@ Discourse.EmbeddedPostView = Discourse.View.extend({
|
||||||
templateName: 'embedded_post',
|
templateName: 'embedded_post',
|
||||||
classNames: ['reply'],
|
classNames: ['reply'],
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this._super();
|
||||||
|
this.set('context', this.get('content'));
|
||||||
|
},
|
||||||
|
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
Discourse.ScreenTrack.instance().track(this.get('elementId'), this.get('post.post_number'));
|
Discourse.ScreenTrack.instance().track(this.get('elementId'), this.get('post.post_number'));
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
This view is used for rendering a basic list of topics.
|
||||||
|
|
||||||
|
@class BasicTopicListView
|
||||||
|
@extends Discourse.View
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.BasicTopicListView = Discourse.View.extend({
|
||||||
|
templateName: 'list/basic_topic_list'
|
||||||
|
});
|
||||||
|
Discourse.View.registerHelper('basicTopicList', Discourse.BasicTopicListView);
|
|
@ -4,34 +4,24 @@
|
||||||
@class ListTopicsView
|
@class ListTopicsView
|
||||||
@extends Discourse.View
|
@extends Discourse.View
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@uses Discourse.Scrolling
|
@uses Discourse.LoadMore
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.ListTopicsView = Discourse.View.extend(Discourse.Scrolling, {
|
Discourse.ListTopicsView = Discourse.View.extend(Discourse.LoadMore, {
|
||||||
templateName: 'list/topics',
|
templateName: 'list/topics',
|
||||||
categoryBinding: 'controller.controllers.list.category',
|
categoryBinding: 'controller.controllers.list.category',
|
||||||
canCreateTopicBinding: 'controller.controllers.list.canCreateTopic',
|
canCreateTopicBinding: 'controller.controllers.list.canCreateTopic',
|
||||||
listBinding: 'controller.model',
|
listBinding: 'controller.model',
|
||||||
loadedMore: false,
|
loadedMore: false,
|
||||||
currentTopicId: null,
|
currentTopicId: null,
|
||||||
|
eyelineSelector: '.topic-list-item',
|
||||||
|
|
||||||
topicTrackingState: function() {
|
topicTrackingState: function() {
|
||||||
return Discourse.TopicTrackingState.current();
|
return Discourse.TopicTrackingState.current();
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
willDestroyElement: function() {
|
|
||||||
this.unbindScrolling();
|
|
||||||
},
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
this.bindScrolling();
|
this._super();
|
||||||
var eyeline = new Discourse.Eyeline('.topic-list-item');
|
|
||||||
|
|
||||||
var listTopicsView = this;
|
|
||||||
eyeline.on('sawBottom', function() {
|
|
||||||
listTopicsView.loadMore();
|
|
||||||
});
|
|
||||||
|
|
||||||
var scrollPos = Discourse.get('transient.topicListScrollPos');
|
var scrollPos = Discourse.get('transient.topicListScrollPos');
|
||||||
if (scrollPos) {
|
if (scrollPos) {
|
||||||
Em.run.schedule('afterRender', function() {
|
Em.run.schedule('afterRender', function() {
|
||||||
|
@ -42,15 +32,10 @@ Discourse.ListTopicsView = Discourse.View.extend(Discourse.Scrolling, {
|
||||||
$('html, body').scrollTop(0);
|
$('html, body').scrollTop(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.set('eyeline', eyeline);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
showTable: function() {
|
hasTopics: Em.computed.gt('list.topics.length', 0),
|
||||||
var topics = this.get('list.topics');
|
showTable: Em.computed.or('hasTopics', 'topicTrackingState.hasIncoming'),
|
||||||
if(topics) {
|
|
||||||
return this.get('list.topics').length > 0 || this.get('topicTrackingState.hasIncoming');
|
|
||||||
}
|
|
||||||
}.property('list.topics.@each','topicTrackingState.hasIncoming'),
|
|
||||||
|
|
||||||
updateTitle: function(){
|
updateTitle: function(){
|
||||||
Discourse.notifyTitle(this.get('topicTrackingState.incomingCount'));
|
Discourse.notifyTitle(this.get('topicTrackingState.incomingCount'));
|
||||||
|
@ -76,9 +61,8 @@ Discourse.ListTopicsView = Discourse.View.extend(Discourse.Scrolling, {
|
||||||
|
|
||||||
// When the topic list is scrolled
|
// When the topic list is scrolled
|
||||||
scrolled: function(e) {
|
scrolled: function(e) {
|
||||||
|
this._super();
|
||||||
this.saveScrollPos();
|
this.saveScrollPos();
|
||||||
var eyeline = this.get('eyeline');
|
|
||||||
if (eyeline) { eyeline.update(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
/**
|
|
||||||
This view handles the rendering of a list
|
|
||||||
|
|
||||||
@class ListView
|
|
||||||
@extends Discourse.View
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.ListView = Discourse.View.extend({
|
|
||||||
templateName: 'list/list',
|
|
||||||
composeViewBinding: Ember.Binding.oneWay('Discourse.composeView'),
|
|
||||||
|
|
||||||
// The window has been scrolled
|
|
||||||
scrolled: function(e) {
|
|
||||||
var currentView;
|
|
||||||
currentView = this.get('container.currentView');
|
|
||||||
return currentView ? typeof currentView.scrolled === "function" ? currentView.scrolled(e) : void 0 : void 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
createTopicText: function() {
|
|
||||||
if (this.get('controller.category.name')) {
|
|
||||||
return I18n.t("topic.create_in", {
|
|
||||||
categoryName: this.get('controller.category.name')
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return I18n.t("topic.create");
|
|
||||||
}
|
|
||||||
}.property('controller.category.name')
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
This view is used for rendering a basic list of topics.
|
||||||
|
|
||||||
|
@class PaginatedTopicListView
|
||||||
|
@extends Discourse.View
|
||||||
|
@namespace Discourse
|
||||||
|
@uses Discourse.LoadMore
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.PaginatedTopicListView = Discourse.BasicTopicListView.extend(Discourse.LoadMore, {
|
||||||
|
topics: Em.computed.alias('controller.model.topics'),
|
||||||
|
classNames: ['paginated-topics-list'],
|
||||||
|
eyelineSelector: '.paginated-topics-list #topic-list tr',
|
||||||
|
|
||||||
|
loadMore: function() {
|
||||||
|
this.get('controller.model').loadMoreTopics();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
|
@ -12,9 +12,7 @@ Discourse.TopicListItemView = Discourse.View.extend({
|
||||||
classNameBindings: ['content.archived', ':topic-list-item', 'content.hasExcerpt:has-excerpt'],
|
classNameBindings: ['content.archived', ':topic-list-item', 'content.hasExcerpt:has-excerpt'],
|
||||||
attributeBindings: ['data-topic-id'],
|
attributeBindings: ['data-topic-id'],
|
||||||
|
|
||||||
'data-topic-id': function() {
|
'data-topic-id': Em.computed.alias('content.id'),
|
||||||
return this.get('content.id');
|
|
||||||
}.property('content.id'),
|
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
this._super();
|
this._super();
|
||||||
|
|
|
@ -10,17 +10,14 @@ Discourse.SearchResultsTypeView = Ember.CollectionView.extend({
|
||||||
tagName: 'ul',
|
tagName: 'ul',
|
||||||
itemViewClass: Ember.View.extend({
|
itemViewClass: Ember.View.extend({
|
||||||
tagName: 'li',
|
tagName: 'li',
|
||||||
classNameBindings: ['selectedClass'],
|
classNameBindings: ['selected'],
|
||||||
|
templateName: Discourse.computed.fmt('parentView.type', "search/%@_result"),
|
||||||
|
selected: Discourse.computed.propertyEqual('content.index', 'controller.selectedIndex'),
|
||||||
|
|
||||||
templateName: function() {
|
init: function() {
|
||||||
return "search/" + (this.get('parentView.type')) + "_result";
|
this._super();
|
||||||
}.property('parentView.type'),
|
this.set('context', this.get('content'));
|
||||||
|
}
|
||||||
// Is this row currently selected by the keyboard?
|
|
||||||
selectedClass: function() {
|
|
||||||
if (this.get('content.index') === this.get('controller.selectedIndex')) return 'selected';
|
|
||||||
return null;
|
|
||||||
}.property('controller.selectedIndex')
|
|
||||||
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
/**
|
|
||||||
This view is used for rendering a suggested topic
|
|
||||||
|
|
||||||
@class SuggestedTopicView
|
|
||||||
@extends Discourse.View
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.SuggestedTopicView = Discourse.View.extend({
|
|
||||||
templateName: 'suggested_topic'
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ Discourse.ActivityFilterView = Discourse.View.extend({
|
||||||
url: function() {
|
url: function() {
|
||||||
var section = this.get('content.isPM') ? "/private-messages" : "/activity";
|
var section = this.get('content.isPM') ? "/private-messages" : "/activity";
|
||||||
return "/users/" + this.get('user.username_lower') + section + this.get('typeKey');
|
return "/users/" + this.get('user.username_lower') + section + this.get('typeKey');
|
||||||
}.property('typeKey'),
|
}.property('typeKey', 'user.username_lower'),
|
||||||
|
|
||||||
description: function() {
|
description: function() {
|
||||||
return this.get('content.description') || I18n.t("user.filters.all");
|
return this.get('content.description') || I18n.t("user.filters.all");
|
||||||
|
|
|
@ -4,45 +4,32 @@
|
||||||
@class UserStreamView
|
@class UserStreamView
|
||||||
@extends Discourse.View
|
@extends Discourse.View
|
||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@uses Discourse.Scrolling
|
@uses Discourse.LoadMore
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.UserStreamView = Ember.CollectionView.extend(Discourse.Scrolling, {
|
Discourse.UserStreamView = Ember.CollectionView.extend(Discourse.LoadMore, {
|
||||||
loading: false,
|
loading: false,
|
||||||
elementId: 'user-stream',
|
|
||||||
content: Em.computed.alias('controller.model.content'),
|
content: Em.computed.alias('controller.model.content'),
|
||||||
itemViewClass: Ember.View.extend({ templateName: 'user/stream_item' }),
|
eyelineSelector: '#user-activity .user-stream .item',
|
||||||
|
classNames: ['user-stream'],
|
||||||
|
|
||||||
scrolled: function(e) {
|
itemViewClass: Ember.View.extend({
|
||||||
var eyeline = this.get('eyeline');
|
templateName: 'user/stream_item',
|
||||||
if (eyeline) { eyeline.update(); }
|
init: function() {
|
||||||
},
|
this._super();
|
||||||
|
this.set('context', this.get('content'));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
loadMore: function() {
|
loadMore: function() {
|
||||||
var userStreamView = this;
|
var userStreamView = this;
|
||||||
if (userStreamView.get('loading')) { return; }
|
if (userStreamView.get('loading')) { return; }
|
||||||
|
|
||||||
var stream = this.get('stream');
|
var stream = this.get('controller.model');
|
||||||
stream.findItems().then(function() {
|
stream.findItems().then(function() {
|
||||||
userStreamView.set('loading', false);
|
userStreamView.set('loading', false);
|
||||||
userStreamView.get('eyeline').flushRest();
|
userStreamView.get('eyeline').flushRest();
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
willDestroyElement: function() {
|
|
||||||
this.unbindScrolling();
|
|
||||||
},
|
|
||||||
|
|
||||||
didInsertElement: function() {
|
|
||||||
this.bindScrolling();
|
|
||||||
|
|
||||||
var eyeline = new Discourse.Eyeline('#user-stream .item');
|
|
||||||
this.set('eyeline', eyeline);
|
|
||||||
|
|
||||||
var userStreamView = this;
|
|
||||||
eyeline.on('sawBottom', function() {
|
|
||||||
userStreamView.loadMore();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
//= require ./pagedown_custom.js
|
//= require ./pagedown_custom.js
|
||||||
|
|
||||||
// Stuff we need to load first
|
// Stuff we need to load first
|
||||||
|
//= require ./discourse/mixins/scrolling
|
||||||
//= require_tree ./discourse/mixins
|
//= require_tree ./discourse/mixins
|
||||||
//= require ./discourse/components/computed
|
//= require ./discourse/components/computed
|
||||||
//= require ./discourse/views/view
|
//= require ./discourse/views/view
|
||||||
|
|
|
@ -282,6 +282,11 @@
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#topic-list {
|
||||||
|
th {
|
||||||
|
background-color: $topic-list-th-background-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#suggested-topics {
|
#suggested-topics {
|
||||||
margin: 40px 0 40px 20px;
|
margin: 40px 0 40px 20px;
|
||||||
|
@ -294,9 +299,6 @@
|
||||||
color: darken($darkish_gray, 20%);
|
color: darken($darkish_gray, 20%);
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
th {
|
|
||||||
background-color: $topic-list-th-background-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#topic-footer-buttons {
|
#topic-footer-buttons {
|
||||||
|
|
|
@ -237,62 +237,64 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#user-stream {
|
#user-activity {
|
||||||
width: 840px;
|
width: 840px;
|
||||||
float: left;
|
float: left;
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
|
|
||||||
.excerpt {
|
.user-stream {
|
||||||
margin: 5px 0px;
|
.excerpt {
|
||||||
font-size: 13px;
|
margin: 5px 0px;
|
||||||
word-wrap: break-word;
|
font-size: 13px;
|
||||||
color: lighten($black, 30%);
|
word-wrap: break-word;
|
||||||
}
|
color: lighten($black, 30%);
|
||||||
.item.moderator-action {
|
}
|
||||||
background-color: #eef0ff;
|
.item.moderator-action {
|
||||||
}
|
background-color: #eef0ff;
|
||||||
.item.deleted {
|
}
|
||||||
opacity: 0.8;
|
.item.deleted {
|
||||||
background-color: #ffcece;
|
opacity: 0.8;
|
||||||
}
|
background-color: #ffcece;
|
||||||
.item.hidden {
|
}
|
||||||
display: block;
|
.item.hidden {
|
||||||
opacity: 0.4;
|
display: block;
|
||||||
}
|
opacity: 0.4;
|
||||||
.item {
|
}
|
||||||
padding: 10px 8px;
|
.item {
|
||||||
background-color: white;
|
padding: 10px 8px;
|
||||||
border: 1px solid #b9b9b9;
|
background-color: white;
|
||||||
margin-bottom: 10px;
|
border: 1px solid #b9b9b9;
|
||||||
@include border-radius-all(4px);
|
margin-bottom: 10px;
|
||||||
@include box-shadow((0 1px 2px rgba($black, 0.07), inset 0 -4px 4px -4px rgba($black, 0.14)));
|
@include border-radius-all(4px);
|
||||||
}
|
@include box-shadow((0 1px 2px rgba($black, 0.07), inset 0 -4px 4px -4px rgba($black, 0.14)));
|
||||||
.type {
|
}
|
||||||
color: lighten($black, 40%);
|
.type {
|
||||||
}
|
color: lighten($black, 40%);
|
||||||
span.name {
|
}
|
||||||
color: lighten($black, 40%);
|
span.name {
|
||||||
}
|
color: lighten($black, 40%);
|
||||||
.time {
|
}
|
||||||
display: block;
|
.time {
|
||||||
float: right;
|
display: block;
|
||||||
color: silver;
|
float: right;
|
||||||
margin-right: 8px;
|
color: silver;
|
||||||
font-size: 11px;
|
margin-right: 8px;
|
||||||
}
|
font-size: 11px;
|
||||||
.avatar-link {
|
}
|
||||||
float: left;
|
.avatar-link {
|
||||||
margin-right: 10px;
|
float: left;
|
||||||
}
|
margin-right: 10px;
|
||||||
.title {
|
}
|
||||||
display: block;
|
.title {
|
||||||
margin-bottom: 4px;
|
display: block;
|
||||||
font-size: 14px;
|
margin-bottom: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// styling of bottom section
|
// styling of bottom section
|
||||||
#user-stream .child-actions {
|
.user-stream .child-actions {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
.avatar-link {
|
.avatar-link {
|
||||||
float: none;
|
float: none;
|
||||||
|
@ -312,12 +314,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@include medium-width {
|
@include medium-width {
|
||||||
#user-stream {
|
#user-activity {
|
||||||
width: 725px;
|
width: 725px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@include small-width {
|
@include small-width {
|
||||||
#user-stream {
|
#user-activity {
|
||||||
width: 680px;
|
width: 680px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class ListController < ApplicationController
|
class ListController < ApplicationController
|
||||||
|
|
||||||
before_filter :ensure_logged_in, except: [:latest, :hot, :category, :category_feed, :latest_feed, :hot_feed]
|
before_filter :ensure_logged_in, except: [:latest, :hot, :category, :category_feed, :latest_feed, :hot_feed, :topics_by]
|
||||||
before_filter :set_category, only: [:category, :category_feed]
|
before_filter :set_category, only: [:category, :category_feed]
|
||||||
skip_before_filter :check_xhr
|
skip_before_filter :check_xhr
|
||||||
|
|
||||||
|
@ -28,6 +28,14 @@ class ListController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def topics_by
|
||||||
|
list_opts = build_topic_list_options
|
||||||
|
list = TopicQuery.new(current_user, list_opts).list_topics_by(fetch_user_from_params)
|
||||||
|
list.more_topics_url = url_for(topics_by_path(list_opts.merge(format: 'json', page: next_page)))
|
||||||
|
|
||||||
|
respond(list)
|
||||||
|
end
|
||||||
|
|
||||||
def category
|
def category
|
||||||
query = TopicQuery.new(current_user, page: params[:page])
|
query = TopicQuery.new(current_user, page: params[:page])
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,7 @@ Discourse::Application.routes.draw do
|
||||||
post 't' => 'topics#create'
|
post 't' => 'topics#create'
|
||||||
post 'topics/timings'
|
post 'topics/timings'
|
||||||
get 'topics/similar_to'
|
get 'topics/similar_to'
|
||||||
|
get 'topics/created-by/:username' => 'list#topics_by', as: 'topics_by', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
|
|
||||||
# Legacy route for old avatars
|
# Legacy route for old avatars
|
||||||
get 'threads/:topic_id/:post_number/avatar' => 'topics#avatar', constraints: {topic_id: /\d+/, post_number: /\d+/}
|
get 'threads/:topic_id/:post_number/avatar' => 'topics#avatar', constraints: {topic_id: /\d+/, post_number: /\d+/}
|
||||||
|
|
|
@ -8,7 +8,7 @@ task 'integration:create_fixtures' => :environment do
|
||||||
topic: ["/t/280.json"],
|
topic: ["/t/280.json"],
|
||||||
user: ["/users/eviltrout.json",
|
user: ["/users/eviltrout.json",
|
||||||
"/user_actions.json?offset=0&username=eviltrout",
|
"/user_actions.json?offset=0&username=eviltrout",
|
||||||
"/user_actions.json?offset=0&username=eviltrout&filter=4",
|
"/topics/created-by/eviltrout.json",
|
||||||
"/user_actions.json?offset=0&username=eviltrout&filter=5",
|
"/user_actions.json?offset=0&username=eviltrout&filter=5",
|
||||||
"/user_actions.json?offset=0&username=eviltrout&filter=6,7,9",
|
"/user_actions.json?offset=0&username=eviltrout&filter=6,7,9",
|
||||||
"/user_actions.json?offset=0&username=eviltrout&filter=1",
|
"/user_actions.json?offset=0&username=eviltrout&filter=1",
|
||||||
|
|
|
@ -129,6 +129,14 @@ class TopicQuery
|
||||||
create_list(:posted) {|l| l.where('tu.user_id IS NOT NULL') }
|
create_list(:posted) {|l| l.where('tu.user_id IS NOT NULL') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def list_topics_by(user)
|
||||||
|
Rails.logger.info ">>> #{user.id}"
|
||||||
|
create_list(:user_topics) do |topics|
|
||||||
|
topics.where(user_id: user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def list_uncategorized
|
def list_uncategorized
|
||||||
create_list(:uncategorized, unordered: true) do |list|
|
create_list(:uncategorized, unordered: true) do |list|
|
||||||
list = list.where(category_id: nil)
|
list = list.where(category_id: nil)
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -6,7 +6,7 @@ test("Activity Streams", function() {
|
||||||
var streamTest = function(url) {
|
var streamTest = function(url) {
|
||||||
visit(url).then(function() {
|
visit(url).then(function() {
|
||||||
ok(exists(".user-heading"), "The heading is rendered");
|
ok(exists(".user-heading"), "The heading is rendered");
|
||||||
ok(exists("#user-stream"), "The stream is rendered");
|
ok(exists("#user-activity"), "The activity is rendered");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue