mirror of
https://github.com/codeninjasllc/discourse.git
synced 2025-02-17 12:11:16 -05:00
Split Topic Progres widget into its own controller, view, template
This commit is contained in:
parent
e5eccfc70a
commit
33e9bc68fc
9 changed files with 142 additions and 139 deletions
|
@ -0,0 +1,46 @@
|
|||
export default Ember.ObjectController.extend({
|
||||
needs: ['topic'],
|
||||
progressPosition: null,
|
||||
|
||||
streamPercentage: function() {
|
||||
if (!this.get('postStream.loaded')) { return 0; }
|
||||
if (this.get('postStream.highest_post_number') === 0) { return 0; }
|
||||
var perc = this.get('progressPosition') / this.get('postStream.filteredPostsCount');
|
||||
return (perc > 1.0) ? 1.0 : perc;
|
||||
}.property('postStream.loaded', 'progressPosition', 'postStream.filteredPostsCount'),
|
||||
|
||||
jumpTopDisabled: function() {
|
||||
return (this.get('progressPosition') < 2);
|
||||
}.property('progressPosition'),
|
||||
|
||||
filteredPostCountChanged: function(){
|
||||
if(this.get('postStream.filteredPostsCount') < this.get('progressPosition')){
|
||||
this.set('progressPosition', this.get('postStream.filteredPostsCount'));
|
||||
}
|
||||
}.observes('postStream.filteredPostsCount'),
|
||||
|
||||
jumpBottomDisabled: function() {
|
||||
return this.get('progressPosition') >= this.get('postStream.filteredPostsCount') ||
|
||||
this.get('progressPosition') >= this.get('highest_post_number');
|
||||
}.property('postStream.filteredPostsCount', 'highest_post_number', 'progressPosition'),
|
||||
|
||||
hideProgress: function() {
|
||||
if (!this.get('postStream.loaded')) return true;
|
||||
if (!this.get('currentPost')) return true;
|
||||
if (this.get('postStream.filteredPostsCount') < 2) return true;
|
||||
return false;
|
||||
}.property('postStream.loaded', 'currentPost', 'postStream.filteredPostsCount'),
|
||||
|
||||
hugeNumberOfPosts: function() {
|
||||
return (this.get('postStream.filteredPostsCount') >= Discourse.SiteSettings.short_progress_text_threshold);
|
||||
}.property('highest_post_number'),
|
||||
|
||||
jumpToBottomTitle: function() {
|
||||
if (this.get('hugeNumberOfPosts')) {
|
||||
return I18n.t('topic.progress.jump_bottom_with_number', {post_number: this.get('highest_post_number')});
|
||||
} else {
|
||||
return I18n.t('topic.progress.jump_bottom');
|
||||
}
|
||||
}.property('hugeNumberOfPosts', 'highest_post_number')
|
||||
|
||||
});
|
|
@ -8,7 +8,7 @@
|
|||
**/
|
||||
Discourse.TopicController = Discourse.ObjectController.extend(Discourse.SelectedPostsCount, {
|
||||
multiSelect: false,
|
||||
needs: ['header', 'modal', 'composer', 'quote-button', 'search'],
|
||||
needs: ['header', 'modal', 'composer', 'quote-button', 'search', 'topic-progress'],
|
||||
allPostsSelected: false,
|
||||
editingTopic: false,
|
||||
selectedPosts: null,
|
||||
|
@ -391,21 +391,6 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
return post.get('post_number') === 1 && post.get('topic.expandable_first_post');
|
||||
}.property(),
|
||||
|
||||
jumpTopDisabled: function() {
|
||||
return (this.get('progressPosition') < 2);
|
||||
}.property('progressPosition'),
|
||||
|
||||
filteredPostCountChanged: function(){
|
||||
if(this.get('postStream.filteredPostsCount') < this.get('progressPosition')){
|
||||
this.set('progressPosition', this.get('postStream.filteredPostsCount'));
|
||||
}
|
||||
}.observes('postStream.filteredPostsCount'),
|
||||
|
||||
jumpBottomDisabled: function() {
|
||||
return this.get('progressPosition') >= this.get('postStream.filteredPostsCount') ||
|
||||
this.get('progressPosition') >= this.get('highest_post_number');
|
||||
}.property('postStream.filteredPostsCount', 'highest_post_number', 'progressPosition'),
|
||||
|
||||
canMergeTopic: function() {
|
||||
if (!this.get('details.can_move_posts')) return false;
|
||||
return (this.get('selectedPostsCount') > 0);
|
||||
|
@ -451,13 +436,6 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
|
||||
hasError: Ember.computed.or('errorBodyHtml', 'message'),
|
||||
|
||||
streamPercentage: function() {
|
||||
if (!this.get('postStream.loaded')) { return 0; }
|
||||
if (this.get('postStream.highest_post_number') === 0) { return 0; }
|
||||
var perc = this.get('progressPosition') / this.get('postStream.filteredPostsCount');
|
||||
return (perc > 1.0) ? 1.0 : perc;
|
||||
}.property('postStream.loaded', 'progressPosition', 'postStream.filteredPostsCount'),
|
||||
|
||||
multiSelectChanged: function() {
|
||||
// Deselect all posts when multi select is turned off
|
||||
if (!this.get('multiSelect')) {
|
||||
|
@ -465,25 +443,6 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
}
|
||||
}.observes('multiSelect'),
|
||||
|
||||
hideProgress: function() {
|
||||
if (!this.get('postStream.loaded')) return true;
|
||||
if (!this.get('currentPost')) return true;
|
||||
if (this.get('postStream.filteredPostsCount') < 2) return true;
|
||||
return false;
|
||||
}.property('postStream.loaded', 'currentPost', 'postStream.filteredPostsCount'),
|
||||
|
||||
hugeNumberOfPosts: function() {
|
||||
return (this.get('postStream.filteredPostsCount') >= Discourse.SiteSettings.short_progress_text_threshold);
|
||||
}.property('highest_post_number'),
|
||||
|
||||
jumpToBottomTitle: function() {
|
||||
if (this.get('hugeNumberOfPosts')) {
|
||||
return I18n.t('topic.progress.jump_bottom_with_number', {post_number: this.get('highest_post_number')});
|
||||
} else {
|
||||
return I18n.t('topic.progress.jump_bottom');
|
||||
}
|
||||
}.property('hugeNumberOfPosts', 'highest_post_number'),
|
||||
|
||||
deselectPost: function(post) {
|
||||
this.get('selectedPosts').removeObject(post);
|
||||
|
||||
|
@ -663,7 +622,7 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
lastLoadedPost = postStream.get('lastLoadedPost'),
|
||||
index = postStream.get('stream').indexOf(post.get('id'))+1;
|
||||
|
||||
this.set('progressPosition', index);
|
||||
this.set('controllers.topic-progress.progressPosition', index);
|
||||
|
||||
if (lastLoadedPost && lastLoadedPost === post) {
|
||||
postStream.appendMore();
|
||||
|
|
|
@ -162,7 +162,9 @@ Discourse.URL = Em.Object.createWithMixins({
|
|||
if (oldTopicId === newTopicId) {
|
||||
Discourse.URL.replaceState(path);
|
||||
|
||||
var topicController = Discourse.__container__.lookup('controller:topic'),
|
||||
var container = Discourse.__container__,
|
||||
topicController = container.lookup('controller:topic'),
|
||||
topicProgressController = container.lookup('controller:topic-progress'),
|
||||
opts = {},
|
||||
postStream = topicController.get('postStream');
|
||||
|
||||
|
@ -173,10 +175,10 @@ Discourse.URL = Em.Object.createWithMixins({
|
|||
postStream.refresh(opts).then(function() {
|
||||
topicController.setProperties({
|
||||
currentPost: closest,
|
||||
progressPosition: closest,
|
||||
highlightOnInsert: closest,
|
||||
enteredAt: new Date().getTime().toString()
|
||||
});
|
||||
topicProgressController.set('progressPosition', closest);
|
||||
}).then(function() {
|
||||
Discourse.TopicView.jumpToPost(closest);
|
||||
});
|
||||
|
|
|
@ -15,6 +15,7 @@ Discourse.TopicFromParamsRoute = Discourse.Route.extend({
|
|||
postStream = topic.get('postStream');
|
||||
|
||||
var topicController = this.controllerFor('topic'),
|
||||
topicProgressController = this.controllerFor('topic-progress'),
|
||||
composerController = this.controllerFor('composer');
|
||||
|
||||
// I sincerely hope no topic gets this many posts
|
||||
|
@ -26,11 +27,11 @@ Discourse.TopicFromParamsRoute = Discourse.Route.extend({
|
|||
|
||||
topicController.setProperties({
|
||||
currentPost: closest,
|
||||
progressPosition: closest,
|
||||
enteredAt: new Date().getTime().toString(),
|
||||
highlightOnInsert: closest
|
||||
});
|
||||
|
||||
topicProgressController.set('progressPosition', closest);
|
||||
Discourse.TopicView.jumpToPost(closest);
|
||||
|
||||
if (topic.present('draft')) {
|
||||
|
|
|
@ -182,6 +182,7 @@ Discourse.TopicRoute = Discourse.Route.extend({
|
|||
Discourse.TopicTrackingState.current().trackIncoming('all');
|
||||
controller.subscribe();
|
||||
|
||||
this.controllerFor('topic-progress').set('model', model);
|
||||
// We reset screen tracking every time a topic is entered
|
||||
Discourse.ScreenTrack.current().start(model.get('id'), controller);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<nav id='topic-progress' title="{{i18n topic.progress.title}}" {{bind-attr class="hideProgress:hidden"}}>
|
||||
<button id='jump-top' title="{{i18n topic.progress.jump_top}}" {{bind-attr disabled="jumpTopDisabled"}} {{action jumpTop}}><i class="fa fa-arrow-circle-up"></i></button>
|
||||
<div class='nums'>
|
||||
<h4>{{progressPosition}}</h4><span {{bind-attr class="hugeNumberOfPosts:hidden"}}> <span>{{i18n of_value}}</span> <h4>{{postStream.filteredPostsCount}}</h4></span>
|
||||
</div>
|
||||
<button id='jump-bottom' {{bind-attr title="jumpToBottomTitle"}} {{bind-attr disabled="jumpBottomDisabled"}} {{action jumpBottom}}><i class="fa fa-arrow-circle-down"></i></button>
|
||||
<div class='bg'> </div>
|
||||
</nav>
|
|
@ -62,16 +62,7 @@
|
|||
<section class="topic-area" id='topic' data-topic-id='{{unbound id}}'>
|
||||
<div class='posts-wrapper'>
|
||||
|
||||
<div id='topic-progress-wrapper' {{bind-attr class="dockedCounter:docked"}}>
|
||||
<nav id='topic-progress' title="{{i18n topic.progress.title}}" {{bind-attr class="hideProgress:hidden"}}>
|
||||
<button id='jump-top' title="{{i18n topic.progress.jump_top}}" {{bind-attr disabled="jumpTopDisabled"}} {{action jumpTop}}><i class="fa fa-arrow-circle-up"></i></button>
|
||||
<div class='nums' {{bind-attr title="progressPositionTitle"}}>
|
||||
<h4>{{progressPosition}}</h4><span {{bind-attr class="hugeNumberOfPosts:hidden"}}> <span>{{i18n of_value}}</span> <h4>{{postStream.filteredPostsCount}}</h4></span>
|
||||
</div>
|
||||
<button id='jump-bottom' {{bind-attr title="jumpToBottomTitle"}} {{bind-attr disabled="jumpBottomDisabled"}} {{action jumpBottom}}><i class="fa fa-arrow-circle-down"></i></button>
|
||||
<div class='bg'> </div>
|
||||
</nav>
|
||||
</div>
|
||||
{{render 'topic-progress'}}
|
||||
|
||||
{{#if postStream.loadingAbove}}
|
||||
<div class='spinner'>{{i18n loading}}</div>
|
||||
|
|
76
app/assets/javascripts/discourse/views/topic-progress.js.es6
Normal file
76
app/assets/javascripts/discourse/views/topic-progress.js.es6
Normal file
|
@ -0,0 +1,76 @@
|
|||
export default Ember.View.extend({
|
||||
elementId: 'topic-progress-wrapper',
|
||||
|
||||
_inserted: function() {
|
||||
// This get seems counter intuitive, but it's to trigger the observer on
|
||||
// the streamPercentage for this view. Otherwise the process bar does not
|
||||
// update.
|
||||
this.get('controller.streamPercentage');
|
||||
|
||||
this.appEvents.on("composer:opened", this, '_dock')
|
||||
.on("composer:resized", this, '_dock')
|
||||
.on("composer:closed", this, '_dock')
|
||||
.on("topic:scrolled", this, '_dock');
|
||||
|
||||
// Reflows are expensive. Cache the jQuery selector
|
||||
// and the width when inserted into the DOM
|
||||
this._$topicProgress = this.$('#topic-progress');
|
||||
this._progressWidth = this._$topicProgress[0].offsetWidth;
|
||||
}.on('didInsertElement'),
|
||||
|
||||
_unbindEvents: function() {
|
||||
this.appEvents.off("composer:opened", this, '_dock')
|
||||
.off("composer:resized", this, '_dock')
|
||||
.off("composer:closed", this, '_dock')
|
||||
.off('topic:scrolled', this, '_dock');
|
||||
}.on('willDestroyElement'),
|
||||
|
||||
_updateBar: function() {
|
||||
Em.run.scheduleOnce('afterRender', this, '_updateProgressBar');
|
||||
}.observes('controller.streamPercentage', 'postStream.stream.@each'),
|
||||
|
||||
_updateProgressBar: function() {
|
||||
// speeds up stuff, bypass jquery slowness and extra checks
|
||||
var totalWidth = this._progressWidth,
|
||||
progressWidth = this.get('controller.streamPercentage') * totalWidth;
|
||||
|
||||
this._$topicProgress.find('.bg')
|
||||
.css("border-right-width", (progressWidth === totalWidth) ? "0px" : "1px")
|
||||
.width(progressWidth);
|
||||
},
|
||||
|
||||
_dock: function () {
|
||||
var maximumOffset = $('#topic-footer-buttons').offset(),
|
||||
composerHeight = $('#reply-control').height() || 0,
|
||||
$topicProgressWrapper = this.$(),
|
||||
style = $topicProgressWrapper.attr('style') || '',
|
||||
isDocked = false,
|
||||
offset = window.pageYOffset || $('html').scrollTop();
|
||||
|
||||
if (maximumOffset) {
|
||||
var threshold = maximumOffset.top,
|
||||
windowHeight = $(window).height(),
|
||||
topicProgressHeight = $('#topic-progress').height();
|
||||
|
||||
isDocked = offset >= threshold - windowHeight + topicProgressHeight + composerHeight;
|
||||
}
|
||||
|
||||
if (composerHeight > 0) {
|
||||
if (isDocked) {
|
||||
if (style.indexOf('bottom') >= 0) {
|
||||
$topicProgressWrapper.css('bottom', '');
|
||||
}
|
||||
} else {
|
||||
var height = composerHeight + "px";
|
||||
if ($topicProgressWrapper.css('bottom') !== height) {
|
||||
$topicProgressWrapper.css('bottom', height);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (style.indexOf('bottom') >= 0) {
|
||||
$topicProgressWrapper.css('bottom', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
|
@ -23,35 +23,6 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
|
|||
|
||||
postStream: Em.computed.alias('controller.postStream'),
|
||||
|
||||
updateBar: function() {
|
||||
Em.run.scheduleOnce('afterRender', this, '_updateProgressBar');
|
||||
}.observes('controller.streamPercentage', 'postStream.stream.@each'),
|
||||
|
||||
_updateProgressBar: function() {
|
||||
var $topicProgress = this._topicProgress;
|
||||
|
||||
// cache lookup
|
||||
if (!$topicProgress) {
|
||||
$topicProgress = $('#topic-progress');
|
||||
if (!$topicProgress.length) {
|
||||
return;
|
||||
}
|
||||
this._topicProgress = $topicProgress;
|
||||
// CAREFUL WITH THIS AXE
|
||||
// offsetWidth will cause a reflow, this ensures it only happens once
|
||||
// in future it may make sense to move this offscreen to do the measurement
|
||||
Discourse.TopicView._progressWidth = Discourse.TopicView._progressWidth || $topicProgress[0].offsetWidth;
|
||||
}
|
||||
|
||||
// speeds up stuff, bypass jquery slowness and extra checks
|
||||
var totalWidth = Discourse.TopicView._progressWidth,
|
||||
progressWidth = this.get('controller.streamPercentage') * totalWidth;
|
||||
|
||||
$topicProgress.find('.bg')
|
||||
.css("border-right-width", (progressWidth === totalWidth) ? "0px" : "1px")
|
||||
.width(progressWidth);
|
||||
},
|
||||
|
||||
_updateTitle: function() {
|
||||
var title = this.get('topic.title');
|
||||
if (title) return Discourse.set('title', _.unescape(title));
|
||||
|
@ -64,8 +35,6 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
|
|||
}.observes('composer'),
|
||||
|
||||
_enteredTopic: function() {
|
||||
this._topicProgress = undefined;
|
||||
|
||||
// Ember is supposed to only call observers when values change but something
|
||||
// in our view set up is firing this observer with the same value. This check
|
||||
// prevents scrolled from being called twice.
|
||||
|
@ -84,21 +53,12 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
|
|||
self.scrolled();
|
||||
});
|
||||
|
||||
// This get seems counter intuitive, but it's to trigger the observer on
|
||||
// the streamPercentage for this view. Otherwise the process bar does not
|
||||
// update.
|
||||
this.get('controller.streamPercentage');
|
||||
|
||||
this.$().on('mouseup.discourse-redirect', '.cooked a, a.track-link', function(e) {
|
||||
var $target = $(e.target);
|
||||
if ($target.hasClass('mention') || $target.parents('.expanded-embed').length) { return false; }
|
||||
return Discourse.ClickTrack.trackClick(e);
|
||||
});
|
||||
|
||||
var dockProgressBar = function () { self._dockProgressBar(); };
|
||||
this.appEvents.on("composer:opened", dockProgressBar)
|
||||
.on("composer:resized", dockProgressBar)
|
||||
.on("composer:closed", dockProgressBar);
|
||||
}.on('didInsertElement'),
|
||||
|
||||
// This view is being removed. Shut down operations
|
||||
|
@ -114,10 +74,6 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
|
|||
// this happens after route exit, stuff could have trickled in
|
||||
this.set('controller.controllers.header.showExtraInfo', false);
|
||||
|
||||
// unbind events
|
||||
this.appEvents.off("composer:opened")
|
||||
.off("composer:resized")
|
||||
.off("composer:closed");
|
||||
}.on('willDestroyElement'),
|
||||
|
||||
debounceLoadSuggested: Discourse.debounce(function(){
|
||||
|
@ -181,45 +137,8 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
|
|||
headerController.set('showExtraInfo', topic.get('postStream.firstPostNotLoaded'));
|
||||
}
|
||||
|
||||
// dock the counter if necessary
|
||||
this._dockProgressBar(offset);
|
||||
},
|
||||
|
||||
_dockProgressBar: function (offset) {
|
||||
var maximumOffset = $('#topic-footer-buttons').offset(),
|
||||
composerHeight = $('#reply-control').height() || 0,
|
||||
$topicProgressWrapper = $('#topic-progress-wrapper'),
|
||||
style = $topicProgressWrapper.attr('style') || '',
|
||||
isDocked = false;
|
||||
|
||||
offset = offset || window.pageYOffset || $('html').scrollTop();
|
||||
|
||||
if (maximumOffset) {
|
||||
var threshold = maximumOffset.top,
|
||||
windowHeight = $(window).height(),
|
||||
topicProgressHeight = $('#topic-progress').height();
|
||||
|
||||
isDocked = offset >= threshold - windowHeight + topicProgressHeight + composerHeight;
|
||||
}
|
||||
|
||||
if (composerHeight > 0) {
|
||||
if (isDocked) {
|
||||
if (style.indexOf('bottom') >= 0) {
|
||||
$topicProgressWrapper.css('bottom', '');
|
||||
}
|
||||
} else {
|
||||
var height = composerHeight + "px";
|
||||
if ($topicProgressWrapper.css('bottom') !== height) {
|
||||
$topicProgressWrapper.css('bottom', height);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (style.indexOf('bottom') >= 0) {
|
||||
$topicProgressWrapper.css('bottom', '');
|
||||
}
|
||||
}
|
||||
|
||||
this.set("controller.dockedCounter", isDocked);
|
||||
// Trigger a scrolled event
|
||||
this.appEvents.trigger('topic:scrolled');
|
||||
},
|
||||
|
||||
topicTrackingState: function() {
|
||||
|
|
Loading…
Reference in a new issue