Merge pull request #229 from mailpoet/editor_posts

Editor: Posts widget
This commit is contained in:
Marco
2015-11-19 10:31:31 +01:00
14 changed files with 101 additions and 49 deletions

View File

@ -19,6 +19,10 @@ $divider-hover-border-color = $primary-active-color
width: 100%
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
border: 1px solid $divider-hover-border-color

View File

@ -1,15 +1,12 @@
.mailpoet_posts_block
box-shadow(none)
padding-left: 0
padding-right: 0
& > .mailpoet_content
font-size: 1em
text-align: center
background-color: $primary-active-color
margin: 20px 0
padding: 15px
box-shadow(inset 1px 2px 1px $primary-inset-shadow-color)
color: $white-color
border-radius(3px)
.mailpoet_posts_block_posts
overflow: auto
& > .mailpoet_block
width: 100%
.mailpoet_post_selection_filter_row
margin-top: 5px

View File

@ -214,6 +214,7 @@ define([
this.model.set(field, value);
},
onBeforeDestroy: function() {
console.log('Calling close');
MailPoet.Modal.close();
},
});

View File

@ -31,7 +31,7 @@ define([
base = BaseBlock;
Module.PostsBlockModel = base.BlockModel.extend({
stale: ['_selectedPosts', '_availablePosts'],
stale: ['_selectedPosts', '_availablePosts', '_transformedPosts'],
defaults: function() {
return this._getDefaults({
type: 'posts',
@ -63,6 +63,7 @@ define([
divider: {},
_selectedPosts: [],
_availablePosts: [],
_transformedPosts: new (App.getBlockTypeModel('container'))(),
}, App.getConfig().get('blockDefaults.posts'));
},
relations: function() {
@ -71,15 +72,26 @@ define([
divider: App.getBlockTypeModel('divider'),
_selectedPosts: Backbone.Collection,
_availablePosts: Backbone.Collection,
_transformedPosts: App.getBlockTypeModel('container'),
};
},
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
_.extend(this, Radio.Requests);
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);
},
fetchAvailablePosts: function() {
@ -93,20 +105,23 @@ define([
console.log('Posts fetchPosts error', arguments);
});
},
/**
* Batch more changes during a specific time, instead of fetching
* ALC posts on each model change
*/
_scheduleFetchAvailablePosts: function() {
var timeout = 500,
that = this;
if (this._fetchPostsTimer !== undefined) {
clearTimeout(this._fetchPostsTimer);
_refreshTransformedPosts: function() {
var that = this,
data = this.toJSON();
data.posts = this.get('_selectedPosts').pluck('ID');
if (data.posts.length === 0) {
this.get('_transformedPosts.blocks').reset();
return;
}
this._fetchPostsTimer = setTimeout(function() {
that.fetchAvailablePosts();
that._fetchPostsTimer = undefined;
}, timeout);
WordpressComponent.getTransformedPosts(data).done(function(posts) {
console.log('Transformed posts fetched', arguments);
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
}).fail(function() {
console.log('Posts _refreshTransformedPosts error', arguments);
});
},
_insertSelectedPosts: function() {
var that = this,
@ -131,6 +146,9 @@ define([
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
getTemplate: function() { return templates.postsBlock; },
modelEvents: {},
regions: _.extend({
postsRegion: '.mailpoet_posts_block_posts',
}, base.BlockView.prototype.regions),
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
initialize: function() {
base.BlockView.prototype.initialize.apply(this, arguments);
@ -142,6 +160,13 @@ define([
this.toolsRegion.show(this.toolsView);
}
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() {
return this;
@ -216,6 +241,7 @@ define([
insertPosts: function() {
this.model.trigger('insertSelectedPosts');
this.model.destroy();
this.close();
},
});
@ -307,11 +333,6 @@ define([
},
}).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) {
this.model.set(field, jQuery(event.target).val());
},

View File

@ -56,7 +56,7 @@ define([
};
Module.getTransformedPosts = function(options) {
return Module._cachedQuery({
return Module._query({
action: 'getTransformedPosts',
options: options,
});

View File

@ -50,9 +50,11 @@ class MetaInformationManager {
// check if the user specified a label to be displayed before the author's name
if(strlen($preceded_by) > 0) {
$content = stripslashes($preceded_by) . ' ';
} else {
$content = '';
}
return join(', ', $categories);
return $content . join(', ', $categories);
} else {
return '';
}

View File

@ -24,14 +24,24 @@ class PostTransformer {
$structure_transformer = new StructureTransformer();
$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->appendReadMore($post->ID, $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(
$post->ID,
$post->post_title,
@ -68,7 +78,7 @@ class PostTransformer {
return array(
'type' => 'image',
'link' => '',
'link' => get_permalink($post_id),
'src' => $image_info[0],
'alt' => $alt_text,
'padded' => $image_padded,
@ -84,6 +94,8 @@ class PostTransformer {
}
private function appendPostTitle($post, $structure) {
$title = $this->getPostTitle($post);
if ($this->args['titlePosition'] === 'inTextBlock') {
// Attach title to the first text block
$text_block_index = null;
@ -94,7 +106,6 @@ class PostTransformer {
}
}
$title = $this->getPostTitle($post);
if ($text_block_index === null) {
$structure[] = array(
'type' => 'text',
@ -103,6 +114,14 @@ class PostTransformer {
} else {
$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;
@ -113,6 +132,15 @@ class PostTransformer {
$button = $this->args['readMoreButton'];
$button['url'] = get_permalink($post_id);
$structure[] = $button;
} else {
$structure[] = array(
'type' => 'text',
'text' => sprintf(
'<a href="%s">%s</a>',
get_permalink($post_id),
$this->args['readMoreText']
),
);
}
return $structure;
@ -121,7 +149,7 @@ class PostTransformer {
private function getPostTitle($post) {
$title = $post->post_title;
if ((bool)$this->args['titleIsLink']) {
if ($this->args['titleIsLink'] === 'true') {
$title = '<a href="' . get_permalink($post->ID) . '">' . $title . '</a>';
}

View File

@ -1,7 +1,7 @@
define([
'newsletter_editor/App',
'newsletter_editor/components/wordpress',
'newsletter_editor/blocks/posts',
'newsletter_editor/blocks/posts'
], function(EditorApplication, WordpressComponent, PostsBlock) {
describe('Posts', function () {
@ -373,12 +373,7 @@ define([
});
describe('when "title as list" is selected', function() {
var model, view;
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_title_format').val('ul').change();
});

View File

@ -1,6 +1,6 @@
<div class="mailpoet_tools"></div>
<div class="mailpoet_content">
<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_overlay"></div>
<div class="mailpoet_automated_latest_content_block_posts"></div>
</div>
<div class="mailpoet_block_highlight"></div>

View File

@ -215,7 +215,7 @@
<%= __('Below text') %>
</label>
</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">
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_automated_latest_content_categories" value="{{ model.categoriesPrecededBy }}" />
</div>

View File

@ -20,6 +20,7 @@
{{/ifCond}}
<div class="mailpoet_form_field">
<div class="mailpoet_form_field_title"><%= __('Alignment') %></div>
<div class="mailpoet_form_field_radio_option">
<label>
<input type="radio" name="alignment" class="mailpoet_field_button_alignment" value="left" {{#ifCond model.styles.block.textAlign '===' 'left'}}CHECKED{{/ifCond}}/>

View File

@ -1,5 +1,5 @@
<div class="mailpoet_tools"></div>
<div class="mailpoet_content">
<%= __('Your posts will be inserted here') %>
<div class="mailpoet_posts_block_posts"></div>
</div>
<div class="mailpoet_block_highlight"></div>

View File

@ -170,7 +170,7 @@
<%= __('Below text') %>
</label>
</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">
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_posts_categories" value="{{ model.categoriesPrecededBy }}" />
</div>

View File

@ -13,6 +13,9 @@
<option value="pending"><%= __('Pending Review') %></option>
<option value="private"><%= __('Private') %></option>
</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">
<select class="mailpoet_select mailpoet_posts_categories_and_tags" multiple="multiple">
{{#each terms}}