mirror of
https://github.com/flarum/core.git
synced 2025-08-06 16:36:47 +02:00
Add user activity system
This commit is contained in:
@@ -7,6 +7,13 @@ import AlertMessage from 'flarum/components/ui/alert-message';
|
||||
export default JsonApiAdapter.extend({
|
||||
host: config.apiURL,
|
||||
|
||||
pathForType: function(type) {
|
||||
if (type == 'activity') {
|
||||
return type;
|
||||
}
|
||||
return this._super(type);
|
||||
},
|
||||
|
||||
ajaxError: function(jqXHR) {
|
||||
var errors = this._super(jqXHR);
|
||||
|
||||
|
12
ember/app/components/user/activity-item.js
Normal file
12
ember/app/components/user/activity-item.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
import FadeIn from 'flarum/mixins/fade-in';
|
||||
|
||||
export default Ember.Component.extend(FadeIn, {
|
||||
layoutName: 'components/user/activity-item',
|
||||
tagName: 'li',
|
||||
|
||||
componentName: Ember.computed('activity.type', function() {
|
||||
return 'user/activity-'+this.get('activity.type');
|
||||
})
|
||||
});
|
9
ember/app/components/user/activity-post.js
Normal file
9
ember/app/components/user/activity-post.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
layoutName: 'components/user/activity-post',
|
||||
|
||||
isFirstPost: Ember.computed('activity.post.number', function() {
|
||||
return this.get('activity.post.number') === 1;
|
||||
})
|
||||
});
|
71
ember/app/controllers/user/activity.js
Normal file
71
ember/app/controllers/user/activity.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['user'],
|
||||
|
||||
queryParams: ['filter'],
|
||||
filter: '',
|
||||
|
||||
resultsLoading: false,
|
||||
|
||||
moreResults: true,
|
||||
|
||||
loadCount: 10,
|
||||
|
||||
getResults: function(start) {
|
||||
var type;
|
||||
switch (this.get('filter')) {
|
||||
case 'discussions':
|
||||
type = 'discussion';
|
||||
break;
|
||||
|
||||
case 'posts':
|
||||
type = 'post';
|
||||
break;
|
||||
}
|
||||
var controller = this;
|
||||
return this.store.find('activity', {
|
||||
users: this.get('controllers.user.model.id'),
|
||||
type: type,
|
||||
start: start,
|
||||
count: this.get('loadCount')
|
||||
}).then(function(results) {
|
||||
controller.set('moreResults', results.get('length') >= controller.get('loadCount'));
|
||||
return results;
|
||||
});
|
||||
},
|
||||
|
||||
paramsDidChange: Ember.observer('filter', function() {
|
||||
if (this.get('model') && !this.get('resultsLoading')) {
|
||||
Ember.run.once(this, this.loadResults);
|
||||
}
|
||||
}),
|
||||
|
||||
loadResults: function() {
|
||||
this.send('loadResults');
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadResults: function() {
|
||||
var controller = this;
|
||||
controller.get('model').set('content', []);
|
||||
controller.set('resultsLoading', true);
|
||||
controller.getResults().then(function(results) {
|
||||
controller
|
||||
.set('resultsLoading', false)
|
||||
.set('meta', results.get('meta'))
|
||||
.set('model.content', results);
|
||||
});
|
||||
},
|
||||
|
||||
loadMore: function() {
|
||||
var controller = this;
|
||||
this.set('resultsLoading', true);
|
||||
this.getResults(this.get('model.length')).then(function(results) {
|
||||
controller.get('model.content').addObjects(results);
|
||||
controller.set('meta', results.get('meta'));
|
||||
controller.set('resultsLoading', false);
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
11
ember/app/models/activity.js
Normal file
11
ember/app/models/activity.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import DS from 'ember-data';
|
||||
|
||||
export default DS.Model.extend({
|
||||
type: DS.attr('string'),
|
||||
content: DS.attr('string'),
|
||||
time: DS.attr('date'),
|
||||
|
||||
user: DS.belongsTo('user'),
|
||||
sender: DS.belongsTo('user'),
|
||||
post: DS.belongsTo('post')
|
||||
});
|
@@ -14,8 +14,6 @@ Router.map(function() {
|
||||
|
||||
this.resource('user', {path: '/u/:username'}, function() {
|
||||
this.route('activity', {path: '/'});
|
||||
this.route('discussions');
|
||||
this.route('posts');
|
||||
this.route('edit');
|
||||
});
|
||||
|
||||
|
12
ember/app/routes/user/activity.js
Normal file
12
ember/app/routes/user/activity.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model: function() {
|
||||
return Ember.RSVP.resolve(Ember.ArrayProxy.create());
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set('model', model);
|
||||
controller.send('loadResults');
|
||||
}
|
||||
});
|
@@ -95,3 +95,76 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-content .loading-indicator {
|
||||
height: 46px;
|
||||
}
|
||||
.user-activity {
|
||||
border-left: 3px solid @fl-body-secondary-color;
|
||||
list-style: none;
|
||||
margin: 0 0 0 16px;
|
||||
padding: 0;
|
||||
|
||||
& > li {
|
||||
margin-bottom: 30px;
|
||||
padding-left: 32px;
|
||||
}
|
||||
& .activity-icon {
|
||||
.avatar-size(32px);
|
||||
float: left;
|
||||
margin-left: -49px;
|
||||
.box-shadow(0 0 0 3px #fff);
|
||||
margin-top: -5px;
|
||||
}
|
||||
}
|
||||
.activity-info {
|
||||
color: @fl-body-muted-color;
|
||||
margin-bottom: 10px;
|
||||
|
||||
& strong {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.activity-content {
|
||||
display: block;
|
||||
padding: 20px;
|
||||
background: @fl-body-secondary-color;
|
||||
border-radius: @border-radius-base;
|
||||
color: @fl-body-muted-color;
|
||||
|
||||
&, &:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
& .discussion-summary {
|
||||
margin: -20px 0;
|
||||
padding-left: 0;
|
||||
|
||||
& .author {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.activity-post {
|
||||
overflow: hidden;
|
||||
|
||||
& .title {
|
||||
margin: 0 0 10px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
|
||||
&, & a {
|
||||
color: @fl-body-heading-color;
|
||||
}
|
||||
}
|
||||
&:hover .title {
|
||||
text-decoration: underline;
|
||||
}
|
||||
& .body {
|
||||
color: @fl-body-muted-color;
|
||||
line-height: 1.7em;
|
||||
|
||||
& :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1
ember/app/templates/components/user/activity-item.hbs
Normal file
1
ember/app/templates/components/user/activity-item.hbs
Normal file
@@ -0,0 +1 @@
|
||||
{{component componentName activity=activity}}
|
6
ember/app/templates/components/user/activity-join.hbs
Normal file
6
ember/app/templates/components/user/activity-join.hbs
Normal file
@@ -0,0 +1,6 @@
|
||||
{{user-avatar activity.user class="activity-icon"}}
|
||||
|
||||
<div class="activity-info">
|
||||
<strong>Joined the forum</strong>
|
||||
{{human-time activity.time}}
|
||||
</div>
|
21
ember/app/templates/components/user/activity-post.hbs
Normal file
21
ember/app/templates/components/user/activity-post.hbs
Normal file
@@ -0,0 +1,21 @@
|
||||
{{user-avatar activity.post.user class="activity-icon"}}
|
||||
|
||||
<div class="activity-info">
|
||||
<strong>{{if isFirstPost "Started a discussion" "Posted a reply"}}</strong>
|
||||
{{human-time activity.time}}
|
||||
</div>
|
||||
|
||||
{{#if isFirstPost}}
|
||||
<div class="activity-content activity-discussion">
|
||||
{{index/discussion-listing discussion=activity.post.discussion}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{#link-to "discussion" activity.post.discussion (query-params start=activity.post.number) class="activity-content activity-post"}}
|
||||
<h3 class="title">
|
||||
{{activity.post.discussion.title}}
|
||||
</h3>
|
||||
<div class="body">
|
||||
{{{activity.post.contentHtml}}}
|
||||
</div>
|
||||
{{/link-to}}
|
||||
{{/if}}
|
@@ -5,5 +5,7 @@
|
||||
{{ui/item-list items=view.sidebar}}
|
||||
</nav>
|
||||
|
||||
{{outlet}}
|
||||
<div class="offset-content user-content">
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
|
13
ember/app/templates/user/activity.hbs
Normal file
13
ember/app/templates/user/activity.hbs
Normal file
@@ -0,0 +1,13 @@
|
||||
<ul class="user-activity">
|
||||
{{#each activity in model}}
|
||||
{{user/activity-item activity=activity}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
{{#if resultsLoading}}
|
||||
{{ui/loading-indicator size="small"}}
|
||||
{{else if moreResults}}
|
||||
<div class="load-more">
|
||||
{{ui/action-button class="control-loadMore btn btn-default" action="loadMore" label="Load More"}}
|
||||
</div>
|
||||
{{/if}}
|
@@ -9,6 +9,22 @@ var precompileTemplate = Ember.Handlebars.compile;
|
||||
export default Ember.View.extend(HasItemLists, {
|
||||
itemLists: ['sidebar'],
|
||||
|
||||
didInsertElement: function() {
|
||||
// Affix the sidebar so that when the user scrolls down it will stick
|
||||
// to the top of their viewport.
|
||||
var $sidebar = this.$('.user-nav');
|
||||
$sidebar.find('> ul').affix({
|
||||
offset: {
|
||||
top: function () {
|
||||
return $sidebar.offset().top - $('#header').outerHeight(true) - parseInt($sidebar.css('margin-top'));
|
||||
},
|
||||
bottom: function () {
|
||||
return (this.bottom = $('#footer').outerHeight(true));
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
populateSidebar: function(items) {
|
||||
var nav = this.populateItemList('nav');
|
||||
items.pushObjectWithTag(DropdownSelect.extend({items: nav, listItemClass: 'title-control'}), 'nav');
|
||||
@@ -18,7 +34,7 @@ export default Ember.View.extend(HasItemLists, {
|
||||
items.pushObjectWithTag(NavItem.extend({
|
||||
label: 'Activity',
|
||||
icon: 'user',
|
||||
layout: precompileTemplate('{{#link-to "user.activity"}}{{fa-icon icon}} {{label}}{{/link-to}}')
|
||||
layout: precompileTemplate('{{#link-to "user.activity" (query-params filter="")}}{{fa-icon icon}} {{label}}{{/link-to}}')
|
||||
}), 'activity');
|
||||
|
||||
items.pushObjectWithTag(NavItem.extend({
|
||||
@@ -26,7 +42,7 @@ export default Ember.View.extend(HasItemLists, {
|
||||
icon: 'reorder',
|
||||
badge: Ember.computed.alias('user.discussionsCount'),
|
||||
user: this.get('controller.model'),
|
||||
layout: precompileTemplate('{{#link-to "user.discussions"}}{{fa-icon icon}} {{label}} <span class="count">{{badge}}</span>{{/link-to}}')
|
||||
layout: precompileTemplate('{{#link-to "user.activity" (query-params filter="discussions")}}{{fa-icon icon}} {{label}} <span class="count">{{badge}}</span>{{/link-to}}')
|
||||
}), 'discussions');
|
||||
|
||||
items.pushObjectWithTag(NavItem.extend({
|
||||
@@ -34,7 +50,7 @@ export default Ember.View.extend(HasItemLists, {
|
||||
icon: 'comment-o',
|
||||
badge: Ember.computed.alias('user.commentsCount'),
|
||||
user: this.get('controller.model'),
|
||||
layout: precompileTemplate('{{#link-to "user.posts"}}{{fa-icon icon}} {{label}} <span class="count">{{badge}}</span>{{/link-to}}')
|
||||
layout: precompileTemplate('{{#link-to "user.activity" (query-params filter="posts")}}{{fa-icon icon}} {{label}} <span class="count">{{badge}}</span>{{/link-to}}')
|
||||
}), 'posts');
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user