Merge pull request #965 from mailpoet/posts_dynamic_loading

Add dynamic post loading in Posts widget settings [MAILPOET-971]
This commit is contained in:
Tautvidas Sipavičius
2017-07-03 17:18:12 +03:00
committed by GitHub
6 changed files with 120 additions and 2 deletions

View File

@@ -18,6 +18,7 @@
.mailpoet_settings_posts_display_options .mailpoet_settings_posts_display_options
.mailpoet_settings_posts_selection .mailpoet_settings_posts_selection
animation-slide-open-downwards() animation-slide-open-downwards()
overflow-x: hidden
.mailpoet_settings_posts_show_display_options, .mailpoet_settings_posts_show_display_options,
.mailpoet_settings_posts_show_post_selection .mailpoet_settings_posts_show_post_selection
@@ -26,7 +27,12 @@
.mailpoet_post_selection_container .mailpoet_post_selection_container
margin-top: 20px margin-top: 20px
margin-bottom: 20px margin-bottom: 0
.mailpoet_post_scroll_container
overflow-y: scroll
overflow-x: hidden
max-height: 400px
.mailpoet_settings_posts_single_post .mailpoet_settings_posts_single_post
border-radius(1px) border-radius(1px)
@@ -45,3 +51,6 @@
.mailpoet_select_post_checkbox .mailpoet_select_post_checkbox
margin-left: 10px margin-left: 10px
margin-right: 8px margin-right: 8px
.mailpoet_post_selection_loading
color: #999

View File

@@ -48,6 +48,7 @@ define([
return this._getDefaults({ return this._getDefaults({
type: 'posts', type: 'posts',
amount: '10', amount: '10',
offset: 0,
contentType: 'post', // 'post'|'page'|'mailpoet_page' contentType: 'post', // 'post'|'page'|'mailpoet_page'
postStatus: 'publish', // 'draft'|'pending'|'private'|'publish'|'future' postStatus: 'publish', // 'draft'|'pending'|'private'|'publish'|'future'
terms: [], // List of category and tag objects terms: [], // List of category and tag objects
@@ -98,6 +99,7 @@ define([
this.fetchAvailablePosts(); this.fetchAvailablePosts();
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts); this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts);
this.on('loadMorePosts', this._loadMorePosts, this);
this.listenTo(this.get('_selectedPosts'), 'add remove reset', refreshTransformedPosts); this.listenTo(this.get('_selectedPosts'), 'add remove reset', refreshTransformedPosts);
this.on('change:displayType change:titleFormat change:featuredImagePosition change:titleAlignment change:titleIsLink change:imageFullWidth change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:showDivider', refreshTransformedPosts); this.on('change:displayType change:titleFormat change:featuredImagePosition change:titleAlignment change:titleIsLink change:imageFullWidth change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:showDivider', refreshTransformedPosts);
@@ -108,6 +110,7 @@ define([
}, },
fetchAvailablePosts: function() { fetchAvailablePosts: function() {
var that = this; var that = this;
this.set('offset', 0);
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) { CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
that.get('_availablePosts').reset(posts); that.get('_availablePosts').reset(posts);
that.get('_selectedPosts').reset(); // Empty out the collection that.get('_selectedPosts').reset(); // Empty out the collection
@@ -116,6 +119,27 @@ define([
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts')); MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
}); });
}, },
_loadMorePosts: function() {
var that = this,
postCount = this.get('_availablePosts').length,
nextOffset = this.get('offset') + Number(this.get('amount'));
if(postCount === 0 || postCount < nextOffset) {
// No more posts to load
return false;
}
this.set('offset', nextOffset);
this.trigger('loadingMorePosts');
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
that.get('_availablePosts').add(posts);
that.trigger('change:_availablePosts');
}).fail(function() {
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
}).always(function() {
that.trigger('morePostsLoaded');
});
},
_refreshTransformedPosts: function() { _refreshTransformedPosts: function() {
var that = this, var that = this,
data = this.toJSON(); data = this.toJSON();
@@ -260,6 +284,7 @@ define([
}); });
var PostsSelectionCollectionView = Marionette.CollectionView.extend({ var PostsSelectionCollectionView = Marionette.CollectionView.extend({
className: 'mailpoet_post_scroll_container',
childView: function() { return SinglePostSelectionSettingsView; }, childView: function() { return SinglePostSelectionSettingsView; },
emptyView: function() { return EmptyPostSelectionSettingsView; }, emptyView: function() { return EmptyPostSelectionSettingsView; },
childViewOptions: function() { childViewOptions: function() {
@@ -270,6 +295,16 @@ define([
initialize: function(options) { initialize: function(options) {
this.blockModel = options.blockModel; this.blockModel = options.blockModel;
}, },
events: {
'scroll': 'onPostsScroll',
},
onPostsScroll: function(event) {
var $postsBox = jQuery(event.target);
if($postsBox.scrollTop() + $postsBox.innerHeight() >= $postsBox[0].scrollHeight){
// Load more posts if scrolled to bottom
this.blockModel.trigger('loadMorePosts');
}
},
}); });
var PostSelectionSettingsView = Marionette.View.extend({ var PostSelectionSettingsView = Marionette.View.extend({
@@ -284,6 +319,20 @@ define([
'input .mailpoet_posts_search_term': _.partial(this.changeField, 'search'), 'input .mailpoet_posts_search_term': _.partial(this.changeField, 'search'),
}; };
}, },
modelEvents: {
'change:offset': function(model, value) {
// Scroll posts view to top if settings are changed
if (value === 0) {
this.$('.mailpoet_post_scroll_container').scrollTop(0);
}
},
'loadingMorePosts': function() {
this.$('.mailpoet_post_selection_loading').css('visibility', 'visible');
},
'morePostsLoaded': function() {
this.$('.mailpoet_post_selection_loading').css('visibility', 'hidden');
}
},
onRender: function() { onRender: function() {
// Dynamically update available post types // Dynamically update available post types
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this)); CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));

View File

@@ -39,11 +39,15 @@ class AutomatedLatestContent {
'orderby' => 'date', 'orderby' => 'date',
'order' => ($args['sortBy'] === 'newest') ? 'DESC' : 'ASC', 'order' => ($args['sortBy'] === 'newest') ? 'DESC' : 'ASC',
); );
if(!empty($args['offset']) && (int)$args['offset'] > 0) {
$parameters['offset'] = (int)$args['offset'];
}
if(isset($args['search'])) { if(isset($args['search'])) {
$parameters['s'] = $args['search']; $parameters['s'] = $args['search'];
} }
if(isset($args['posts']) && is_array($args['posts'])) { if(isset($args['posts']) && is_array($args['posts'])) {
$parameters['post__in'] = $args['posts']; $parameters['post__in'] = $args['posts'];
$parameters['posts_per_page'] = -1; // Get all posts with matching IDs
} }
if(!empty($posts_to_exclude)) { if(!empty($posts_to_exclude)) {
$parameters['post__not_in'] = $posts_to_exclude; $parameters['post__not_in'] = $posts_to_exclude;

View File

@@ -43,6 +43,10 @@ define([
expect(model.get('amount')).to.match(/^\d+$/); expect(model.get('amount')).to.match(/^\d+$/);
}); });
it('has post offset initialized', function () {
expect(model.get('offset')).to.equal(0);
});
it('has post type filter', function () { it('has post type filter', function () {
expect(model.get('contentType')).to.match(/^(post|page|mailpoet_page)$/); expect(model.get('contentType')).to.match(/^(post|page|mailpoet_page)$/);
}); });
@@ -197,6 +201,55 @@ define([
expect(model.get('divider.styles.block.backgroundColor')).to.equal('#456789'); expect(model.get('divider.styles.block.backgroundColor')).to.equal('#456789');
expect(model.get('divider.styles.block.padding')).to.equal('38px'); expect(model.get('divider.styles.block.padding')).to.equal('38px');
}); });
it('resets offset when fetching posts', function () {
model.set('offset', 10);
model.fetchAvailablePosts();
expect(model.get('offset')).to.equal(0);
});
it('increases offset when loading more posts', function () {
model.set({
amount: 2,
offset: 0
});
model.set('_availablePosts', new Backbone.Collection([{}, {}])); // 2 posts
model.trigger('loadMorePosts');
expect(model.get('offset')).to.equal(2);
});
it('does not increase offset when there is no more posts to load', function () {
model.set({
amount: 10,
offset: 0
});
model.set('_availablePosts', new Backbone.Collection([{}, {}])); // 2 posts
model.trigger('loadMorePosts');
expect(model.get('offset')).to.equal(0);
});
it('triggers loading and loaded events for more posts', function () {
var stub = sinon.stub(CommunicationComponent, 'getPosts', function() {
var deferred = jQuery.Deferred();
deferred.resolve([{}]); // 1 post
return deferred;
});
var spy = sinon.spy(model, 'trigger');
model.set({
amount: 2,
offset: 0
});
model.set('_availablePosts', new Backbone.Collection([{}, {}])); // 2 posts
model._loadMorePosts();
stub.restore();
spy.restore();
expect(spy.withArgs('loadingMorePosts').calledOnce).to.be.true;
expect(spy.withArgs('morePostsLoaded').calledOnce).to.be.true;
expect(model.get('_availablePosts').length).to.equal(3);
});
}); });
describe('block view', function () { describe('block view', function () {

View File

@@ -1073,7 +1073,7 @@
}, },
}, },
posts: { posts: {
amount: '8', amount: '10',
contentType: 'post', // 'post'|'page'|'mailpoet_page' contentType: 'post', // 'post'|'page'|'mailpoet_page'
postStatus: 'publish', // 'draft'|'pending'|'private'|'publish'|'future' postStatus: 'publish', // 'draft'|'pending'|'private'|'publish'|'future'
inclusionType: 'include', // 'include'|'exclude' inclusionType: 'include', // 'include'|'exclude'

View File

@@ -23,3 +23,6 @@
</div> </div>
<div class="mailpoet_post_selection_container"> <div class="mailpoet_post_selection_container">
</div> </div>
<div class="mailpoet_post_selection_loading" style="visibility: hidden;">
<%= __('Loading posts...') %>
</div>