Merge pull request #229 from mailpoet/editor_posts
Editor: Posts widget
This commit is contained in:
@ -19,6 +19,10 @@ $divider-hover-border-color = $primary-active-color
|
|||||||
width: 100%
|
width: 100%
|
||||||
border: 1px solid transparent
|
border: 1px solid transparent
|
||||||
|
|
||||||
|
.mailpoet_active_divider_style
|
||||||
|
border: 1px solid $active-divider-border-color
|
||||||
|
background: $active-divider-background-color
|
||||||
|
|
||||||
.mailpoet_field_divider_style:hover
|
.mailpoet_field_divider_style:hover
|
||||||
border: 1px solid $divider-hover-border-color
|
border: 1px solid $divider-hover-border-color
|
||||||
|
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
.mailpoet_posts_block
|
.mailpoet_posts_block
|
||||||
box-shadow(none)
|
padding-left: 0
|
||||||
|
padding-right: 0
|
||||||
|
|
||||||
& > .mailpoet_content
|
.mailpoet_posts_block_posts
|
||||||
font-size: 1em
|
overflow: auto
|
||||||
text-align: center
|
|
||||||
background-color: $primary-active-color
|
& > .mailpoet_block
|
||||||
margin: 20px 0
|
width: 100%
|
||||||
padding: 15px
|
|
||||||
box-shadow(inset 1px 2px 1px $primary-inset-shadow-color)
|
|
||||||
color: $white-color
|
|
||||||
border-radius(3px)
|
|
||||||
|
|
||||||
.mailpoet_post_selection_filter_row
|
.mailpoet_post_selection_filter_row
|
||||||
margin-top: 5px
|
margin-top: 5px
|
||||||
|
@ -214,6 +214,7 @@ define([
|
|||||||
this.model.set(field, value);
|
this.model.set(field, value);
|
||||||
},
|
},
|
||||||
onBeforeDestroy: function() {
|
onBeforeDestroy: function() {
|
||||||
|
console.log('Calling close');
|
||||||
MailPoet.Modal.close();
|
MailPoet.Modal.close();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,7 @@ define([
|
|||||||
base = BaseBlock;
|
base = BaseBlock;
|
||||||
|
|
||||||
Module.PostsBlockModel = base.BlockModel.extend({
|
Module.PostsBlockModel = base.BlockModel.extend({
|
||||||
stale: ['_selectedPosts', '_availablePosts'],
|
stale: ['_selectedPosts', '_availablePosts', '_transformedPosts'],
|
||||||
defaults: function() {
|
defaults: function() {
|
||||||
return this._getDefaults({
|
return this._getDefaults({
|
||||||
type: 'posts',
|
type: 'posts',
|
||||||
@ -63,6 +63,7 @@ define([
|
|||||||
divider: {},
|
divider: {},
|
||||||
_selectedPosts: [],
|
_selectedPosts: [],
|
||||||
_availablePosts: [],
|
_availablePosts: [],
|
||||||
|
_transformedPosts: new (App.getBlockTypeModel('container'))(),
|
||||||
}, App.getConfig().get('blockDefaults.posts'));
|
}, App.getConfig().get('blockDefaults.posts'));
|
||||||
},
|
},
|
||||||
relations: function() {
|
relations: function() {
|
||||||
@ -71,15 +72,26 @@ define([
|
|||||||
divider: App.getBlockTypeModel('divider'),
|
divider: App.getBlockTypeModel('divider'),
|
||||||
_selectedPosts: Backbone.Collection,
|
_selectedPosts: Backbone.Collection,
|
||||||
_availablePosts: Backbone.Collection,
|
_availablePosts: Backbone.Collection,
|
||||||
|
_transformedPosts: App.getBlockTypeModel('container'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
var that = this;
|
var that = this,
|
||||||
|
POST_REFRESH_DELAY_MS = 500,
|
||||||
|
refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS),
|
||||||
|
refreshTransformedPosts = _.debounce(this._refreshTransformedPosts.bind(this), POST_REFRESH_DELAY_MS);
|
||||||
|
|
||||||
// Attach Radio.Requests API primarily for highlighting
|
// Attach Radio.Requests API primarily for highlighting
|
||||||
_.extend(this, Radio.Requests);
|
_.extend(this, Radio.Requests);
|
||||||
|
|
||||||
this.fetchAvailablePosts();
|
this.fetchAvailablePosts();
|
||||||
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', this._scheduleFetchAvailablePosts, this);
|
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts);
|
||||||
|
|
||||||
|
this.listenTo(this.get('_selectedPosts'), 'add remove reset', refreshTransformedPosts);
|
||||||
|
this.on('change:displayType change:titleFormat change:titlePosition change:titleAlignment change:titleIsLink change:imagePadded change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:showDivider', refreshTransformedPosts);
|
||||||
|
this.listenTo(this.get('readMoreButton'), 'change', refreshTransformedPosts);
|
||||||
|
this.listenTo(this.get('divider'), 'change', refreshTransformedPosts);
|
||||||
|
|
||||||
this.on('insertSelectedPosts', this._insertSelectedPosts, this);
|
this.on('insertSelectedPosts', this._insertSelectedPosts, this);
|
||||||
},
|
},
|
||||||
fetchAvailablePosts: function() {
|
fetchAvailablePosts: function() {
|
||||||
@ -93,20 +105,23 @@ define([
|
|||||||
console.log('Posts fetchPosts error', arguments);
|
console.log('Posts fetchPosts error', arguments);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**
|
_refreshTransformedPosts: function() {
|
||||||
* Batch more changes during a specific time, instead of fetching
|
var that = this,
|
||||||
* ALC posts on each model change
|
data = this.toJSON();
|
||||||
*/
|
|
||||||
_scheduleFetchAvailablePosts: function() {
|
data.posts = this.get('_selectedPosts').pluck('ID');
|
||||||
var timeout = 500,
|
|
||||||
that = this;
|
if (data.posts.length === 0) {
|
||||||
if (this._fetchPostsTimer !== undefined) {
|
this.get('_transformedPosts.blocks').reset();
|
||||||
clearTimeout(this._fetchPostsTimer);
|
return;
|
||||||
}
|
}
|
||||||
this._fetchPostsTimer = setTimeout(function() {
|
|
||||||
that.fetchAvailablePosts();
|
WordpressComponent.getTransformedPosts(data).done(function(posts) {
|
||||||
that._fetchPostsTimer = undefined;
|
console.log('Transformed posts fetched', arguments);
|
||||||
}, timeout);
|
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
|
||||||
|
}).fail(function() {
|
||||||
|
console.log('Posts _refreshTransformedPosts error', arguments);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
_insertSelectedPosts: function() {
|
_insertSelectedPosts: function() {
|
||||||
var that = this,
|
var that = this,
|
||||||
@ -131,6 +146,9 @@ define([
|
|||||||
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
|
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
|
||||||
getTemplate: function() { return templates.postsBlock; },
|
getTemplate: function() { return templates.postsBlock; },
|
||||||
modelEvents: {},
|
modelEvents: {},
|
||||||
|
regions: _.extend({
|
||||||
|
postsRegion: '.mailpoet_posts_block_posts',
|
||||||
|
}, base.BlockView.prototype.regions),
|
||||||
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
|
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||||
@ -142,6 +160,13 @@ define([
|
|||||||
this.toolsRegion.show(this.toolsView);
|
this.toolsRegion.show(this.toolsView);
|
||||||
}
|
}
|
||||||
this.trigger('showSettings');
|
this.trigger('showSettings');
|
||||||
|
|
||||||
|
var ContainerView = App.getBlockTypeView('container'),
|
||||||
|
renderOptions = {
|
||||||
|
disableTextEditor: true,
|
||||||
|
disableDragAndDrop: true,
|
||||||
|
};
|
||||||
|
this.postsRegion.show(new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions }));
|
||||||
},
|
},
|
||||||
notifyAboutSelf: function() {
|
notifyAboutSelf: function() {
|
||||||
return this;
|
return this;
|
||||||
@ -216,6 +241,7 @@ define([
|
|||||||
insertPosts: function() {
|
insertPosts: function() {
|
||||||
this.model.trigger('insertSelectedPosts');
|
this.model.trigger('insertSelectedPosts');
|
||||||
this.model.destroy();
|
this.model.destroy();
|
||||||
|
this.close();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -307,11 +333,6 @@ define([
|
|||||||
},
|
},
|
||||||
}).trigger( 'change' );
|
}).trigger( 'change' );
|
||||||
},
|
},
|
||||||
onBeforeDestroy: function() {
|
|
||||||
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
|
|
||||||
// Force close select2 if it hasn't closed yet
|
|
||||||
this.$('.mailpoet_posts_categories_and_tags').select2('close');
|
|
||||||
},
|
|
||||||
changeField: function(field, event) {
|
changeField: function(field, event) {
|
||||||
this.model.set(field, jQuery(event.target).val());
|
this.model.set(field, jQuery(event.target).val());
|
||||||
},
|
},
|
||||||
|
@ -56,7 +56,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
Module.getTransformedPosts = function(options) {
|
Module.getTransformedPosts = function(options) {
|
||||||
return Module._cachedQuery({
|
return Module._query({
|
||||||
action: 'getTransformedPosts',
|
action: 'getTransformedPosts',
|
||||||
options: options,
|
options: options,
|
||||||
});
|
});
|
||||||
|
@ -50,9 +50,11 @@ class MetaInformationManager {
|
|||||||
// check if the user specified a label to be displayed before the author's name
|
// check if the user specified a label to be displayed before the author's name
|
||||||
if(strlen($preceded_by) > 0) {
|
if(strlen($preceded_by) > 0) {
|
||||||
$content = stripslashes($preceded_by) . ' ';
|
$content = stripslashes($preceded_by) . ' ';
|
||||||
|
} else {
|
||||||
|
$content = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return join(', ', $categories);
|
return $content . join(', ', $categories);
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,24 @@ class PostTransformer {
|
|||||||
$structure_transformer = new StructureTransformer();
|
$structure_transformer = new StructureTransformer();
|
||||||
$structure = $structure_transformer->transform($content, (bool)$this->args['imagePadded']);
|
$structure = $structure_transformer->transform($content, (bool)$this->args['imagePadded']);
|
||||||
|
|
||||||
$structure = $this->appendFeaturedImage($post, (bool)$this->args['imagePadded'], $structure);
|
$structure = $this->appendFeaturedImage(
|
||||||
|
$post,
|
||||||
|
$this->args['displayType'],
|
||||||
|
$this->args['imagePadded'] === 'true',
|
||||||
|
$structure
|
||||||
|
);
|
||||||
$structure = $this->appendPostTitle($post, $structure);
|
$structure = $this->appendPostTitle($post, $structure);
|
||||||
$structure = $this->appendReadMore($post->ID, $structure);
|
$structure = $this->appendReadMore($post->ID, $structure);
|
||||||
|
|
||||||
return $structure;
|
return $structure;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function appendFeaturedImage($post, $image_padded, $structure) {
|
private function appendFeaturedImage($post, $display_type, $image_padded, $structure) {
|
||||||
|
if ($display_type === 'full') {
|
||||||
|
// No featured images for full posts
|
||||||
|
return $structure;
|
||||||
|
}
|
||||||
|
|
||||||
$featured_image = $this->getFeaturedImage(
|
$featured_image = $this->getFeaturedImage(
|
||||||
$post->ID,
|
$post->ID,
|
||||||
$post->post_title,
|
$post->post_title,
|
||||||
@ -68,7 +78,7 @@ class PostTransformer {
|
|||||||
|
|
||||||
return array(
|
return array(
|
||||||
'type' => 'image',
|
'type' => 'image',
|
||||||
'link' => '',
|
'link' => get_permalink($post_id),
|
||||||
'src' => $image_info[0],
|
'src' => $image_info[0],
|
||||||
'alt' => $alt_text,
|
'alt' => $alt_text,
|
||||||
'padded' => $image_padded,
|
'padded' => $image_padded,
|
||||||
@ -84,6 +94,8 @@ class PostTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function appendPostTitle($post, $structure) {
|
private function appendPostTitle($post, $structure) {
|
||||||
|
$title = $this->getPostTitle($post);
|
||||||
|
|
||||||
if ($this->args['titlePosition'] === 'inTextBlock') {
|
if ($this->args['titlePosition'] === 'inTextBlock') {
|
||||||
// Attach title to the first text block
|
// Attach title to the first text block
|
||||||
$text_block_index = null;
|
$text_block_index = null;
|
||||||
@ -94,7 +106,6 @@ class PostTransformer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$title = $this->getPostTitle($post);
|
|
||||||
if ($text_block_index === null) {
|
if ($text_block_index === null) {
|
||||||
$structure[] = array(
|
$structure[] = array(
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
@ -103,6 +114,14 @@ class PostTransformer {
|
|||||||
} else {
|
} else {
|
||||||
$structure[$text_block_index]['text'] = $title . $structure[$text_block_index]['text'];
|
$structure[$text_block_index]['text'] = $title . $structure[$text_block_index]['text'];
|
||||||
}
|
}
|
||||||
|
} elseif ($this->args['titlePosition'] === 'aboveBlock') {
|
||||||
|
array_unshift(
|
||||||
|
$structure,
|
||||||
|
array(
|
||||||
|
'type' => 'text',
|
||||||
|
'text' => $title,
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $structure;
|
return $structure;
|
||||||
@ -113,6 +132,15 @@ class PostTransformer {
|
|||||||
$button = $this->args['readMoreButton'];
|
$button = $this->args['readMoreButton'];
|
||||||
$button['url'] = get_permalink($post_id);
|
$button['url'] = get_permalink($post_id);
|
||||||
$structure[] = $button;
|
$structure[] = $button;
|
||||||
|
} else {
|
||||||
|
$structure[] = array(
|
||||||
|
'type' => 'text',
|
||||||
|
'text' => sprintf(
|
||||||
|
'<a href="%s">%s</a>',
|
||||||
|
get_permalink($post_id),
|
||||||
|
$this->args['readMoreText']
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $structure;
|
return $structure;
|
||||||
@ -121,7 +149,7 @@ class PostTransformer {
|
|||||||
private function getPostTitle($post) {
|
private function getPostTitle($post) {
|
||||||
$title = $post->post_title;
|
$title = $post->post_title;
|
||||||
|
|
||||||
if ((bool)$this->args['titleIsLink']) {
|
if ($this->args['titleIsLink'] === 'true') {
|
||||||
$title = '<a href="' . get_permalink($post->ID) . '">' . $title . '</a>';
|
$title = '<a href="' . get_permalink($post->ID) . '">' . $title . '</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
define([
|
define([
|
||||||
'newsletter_editor/App',
|
'newsletter_editor/App',
|
||||||
'newsletter_editor/components/wordpress',
|
'newsletter_editor/components/wordpress',
|
||||||
'newsletter_editor/blocks/posts',
|
'newsletter_editor/blocks/posts'
|
||||||
], function(EditorApplication, WordpressComponent, PostsBlock) {
|
], function(EditorApplication, WordpressComponent, PostsBlock) {
|
||||||
|
|
||||||
describe('Posts', function () {
|
describe('Posts', function () {
|
||||||
@ -373,12 +373,7 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('when "title as list" is selected', function() {
|
describe('when "title as list" is selected', function() {
|
||||||
var model, view;
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
model = new (PostsBlock.PostsBlockModel)();
|
|
||||||
model.request = sinon.stub().returns({$el: {}});
|
|
||||||
view = new (PostsBlock.PostsBlockSettingsView)({model: model});
|
|
||||||
view.render();
|
|
||||||
view.$('.mailpoet_posts_display_type').val('titleOnly').change();
|
view.$('.mailpoet_posts_display_type').val('titleOnly').change();
|
||||||
view.$('.mailpoet_posts_title_format').val('ul').change();
|
view.$('.mailpoet_posts_title_format').val('ul').change();
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div class="mailpoet_tools"></div>
|
<div class="mailpoet_tools"></div>
|
||||||
<div class="mailpoet_content">
|
<div class="mailpoet_content">
|
||||||
<div class="mailpoet_automated_latest_content_block_overlay"></div>
|
<div class="mailpoet_automated_latest_content_block_overlay"></div>
|
||||||
<div class="mailpoet_automated_latest_content_block_posts"></div>
|
<div class="mailpoet_automated_latest_content_block_posts"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_block_highlight"></div>
|
<div class="mailpoet_block_highlight"></div>
|
||||||
|
@ -215,7 +215,7 @@
|
|||||||
<%= __('Below text') %>
|
<%= __('Below text') %>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Categories:') %></div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Preceded by:') %></div>
|
||||||
<div class="mailpoet_form_field_input_option">
|
<div class="mailpoet_form_field_input_option">
|
||||||
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_automated_latest_content_categories" value="{{ model.categoriesPrecededBy }}" />
|
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_automated_latest_content_categories" value="{{ model.categoriesPrecededBy }}" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
{{/ifCond}}
|
{{/ifCond}}
|
||||||
|
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
|
<div class="mailpoet_form_field_title"><%= __('Alignment') %></div>
|
||||||
<div class="mailpoet_form_field_radio_option">
|
<div class="mailpoet_form_field_radio_option">
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="alignment" class="mailpoet_field_button_alignment" value="left" {{#ifCond model.styles.block.textAlign '===' 'left'}}CHECKED{{/ifCond}}/>
|
<input type="radio" name="alignment" class="mailpoet_field_button_alignment" value="left" {{#ifCond model.styles.block.textAlign '===' 'left'}}CHECKED{{/ifCond}}/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="mailpoet_tools"></div>
|
<div class="mailpoet_tools"></div>
|
||||||
<div class="mailpoet_content">
|
<div class="mailpoet_content">
|
||||||
<%= __('Your posts will be inserted here') %>
|
<div class="mailpoet_posts_block_posts"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_block_highlight"></div>
|
<div class="mailpoet_block_highlight"></div>
|
||||||
|
@ -170,7 +170,7 @@
|
|||||||
<%= __('Below text') %>
|
<%= __('Below text') %>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Categories:') %></div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Preceded by:') %></div>
|
||||||
<div class="mailpoet_form_field_input_option">
|
<div class="mailpoet_form_field_input_option">
|
||||||
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_posts_categories" value="{{ model.categoriesPrecededBy }}" />
|
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_posts_categories" value="{{ model.categoriesPrecededBy }}" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
<option value="pending"><%= __('Pending Review') %></option>
|
<option value="pending"><%= __('Pending Review') %></option>
|
||||||
<option value="private"><%= __('Private') %></option>
|
<option value="private"><%= __('Private') %></option>
|
||||||
</select></div>
|
</select></div>
|
||||||
|
<div class="mailpoet_post_selection_filter_row">
|
||||||
|
<div class="mailpoet_form_field_title"><%= __('Categories & tags:') %></div>
|
||||||
|
</div>
|
||||||
<div class="mailpoet_post_selection_filter_row">
|
<div class="mailpoet_post_selection_filter_row">
|
||||||
<select class="mailpoet_select mailpoet_posts_categories_and_tags" multiple="multiple">
|
<select class="mailpoet_select mailpoet_posts_categories_and_tags" multiple="multiple">
|
||||||
{{#each terms}}
|
{{#each terms}}
|
||||||
|
Reference in New Issue
Block a user