Bulk actions + Extra data

- fixed issue on bulk action being run even without any items selected
- added WP like feature regarding item selection, if all items are checked, it also checks the header/footer checkboxes
- fixed issue where the selection state was not properly reset
- added List column to subscribers
- added json_encode/json_decode to Twig
This commit is contained in:
Jonathan Labreuille
2015-09-23 14:13:25 +02:00
parent 239e2583d2
commit 56e40feb56
8 changed files with 113 additions and 9 deletions

View File

@@ -32,9 +32,15 @@ function(
e.preventDefault();
var action = this.getSelectedAction();
if(action === null) {
return;
}
var selected_ids = (this.props.selection !== 'all')
? this.props.selected_ids
: [];
var data = (action['getData'] !== undefined)
? action.getData()
: {};
@@ -78,17 +84,17 @@ function(
<select ref="action" value={ this.state.action } onChange={this.handleChangeAction}>
<option value="">Bulk Actions</option>
{this.props.bulk_actions.map(function(action, index) {
{ this.props.bulk_actions.map(function(action, index) {
return (
<option
value={ action.name }
key={ 'action-' + index }
>{ action.label }</option>
);
}.bind(this))}
}.bind(this)) }
</select>
<input
onClick={this.handleApplyAction}
onClick={ this.handleApplyAction }
type="submit"
defaultValue="Apply"
className="button action" />

View File

@@ -237,6 +237,10 @@ define(
}.bind(this));
},
handleBulkAction: function(selected_ids, params) {
if(this.state.selection === false) {
return;
}
this.setState({ loading: true });
var data = params || {};
@@ -275,21 +279,29 @@ define(
}.bind(this));
},
handleSelectItem: function(id, is_checked) {
var selected_ids = this.state.selected_ids;
var selected_ids = this.state.selected_ids,
selection = false;
if(is_checked) {
selected_ids = jQuery.merge(selected_ids, [ id ]);
// check whether all items on the page are selected
if(
jQuery('tbody .check-column :checkbox:not(:checked)').length === 0
) {
selection = 'page';
}
} else {
selected_ids.splice(selected_ids.indexOf(id), 1);
}
this.setState({
selection: false,
selection: selection,
selected_ids: selected_ids
});
},
handleSelectItems: function(is_checked) {
if(is_checked === false) {
this.clearSelection();
} else {
var selected_ids = this.state.items.map(function(item) {
return ~~item.id;

View File

@@ -1,6 +1,7 @@
define(
[
'react',
'react-router',
'listing/listing.jsx',
'classnames',
'mailpoet',
@@ -9,11 +10,14 @@ define(
],
function(
React,
Router,
Listing,
classNames,
MailPoet,
jQuery
) {
var Link = Router.Link;
var columns = [
{
name: 'email',
@@ -35,6 +39,12 @@ define(
label: 'Status',
sortable: true
},
{
name: 'lists',
label: 'Lists',
sortable: false
},
{
name: 'created_at',
label: 'Subscribed on',
@@ -57,7 +67,16 @@ define(
}
},
componentDidMount: function() {
this.loadItems();
// this.loadItems();
this.loadCachedItems();
},
loadCachedItems: function() {
if(typeof(window['mailpoet_'+this.props.endpoint]) !== 'undefined') {
var items = window['mailpoet_'+this.props.endpoint];
this.setState({
items: items
});
}
},
loadItems: function() {
this.setState({ loading: true });
@@ -222,11 +241,19 @@ define(
break;
}
var segments = mailpoet_segments.filter(function(segment) {
return (jQuery.inArray(segment.id, subscriber.segments) !== -1);
}).map(function(segment) {
return segment.name;
}).join(', ');
return (
<div>
<td className={ row_classes }>
<strong>
<a>{ subscriber.email }</a>
<Link to="edit" params={{ id: subscriber.id }}>
{ subscriber.email }
</Link>
</strong>
{ actions }
</td>
@@ -239,6 +266,9 @@ define(
<td className="column" data-colname="Status">
{ status }
</td>
<td className="column" data-colname="Status">
{ segments }
</td>
<td className="column-date" data-colname="Subscribed on">
<abbr>{ subscriber.created_at }</abbr>
</td>

View File

@@ -1,5 +1,6 @@
<?php
namespace MailPoet\Config;
use \MailPoet\Models\Segment;
if(!defined('ABSPATH')) exit;
@@ -80,6 +81,9 @@ class Menu {
function subscribers() {
$data = array();
$data['segments'] = Segment::findArray();
echo $this->renderer->render('subscribers.html', $data);
}

View File

@@ -18,6 +18,7 @@ class Renderer {
function init() {
$this->setupTranslations();
$this->setupFunctions();
$this->setupHandlebars();
$this->setupGlobalVariables();
$this->setupSyntax();
@@ -28,6 +29,10 @@ class Renderer {
$this->renderer->addExtension(new Twig\i18n(Env::$plugin_name));
}
function setupFunctions() {
$this->renderer->addExtension(new Twig\Functions());
}
function setupHandlebars() {
$this->renderer->addExtension(new Twig\Handlebars());
}
@@ -51,7 +56,9 @@ class Renderer {
function detectCache() {
$cache_path = Env::$views_path . '/cache';
if (WP_DEBUG === false) return $cache_path;
if(WP_DEBUG === false) {
return $cache_path;
}
return false;
}
}

View File

@@ -27,7 +27,21 @@ class Subscribers {
\Model::factory('\MailPoet\Models\Subscriber'),
$data
);
wp_send_json($listing->get());
$listing_data = $listing->get();
// fetch segments relations for each returned item
foreach($listing_data['items'] as &$item) {
$segments = SubscriberSegment::select('segment_id')
->where('subscriber_id', $item['id'])
->findMany();
$item['segments'] = array_map(function($relation) {
return $relation->segment_id;
}, $segments);
}
wp_send_json($listing_data);
}
function getAll() {

27
lib/Twig/Functions.php Normal file
View File

@@ -0,0 +1,27 @@
<?php
namespace MailPoet\Twig;
class Functions extends \Twig_Extension {
public function __construct() {
}
public function getName() {
return 'functions';
}
public function getFunctions() {
return array(
new \Twig_SimpleFunction(
'json_encode',
'json_encode',
array('is_safe' => array('all'))
),
new \Twig_SimpleFunction(
'json_decode',
'json_decode',
array('is_safe' => array('all'))
)
);
}
}

View File

@@ -12,4 +12,8 @@
'selectAllLink': __('Select all pages.'),
'clearSelection': __('Clear selection.')
}) %>
<script type="text/javascript">
var mailpoet_segments = <%= json_encode(segments) %>;
</script>
<% endblock %>