many improvements on listing + cleaned up modal library
This commit is contained in:
committed by
marco
parent
739f06bad7
commit
0e2c04d97a
@ -1,8 +1,7 @@
|
|||||||
define('admin', [
|
define('admin', [
|
||||||
'mailpoet',
|
|
||||||
'jquery'
|
'jquery'
|
||||||
],
|
],
|
||||||
function(MailPoet, jQuery) {
|
function(jQuery) {
|
||||||
jQuery(function($) {
|
jQuery(function($) {
|
||||||
// dom ready
|
// dom ready
|
||||||
$(function() {
|
$(function() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
define('ajax', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
define('ajax', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||||
"use strict";
|
'use strict';
|
||||||
MailPoet.Ajax = {
|
MailPoet.Ajax = {
|
||||||
version: 0.5,
|
version: 0.5,
|
||||||
options: {},
|
options: {},
|
||||||
|
48
assets/js/src/listing/column.jsx
Normal file
48
assets/js/src/listing/column.jsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
define('listing.column', ['react', 'classnames'], function(React, classNames) {
|
||||||
|
/*
|
||||||
|
props:
|
||||||
|
onSort -> callback(sort_by, sort_order)
|
||||||
|
column -> {
|
||||||
|
sorted: (string) asc | desc
|
||||||
|
sortable: (bool)
|
||||||
|
name: (string) field name
|
||||||
|
label: (string) displayed label
|
||||||
|
*/
|
||||||
|
var ListingColumn = React.createClass({
|
||||||
|
handleSort: function() {
|
||||||
|
var sort_by = this.props.column.name,
|
||||||
|
sort_order = (this.props.column.sorted === 'asc') ? 'desc' : 'asc';
|
||||||
|
this.props.onSort(sort_by, sort_order);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var classes = classNames(
|
||||||
|
'manage-column',
|
||||||
|
{ 'sortable': this.props.column.sortable },
|
||||||
|
this.props.column.sorted
|
||||||
|
);
|
||||||
|
|
||||||
|
var label;
|
||||||
|
|
||||||
|
if(this.props.column.sortable === true) {
|
||||||
|
label = (
|
||||||
|
<a onClick={this.handleSort}>
|
||||||
|
<span>{ this.props.column.label }</span>
|
||||||
|
<span className="sorting-indicator"></span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
label = this.props.column.label;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<th
|
||||||
|
className={ classes }
|
||||||
|
id={this.props.column.name }
|
||||||
|
scope="col">
|
||||||
|
{label}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ListingColumn;
|
||||||
|
});
|
51
assets/js/src/listing/header.jsx
Normal file
51
assets/js/src/listing/header.jsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
define('listing.header', ['react', 'classnames'], function(React, classNames) {
|
||||||
|
/*
|
||||||
|
props:
|
||||||
|
onSort: callback(sort_by, sort_order)
|
||||||
|
onSelectAll: callback(is_checked)
|
||||||
|
sort_by: (string) field name
|
||||||
|
columns -> (array)
|
||||||
|
column -> {
|
||||||
|
sorted: (string) asc | desc
|
||||||
|
sortable: (bool)
|
||||||
|
name: (string) field name
|
||||||
|
label: (string) displayed label
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
var ListingColumn = require('listing/column.jsx');
|
||||||
|
var ListingHeader = React.createClass({
|
||||||
|
handleSelectAll: function() {
|
||||||
|
return this.props.onSelectAll(
|
||||||
|
this.refs.select_all.getDOMNode().checked
|
||||||
|
);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var columns = this.props.columns.map(function(column) {
|
||||||
|
return (
|
||||||
|
<ListingColumn
|
||||||
|
onSort={this.props.onSort}
|
||||||
|
sort_by={this.props.sort_by}
|
||||||
|
key={column.name}
|
||||||
|
column={column} />
|
||||||
|
);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td className="manage-column column-cb check-column" id="cb">
|
||||||
|
<label className="screen-reader-text">
|
||||||
|
{ 'Select All' }
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
ref="select_all"
|
||||||
|
onChange={this.handleSelectAll} />
|
||||||
|
</td>
|
||||||
|
{columns}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ListingHeader;
|
||||||
|
});
|
143
assets/js/src/listing/pages.jsx
Normal file
143
assets/js/src/listing/pages.jsx
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
define('listing.pages', ['react', 'classnames'], function(React, classNames) {
|
||||||
|
/*
|
||||||
|
props:
|
||||||
|
onSetPage -> callback(page)
|
||||||
|
page -> (int) current page
|
||||||
|
count -> (int) total number of items
|
||||||
|
limit -> (int) limit per page
|
||||||
|
*/
|
||||||
|
var ListingPages = React.createClass({
|
||||||
|
setFirstPage: function() {
|
||||||
|
this.props.onSetPage(1);
|
||||||
|
},
|
||||||
|
setLastPage: function() {
|
||||||
|
this.props.onSetPage(this.getLastPage());
|
||||||
|
},
|
||||||
|
setPreviousPage: function() {
|
||||||
|
this.props.onSetPage(this.constrainPage(this.props.page - 1));
|
||||||
|
},
|
||||||
|
setNextPage: function() {
|
||||||
|
this.props.onSetPage(this.constrainPage(this.props.page + 1));
|
||||||
|
},
|
||||||
|
constrainPage: function(page) {
|
||||||
|
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
|
||||||
|
},
|
||||||
|
handleSetPage: function() {
|
||||||
|
this.props.onSetPage(
|
||||||
|
this.constrainPage(this.refs.page.getDOMNode().value)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getLastPage: function() {
|
||||||
|
return Math.ceil(this.props.count / this.props.limit);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
if(this.props.count === 0) {
|
||||||
|
return (<div></div>);
|
||||||
|
} else {
|
||||||
|
var pagination,
|
||||||
|
firstPage = (
|
||||||
|
<span aria-hidden="true" className="tablenav-pages-navspan">«</span>
|
||||||
|
),
|
||||||
|
previousPage = (
|
||||||
|
<span aria-hidden="true" className="tablenav-pages-navspan">‹</span>
|
||||||
|
),
|
||||||
|
nextPage = (
|
||||||
|
<span aria-hidden="true" className="tablenav-pages-navspan">›</span>
|
||||||
|
),
|
||||||
|
lastPage = (
|
||||||
|
<span aria-hidden="true" className="tablenav-pages-navspan">»</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
if(this.props.count > this.props.limit) {
|
||||||
|
if(this.props.page > 1) {
|
||||||
|
previousPage = (
|
||||||
|
<a href="javascript:;"
|
||||||
|
onClick={this.setPreviousPage}
|
||||||
|
className="prev-page">
|
||||||
|
<span className="screen-reader-text">Previous page</span>
|
||||||
|
<span aria-hidden="true">‹</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.props.page > 2) {
|
||||||
|
firstPage = (
|
||||||
|
<a href="javascript:;"
|
||||||
|
onClick={this.setFirstPage}
|
||||||
|
className="first-page">
|
||||||
|
<span className="screen-reader-text">First page</span>
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.props.page < this.getLastPage()) {
|
||||||
|
nextPage = (
|
||||||
|
<a href="javascript:;"
|
||||||
|
onClick={this.setNextPage}
|
||||||
|
className="next-page">
|
||||||
|
<span className="screen-reader-text">Next page</span>
|
||||||
|
<span aria-hidden="true">›</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.props.page < this.getLastPage() - 1) {
|
||||||
|
lastPage = (
|
||||||
|
<a href="javascript:;"
|
||||||
|
onClick={this.setLastPage}
|
||||||
|
className="last-page">
|
||||||
|
<span className="screen-reader-text">Last page</span>
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pagination = (
|
||||||
|
<span className="pagination-links">
|
||||||
|
{firstPage}
|
||||||
|
{previousPage}
|
||||||
|
|
||||||
|
<span className="paging-input">
|
||||||
|
<label
|
||||||
|
className="screen-reader-text"
|
||||||
|
htmlFor="current-page-selector">Current Page</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
onChange={this.handleSetPage}
|
||||||
|
aria-describedby="table-paging"
|
||||||
|
size="1"
|
||||||
|
ref="page"
|
||||||
|
value={this.props.page}
|
||||||
|
name="paged"
|
||||||
|
id="current-page-selector"
|
||||||
|
className="current-page" />
|
||||||
|
of
|
||||||
|
<span className="total-pages">
|
||||||
|
{Math.ceil(this.props.count / this.props.limit)}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{nextPage}
|
||||||
|
{lastPage}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var classes = classNames(
|
||||||
|
'tablenav-pages',
|
||||||
|
{ 'one-page': (this.props.count <= this.props.limit) }
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes}>
|
||||||
|
<span className="displaying-num">{ this.props.count } item(s)</span>
|
||||||
|
{ pagination }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ListingPages;
|
||||||
|
});
|
36
assets/js/src/listing/search.jsx
Normal file
36
assets/js/src/listing/search.jsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
define('listing.search', ['react'], function(React) {
|
||||||
|
/*
|
||||||
|
props:
|
||||||
|
onSearch -> callback(search)
|
||||||
|
search -> string
|
||||||
|
*/
|
||||||
|
var ListingSearch = React.createClass({
|
||||||
|
handleSearch: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onSearch(
|
||||||
|
this.refs.search.getDOMNode().value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<form name="search" onSubmit={this.handleSearch}>
|
||||||
|
<p className="search-box">
|
||||||
|
<label htmlFor="search_input" className="screen-reader-text">
|
||||||
|
Search
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
ref="search"
|
||||||
|
defaultValue={this.props.search} />
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
defaultValue="Search"
|
||||||
|
className="button" />
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ListingSearch;
|
||||||
|
});
|
@ -1,84 +1,27 @@
|
|||||||
define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
define('modal', ['mailpoet', 'jquery'],
|
||||||
"use strict";
|
function(MailPoet, jQuery) {
|
||||||
/*==================================================================================================
|
'use strict';
|
||||||
|
/***************************************************************************
|
||||||
MailPoet Modal:
|
MailPoet Modal:
|
||||||
|
|
||||||
version: 0.8
|
version: 0.9
|
||||||
author: Jonathan Labreuille
|
author: Jonathan Labreuille
|
||||||
company: Wysija
|
company: Wysija
|
||||||
dependencies: jQuery
|
dependencies: jQuery
|
||||||
|
|
||||||
|
|
||||||
Options:
|
|
||||||
|
|
||||||
Mandatory:
|
|
||||||
// Modal window's title
|
|
||||||
(string) title: 'Modal title'
|
|
||||||
|
|
||||||
// template
|
|
||||||
(string) template: jQuery('#handlebars_template').html() or
|
|
||||||
literal html
|
|
||||||
|
|
||||||
Optional:
|
|
||||||
// jQuery cached element object node to be displayed,
|
|
||||||
// instead of creating a new one
|
|
||||||
(object) element: jQuery(selector)
|
|
||||||
|
|
||||||
// - data object that will be passed to the template when rendering
|
|
||||||
(object) data: {},
|
|
||||||
|
|
||||||
// - data will be loaded via this url and passed to the template
|
|
||||||
// when rendering
|
|
||||||
// - if a "data" option was specified, it will be merged with the
|
|
||||||
// ajax's response data
|
|
||||||
(string) url: '/url.json'
|
|
||||||
|
|
||||||
// ajax method
|
|
||||||
(string) method: 'post' (default: 'get')
|
|
||||||
|
|
||||||
// ajax post params
|
|
||||||
(object) params: {}
|
|
||||||
|
|
||||||
// - integers are expressed in pixels
|
|
||||||
(mixed) width: '50%' | 100 | '100px'
|
|
||||||
|
|
||||||
// - integers are expressed in pixels
|
|
||||||
// - will be ignored when in "panel" mode
|
|
||||||
(mixed) height: '50%' | 100 | '100px'
|
|
||||||
|
|
||||||
// - only used for "panel" mode
|
|
||||||
// - will be ignored in "popup" mode
|
|
||||||
(string) position: 'left' | 'right'
|
|
||||||
|
|
||||||
// display overlay or not
|
|
||||||
(boolean) overlay: true | false
|
|
||||||
|
|
||||||
// element(s) to be highlighted when the overlay is "on"
|
|
||||||
(object) highlight: jQuery element
|
|
||||||
|
|
||||||
// callbacks
|
|
||||||
(function) onInit: called when the modal is displayed
|
|
||||||
(function) onSuccess: called by calling MailPoet_Guide.success()
|
|
||||||
(function) onCancel: called when closing the popup
|
|
||||||
or by calling MailPoet_Guide.cancel()
|
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
// popup mode
|
// popup mode
|
||||||
MailPoet.Modal.popup(options);
|
MailPoet.Modal.popup(options);
|
||||||
|
|
||||||
// panel mode
|
// panel mode
|
||||||
MailPoet.Modal.panel(options);
|
MailPoet.Modal.panel(options);
|
||||||
|
|
||||||
// loading states
|
// loading mode
|
||||||
MailPoet.Modal.loading(true); // displays loading indicator
|
MailPoet.Modal.loading(bool);
|
||||||
MailPoet.Modal.loading(false); // hides loading indicator
|
***************************************************************************/
|
||||||
|
|
||||||
==================================================================================================*/
|
|
||||||
|
|
||||||
MailPoet.Modal = {
|
MailPoet.Modal = {
|
||||||
version: 0.8,
|
version: 0.9,
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
initialized: false,
|
initialized: false,
|
||||||
@ -150,8 +93,12 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
'<div class="mailpoet_panel_body clearfix"></div>'+
|
'<div class="mailpoet_panel_body clearfix"></div>'+
|
||||||
'</div>'
|
'</div>'
|
||||||
},
|
},
|
||||||
setRenderer: function() {
|
getContentContainer: function() {
|
||||||
this.renderer = (typeof(Handlebars) === "undefined") ? 'html' : 'handlebars';
|
return jQuery('.mailpoet_'+this.options.type+'_body');
|
||||||
|
},
|
||||||
|
setRenderer: function(renderer) {
|
||||||
|
this.renderer = renderer;
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
compileTemplate: function(template) {
|
compileTemplate: function(template) {
|
||||||
if(this.renderer === 'html') {
|
if(this.renderer === 'html') {
|
||||||
@ -159,17 +106,17 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
} else {
|
} else {
|
||||||
return Handlebars.compile(template);
|
return Handlebars.compile(template);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
init: function(options) {
|
init: function(options) {
|
||||||
if(this.initialized === true) {
|
if(this.initialized === true) {
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge options
|
// merge options
|
||||||
this.options = jQuery.extend({}, this.defaults, options);
|
this.options = jQuery.extend({}, this.defaults, options);
|
||||||
|
|
||||||
// set renderer
|
// set renderer
|
||||||
this.setRenderer();
|
this.setRenderer(this.options.renderer);
|
||||||
|
|
||||||
// init overlay
|
// init overlay
|
||||||
this.initOverlay();
|
this.initOverlay();
|
||||||
@ -180,14 +127,19 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
if(this.options.type !== null) {
|
if(this.options.type !== null) {
|
||||||
// insert modal depending on its type
|
// insert modal depending on its type
|
||||||
if(this.options.type === 'popup') {
|
if(this.options.type === 'popup') {
|
||||||
var modal = this.compileTemplate(this.templates[this.options.type]);
|
var modal = this.compileTemplate(
|
||||||
|
this.templates[this.options.type]
|
||||||
|
);
|
||||||
// create modal
|
// create modal
|
||||||
jQuery('#mailpoet_modal_overlay').append(modal(this.options));
|
jQuery('#mailpoet_modal_overlay')
|
||||||
|
.append(modal(this.options));
|
||||||
// set title
|
// set title
|
||||||
jQuery('#mailpoet_popup_title h2').html(this.options.title);
|
jQuery('#mailpoet_popup_title h2')
|
||||||
|
.html(this.options.title);
|
||||||
} else if(this.options.type === 'panel') {
|
} else if(this.options.type === 'panel') {
|
||||||
// create panel
|
// create panel
|
||||||
jQuery('#mailpoet_modal_overlay').after(this.templates[this.options.type]);
|
jQuery('#mailpoet_modal_overlay')
|
||||||
|
.after(this.templates[this.options.type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add proper overlay class
|
// add proper overlay class
|
||||||
@ -196,8 +148,6 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
.addClass('mailpoet_'+this.options.type+'_overlay');
|
.addClass('mailpoet_'+this.options.type+'_overlay');
|
||||||
}
|
}
|
||||||
|
|
||||||
// render template if specified
|
|
||||||
if(this.options.template !== null) {
|
|
||||||
// set "success" callback if specified
|
// set "success" callback if specified
|
||||||
if(options.onSuccess !== undefined) {
|
if(options.onSuccess !== undefined) {
|
||||||
this.options.onSuccess = options.onSuccess;
|
this.options.onSuccess = options.onSuccess;
|
||||||
@ -209,11 +159,12 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compile template
|
// compile template
|
||||||
this.options.body_template = this.compileTemplate(this.options.template);
|
this.options.body_template = this.compileTemplate(
|
||||||
|
this.options.template
|
||||||
|
);
|
||||||
|
|
||||||
// setup events
|
// setup events
|
||||||
this.setupEvents();
|
this.setupEvents();
|
||||||
}
|
|
||||||
|
|
||||||
// set popup as initialized
|
// set popup as initialized
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
@ -231,9 +182,11 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
},
|
},
|
||||||
toggleOverlay: function(toggle) {
|
toggleOverlay: function(toggle) {
|
||||||
if(toggle === true) {
|
if(toggle === true) {
|
||||||
jQuery('#mailpoet_modal_overlay').removeClass('mailpoet_overlay_hidden');
|
jQuery('#mailpoet_modal_overlay')
|
||||||
|
.removeClass('mailpoet_overlay_hidden');
|
||||||
} else {
|
} else {
|
||||||
jQuery('#mailpoet_modal_overlay').addClass('mailpoet_overlay_hidden');
|
jQuery('#mailpoet_modal_overlay')
|
||||||
|
.addClass('mailpoet_overlay_hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -245,8 +198,8 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
// close popup when user clicks on overlay
|
// close popup when user clicks on overlay
|
||||||
jQuery('#mailpoet_modal_overlay').on('click', function(e) {
|
jQuery('#mailpoet_modal_overlay').on('click', function(e) {
|
||||||
// we need to make sure that we are actually clicking on the overlay
|
// we need to make sure that we are actually clicking on the overlay
|
||||||
// because when clicking on the popup content, it will trigger the click
|
// because when clicking on the popup content, it will trigger
|
||||||
// event on the overlay
|
// the click event on the overlay
|
||||||
if(e.target.id === 'mailpoet_modal_overlay') { this.cancel(); }
|
if(e.target.id === 'mailpoet_modal_overlay') { this.cancel(); }
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
@ -292,15 +245,19 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
jQuery('.mailpoet_'+this.options.type+'_wrapper').hide();
|
jQuery('.mailpoet_'+this.options.type+'_wrapper').hide();
|
||||||
|
|
||||||
// add sub panel wrapper
|
// add sub panel wrapper
|
||||||
jQuery('#mailpoet_'+this.options.type).append(this.templates['subpanel']);
|
jQuery('#mailpoet_'+this.options.type)
|
||||||
|
.append(this.templates['subpanel']);
|
||||||
|
|
||||||
// add sub panel content
|
// add sub panel content
|
||||||
jQuery('.mailpoet_'+this.options.type+'_body').last().html(this.subpanels[(this.subpanels.length - 1)].element);
|
jQuery('.mailpoet_'+this.options.type+'_body').last()
|
||||||
|
.html(this.subpanels[(this.subpanels.length - 1)].element);
|
||||||
} else if (this.options.element) {
|
} else if (this.options.element) {
|
||||||
jQuery('.mailpoet_'+this.options.type+'_body').empty();
|
jQuery('.mailpoet_'+this.options.type+'_body').empty();
|
||||||
jQuery('.mailpoet_'+this.options.type+'_body').append(this.options.element);
|
jQuery('.mailpoet_'+this.options.type+'_body')
|
||||||
|
.append(this.options.element);
|
||||||
} else {
|
} else {
|
||||||
jQuery('.mailpoet_'+this.options.type+'_body').html(
|
jQuery('.mailpoet_'+this.options.type+'_body')
|
||||||
|
.html(
|
||||||
this.options.body_template(
|
this.options.body_template(
|
||||||
this.options.data
|
this.options.data
|
||||||
)
|
)
|
||||||
@ -312,24 +269,27 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
loadUrl: function() {
|
loadUrl: function() {
|
||||||
if(this.options.method === 'get') {
|
if(this.options.method === 'get') {
|
||||||
// make ajax request
|
// make ajax request
|
||||||
jQuery.getJSON(this.options.url, function(data) {
|
jQuery.getJSON(this.options.url,
|
||||||
// merge returned data with existing data passed when calling the "open" method
|
function(data) {
|
||||||
this.options.data = jQuery.extend({}, this.options.data, data);
|
this.options.data = jQuery.extend({}, this.options.data, data);
|
||||||
// load template using fetched data
|
// load template using fetched data
|
||||||
this.loadTemplate();
|
this.loadTemplate();
|
||||||
// show modal window
|
// show modal window
|
||||||
this.showModal();
|
this.showModal();
|
||||||
}.bind(this));
|
}.bind(this)
|
||||||
|
);
|
||||||
} else if(this.options.method === 'post') {
|
} else if(this.options.method === 'post') {
|
||||||
// make ajax request
|
// make ajax request
|
||||||
jQuery.post(this.options.url, JSON.stringify(this.options.params), function(data) {
|
jQuery.post(this.options.url, JSON.stringify(this.options.params),
|
||||||
// merge returned data with existing data passed when calling the "open" method
|
function(data) {
|
||||||
this.options.data = jQuery.extend({}, this.options.data, data);
|
this.options.data = jQuery.extend({}, this.options.data, data);
|
||||||
// load template using fetched data
|
// load template using fetched data
|
||||||
this.loadTemplate();
|
this.loadTemplate();
|
||||||
// show modal window
|
// show modal window
|
||||||
this.showModal();
|
this.showModal();
|
||||||
}.bind(this), 'json');
|
}.bind(this),
|
||||||
|
'json'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -343,7 +303,9 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
minHeight: this.options.height
|
minHeight: this.options.height
|
||||||
});
|
});
|
||||||
// set popup wrapper height
|
// set popup wrapper height
|
||||||
jQuery('#mailpoet_popup_wrapper').css({ height: this.options.height});
|
jQuery('#mailpoet_popup_wrapper').css({
|
||||||
|
height: this.options.height
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case 'panel':
|
case 'panel':
|
||||||
// set dimensions
|
// set dimensions
|
||||||
@ -389,13 +351,13 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
// set position of popup depending on screen dimensions.
|
// set position of popup depending on screen dimensions.
|
||||||
if(this.options.position === 'right') {
|
if(this.options.position === 'right') {
|
||||||
jQuery('#mailpoet_panel').css(
|
jQuery('#mailpoet_panel').css({
|
||||||
{ marginRight: 0 }
|
marginRight: 0
|
||||||
);
|
});
|
||||||
} else if(this.options.position === 'left') {
|
} else if(this.options.position === 'left') {
|
||||||
jQuery('#mailpoet_panel').css(
|
jQuery('#mailpoet_panel').css({
|
||||||
{ marginLeft: 0 }
|
marginLeft: 0
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
}.bind(this), 0);
|
}.bind(this), 0);
|
||||||
break;
|
break;
|
||||||
@ -407,7 +369,7 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
// set modal dimensions
|
// set modal dimensions
|
||||||
this.setDimensions();
|
this.setDimensions();
|
||||||
|
|
||||||
// add a flag on the body so that we can prevent scrolling (setting overflow hidden)
|
// add a flag on the body so that we can prevent scrolling
|
||||||
jQuery('body').addClass('mailpoet_modal_opened');
|
jQuery('body').addClass('mailpoet_modal_opened');
|
||||||
|
|
||||||
// show popup
|
// show popup
|
||||||
@ -431,7 +393,7 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
|
|
||||||
// trigger init event if specified
|
// trigger init event if specified
|
||||||
if(this.options.onInit !== null) {
|
if(this.options.onInit !== null) {
|
||||||
this.options.onInit();
|
this.options.onInit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -441,7 +403,8 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
highlightOff: function() {
|
highlightOff: function() {
|
||||||
jQuery('.mailpoet_modal_highlight').removeClass('mailpoet_modal_highlight');
|
jQuery('.mailpoet_modal_highlight')
|
||||||
|
.removeClass('mailpoet_modal_highlight');
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
hideModal: function(callback) {
|
hideModal: function(callback) {
|
||||||
@ -530,7 +493,8 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
jQuery('#mailpoet_loading').show();
|
jQuery('#mailpoet_loading').show();
|
||||||
|
|
||||||
// add loading class to overlay
|
// add loading class to overlay
|
||||||
jQuery('#mailpoet_modal_overlay').addClass('mailpoet_overlay_loading');
|
jQuery('#mailpoet_modal_overlay')
|
||||||
|
.addClass('mailpoet_overlay_loading');
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
@ -538,7 +502,8 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
jQuery('#mailpoet_loading').hide();
|
jQuery('#mailpoet_loading').hide();
|
||||||
|
|
||||||
// remove loading class from overlay
|
// remove loading class from overlay
|
||||||
jQuery('#mailpoet_modal_overlay').removeClass('mailpoet_overlay_loading');
|
jQuery('#mailpoet_modal_overlay')
|
||||||
|
.removeClass('mailpoet_overlay_loading');
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
@ -602,10 +567,9 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
if(this.isLocked() === true) return this;
|
if(this.isLocked() === true) { return this; }
|
||||||
|
|
||||||
if(this.subpanels.length > 0) {
|
if(this.subpanels.length > 0) {
|
||||||
|
|
||||||
// close subpanel
|
// close subpanel
|
||||||
jQuery('.mailpoet_'+this.options.type+'_wrapper').last().remove();
|
jQuery('.mailpoet_'+this.options.type+'_wrapper').last().remove();
|
||||||
|
|
||||||
@ -636,4 +600,6 @@ define('modal', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
@ -2,6 +2,11 @@ define('subscribers.listing',
|
|||||||
['mailpoet', 'jquery', 'react/addons', 'classnames'],
|
['mailpoet', 'jquery', 'react/addons', 'classnames'],
|
||||||
function(MailPoet, jQuery, React, classNames) {
|
function(MailPoet, jQuery, React, classNames) {
|
||||||
|
|
||||||
|
var ListingSearch = require('listing/search.jsx');
|
||||||
|
var ListingPages = require('listing/pages.jsx');
|
||||||
|
var ListingColumn = require('listing/column.jsx');
|
||||||
|
var ListingHeader = require('listing/header.jsx');
|
||||||
|
|
||||||
var ListingGroups = React.createClass({
|
var ListingGroups = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
@ -23,35 +28,6 @@ define('subscribers.listing',
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var ListingSearch = React.createClass({
|
|
||||||
handleSearch: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.onSearch(
|
|
||||||
this.refs.search.getDOMNode().value
|
|
||||||
);
|
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
return (
|
|
||||||
<form name="search" onSubmit={this.handleSearch}>
|
|
||||||
<p className="search-box">
|
|
||||||
<label htmlFor="search_input" className="screen-reader-text">
|
|
||||||
Search
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="search"
|
|
||||||
ref="search"
|
|
||||||
id="search_input"
|
|
||||||
defaultValue={this.props.search} />
|
|
||||||
<input
|
|
||||||
type="submit"
|
|
||||||
defaultValue="Search"
|
|
||||||
className="button" />
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var ListingFilters = React.createClass({
|
var ListingFilters = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
@ -60,222 +36,110 @@ define('subscribers.listing',
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var ListingPages = React.createClass({
|
var ListSelector = React.createClass({
|
||||||
setFirstPage: function() {
|
getList: function(e) {
|
||||||
this.props.onSetPage(1);
|
e.preventDefault();
|
||||||
},
|
MailPoet.Modal.popup({
|
||||||
setLastPage: function() {
|
title: 'Bulk action',
|
||||||
this.props.onSetPage(this.getLastPage());
|
template: '',
|
||||||
},
|
onInit: function(modal) {
|
||||||
setPreviousPage: function() {
|
var target = modal.getContentContainer();
|
||||||
this.props.onSetPage(this.constrainPage(this.props.page - 1));
|
React.render(
|
||||||
},
|
<ListSelector />,
|
||||||
setNextPage: function() {
|
target[0]
|
||||||
this.props.onSetPage(this.constrainPage(this.props.page + 1));
|
|
||||||
},
|
|
||||||
constrainPage: function(page) {
|
|
||||||
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
|
|
||||||
},
|
|
||||||
handleSetPage: function() {
|
|
||||||
this.props.onSetPage(
|
|
||||||
this.constrainPage(this.refs.page.getDOMNode().value)
|
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
getLastPage: function() {
|
})
|
||||||
return Math.ceil(this.props.count / this.props.limit);
|
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
if(this.props.count === 0) {
|
|
||||||
return (<div></div>);
|
|
||||||
} else {
|
|
||||||
var pagination,
|
|
||||||
firstPage = (
|
|
||||||
<span aria-hidden="true" className="tablenav-pages-navspan">«</span>
|
|
||||||
),
|
|
||||||
previousPage = (
|
|
||||||
<span aria-hidden="true" className="tablenav-pages-navspan">‹</span>
|
|
||||||
),
|
|
||||||
nextPage = (
|
|
||||||
<span aria-hidden="true" className="tablenav-pages-navspan">›</span>
|
|
||||||
),
|
|
||||||
lastPage = (
|
|
||||||
<span aria-hidden="true" className="tablenav-pages-navspan">»</span>
|
|
||||||
);
|
|
||||||
|
|
||||||
if(this.props.count > this.props.limit) {
|
|
||||||
if(this.props.page > 1) {
|
|
||||||
previousPage = (
|
|
||||||
<a href="javascript:;"
|
|
||||||
onClick={this.setPreviousPage}
|
|
||||||
className="prev-page">
|
|
||||||
<span className="screen-reader-text">Previous page</span>
|
|
||||||
<span aria-hidden="true">‹</span>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.props.page > 2) {
|
|
||||||
firstPage = (
|
|
||||||
<a href="javascript:;"
|
|
||||||
onClick={this.setFirstPage}
|
|
||||||
className="first-page">
|
|
||||||
<span className="screen-reader-text">First page</span>
|
|
||||||
<span aria-hidden="true">«</span>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.props.page < this.getLastPage()) {
|
|
||||||
nextPage = (
|
|
||||||
<a href="javascript:;"
|
|
||||||
onClick={this.setNextPage}
|
|
||||||
className="next-page">
|
|
||||||
<span className="screen-reader-text">Next page</span>
|
|
||||||
<span aria-hidden="true">›</span>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.props.page < this.getLastPage() - 1) {
|
|
||||||
lastPage = (
|
|
||||||
<a href="javascript:;"
|
|
||||||
onClick={this.setLastPage}
|
|
||||||
className="last-page">
|
|
||||||
<span className="screen-reader-text">Last page</span>
|
|
||||||
<span aria-hidden="true">»</span>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pagination = (
|
|
||||||
<span className="pagination-links">
|
|
||||||
{firstPage}
|
|
||||||
{previousPage}
|
|
||||||
|
|
||||||
<span className="paging-input">
|
|
||||||
<label
|
|
||||||
className="screen-reader-text"
|
|
||||||
htmlFor="current-page-selector">Current Page</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onChange={this.handleSetPage}
|
|
||||||
aria-describedby="table-paging"
|
|
||||||
size="1"
|
|
||||||
ref="page"
|
|
||||||
value={this.props.page}
|
|
||||||
name="paged"
|
|
||||||
id="current-page-selector"
|
|
||||||
className="current-page" />
|
|
||||||
of
|
|
||||||
<span className="total-pages">
|
|
||||||
{Math.ceil(this.props.count / this.props.limit)}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{nextPage}
|
|
||||||
{lastPage}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var classes = classNames(
|
|
||||||
'tablenav-pages',
|
|
||||||
{ 'one-page': (this.props.count <= this.props.limit) }
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes}>
|
<div>
|
||||||
<span className="displaying-num">{ this.props.count } item(s)</span>
|
<select >
|
||||||
{ pagination }
|
<option>Select a list</option>
|
||||||
|
</select>
|
||||||
|
<a onClick={this.getList}>Test me</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var ListingBulkAction = React.createClass({
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<option value={this.props.action.action}>
|
||||||
|
{ this.props.action.label }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var ListingBulkActions = React.createClass({
|
var ListingBulkActions = React.createClass({
|
||||||
render: function() {
|
handleAction: function() {
|
||||||
return (
|
var action = jQuery(this.refs.action.getDOMNode()).val();
|
||||||
<div></div>
|
console.log(action, this.props.selected);
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var ListingColumn = React.createClass({
|
|
||||||
handleSort: function() {
|
|
||||||
var sort_by = this.props.column.name,
|
|
||||||
sort_order = (this.props.column.sorted === 'asc') ? 'desc' : 'asc';
|
|
||||||
this.props.onSort(sort_by, sort_order);
|
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var classes = classNames(
|
|
||||||
'manage-column',
|
|
||||||
{ 'sortable': this.props.column.sortable },
|
|
||||||
this.props.column.sorted
|
|
||||||
);
|
|
||||||
|
|
||||||
var label;
|
|
||||||
|
|
||||||
if(this.props.column.sortable === true) {
|
|
||||||
label = (
|
|
||||||
<a onClick={this.handleSort}>
|
|
||||||
<span>{ this.props.column.label }</span>
|
|
||||||
<span className="sorting-indicator"></span>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
label = this.props.column.label;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<th
|
<div className="alignleft actions bulkactions">
|
||||||
className={ classes }
|
<label
|
||||||
id={this.props.column.name }
|
className="screen-reader-text"
|
||||||
scope="col">
|
htmlFor="bulk-action-selector-top">
|
||||||
{label}
|
Select bulk action
|
||||||
</th>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var ListingHeader = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
var columns = this.props.columns.map(function(column) {
|
|
||||||
return (
|
|
||||||
<ListingColumn
|
|
||||||
onSort={this.props.onSort}
|
|
||||||
sort_by={this.props.sort_by}
|
|
||||||
key={column.name}
|
|
||||||
column={column} />
|
|
||||||
);
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td className="manage-column column-cb check-column" id="cb">
|
|
||||||
<label htmlFor="cb-select-all-1" className="screen-reader-text">
|
|
||||||
Select All
|
|
||||||
</label>
|
</label>
|
||||||
<input type="checkbox" id="cb-select-all-1" />
|
|
||||||
</td>
|
<select ref="action">
|
||||||
{columns}
|
<option>Bulk Actions</option>
|
||||||
</tr>
|
{this.props.actions.map(function(action, index) {
|
||||||
|
return (
|
||||||
|
<ListingBulkAction
|
||||||
|
action={action}
|
||||||
|
key={index} />
|
||||||
|
);
|
||||||
|
}.bind(this))}
|
||||||
|
</select>
|
||||||
|
<input
|
||||||
|
onClick={this.handleAction}
|
||||||
|
type="submit"
|
||||||
|
defaultValue="Apply"
|
||||||
|
className="button action" />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var ListingItem = React.createClass({
|
var ListingItem = React.createClass({
|
||||||
|
handleSelect: function(e) {
|
||||||
|
var is_checked = jQuery(e.target).is(':checked');
|
||||||
|
|
||||||
|
this.props.onSelect(
|
||||||
|
parseInt(e.target.value, 10),
|
||||||
|
is_checked
|
||||||
|
);
|
||||||
|
|
||||||
|
return !e.target.checked;
|
||||||
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
|
var rowClasses = classNames(
|
||||||
|
'title',
|
||||||
|
'column-title',
|
||||||
|
'has-row-actions',
|
||||||
|
'column-primary',
|
||||||
|
'page-title'
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<th className="check-column" scope="row">
|
<th className="check-column" scope="row">
|
||||||
<label htmlFor="cb-select-1" className="screen-reader-text">
|
<label className="screen-reader-text">
|
||||||
Select { this.props.item.email }</label>
|
{ 'Select ' + this.props.item.email }</label>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
defaultValue={ this.props.item.id }
|
defaultValue={ this.props.item.id }
|
||||||
name="item[]" id="cb-select-1" />
|
defaultChecked={ this.props.item.selected }
|
||||||
|
onChange={ this.handleSelect } />
|
||||||
</th>
|
</th>
|
||||||
<td className="title column-title has-row-actions column-primary page-title">
|
<td className={rowClasses}>
|
||||||
<strong>
|
<strong>
|
||||||
<a className="row-title">{ this.props.item.email }</a>
|
<a className="row-title">{ this.props.item.email }</a>
|
||||||
</strong>
|
</strong>
|
||||||
@ -311,9 +175,11 @@ define('subscribers.listing',
|
|||||||
return (
|
return (
|
||||||
<tbody>
|
<tbody>
|
||||||
{this.props.items.map(function(item) {
|
{this.props.items.map(function(item) {
|
||||||
|
item.selected = (this.props.selected.indexOf(item.id) !== -1);
|
||||||
return (
|
return (
|
||||||
<ListingItem
|
<ListingItem
|
||||||
columns={this.props.columns}
|
columns={this.props.columns}
|
||||||
|
onSelect={this.props.onSelect}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
item={item} />
|
item={item} />
|
||||||
);
|
);
|
||||||
@ -334,7 +200,8 @@ define('subscribers.listing',
|
|||||||
limit: 10,
|
limit: 10,
|
||||||
sort_by: 'email',
|
sort_by: 'email',
|
||||||
sort_order: 'asc',
|
sort_order: 'asc',
|
||||||
items: []
|
items: [],
|
||||||
|
selected: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
@ -377,6 +244,31 @@ define('subscribers.listing',
|
|||||||
this.getItems();
|
this.getItems();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
handleSelect: function(id, is_checked) {
|
||||||
|
var selected = this.state.selected;
|
||||||
|
|
||||||
|
if(is_checked) {
|
||||||
|
selected = jQuery.merge(selected, [ id ]);
|
||||||
|
} else {
|
||||||
|
selected.splice(selected.indexOf(id), 1);
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
selected: selected
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSelectAll: function(is_checked) {
|
||||||
|
if(is_checked === false) {
|
||||||
|
this.setState({ selected: [] });
|
||||||
|
} else {
|
||||||
|
var selected = this.state.items.map(function(item) {
|
||||||
|
return ~~item.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selected: selected
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
handleSetPage: function(page) {
|
handleSetPage: function(page) {
|
||||||
this.setState({ page: page }, function() {
|
this.setState({ page: page }, function() {
|
||||||
this.getItems();
|
this.getItems();
|
||||||
@ -408,7 +300,9 @@ define('subscribers.listing',
|
|||||||
onSearch={this.handleSearch}
|
onSearch={this.handleSearch}
|
||||||
search={this.state.search} />
|
search={this.state.search} />
|
||||||
<div className="tablenav top clearfix">
|
<div className="tablenav top clearfix">
|
||||||
<ListingBulkActions />
|
<ListingBulkActions
|
||||||
|
actions={this.props.actions}
|
||||||
|
selected={this.state.selected} />
|
||||||
<ListingFilters />
|
<ListingFilters />
|
||||||
<ListingPages
|
<ListingPages
|
||||||
count={this.state.count}
|
count={this.state.count}
|
||||||
@ -420,6 +314,7 @@ define('subscribers.listing',
|
|||||||
<thead>
|
<thead>
|
||||||
<ListingHeader
|
<ListingHeader
|
||||||
onSort={this.handleSort}
|
onSort={this.handleSort}
|
||||||
|
onSelectAll={this.handleSelectAll}
|
||||||
sort_by={this.state.sort_by}
|
sort_by={this.state.sort_by}
|
||||||
sort_order={this.state.sort_order}
|
sort_order={this.state.sort_order}
|
||||||
columns={this.props.columns} />
|
columns={this.props.columns} />
|
||||||
@ -427,11 +322,14 @@ define('subscribers.listing',
|
|||||||
|
|
||||||
<ListingItems
|
<ListingItems
|
||||||
columns={this.props.columns}
|
columns={this.props.columns}
|
||||||
|
selected={this.state.selected}
|
||||||
|
onSelect={this.handleSelect}
|
||||||
items={items} />
|
items={items} />
|
||||||
|
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<ListingHeader
|
<ListingHeader
|
||||||
onSort={this.handleSort}
|
onSort={this.handleSort}
|
||||||
|
onSelectAll={this.handleSelectAll}
|
||||||
sort_by={this.state.sort_by}
|
sort_by={this.state.sort_by}
|
||||||
sort_order={this.state.sort_order}
|
sort_order={this.state.sort_order}
|
||||||
columns={this.props.columns} />
|
columns={this.props.columns} />
|
||||||
@ -439,7 +337,9 @@ define('subscribers.listing',
|
|||||||
|
|
||||||
</table>
|
</table>
|
||||||
<div className="tablenav bottom">
|
<div className="tablenav bottom">
|
||||||
<ListingBulkActions />
|
<ListingBulkActions
|
||||||
|
actions={this.props.actions}
|
||||||
|
selected={this.state.selected} />
|
||||||
<ListingPages
|
<ListingPages
|
||||||
count={this.state.count}
|
count={this.state.count}
|
||||||
page={this.state.page}
|
page={this.state.page}
|
||||||
@ -480,11 +380,32 @@ define('subscribers.listing',
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var actions = [
|
||||||
|
{
|
||||||
|
label: 'Move to list...',
|
||||||
|
endpoint: 'subscribers',
|
||||||
|
action: 'move',
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Add to list...',
|
||||||
|
endpoint: 'subscribers',
|
||||||
|
action: 'add',
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Remove from list...',
|
||||||
|
endpoint: 'subscribers',
|
||||||
|
action: 'remove',
|
||||||
|
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
var element = jQuery('#mailpoet_subscribers_listing');
|
var element = jQuery('#mailpoet_subscribers_listing');
|
||||||
|
|
||||||
if(element.length > 0) {
|
if(element.length > 0) {
|
||||||
React.render(
|
React.render(
|
||||||
<Listing columns={columns} />,
|
<Listing columns={columns} actions={actions} />,
|
||||||
element[0]
|
element[0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,123 +0,0 @@
|
|||||||
define('subscribers.table',
|
|
||||||
['mailpoet', 'jquery', 'react/addons', 'react-waypoint'],
|
|
||||||
function(MailPoet, jQuery, React, Waypoint) {
|
|
||||||
|
|
||||||
var InfiniteScrollExample = React.createClass({
|
|
||||||
_loadMoreItems: function() {
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
this.setState({ page: (this.state.page + 1) }, function() {
|
|
||||||
this.loadItems();
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
loadItems: function() {
|
|
||||||
MailPoet.Ajax.post({
|
|
||||||
endpoint: 'subscribers',
|
|
||||||
action: 'get',
|
|
||||||
data: {
|
|
||||||
offset: (this.state.page - 1) * this.state.limit,
|
|
||||||
limit: this.state.limit
|
|
||||||
},
|
|
||||||
onSuccess: function(response) {
|
|
||||||
if(this.isMounted()) {
|
|
||||||
var items = jQuery.merge(this.state.items, response);
|
|
||||||
this.setState({
|
|
||||||
items: items,
|
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}.bind(this)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.loadItems();
|
|
||||||
},
|
|
||||||
getInitialState: function() {
|
|
||||||
// set up list of items ...
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
items: [],
|
|
||||||
page: 1,
|
|
||||||
limit: 50
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
_renderLoadingMessage: function() {
|
|
||||||
if (this.state.loading) {
|
|
||||||
return (
|
|
||||||
<p>
|
|
||||||
Loading {this.state.limit} more items
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<p>{this.state.items.length} items</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_renderItems: function() {
|
|
||||||
return this.state.items.map(function(subscriber, index) {
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<th className="check-column" scope="row">
|
|
||||||
<label htmlFor="cb-select-1" className="screen-reader-text">
|
|
||||||
Select { subscriber.email }</label>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
value={ subscriber.id }
|
|
||||||
name="item[]" id="cb-select-1" />
|
|
||||||
</th>
|
|
||||||
<td className="title column-title has-row-actions column-primary page-title">
|
|
||||||
<strong>
|
|
||||||
<a className="row-title">{ subscriber.email }</a>
|
|
||||||
</strong>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{ subscriber.first_name }
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{ subscriber.last_name }
|
|
||||||
</td>
|
|
||||||
<td className="date column-date">
|
|
||||||
<abbr title="">{ subscriber.created_at }</abbr>
|
|
||||||
</td>
|
|
||||||
<td className="date column-date">
|
|
||||||
<abbr title="">{ subscriber.updated_at }</abbr>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_renderWaypoint: function() {
|
|
||||||
if (!this.state.loading) {
|
|
||||||
return (
|
|
||||||
<Waypoint
|
|
||||||
onEnter={this._loadMoreItems}
|
|
||||||
threshold={0.8} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{this._renderLoadingMessage()}
|
|
||||||
<div className="infinite-scroll-example">
|
|
||||||
<div className="infinite-scroll-example__scrollable-parent">
|
|
||||||
{this._renderItems()}
|
|
||||||
{this._renderWaypoint()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
React.render(
|
|
||||||
<InfiniteScrollExample />,
|
|
||||||
document.getElementById('example')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
);
|
|
@ -9,10 +9,12 @@ class Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
if(!is_admin() && !is_login_page()) {
|
||||||
add_action('widgets_init', array($this, 'registerWidget'));
|
add_action('widgets_init', array($this, 'registerWidget'));
|
||||||
add_action('widgets_init', array($this, 'setupActions'));
|
add_action('widgets_init', array($this, 'setupActions'));
|
||||||
add_action('widgets_init', array($this, 'setupDependencies'));
|
add_action('widgets_init', array($this, 'setupDependencies'));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function registerWidget() {
|
function registerWidget() {
|
||||||
register_widget('\MailPoet\Form\Widget');
|
register_widget('\MailPoet\Form\Widget');
|
||||||
|
Reference in New Issue
Block a user