Add a method to bulk update ALC blocks in newsletter editor
This commit is contained in:
@ -13,6 +13,7 @@ define([
|
||||
'newsletter_editor/blocks/divider',
|
||||
'newsletter_editor/components/communication',
|
||||
'mailpoet',
|
||||
'backbone.supermodel',
|
||||
'underscore',
|
||||
'jquery'
|
||||
], function(
|
||||
@ -22,6 +23,7 @@ define([
|
||||
DividerBlock,
|
||||
CommunicationComponent,
|
||||
MailPoet,
|
||||
SuperModel,
|
||||
_,
|
||||
jQuery
|
||||
) {
|
||||
@ -31,6 +33,36 @@ define([
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
|
||||
Module.ALCSupervisor = SuperModel.extend({
|
||||
initialize: function() {
|
||||
this.listenTo(App.getChannel(), 'automatedLatestContentRefresh', this.refresh);
|
||||
},
|
||||
refresh: function() {
|
||||
var models = App.findModels(function(model) {
|
||||
return model.get('type') === 'automatedLatestContent';
|
||||
}) || [];
|
||||
|
||||
if (models.length === 0) return;
|
||||
var blocks = _.map(models, function(model) {
|
||||
return model.toJSON();
|
||||
});
|
||||
|
||||
CommunicationComponent.getBulkTransformedPosts({
|
||||
blocks: blocks,
|
||||
}).then(_.partial(this.refreshBlocks, models));
|
||||
},
|
||||
refreshBlocks: function(models, renderedBlocks) {
|
||||
_.each(
|
||||
_.zip(models, renderedBlocks),
|
||||
function(args) {
|
||||
var model = args[0],
|
||||
contents = args[1];
|
||||
model.trigger('refreshPosts', contents);
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Module.AutomatedLatestContentBlockModel = base.BlockModel.extend({
|
||||
stale: ['_container'],
|
||||
defaults: function() {
|
||||
@ -72,34 +104,32 @@ define([
|
||||
},
|
||||
initialize: function() {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
this.fetchPosts();
|
||||
this.on('change:amount change:contentType change:terms change:inclusionType 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:sortBy change:showDivider', this._scheduleFetchPosts, this);
|
||||
this.listenTo(this.get('readMoreButton'), 'change', this._scheduleFetchPosts);
|
||||
this.listenTo(this.get('divider'), 'change', this._scheduleFetchPosts);
|
||||
},
|
||||
fetchPosts: function() {
|
||||
var that = this;
|
||||
CommunicationComponent.getTransformedPosts(this.toJSON()).done(function(content) {
|
||||
that.get('_container').get('blocks').reset(content, {parse: true});
|
||||
that.trigger('postsChanged');
|
||||
}).fail(function(error) {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
|
||||
this.on('add remove update reset', function(model, collection, options) {
|
||||
App.getChannel().trigger('automatedLatestContentRefresh');
|
||||
});
|
||||
this.on('refreshPosts', this.updatePosts, this);
|
||||
},
|
||||
updatePosts: function(posts) {
|
||||
this.get('_container.blocks').reset(posts, {parse: true});
|
||||
},
|
||||
/**
|
||||
* Batch more changes during a specific time, instead of fetching
|
||||
* ALC posts on each model change
|
||||
*/
|
||||
_scheduleFetchPosts: function() {
|
||||
var timeout = 500,
|
||||
var TIMEOUT = 500,
|
||||
that = this;
|
||||
if (this._fetchPostsTimer !== undefined) {
|
||||
clearTimeout(this._fetchPostsTimer);
|
||||
}
|
||||
this._fetchPostsTimer = setTimeout(function() {
|
||||
that.fetchPosts();
|
||||
//that.fetchPosts();
|
||||
App.getChannel().trigger('automatedLatestContentRefresh');
|
||||
that._fetchPostsTimer = undefined;
|
||||
}, timeout);
|
||||
}, TIMEOUT);
|
||||
},
|
||||
});
|
||||
|
||||
@ -363,5 +393,10 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
App.on('start', function() {
|
||||
App._ALCSupervisor = new Module.ALCSupervisor();
|
||||
App._ALCSupervisor.refresh();
|
||||
});
|
||||
|
||||
return Module;
|
||||
});
|
||||
|
@ -40,6 +40,9 @@ define([
|
||||
// Remove stale attributes from resulting JSON object
|
||||
return _.omit(SuperModel.prototype.toJSON.call(this), this.stale);
|
||||
},
|
||||
getChildren: function() {
|
||||
return [];
|
||||
},
|
||||
});
|
||||
|
||||
Module.BlockView = AugmentedView.extend({
|
||||
|
@ -65,6 +65,13 @@ define([
|
||||
}
|
||||
return response;
|
||||
},
|
||||
getChildren: function() {
|
||||
var models = this.get('blocks').map(function(model, index, list) {
|
||||
return [model, model.getChildren()];
|
||||
});
|
||||
|
||||
return _.flatten(models);
|
||||
},
|
||||
});
|
||||
|
||||
Module.ContainerBlockView = Marionette.CompositeView.extend({
|
||||
|
@ -62,6 +62,13 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
Module.getBulkTransformedPosts = function(options) {
|
||||
return Module._query({
|
||||
action: 'getBulkTransformedPosts',
|
||||
options: options,
|
||||
});
|
||||
};
|
||||
|
||||
Module.saveNewsletter = function(options) {
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
|
@ -60,6 +60,11 @@ define([
|
||||
return Module.newsletter;
|
||||
};
|
||||
|
||||
Module.findModels = function(predicate) {
|
||||
var blocks = App._contentContainer.getChildren();
|
||||
return _.filter(blocks, predicate);
|
||||
};
|
||||
|
||||
App.on('before:start', function(options) {
|
||||
// Expose block methods globally
|
||||
App.registerBlockType = Module.registerBlockType;
|
||||
@ -68,6 +73,7 @@ define([
|
||||
App.toJSON = Module.toJSON;
|
||||
App.getBody = Module.getBody;
|
||||
App.getNewsletter = Module.getNewsletter;
|
||||
App.findModels = Module.findModels;
|
||||
|
||||
Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body']));
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,4 +43,22 @@ class AutomatedLatestContent {
|
||||
$posts = $this->ALC->getPosts($args);
|
||||
return $this->ALC->transformPosts($args, $posts);
|
||||
}
|
||||
|
||||
function getBulkTransformedPosts($args) {
|
||||
$alc = new \MailPoet\Newsletter\AutomatedLatestContent();
|
||||
|
||||
$used_posts = array();
|
||||
$rendered_posts = array();
|
||||
|
||||
foreach ($args['blocks'] as $block) {
|
||||
$posts = $alc->getPosts($block, $used_posts);
|
||||
$rendered_posts[] = $alc->transformPosts($block, $posts);
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$used_posts[] = $post->ID;
|
||||
}
|
||||
}
|
||||
|
||||
return $rendered_posts;
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,71 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/blocks/automatedLatestContent',
|
||||
'newsletter_editor/blocks/container',
|
||||
'amd-inject-loader!newsletter_editor/blocks/automatedLatestContent',
|
||||
'newsletter_editor/components/communication',
|
||||
], function(EditorApplication, AutomatedLatestContentBlock, AutomatedLatestContentInjector, CommunicationComponent) {
|
||||
], function(
|
||||
EditorApplication,
|
||||
AutomatedLatestContentBlock,
|
||||
ContainerBlock,
|
||||
AutomatedLatestContentInjector,
|
||||
CommunicationComponent
|
||||
) {
|
||||
|
||||
describe('Automated Latest Content Supervisor', function() {
|
||||
var model;
|
||||
beforeEach(function() {
|
||||
model = new AutomatedLatestContentBlock.ALCSupervisor();
|
||||
});
|
||||
|
||||
it('fetches posts in bulk from the server', function() {
|
||||
global.stubChannel(EditorApplication);
|
||||
EditorApplication.findModels = sinon.stub().returns([new Backbone.SuperModel()]);
|
||||
|
||||
var mock = sinon.mock({ getBulkTransformedPosts: function() {} })
|
||||
.expects('getBulkTransformedPosts').once().returns(jQuery.Deferred());
|
||||
|
||||
var module = AutomatedLatestContentInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
getBulkTransformedPosts: mock
|
||||
},
|
||||
});
|
||||
|
||||
var model = new module.ALCSupervisor();
|
||||
model.refresh();
|
||||
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('refreshes posts for given blocks', function() {
|
||||
var block1 = new Backbone.SuperModel(),
|
||||
block2 = new Backbone.SuperModel(),
|
||||
postsSet1 = [
|
||||
{ type: 'customTypeOne' },
|
||||
],
|
||||
postsSet2 = [
|
||||
{ type: 'customTypeTwo' },
|
||||
{ type: 'customTypeTwo' },
|
||||
],
|
||||
mock1 = sinon.mock(block1),
|
||||
mock2 = sinon.mock(block2);
|
||||
|
||||
mock1.expects('trigger').once().withArgs('refreshPosts', postsSet1);
|
||||
mock2.expects('trigger').once().withArgs('refreshPosts', postsSet2);
|
||||
|
||||
model.refreshBlocks([block1, block2], [postsSet1, postsSet2]);
|
||||
|
||||
mock1.verify();
|
||||
mock2.verify();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Automated latest content', function () {
|
||||
describe('model', function () {
|
||||
var model, module;
|
||||
|
||||
before(function() {
|
||||
module = AutomatedLatestContentInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
getTransformedPosts: function() {
|
||||
return jQuery.Deferred();
|
||||
}
|
||||
},
|
||||
});
|
||||
module = AutomatedLatestContentBlock;
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
@ -28,6 +77,7 @@ define([
|
||||
|
||||
afterEach(function () {
|
||||
delete EditorApplication.getChannel;
|
||||
delete EditorApplication.getBlockTypeModel;
|
||||
});
|
||||
|
||||
it('has automatedLatestContent type', function () {
|
||||
@ -192,19 +242,25 @@ define([
|
||||
expect(model.get('divider.styles.block.backgroundColor')).to.equal('#456789');
|
||||
expect(model.get('divider.styles.block.padding')).to.equal('38px');
|
||||
});
|
||||
|
||||
it('accepts displayable posts', function() {
|
||||
EditorApplication.getBlockTypeModel = sinon.stub().returns(ContainerBlock.ContainerBlockModel);
|
||||
var model = new (module.AutomatedLatestContentBlockModel)();
|
||||
|
||||
model.updatePosts([{
|
||||
type: 'someCustomType',
|
||||
}]);
|
||||
|
||||
expect(model.get('_container.blocks').size()).to.equal(1);
|
||||
expect(model.get('_container.blocks').first().get('type')).to.equal('someCustomType');
|
||||
});
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model, view, module;
|
||||
|
||||
before(function() {
|
||||
module = AutomatedLatestContentInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
getTransformedPosts: function() {
|
||||
return jQuery.Deferred();
|
||||
}
|
||||
},
|
||||
});
|
||||
module = AutomatedLatestContentBlock;
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
@ -232,9 +288,6 @@ define([
|
||||
before(function() {
|
||||
module = AutomatedLatestContentInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
getTransformedPosts: function() {
|
||||
return jQuery.Deferred();
|
||||
},
|
||||
getPostTypes: function() {
|
||||
return jQuery.Deferred();
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ define([
|
||||
});
|
||||
|
||||
it('has a specified font family', function () {
|
||||
expect(view.$('.mailpoet_editor_button').css('font-family')).to.equal(model.get('styles.block.fontFamily'));
|
||||
expect(view.$('.mailpoet_editor_button').css('font-family')).to.contain(model.get('styles.block.fontFamily'));
|
||||
});
|
||||
|
||||
it('has a specified font size', function () {
|
||||
|
Reference in New Issue
Block a user