Compare commits
252 Commits
Author | SHA1 | Date | |
---|---|---|---|
7c9029b227 | |||
1823bf606a | |||
525b7fdd65 | |||
11031d2b56 | |||
4d45635d03 | |||
b81764402b | |||
947e1150d8 | |||
97f0e512af | |||
f15374de43 | |||
f082c065d1 | |||
72a9951125 | |||
a82d9a63d4 | |||
a7e9979781 | |||
cebd1ee7ae | |||
5faa467306 | |||
53eb9cd2ae | |||
7f6eed6d66 | |||
74f3fa65cd | |||
8723aa4e4e | |||
ccab8b4cf3 | |||
4c4a4ab31d | |||
45df02b0ec | |||
dd7067e590 | |||
1219b5ba49 | |||
01496ac813 | |||
3b3ccc18ce | |||
3dce951e66 | |||
db1dc172aa | |||
26c5cc1e43 | |||
f91bfbf473 | |||
3dae0ef13f | |||
3281ac390e | |||
d731a6b432 | |||
bb869e8ae8 | |||
7331e5cabd | |||
ba05ca35af | |||
91e7bf6336 | |||
ff58067d55 | |||
2ba6bb339e | |||
a47afdd313 | |||
608b559ee1 | |||
181ed45d0b | |||
29fac8d052 | |||
a3d7d53eea | |||
3f6caf5fa4 | |||
42c4139ba5 | |||
ad31b143d2 | |||
6ec15bec22 | |||
71d8fb0d93 | |||
2f293da7a3 | |||
17b56f0160 | |||
bb9fce7f82 | |||
ad4f1f8326 | |||
8ece62c9a6 | |||
a9b9e9c631 | |||
6e289b6a8f | |||
20ced8b099 | |||
f38b632707 | |||
8ce0595342 | |||
f11de2f1ad | |||
e28451d410 | |||
72882aaf2b | |||
fdf9dd0fa3 | |||
97dd0abea2 | |||
a099174226 | |||
a054acc6e6 | |||
74254d7e2a | |||
1795964c69 | |||
0118b2472a | |||
5fe03f0dee | |||
9aef6850c2 | |||
f688a69f8b | |||
b2682fa0b7 | |||
18b15c5440 | |||
c3416977bb | |||
88a00bc38c | |||
a1441dfde6 | |||
8e7336d352 | |||
e0e2933cdf | |||
c93ec629ea | |||
d613df6558 | |||
01c9096543 | |||
f120e839dd | |||
f0ab592c04 | |||
1a269d28b3 | |||
8d4a666bf0 | |||
4a96e483a6 | |||
263a66407f | |||
c4b728f4e1 | |||
9970ad7fb6 | |||
eb380499d9 | |||
4b528549f5 | |||
a903017bc2 | |||
afd25e9174 | |||
b1bbf1b3bc | |||
9e84e8df93 | |||
df775b5a07 | |||
c9c22b9b52 | |||
93d20688ea | |||
9ebcddfa2a | |||
85995bc8a6 | |||
a8f2959bc6 | |||
36242bd580 | |||
1e7dbc8449 | |||
12c159c627 | |||
82ed7e51c5 | |||
0b3aa0d12a | |||
4d788f69aa | |||
c721843c12 | |||
d2be407ccb | |||
e6337216cf | |||
f1c396f0b0 | |||
3622bc9fcb | |||
14fe333678 | |||
cf6466197a | |||
f56bee76f2 | |||
2ec6bc8c99 | |||
4aeccb1961 | |||
bd593b1ad4 | |||
bb7812bd5d | |||
73ed070a34 | |||
9e81c48bf8 | |||
f9028d28c0 | |||
da32b243ea | |||
5092c3d328 | |||
06ad4488bf | |||
a856800e6d | |||
dfc680f3a1 | |||
a9baecc504 | |||
11e15659ac | |||
ebe440a272 | |||
853794d459 | |||
cfea13bf81 | |||
7f291d80b9 | |||
9840b55de6 | |||
ca7322933f | |||
81569e5b81 | |||
1942972282 | |||
a23aac370c | |||
99d6f74d1b | |||
a883e1176c | |||
24b98a1154 | |||
8dbb6ab79f | |||
3e7d1690bd | |||
07d533a810 | |||
499936e3ab | |||
580ac989aa | |||
acf300160d | |||
983df4ee13 | |||
03c782d4ab | |||
0daf7e12c1 | |||
6a2e18a0e1 | |||
316d5ab183 | |||
eb6bba5961 | |||
b5864adf06 | |||
9bce50a633 | |||
365a53cf27 | |||
31a4575d43 | |||
1ae584c4e7 | |||
aac2cd6eb8 | |||
9874e1c371 | |||
16b1c0dc41 | |||
9223fbf478 | |||
eb27de36f4 | |||
636fa38ab6 | |||
9b1503dc7a | |||
2ac3b00af6 | |||
5fcdbfe826 | |||
67036ddb61 | |||
6c0f6a07cd | |||
8139a7dd0a | |||
97adfc14c0 | |||
4ed703a351 | |||
2aee853406 | |||
854736fac7 | |||
841c69af59 | |||
56b4688f93 | |||
e60bc7c387 | |||
6094a83f4b | |||
91ddb98f56 | |||
27d5972306 | |||
6088497433 | |||
0d894a6fef | |||
57f0b88299 | |||
5121dbe0c8 | |||
f874ffc19c | |||
e928a5c2bc | |||
d11badf3ce | |||
3006c982cb | |||
b29e31fdd6 | |||
bc42c8e280 | |||
409697ee64 | |||
cfb4265971 | |||
13d78aac05 | |||
6f176f4e6c | |||
9b584296a5 | |||
5ea87c5eed | |||
7522084ccb | |||
214aa60d0e | |||
7a049ce1b7 | |||
94d293deb7 | |||
bd2d38d757 | |||
abec524daa | |||
cac6beb4ac | |||
cac995e15b | |||
b26380fd10 | |||
6c6a4070be | |||
8b001d820b | |||
2ae3d8ebdf | |||
459ec21f9d | |||
9c7790d07e | |||
f9c5b99e46 | |||
95b0b39366 | |||
4b6fa0e760 | |||
67a3440ced | |||
0de372344a | |||
7a04eeb650 | |||
8dbfe82922 | |||
7322f2151c | |||
c43d2f240d | |||
bbcd267b6f | |||
bbc4acb2a4 | |||
c89cc5a919 | |||
33075940de | |||
51c09b8360 | |||
2fbf85f371 | |||
24cb614adb | |||
55f851208b | |||
990dac7727 | |||
233020ca20 | |||
0c419cde16 | |||
35f9530d8e | |||
992fe2a6e9 | |||
c2cb88f995 | |||
ba69d659ab | |||
397d988eb1 | |||
d85f2341ec | |||
2b3c288b5f | |||
8ec28a23a7 | |||
12c9623e2f | |||
8ba9fdccbc | |||
a2ef62302f | |||
24ecc879d3 | |||
a1104a7f90 | |||
aa959810e9 | |||
45b7a79277 | |||
41c8c0dae5 | |||
2aeab7aaff | |||
4fd0c4b484 | |||
d4623cf763 | |||
181c4fed08 | |||
7884dd8389 |
16
.env.sample
16
.env.sample
@ -1,2 +1,16 @@
|
||||
WP_TEST_PATH="/var/www/wordpress"
|
||||
|
||||
WP_TEST_ENABLE_NETWORK_TESTS="true"
|
||||
WP_TEST_IMPORT_MAILCHIMP_API=""
|
||||
WP_TEST_IMPORT_MAILCHIMP_LISTS="" // (separated with comma)
|
||||
WP_TEST_MAILER_ENABLE_SENDING="true"
|
||||
WP_TEST_MAILER_AMAZON_ACCESS=""
|
||||
WP_TEST_MAILER_AMAZON_SECRET=""
|
||||
WP_TEST_MAILER_AMAZON_REGION=""
|
||||
WP_TEST_MAILER_ELASTICEMAIL_API=""
|
||||
WP_TEST_MAILER_MAILGUN_API=""
|
||||
WP_TEST_MAILER_MAILGUN_DOMAIN=""
|
||||
WP_TEST_MAILER_MAILPOET_API=""
|
||||
WP_TEST_MAILER_SENDGRID_API=""
|
||||
WP_TEST_MAILER_SMTP_HOST=""
|
||||
WP_TEST_MAILER_SMTP_LOGIN=""
|
||||
WP_TEST_MAILER_SMTP_PASSWORD=""
|
19
RoboFile.php
19
RoboFile.php
@ -89,14 +89,14 @@ class RoboFile extends \Robo\Tasks {
|
||||
}
|
||||
|
||||
function makepot() {
|
||||
$this->_exec('grunt makepot'.
|
||||
$this->_exec('./node_modules/.bin/grunt makepot'.
|
||||
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
|
||||
' --base_path '.__DIR__
|
||||
);
|
||||
}
|
||||
|
||||
function pushpot() {
|
||||
$this->_exec('grunt pushpot'.
|
||||
$this->_exec('./node_modules/.bin/grunt pushpot'.
|
||||
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
|
||||
' --base_path '.__DIR__
|
||||
);
|
||||
@ -105,14 +105,25 @@ class RoboFile extends \Robo\Tasks {
|
||||
function testUnit($file = null) {
|
||||
$this->loadEnv();
|
||||
$this->_exec('vendor/bin/codecept build');
|
||||
$this->_exec('vendor/bin/codecept run unit '.(($file) ? $file : ''));
|
||||
$this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : ''));
|
||||
}
|
||||
|
||||
function testCoverage($file = null) {
|
||||
$this->loadEnv();
|
||||
$this->_exec('vendor/bin/codecept build');
|
||||
$this->_exec(join(' ', array(
|
||||
'vendor/bin/codecept run',
|
||||
(($file) ? $file : ''),
|
||||
'--coverage',
|
||||
'--coverage-html'
|
||||
)));
|
||||
}
|
||||
|
||||
function testJavascript() {
|
||||
$this->compileJs();
|
||||
|
||||
$this->_exec(join(' ', array(
|
||||
'./node_modules/mocha/bin/mocha',
|
||||
'./node_modules/.bin/mocha',
|
||||
'-r tests/javascript/mochaTestHelper.js',
|
||||
'tests/javascript/testBundles/**/*.js'
|
||||
)));
|
||||
|
@ -17,3 +17,5 @@
|
||||
|
||||
@require 'settings'
|
||||
@require 'progress_bar'
|
||||
|
||||
@require 'subscribers'
|
@ -563,3 +563,6 @@ handle_icon = '../img/handle.png'
|
||||
.CodeMirror
|
||||
border: 1px solid #eee
|
||||
|
||||
/* Settings */
|
||||
#mailpoet_form_segments.parsley-error + span .select2-selection
|
||||
border: 1px solid #b94a48
|
@ -37,3 +37,6 @@
|
||||
|
||||
input[type=text]
|
||||
vertical-align: middle
|
||||
|
||||
.mailpoet_form_field_block
|
||||
display: block
|
||||
|
@ -38,9 +38,7 @@
|
||||
content: '\f142'
|
||||
|
||||
.mailpoet_save_show_options_icon
|
||||
width: auto
|
||||
height: auto
|
||||
line-height: auto
|
||||
vertical-align: middle
|
||||
|
||||
&::before
|
||||
content: '\f140'
|
||||
|
@ -21,3 +21,9 @@
|
||||
|
||||
.mailpoet_automated_latest_content_display_options
|
||||
animation-slide-open-downwards()
|
||||
|
||||
.mailpoet_automated_latest_content_show_amount
|
||||
width: 25px
|
||||
|
||||
.mailpoet_automated_latest_content_content_type
|
||||
width: 180px
|
||||
|
@ -30,3 +30,8 @@ $block-hover-highlight-color = $primary-active-color
|
||||
|
||||
.mailpoet_content
|
||||
position: relative
|
||||
line-height: 1.61803398875
|
||||
|
||||
p, h1, h2, h3, h4, h5, h6
|
||||
line-height: 1.61803398875
|
||||
font-style: normal
|
||||
|
@ -1,6 +1,10 @@
|
||||
.mailpoet_footer_block
|
||||
padding-left: 0
|
||||
padding-right: 0
|
||||
margin-bottom: 0
|
||||
|
||||
.mailpoet_content
|
||||
padding: 5px 20px
|
||||
padding: 10px 20px
|
||||
|
||||
p
|
||||
margin: 0
|
||||
|
@ -1,6 +1,10 @@
|
||||
.mailpoet_header_block
|
||||
padding-left: 0
|
||||
padding-right: 0
|
||||
margin-bottom: 0
|
||||
|
||||
.mailpoet_content
|
||||
padding: 5px 20px
|
||||
padding: 10px 20px
|
||||
|
||||
p
|
||||
margin: 0
|
||||
|
@ -11,9 +11,6 @@
|
||||
padding-right: 0
|
||||
margin-bottom: 0
|
||||
|
||||
img
|
||||
width: 100%
|
||||
|
||||
.mailpoet_content a:hover
|
||||
cursor: all-scroll
|
||||
|
||||
|
@ -1,16 +1,23 @@
|
||||
$text-vertical-padding = 3px
|
||||
|
||||
.mailpoet_text_block
|
||||
padding-left: 0
|
||||
padding-right: 0
|
||||
|
||||
& > .mailpoet_content
|
||||
overflow: hidden
|
||||
padding-top: 13px
|
||||
padding-bottom: 13px
|
||||
padding-top: 0
|
||||
padding-bottom: 0px
|
||||
padding-left: 20px
|
||||
padding-right: 20px
|
||||
|
||||
h1, h2, h3, h4, h5, h6
|
||||
padding: 0
|
||||
margin: 0
|
||||
font-weight: normal
|
||||
|
||||
p
|
||||
margin-top: 0
|
||||
font-weight: normal
|
||||
|
||||
blockquote
|
||||
margin: 1em
|
||||
padding-left: 1em
|
||||
|
@ -133,3 +133,17 @@ body
|
||||
.wrap > .mailpoet_notice,
|
||||
.update-nag
|
||||
margin-left: 2px + 15px !important
|
||||
|
||||
/* Make a button group */
|
||||
.mailpoet_button_group
|
||||
|
||||
.button:first-child
|
||||
border-right: 0
|
||||
border-top-right-radius: 0
|
||||
border-bottom-right-radius: 0
|
||||
|
||||
.button:last-child
|
||||
border-left: 0
|
||||
border-top-left-radius: 0
|
||||
border-bottom-left-radius: 0
|
||||
|
||||
|
@ -2,3 +2,13 @@
|
||||
|
||||
@require 'parsley'
|
||||
@require 'form_validation'
|
||||
|
||||
/* labels */
|
||||
.mailpoet_text_label
|
||||
.mailpoet_textarea_label
|
||||
.mailpoet_select_label
|
||||
.mailpoet_radio_label
|
||||
.mailpoet_checkbox_label
|
||||
.mailpoet_list_label
|
||||
.mailpoet_date_label
|
||||
display:block
|
||||
|
3
assets/css/src/subscribers.styl
Normal file
3
assets/css/src/subscribers.styl
Normal file
@ -0,0 +1,3 @@
|
||||
#subscribers_container
|
||||
.mailpoet_segments_unsubscribed
|
||||
color: lighten(#555, 33)
|
@ -48,28 +48,22 @@ define(
|
||||
})
|
||||
.done(function(response) {
|
||||
if(!response.result) {
|
||||
MailPoet.Notice.error(MailPoetI18n.daemonControlError);
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('daemonControlError'));
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
render: function() {
|
||||
if(this.state.status === 'loading') {
|
||||
return(<div>Loading daemon status...</div>);
|
||||
return(<div>{MailPoet.I18n.t('loadingDaemonStatus')}</div>);
|
||||
}
|
||||
switch(this.state.status) {
|
||||
case 'started':
|
||||
return(
|
||||
<div>
|
||||
Cron daemon is running.
|
||||
{MailPoet.I18n.t('cronDaemonIsRunning')}
|
||||
<br/>
|
||||
<br/>
|
||||
It was started
|
||||
<strong> {this.state.timeSinceStart} </strong> and last executed
|
||||
<strong> {this.state.timeSinceUpdate} </strong> for a total of
|
||||
<strong> {this.state.counter} </strong> times (once every 30 seconds, unless it was interrupted and restarted).
|
||||
<br />
|
||||
<br />
|
||||
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'stop')}>Stop</a>
|
||||
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'stop')}>{MailPoet.I18n.t('stop')}</a>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
@ -77,17 +71,17 @@ define(
|
||||
case 'stopping':
|
||||
return(
|
||||
<div>
|
||||
Daemon is {this.state.status}
|
||||
{MailPoet.I18n.t('cronDaemonState').replace('%$1s', this.state.status)}
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case 'stopped':
|
||||
return(
|
||||
<div>
|
||||
Daemon is {this.state.status}
|
||||
{MailPoet.I18n.t('cronDaemonState').replace('%$1s', this.state.status)}
|
||||
<br />
|
||||
<br />
|
||||
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'start')}>Start</a>
|
||||
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'start')}>{MailPoet.I18n.t('start')}</a>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
|
136
assets/js/src/date.js
Normal file
136
assets/js/src/date.js
Normal file
@ -0,0 +1,136 @@
|
||||
define('date',
|
||||
[
|
||||
'mailpoet',
|
||||
'jquery',
|
||||
'moment'
|
||||
], function(
|
||||
MailPoet,
|
||||
jQuery,
|
||||
Moment
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
MailPoet.Date = {
|
||||
version: 0.1,
|
||||
options: {},
|
||||
defaults: {
|
||||
offset: 0,
|
||||
format: 'F, d Y H:i:s'
|
||||
},
|
||||
init: function(options) {
|
||||
options = options || {};
|
||||
|
||||
// set UTC offset
|
||||
if (
|
||||
options.offset === undefined
|
||||
&& window.mailpoet_date_offset !== undefined
|
||||
) {
|
||||
options.offset = window.mailpoet_date_offset;
|
||||
}
|
||||
// set date format
|
||||
if (
|
||||
options.format === undefined
|
||||
&& window.mailpoet_date_format !== undefined
|
||||
) {
|
||||
options.format = window.mailpoet_date_format;
|
||||
}
|
||||
// merge options
|
||||
this.options = jQuery.extend({}, this.defaults, options);
|
||||
|
||||
return this;
|
||||
},
|
||||
format: function(date, options) {
|
||||
this.init(options);
|
||||
return Moment.utc(date)
|
||||
.local()
|
||||
.format(this.convertFormat(this.options.format));
|
||||
},
|
||||
short: function(date) {
|
||||
return this.format(date, {
|
||||
format: 'F, j Y'
|
||||
});
|
||||
},
|
||||
full: function(date) {
|
||||
return this.format(date, {
|
||||
format: 'F, j Y H:i:s'
|
||||
});
|
||||
},
|
||||
time: function(date) {
|
||||
return this.format(date, {
|
||||
format: 'H:i:s'
|
||||
});
|
||||
},
|
||||
convertFormat: function(format) {
|
||||
const format_mappings = {
|
||||
date: {
|
||||
D: 'ddd',
|
||||
l: 'dddd',
|
||||
d: 'DD',
|
||||
j: 'D',
|
||||
z: 'DDDD',
|
||||
N: 'E',
|
||||
S: '',
|
||||
M: 'MMM',
|
||||
F: 'MMMM',
|
||||
m: 'MM',
|
||||
n: '',
|
||||
t: '',
|
||||
y: 'YY',
|
||||
Y: 'YYYY',
|
||||
H: 'HH',
|
||||
h: 'hh',
|
||||
g: 'h',
|
||||
A: 'A',
|
||||
i: 'mm',
|
||||
s: 'ss',
|
||||
T: 'z',
|
||||
O: 'ZZ',
|
||||
w: 'd',
|
||||
W: 'WW'
|
||||
},
|
||||
strftime: {
|
||||
a: 'ddd',
|
||||
A: 'dddd',
|
||||
b: 'MMM',
|
||||
B: 'MMMM',
|
||||
d: 'DD',
|
||||
e: 'D',
|
||||
F: 'YYYY-MM-DD',
|
||||
H: 'HH',
|
||||
I: 'hh',
|
||||
j: 'DDDD',
|
||||
k: 'H',
|
||||
l: 'h',
|
||||
m: 'MM',
|
||||
M: 'mm',
|
||||
p: 'A',
|
||||
S: 'ss',
|
||||
u: 'E',
|
||||
w: 'd',
|
||||
W: 'WW',
|
||||
y: 'YY',
|
||||
Y: 'YYYY',
|
||||
z: 'ZZ',
|
||||
Z: 'z'
|
||||
}
|
||||
};
|
||||
|
||||
const replacements = format_mappings['date'];
|
||||
|
||||
let outputFormat = '';
|
||||
|
||||
Object.keys(replacements).forEach(function(key) {
|
||||
if (format.indexOf(key) !== -1) {
|
||||
format = format.replace(key, '%'+key);
|
||||
}
|
||||
});
|
||||
outputFormat = format;
|
||||
Object.keys(replacements).forEach(function(key) {
|
||||
if (outputFormat.indexOf('%'+key) !== -1) {
|
||||
outputFormat = outputFormat.replace('%'+key, replacements[key]);
|
||||
}
|
||||
});
|
||||
return outputFormat;
|
||||
}
|
||||
};
|
||||
});
|
@ -10,10 +10,13 @@ function(
|
||||
return this.props.onValueChange(e);
|
||||
},
|
||||
render: function() {
|
||||
const isChecked = !!(this.props.item[this.props.field.name]);
|
||||
if (this.props.field.values === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isChecked = !!(this.props.item[this.props.field.name]);
|
||||
const options = Object.keys(this.props.field.values).map(
|
||||
function(value, index) {
|
||||
(value, index) => {
|
||||
return (
|
||||
<p key={ 'checkbox-' + index }>
|
||||
<label>
|
||||
@ -29,7 +32,7 @@ function(
|
||||
</label>
|
||||
</p>
|
||||
);
|
||||
}.bind(this)
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -4,12 +4,15 @@ define([
|
||||
function(
|
||||
React
|
||||
) {
|
||||
var FormFieldRadio = React.createClass({
|
||||
const FormFieldRadio = React.createClass({
|
||||
render: function() {
|
||||
var selected_value = this.props.item[this.props.field.name];
|
||||
if (this.props.field.values === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var options = Object.keys(this.props.field.values).map(
|
||||
function(value, index) {
|
||||
const selected_value = this.props.item[this.props.field.name];
|
||||
const options = Object.keys(this.props.field.values).map(
|
||||
(value, index) => {
|
||||
return (
|
||||
<p key={ 'radio-' + index }>
|
||||
<label>
|
||||
@ -23,7 +26,7 @@ function(
|
||||
</label>
|
||||
</p>
|
||||
);
|
||||
}.bind(this)
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -4,10 +4,14 @@ define([
|
||||
function(
|
||||
React
|
||||
) {
|
||||
var FormFieldSelect = React.createClass({
|
||||
const FormFieldSelect = React.createClass({
|
||||
render: function() {
|
||||
var options =
|
||||
Object.keys(this.props.field.values).map(function(value, index) {
|
||||
if (this.props.field.values === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const options = Object.keys(this.props.field.values).map(
|
||||
(value, index) => {
|
||||
return (
|
||||
<option
|
||||
key={ 'option-' + index }
|
||||
@ -15,7 +19,7 @@ function(
|
||||
{ this.props.field.values[value] }
|
||||
</option>
|
||||
);
|
||||
}.bind(this)
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -26,7 +26,7 @@ function(
|
||||
&& (this.props.item.id !== prevProps.item.id)
|
||||
) {
|
||||
jQuery('#'+this.refs.select.id)
|
||||
.val(this.props.item[this.props.field.name])
|
||||
.val(this.getSelectedValues())
|
||||
.trigger('change');
|
||||
}
|
||||
},
|
||||
@ -45,7 +45,11 @@ function(
|
||||
if(item.element && item.element.selected) {
|
||||
return null;
|
||||
} else {
|
||||
return item.text;
|
||||
if(item.title) {
|
||||
return item.title;
|
||||
} else {
|
||||
return item.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -65,15 +69,25 @@ function(
|
||||
|
||||
select2.select2(
|
||||
'val',
|
||||
this.props.item[this.props.field.name]
|
||||
this.getSelectedValues()
|
||||
);
|
||||
|
||||
this.setState({ initialized: true });
|
||||
},
|
||||
getSelectedValues: function() {
|
||||
if(this.props.field['selected'] !== undefined) {
|
||||
return this.props.field['selected'](this.props.item);
|
||||
} else if(this.props.item !== undefined && this.props.field.name !== undefined) {
|
||||
return this.props.item[this.props.field.name];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
loadCachedItems: function() {
|
||||
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
|
||||
var items = window['mailpoet_'+this.props.field.endpoint];
|
||||
|
||||
|
||||
if(this.props.field['filter'] !== undefined) {
|
||||
items = items.filter(this.props.field.filter);
|
||||
}
|
||||
@ -98,31 +112,48 @@ function(
|
||||
});
|
||||
}
|
||||
},
|
||||
getLabel: function(item) {
|
||||
if(this.props.field['getLabel'] !== undefined) {
|
||||
return this.props.field.getLabel(item, this.props.item);
|
||||
}
|
||||
return item.name;
|
||||
},
|
||||
getSearchLabel: function(item) {
|
||||
if(this.props.field['getSearchLabel'] !== undefined) {
|
||||
return this.props.field.getSearchLabel(item, this.props.item);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getValue: function(item) {
|
||||
if(this.props.field['getValue'] !== undefined) {
|
||||
return this.props.field.getValue(item, this.props.item);
|
||||
}
|
||||
return item.id;
|
||||
},
|
||||
render: function() {
|
||||
var options = this.state.items.map(function(item, index) {
|
||||
const options = this.state.items.map((item, index) => {
|
||||
let label = this.getLabel(item);
|
||||
let searchLabel = this.getSearchLabel(item);
|
||||
let value = this.getValue(item);
|
||||
|
||||
return (
|
||||
<option
|
||||
key={ item.id }
|
||||
value={ item.id }
|
||||
key={ 'option-'+index }
|
||||
value={ value }
|
||||
title={ searchLabel }
|
||||
>
|
||||
{ item.name }
|
||||
{ label }
|
||||
</option>
|
||||
);
|
||||
});
|
||||
|
||||
var default_value = (
|
||||
(this.props.item !== undefined && this.props.field.name !== undefined)
|
||||
? this.props.item[this.props.field.name]
|
||||
: null
|
||||
);
|
||||
|
||||
return (
|
||||
<select
|
||||
id={ this.props.field.id || this.props.field.name }
|
||||
ref="select"
|
||||
data-placeholder={ this.props.field.placeholder }
|
||||
multiple={ this.props.field.multiple }
|
||||
defaultValue={ default_value }
|
||||
defaultValue={ this.getSelectedValues() }
|
||||
{...this.props.field.validation}
|
||||
>{ options }</select>
|
||||
);
|
||||
|
@ -48,7 +48,7 @@ define(
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'get',
|
||||
data: { id: id }
|
||||
data: id
|
||||
}).done(function(response) {
|
||||
if(response === false) {
|
||||
this.setState({
|
||||
@ -167,7 +167,7 @@ define(
|
||||
<input
|
||||
className="button button-primary"
|
||||
type="submit"
|
||||
value="Save"
|
||||
value={MailPoet.I18n.t('save')}
|
||||
disabled={this.state.loading} />
|
||||
);
|
||||
}
|
||||
|
@ -402,11 +402,30 @@ var WysijaForm = {
|
||||
}
|
||||
});
|
||||
|
||||
// hide list selection if a list widget has been dragged into the editor
|
||||
$('mailpoet_settings_segment_selection')[
|
||||
(($$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0) === true)
|
||||
? 'hide' : 'show'
|
||||
]();
|
||||
var hasSegmentSelection = WysijaForm.hasSegmentSelection();
|
||||
|
||||
if(hasSegmentSelection) {
|
||||
$('mailpoet_form_segments').writeAttribute('required', false).disable();
|
||||
$('mailpoet_settings_segment_selection').hide();
|
||||
} else {
|
||||
$('mailpoet_form_segments').writeAttribute('required', true).enable();
|
||||
$('mailpoet_settings_segment_selection').show();
|
||||
}
|
||||
},
|
||||
hasSegmentSelection: function() {
|
||||
return ($$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0);
|
||||
},
|
||||
isSegmentSelectionValid: function() {
|
||||
var segment_selection = $$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]')[0];
|
||||
if(segment_selection !== undefined) {
|
||||
var block = WysijaForm.get(segment_selection).block.getData();
|
||||
return (
|
||||
(block.params.values !== undefined)
|
||||
&&
|
||||
(block.params.values.length > 0)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setBlockPositions: function(event, target) {
|
||||
// release dragging lock
|
||||
|
@ -8,91 +8,82 @@ import MailPoet from 'mailpoet'
|
||||
const columns = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
label: MailPoet.I18n.t('formName'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
label: MailPoet.I18n.t('segments'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
label: MailPoet.I18n.t('createdOn'),
|
||||
sortable: true
|
||||
}
|
||||
];
|
||||
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form was moved to the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms were moved to the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
if(count === 1) {
|
||||
message = (
|
||||
MailPoet.I18n.t('oneFormTrashed')
|
||||
);
|
||||
} else {
|
||||
message = (
|
||||
MailPoet.I18n.t('multipleFormsTrashed')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
},
|
||||
onDelete: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form was permanently deleted.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms were permanently deleted.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
if(count === 1) {
|
||||
message = (
|
||||
MailPoet.I18n.t('oneFormDeleted')
|
||||
);
|
||||
} else {
|
||||
message = (
|
||||
MailPoet.I18n.t('multipleFormsDeleted')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
},
|
||||
onRestore: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form has been restored from the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms have been restored from the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
if(count === 1) {
|
||||
message = (
|
||||
MailPoet.I18n.t('oneFormRestored')
|
||||
);
|
||||
} else {
|
||||
message = (
|
||||
MailPoet.I18n.t('multipleFormsRestored')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
};
|
||||
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
label: MailPoet.I18n.t('edit'),
|
||||
link: function(item) {
|
||||
return (
|
||||
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>Edit</a>
|
||||
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>{MailPoet.I18n.t('edit')}</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'duplicate_form',
|
||||
label: 'Duplicate',
|
||||
label: MailPoet.I18n.t('duplicate'),
|
||||
onClick: function(item, refresh) {
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'forms',
|
||||
@ -100,7 +91,7 @@ const item_actions = [
|
||||
data: item.id
|
||||
}).done(function(response) {
|
||||
MailPoet.Notice.success(
|
||||
('Form "%$1s" has been duplicated.').replace('%$1s', response.name)
|
||||
(MailPoet.I18n.t('formDuplicated')).replace('%$1s', response.name)
|
||||
);
|
||||
refresh();
|
||||
});
|
||||
@ -114,7 +105,7 @@ const item_actions = [
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
label: MailPoet.I18n.t('trash'),
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
@ -125,8 +116,8 @@ const FormList = React.createClass({
|
||||
endpoint: 'forms',
|
||||
action: 'create'
|
||||
}).done(function(response) {
|
||||
if(response !== false) {
|
||||
window.location = response;
|
||||
if(response.result && response.form_id) {
|
||||
window.location = mailpoet_form_edit_url + response.form_id;
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -151,11 +142,11 @@ const FormList = React.createClass({
|
||||
</strong>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column-format" data-colname="Lists">
|
||||
<td className="column-format" data-colname={MailPoet.I18n.t('segments')}>
|
||||
{ segments }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Created on">
|
||||
<abbr>{ form.created_at }</abbr>
|
||||
<td className="column-date" data-colname={MailPoet.I18n.t('createdOn')}>
|
||||
<abbr>{ MailPoet.Date.full(form.created_at) }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
@ -164,11 +155,11 @@ const FormList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Forms <a
|
||||
{MailPoet.I18n.t('pageTitle')} <a
|
||||
className="add-new-h2"
|
||||
href="javascript:;"
|
||||
onClick={ this.createForm }
|
||||
>New</a>
|
||||
>{MailPoet.I18n.t('new')}</a>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
|
25
assets/js/src/i18n.js
Normal file
25
assets/js/src/i18n.js
Normal file
@ -0,0 +1,25 @@
|
||||
define('i18n',
|
||||
[
|
||||
'mailpoet',
|
||||
'underscore',
|
||||
], function(
|
||||
MailPoet,
|
||||
_
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var translations = {};
|
||||
|
||||
MailPoet.I18n = {
|
||||
add: function(key, value) {
|
||||
translations[key] = value;
|
||||
},
|
||||
t: function(key) {
|
||||
return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace("%$1s", key);
|
||||
},
|
||||
all: function() {
|
||||
return translations;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
23
assets/js/src/iframe.js
Normal file
23
assets/js/src/iframe.js
Normal file
@ -0,0 +1,23 @@
|
||||
define('iframe', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
'use strict';
|
||||
MailPoet.Iframe = {
|
||||
marginY: 20,
|
||||
autoSize: function(iframe) {
|
||||
if(!iframe) return;
|
||||
|
||||
this.setSize(
|
||||
iframe,
|
||||
iframe.contentWindow.document.body.scrollHeight
|
||||
);
|
||||
},
|
||||
setSize: function(iframe, i) {
|
||||
if(!iframe) return;
|
||||
|
||||
iframe.style.height = (
|
||||
parseInt(i) + this.marginY
|
||||
) + "px";
|
||||
}
|
||||
};
|
||||
|
||||
return MailPoet;
|
||||
});
|
@ -1,8 +1,10 @@
|
||||
define([
|
||||
'react'
|
||||
'react',
|
||||
'mailpoet'
|
||||
],
|
||||
function(
|
||||
React
|
||||
React,
|
||||
MailPoet
|
||||
) {
|
||||
var ListingBulkActions = React.createClass({
|
||||
getInitialState: function() {
|
||||
@ -82,7 +84,7 @@ function(
|
||||
<label
|
||||
className="screen-reader-text"
|
||||
htmlFor="bulk-action-selector-top">
|
||||
Select bulk action
|
||||
{MailPoet.I18n.t('selectBulkAction')}
|
||||
</label>
|
||||
|
||||
<select
|
||||
@ -91,7 +93,7 @@ function(
|
||||
value={ this.state.action }
|
||||
onChange={this.handleChangeAction}
|
||||
>
|
||||
<option value="">Bulk Actions</option>
|
||||
<option value="">{MailPoet.I18n.t('bulkActions')}</option>
|
||||
{ this.props.bulk_actions.map(function(action, index) {
|
||||
return (
|
||||
<option
|
||||
@ -104,7 +106,7 @@ function(
|
||||
<input
|
||||
onClick={ this.handleApplyAction }
|
||||
type="submit"
|
||||
defaultValue="Apply"
|
||||
defaultValue={MailPoet.I18n.t('apply')}
|
||||
className="button action" />
|
||||
|
||||
{ this.state.extra }
|
||||
|
@ -1,10 +1,12 @@
|
||||
define([
|
||||
'react',
|
||||
'jquery'
|
||||
'jquery',
|
||||
'mailpoet'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
jQuery
|
||||
jQuery,
|
||||
MailPoet
|
||||
) {
|
||||
var ListingFilters = React.createClass({
|
||||
handleFilterAction: function() {
|
||||
@ -14,6 +16,9 @@ function(
|
||||
})
|
||||
return this.props.onSelectFilter(filters);
|
||||
},
|
||||
handleEmptyTrash: function() {
|
||||
return this.props.onEmptyTrash();
|
||||
},
|
||||
getAvailableFilters: function() {
|
||||
let filters = this.props.filters;
|
||||
|
||||
@ -34,7 +39,7 @@ function(
|
||||
const available_filters = this.getAvailableFilters()
|
||||
.map(function(filter, i) {
|
||||
let default_value = false;
|
||||
if(selected_filters[filter] !== undefined && selected_filters[filter]) {
|
||||
if (selected_filters[filter] !== undefined && selected_filters[filter]) {
|
||||
default_value = selected_filters[filter]
|
||||
} else {
|
||||
jQuery(`select[name="${filter}"]`).val('');
|
||||
@ -60,20 +65,34 @@ function(
|
||||
|
||||
let button = false;
|
||||
|
||||
if(available_filters.length > 0) {
|
||||
if (available_filters.length > 0) {
|
||||
button = (
|
||||
<input
|
||||
id="post-query-submit"
|
||||
onClick={ this.handleFilterAction }
|
||||
type="submit"
|
||||
defaultValue="Filter"
|
||||
defaultValue={MailPoet.I18n.t('filter')}
|
||||
className="button" />
|
||||
);
|
||||
}
|
||||
|
||||
let empty_trash = false;
|
||||
if (this.props.group === 'trash') {
|
||||
empty_trash = (
|
||||
<input
|
||||
onClick={ this.handleEmptyTrash }
|
||||
type="submit"
|
||||
value={MailPoet.I18n.t('emptyTrash')}
|
||||
className="button"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="alignleft actions actions">
|
||||
{ available_filters }
|
||||
{ button }
|
||||
{ empty_trash }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
define(['react', 'classnames'], function(React, classNames) {
|
||||
define([
|
||||
'react',
|
||||
'classnames',
|
||||
'mailpoet'
|
||||
], function(
|
||||
React,
|
||||
classNames,
|
||||
MailPoet
|
||||
) {
|
||||
|
||||
var ListingHeader = React.createClass({
|
||||
handleSelectItems: function() {
|
||||
@ -28,7 +36,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
<th
|
||||
className="manage-column column-cb check-column">
|
||||
<label className="screen-reader-text">
|
||||
{ 'Select All' }
|
||||
{MailPoet.I18n.t('selectAll')}
|
||||
</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
|
@ -74,10 +74,11 @@ define(
|
||||
);
|
||||
}
|
||||
|
||||
var custom_actions = this.props.item_actions;
|
||||
var item_actions = false;
|
||||
const custom_actions = this.props.item_actions;
|
||||
let item_actions = false;
|
||||
|
||||
if(custom_actions.length > 0) {
|
||||
let is_first = true;
|
||||
item_actions = custom_actions.map(function(action, index) {
|
||||
if(action.display !== undefined) {
|
||||
if(action.display(this.props.item) === false) {
|
||||
@ -85,42 +86,44 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
let custom_action = null;
|
||||
|
||||
if(action.name === 'trash') {
|
||||
return (
|
||||
custom_action = (
|
||||
<span key={ 'action-'+index } className="trash">
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
{(!is_first) ? ' | ' : ''}
|
||||
<a
|
||||
href="javascript:;"
|
||||
onClick={ this.handleTrashItem.bind(
|
||||
null,
|
||||
this.props.item.id
|
||||
) }>
|
||||
Trash
|
||||
{MailPoet.I18n.t('trash')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if(action.refresh) {
|
||||
return (
|
||||
custom_action = (
|
||||
<span
|
||||
onClick={ this.props.onRefreshItems }
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
{(!is_first) ? ' | ' : ''}
|
||||
{ action.link(this.props.item) }
|
||||
</span>
|
||||
);
|
||||
} else if(action.link) {
|
||||
return (
|
||||
custom_action = (
|
||||
<span
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
{(!is_first) ? ' | ' : ''}
|
||||
{ action.link(this.props.item) }
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
custom_action = (
|
||||
<span
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
{(!is_first) ? ' | ' : ''}
|
||||
<a href="javascript:;" onClick={
|
||||
(action.onClick !== undefined)
|
||||
? action.onClick.bind(null,
|
||||
@ -132,11 +135,17 @@ define(
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if(custom_action !== null && is_first === true) {
|
||||
is_first = false;
|
||||
}
|
||||
|
||||
return custom_action;
|
||||
}.bind(this));
|
||||
} else {
|
||||
item_actions = (
|
||||
<span className="edit">
|
||||
<Link to={ `/edit/${ this.props.item.id }` }>Edit</Link>
|
||||
<Link to={ `/edit/${ this.props.item.id }` }>{MailPoet.I18n.t('edit')}</Link>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -152,7 +161,7 @@ define(
|
||||
null,
|
||||
this.props.item.id
|
||||
)}
|
||||
>Restore</a>
|
||||
>{MailPoet.I18n.t('restore')}</a>
|
||||
</span>
|
||||
{ ' | ' }
|
||||
<span className="delete">
|
||||
@ -163,13 +172,13 @@ define(
|
||||
null,
|
||||
this.props.item.id
|
||||
)}
|
||||
>Delete permanently</a>
|
||||
>{MailPoet.I18n.t('deletePermanently')}</a>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
||||
className="toggle-row" type="button">
|
||||
<span className="screen-reader-text">Show more details</span>
|
||||
<span className="screen-reader-text">{MailPoet.I18n.t('showMoreDetails')}</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
@ -182,7 +191,7 @@ define(
|
||||
<button
|
||||
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
||||
className="toggle-row" type="button">
|
||||
<span className="screen-reader-text">Show more details</span>
|
||||
<span className="screen-reader-text">{MailPoet.I18n.t('showMoreDetails')}</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
@ -214,8 +223,8 @@ define(
|
||||
className="colspanchange">
|
||||
{
|
||||
(this.props.loading === true)
|
||||
? MailPoetI18n.loadingItems
|
||||
: MailPoetI18n.noItemsFound
|
||||
? MailPoet.I18n.t('loadingItems')
|
||||
: MailPoet.I18n.t('noItemsFound')
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
@ -241,8 +250,8 @@ define(
|
||||
}>
|
||||
{
|
||||
(this.props.selection !== 'all')
|
||||
? MailPoetI18n.selectAllLabel
|
||||
: MailPoetI18n.selectedAllLabel.replace(
|
||||
? MailPoet.I18n.t('selectAllLabel')
|
||||
: MailPoet.I18n.t('selectedAllLabel').replace(
|
||||
'%d',
|
||||
this.props.count
|
||||
)
|
||||
@ -252,8 +261,8 @@ define(
|
||||
onClick={ this.props.onSelectAll }
|
||||
href="javascript:;">{
|
||||
(this.props.selection !== 'all')
|
||||
? MailPoetI18n.selectAllLink
|
||||
: MailPoetI18n.clearSelection
|
||||
? MailPoet.I18n.t('selectAllLink')
|
||||
: MailPoet.I18n.t('clearSelection')
|
||||
}</a>
|
||||
</td>
|
||||
</tr>
|
||||
@ -504,10 +513,21 @@ define(
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
handleEmptyTrash: function() {
|
||||
this.handleBulkAction('all', {
|
||||
action: 'delete',
|
||||
group: 'trash'
|
||||
}, function(response) {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('permanentlyDeleted').replace('%d', response)
|
||||
);
|
||||
});
|
||||
},
|
||||
handleBulkAction: function(selected_ids, params, callback) {
|
||||
if(
|
||||
this.state.selection === false
|
||||
&& this.state.selected_ids.length === 0
|
||||
&& selected_ids !== 'all'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -520,8 +540,10 @@ define(
|
||||
limit: 0,
|
||||
filter: this.state.filter,
|
||||
group: this.state.group,
|
||||
search: this.state.search,
|
||||
selection: selected_ids
|
||||
search: this.state.search
|
||||
}
|
||||
if(selected_ids !== 'all') {
|
||||
data.listing.selection = selected_ids;
|
||||
}
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
@ -656,12 +678,12 @@ define(
|
||||
bulk_actions = [
|
||||
{
|
||||
name: 'restore',
|
||||
label: 'Restore',
|
||||
label: MailPoet.I18n.t('restore'),
|
||||
onSuccess: this.props.messages.onRestore
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
label: 'Delete permanently',
|
||||
label: MailPoet.I18n.t('deletePermanently'),
|
||||
onSuccess: this.props.messages.onDelete
|
||||
}
|
||||
];
|
||||
@ -715,7 +737,10 @@ define(
|
||||
<ListingFilters
|
||||
filters={ this.state.filters }
|
||||
filter={ this.state.filter }
|
||||
onSelectFilter={ this.handleFilter } />
|
||||
group={ this.state.group }
|
||||
onSelectFilter={ this.handleFilter }
|
||||
onEmptyTrash={ this.handleEmptyTrash }
|
||||
/>
|
||||
<ListingPages
|
||||
count={ this.state.count }
|
||||
page={ this.state.page }
|
||||
|
@ -1,4 +1,12 @@
|
||||
define(['react', 'classnames'], function(React, classNames) {
|
||||
define([
|
||||
'react',
|
||||
'classnames',
|
||||
'mailpoet'
|
||||
], function(
|
||||
React,
|
||||
classNames,
|
||||
MailPoet
|
||||
) {
|
||||
|
||||
var ListingPages = React.createClass({
|
||||
getInitialState: function() {
|
||||
@ -7,7 +15,11 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
}
|
||||
},
|
||||
setPage: function(page) {
|
||||
this.props.onSetPage(page);
|
||||
this.setState({
|
||||
page: null
|
||||
}, function () {
|
||||
this.props.onSetPage(this.constrainPage(page));
|
||||
}.bind(this));
|
||||
},
|
||||
setFirstPage: function() {
|
||||
this.setPage(1);
|
||||
@ -16,10 +28,14 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
this.setPage(this.getLastPage());
|
||||
},
|
||||
setPreviousPage: function() {
|
||||
this.setPage(this.constrainPage(this.props.page - 1));
|
||||
this.setPage(this.constrainPage(
|
||||
parseInt(this.props.page, 10) - 1)
|
||||
);
|
||||
},
|
||||
setNextPage: function() {
|
||||
this.setPage(this.constrainPage(this.props.page + 1));
|
||||
this.setPage(this.constrainPage(
|
||||
parseInt(this.props.page, 10) + 1)
|
||||
);
|
||||
},
|
||||
constrainPage: function(page) {
|
||||
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
|
||||
@ -27,14 +43,16 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
handleSetManualPage: function(e) {
|
||||
if(e.which === 13) {
|
||||
this.setPage(this.state.page);
|
||||
this.setState({ page: null });
|
||||
}
|
||||
},
|
||||
handleChangeManualPage: function(e) {
|
||||
this.setState({
|
||||
page: this.constrainPage(e.target.value)
|
||||
page: e.target.value
|
||||
});
|
||||
},
|
||||
handleBlurManualPage: function(e) {
|
||||
this.setPage(e.target.value);
|
||||
},
|
||||
getLastPage: function() {
|
||||
return Math.ceil(this.props.count / this.props.limit);
|
||||
},
|
||||
@ -62,7 +80,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
<a href="javascript:;"
|
||||
onClick={ this.setPreviousPage }
|
||||
className="prev-page">
|
||||
<span className="screen-reader-text">Previous page</span>
|
||||
<span className="screen-reader-text">{MailPoet.I18n.t('previousPage')}</span>
|
||||
<span aria-hidden="true">‹</span>
|
||||
</a>
|
||||
);
|
||||
@ -73,7 +91,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
<a href="javascript:;"
|
||||
onClick={ this.setFirstPage }
|
||||
className="first-page">
|
||||
<span className="screen-reader-text">First page</span>
|
||||
<span className="screen-reader-text">{MailPoet.I18n.t('firstPage')}</span>
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
);
|
||||
@ -84,7 +102,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
<a href="javascript:;"
|
||||
onClick={ this.setNextPage }
|
||||
className="next-page">
|
||||
<span className="screen-reader-text">Next page</span>
|
||||
<span className="screen-reader-text">{MailPoet.I18n.t('nextPage')}</span>
|
||||
<span aria-hidden="true">›</span>
|
||||
</a>
|
||||
);
|
||||
@ -95,12 +113,17 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
<a href="javascript:;"
|
||||
onClick={ this.setLastPage }
|
||||
className="last-page">
|
||||
<span className="screen-reader-text">Last page</span>
|
||||
<span className="screen-reader-text">{MailPoet.I18n.t('lastPage')}</span>
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
let pageValue = this.props.page;
|
||||
if(this.state.page !== null) {
|
||||
pageValue = this.state.page;
|
||||
}
|
||||
|
||||
pagination = (
|
||||
<span className="pagination-links">
|
||||
{firstPage}
|
||||
@ -110,19 +133,20 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
<span className="paging-input">
|
||||
<label
|
||||
className="screen-reader-text"
|
||||
htmlFor="current-page-selector">Current Page</label>
|
||||
htmlFor="current-page-selector">{MailPoet.I18n.t('currentPage')}</label>
|
||||
<input
|
||||
type="text"
|
||||
onChange={ this.handleChangeManualPage }
|
||||
onKeyUp={ this.handleSetManualPage }
|
||||
onBlur={ this.handleBlurManualPage }
|
||||
aria-describedby="table-paging"
|
||||
size="1"
|
||||
size="2"
|
||||
ref="page"
|
||||
value={ this.state.page || this.props.page }
|
||||
value={ pageValue }
|
||||
name="paged"
|
||||
id="current-page-selector"
|
||||
className="current-page" />
|
||||
of
|
||||
{MailPoet.I18n.t('pageOutOf')}
|
||||
<span className="total-pages">
|
||||
{Math.ceil(this.props.count / this.props.limit)}
|
||||
</span>
|
||||
@ -142,7 +166,9 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
|
||||
return (
|
||||
<div className={ classes }>
|
||||
<span className="displaying-num">{ this.props.count } items</span>
|
||||
<span className="displaying-num">{
|
||||
MailPoet.I18n.t('numberOfItems').replace('%$1d', this.props.count)
|
||||
}</span>
|
||||
{ pagination }
|
||||
</div>
|
||||
);
|
||||
|
@ -1,4 +1,10 @@
|
||||
define(['react'], function(React) {
|
||||
define([
|
||||
'mailpoet',
|
||||
'react'
|
||||
], function(
|
||||
MailPoet,
|
||||
React
|
||||
) {
|
||||
|
||||
var ListingSearch = React.createClass({
|
||||
handleSearch: function(e) {
|
||||
@ -18,7 +24,7 @@ define(['react'], function(React) {
|
||||
<form name="search" onSubmit={this.handleSearch}>
|
||||
<p className="search-box">
|
||||
<label htmlFor="search_input" className="screen-reader-text">
|
||||
Search
|
||||
{MailPoet.I18n.t('searchLabel')}
|
||||
</label>
|
||||
<input
|
||||
type="search"
|
||||
@ -28,7 +34,7 @@ define(['react'], function(React) {
|
||||
defaultValue={this.props.search} />
|
||||
<input
|
||||
type="submit"
|
||||
defaultValue={MailPoetI18n.searchLabel}
|
||||
defaultValue={MailPoet.I18n.t('searchLabel')}
|
||||
className="button" />
|
||||
</p>
|
||||
</form>
|
||||
|
@ -12,9 +12,19 @@ define([
|
||||
'newsletter_editor/blocks/button',
|
||||
'newsletter_editor/blocks/divider',
|
||||
'newsletter_editor/components/communication',
|
||||
'mailpoet',
|
||||
'underscore',
|
||||
'jquery'
|
||||
], function(App, BaseBlock, ButtonBlock, DividerBlock, CommunicationComponent, _, jQuery) {
|
||||
], function(
|
||||
App,
|
||||
BaseBlock,
|
||||
ButtonBlock,
|
||||
DividerBlock,
|
||||
CommunicationComponent,
|
||||
MailPoet,
|
||||
_,
|
||||
jQuery
|
||||
) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -32,10 +42,10 @@ define([
|
||||
inclusionType: 'include', // 'include'|'exclude'
|
||||
displayType: 'excerpt', // 'excerpt'|'full'|'titleOnly'
|
||||
titleFormat: 'h1', // 'h1'|'h2'|'h3'|'ul'
|
||||
titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock',
|
||||
titleAlignment: 'left', // 'left'|'center'|'right'
|
||||
titleIsLink: false, // false|true
|
||||
imagePadded: true, // true|false
|
||||
imageFullWidth: false, // true|false
|
||||
featuredImagePosition: 'belowTitle', // 'aboveTitle'|'belowTitle'|'none'
|
||||
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
|
||||
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
|
||||
authorPrecededBy: 'Author:',
|
||||
@ -63,7 +73,7 @@ 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:titlePosition change:titleAlignment change:titleIsLink change:imagePadded change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:sortBy change:showDivider', this._scheduleFetchPosts, this);
|
||||
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);
|
||||
},
|
||||
@ -73,7 +83,7 @@ define([
|
||||
that.get('_container').get('blocks').reset(content, {parse: true});
|
||||
that.trigger('postsChanged');
|
||||
}).fail(function(error) {
|
||||
console.log('ALC fetchPosts error', arguments);
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
|
||||
});
|
||||
},
|
||||
/**
|
||||
@ -81,7 +91,7 @@ define([
|
||||
* ALC posts on each model change
|
||||
*/
|
||||
_scheduleFetchPosts: function() {
|
||||
var timeout = 2000,
|
||||
var timeout = 500,
|
||||
that = this;
|
||||
if (this._fetchPostsTimer !== undefined) {
|
||||
clearTimeout(this._fetchPostsTimer);
|
||||
@ -142,9 +152,9 @@ define([
|
||||
"keyup .mailpoet_automated_latest_content_show_amount": _.partial(this.changeField, "amount"),
|
||||
"change .mailpoet_automated_latest_content_content_type": _.partial(this.changeField, "contentType"),
|
||||
"change .mailpoet_automated_latest_content_include_or_exclude": _.partial(this.changeField, "inclusionType"),
|
||||
"change .mailpoet_automated_latest_content_title_position": _.partial(this.changeField, "titlePosition"),
|
||||
"change .mailpoet_automated_latest_content_title_alignment": _.partial(this.changeField, "titleAlignment"),
|
||||
"change .mailpoet_automated_latest_content_image_padded": _.partial(this.changeBoolField, "imagePadded"),
|
||||
"change .mailpoet_automated_latest_content_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
|
||||
"change .mailpoet_automated_latest_content_featured_image_position": _.partial(this.changeField, "featuredImagePosition"),
|
||||
"change .mailpoet_automated_latest_content_show_author": _.partial(this.changeField, "showAuthor"),
|
||||
"keyup .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
||||
"change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"),
|
||||
@ -273,12 +283,13 @@ define([
|
||||
},
|
||||
changeDisplayType: function(event) {
|
||||
var value = jQuery(event.target).val();
|
||||
|
||||
if (value == 'titleOnly') {
|
||||
this.$('.mailpoet_automated_latest_content_title_position_container').addClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_automated_latest_content_title_as_list').removeClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_automated_latest_content_image_full_width_option').addClass('mailpoet_hidden');
|
||||
} else {
|
||||
this.$('.mailpoet_automated_latest_content_title_position_container').removeClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_automated_latest_content_title_as_list').addClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_automated_latest_content_image_full_width_option').removeClass('mailpoet_hidden');
|
||||
|
||||
// Reset titleFormat if it was set to List when switching away from displayType=titleOnly
|
||||
if (this.model.get('titleFormat') === 'ul') {
|
||||
@ -287,6 +298,12 @@ define([
|
||||
this.$('.mailpoet_automated_latest_content_title_as_link').removeClass('mailpoet_hidden');
|
||||
}
|
||||
}
|
||||
|
||||
if (value === 'excerpt') {
|
||||
this.$('.mailpoet_automated_latest_content_featured_image_position_container').removeClass('mailpoet_hidden');
|
||||
} else {
|
||||
this.$('.mailpoet_automated_latest_content_featured_image_position_container').addClass('mailpoet_hidden');
|
||||
}
|
||||
this.changeField('displayType', event);
|
||||
},
|
||||
changeTitleFormat: function(event) {
|
||||
|
@ -32,6 +32,7 @@ define([
|
||||
fontColor: '#000000',
|
||||
fontFamily: 'Arial',
|
||||
fontSize: '16px',
|
||||
fontWeight: 'normal', // 'normal'|'bold'
|
||||
textAlign: 'center',
|
||||
},
|
||||
},
|
||||
@ -72,6 +73,7 @@ define([
|
||||
"change .mailpoet_field_button_font_size": _.partial(this.changeField, "styles.block.fontSize"),
|
||||
"change .mailpoet_field_button_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||
"change .mailpoet_field_button_border_color": _.partial(this.changeColorField, "styles.block.borderColor"),
|
||||
"change .mailpoet_field_button_font_weight": "changeFontWeight",
|
||||
|
||||
"input .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
|
||||
"change .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
|
||||
@ -128,6 +130,13 @@ define([
|
||||
this.$(fieldToUpdate).val(jQuery(event.target).val());
|
||||
callable(event);
|
||||
},
|
||||
changeFontWeight: function(event) {
|
||||
var checked = !!jQuery(event.target).prop('checked');
|
||||
this.model.set(
|
||||
'styles.block.fontWeight',
|
||||
(checked) ? jQuery(event.target).val() : 'normal'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Module.ButtonWidgetView = base.WidgetView.extend({
|
||||
|
@ -16,7 +16,7 @@ define([
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
type: 'footer',
|
||||
text: '<a href="[unsubscribeUrl]">Unsubscribe</a> | <a href="[manageSubscriptionUrl]">Manage subscription</a><br /><b>Add your postal address here!</b>',
|
||||
text: '<a href="[subscription:unsubscribe_url]">Unsubscribe</a> | <a href="[subscription:manage_url]">Manage subscription</a><br /><b>Add your postal address here!</b>',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
@ -41,7 +41,7 @@ define([
|
||||
getTemplate: function() { return templates.footerBlock; },
|
||||
modelEvents: _.extend({
|
||||
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
|
||||
}, base.BlockView.prototype.modelEvents),
|
||||
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
|
||||
onDragSubstituteBy: function() { return Module.FooterWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.FooterBlockToolsView({ model: this.model });
|
||||
@ -60,11 +60,9 @@ define([
|
||||
|
||||
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
|
||||
invalid_elements: "script",
|
||||
style_formats: [
|
||||
{title: 'Paragraph', block: 'p'},
|
||||
],
|
||||
block_formats: 'Paragraph=p',
|
||||
|
||||
plugins: "link textcolor mailpoet_custom_fields",
|
||||
plugins: "link textcolor colorpicker mailpoet_custom_fields",
|
||||
|
||||
setup: function(editor) {
|
||||
editor.on('change', function(e) {
|
||||
@ -81,7 +79,7 @@ define([
|
||||
},
|
||||
|
||||
mailpoet_custom_fields: App.getConfig().get('customFields').toJSON(),
|
||||
mailpoet_custom_fields_window_title: App.getConfig().get('translations.customFieldsWindowTitle'),
|
||||
mailpoet_custom_fields_window_title: MailPoet.I18n.t('customFieldsWindowTitle'),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ define([
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
type: 'header',
|
||||
text: 'Display problems? <a href="[viewInBrowserUrl]">View it in your browser</a>',
|
||||
text: 'Display problems? <a href="[newsletter:view_in_browser_url]">View it in your browser</a>',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
@ -41,7 +41,7 @@ define([
|
||||
getTemplate: function() { return templates.headerBlock; },
|
||||
modelEvents: _.extend({
|
||||
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
|
||||
}, base.BlockView.prototype.modelEvents),
|
||||
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
|
||||
onDragSubstituteBy: function() { return Module.HeaderWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.HeaderBlockToolsView({ model: this.model });
|
||||
@ -60,11 +60,9 @@ define([
|
||||
|
||||
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
|
||||
invalid_elements: "script",
|
||||
style_formats: [
|
||||
{title: 'Paragraph', block: 'p'},
|
||||
],
|
||||
block_formats: 'Paragraph=p',
|
||||
|
||||
plugins: "link textcolor mailpoet_custom_fields",
|
||||
plugins: "link textcolor colorpicker mailpoet_custom_fields",
|
||||
|
||||
setup: function(editor) {
|
||||
editor.on('change', function(e) {
|
||||
@ -81,7 +79,7 @@ define([
|
||||
},
|
||||
|
||||
mailpoet_custom_fields: App.getConfig().get('customFields').toJSON(),
|
||||
mailpoet_custom_fields_window_title: App.getConfig().get('translations.customFieldsWindowTitle'),
|
||||
mailpoet_custom_fields_window_title: MailPoet.I18n.t('customFieldsWindowTitle'),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ define([
|
||||
link: 'http://example.org',
|
||||
src: 'no-image.png',
|
||||
alt: 'An image of...',
|
||||
padded: true, // true | false - Padded or full width
|
||||
fullWidth: true, // true | false
|
||||
width: '64px',
|
||||
height: '64px',
|
||||
styles: {
|
||||
@ -45,10 +45,10 @@ define([
|
||||
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
|
||||
if (this.model.get('padded')) {
|
||||
this.$el.removeClass('mailpoet_full_image');
|
||||
} else {
|
||||
if (this.model.get('fullWidth')) {
|
||||
this.$el.addClass('mailpoet_full_image');
|
||||
} else {
|
||||
this.$el.removeClass('mailpoet_full_image');
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -64,7 +64,7 @@ define([
|
||||
"keyup .mailpoet_field_image_link": _.partial(this.changeField, "link"),
|
||||
"keyup .mailpoet_field_image_address": _.partial(this.changeField, "src"),
|
||||
"keyup .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
|
||||
"change .mailpoet_field_image_padded": _.partial(this.changeBoolCheckboxField, "padded"),
|
||||
"change .mailpoet_field_image_full_width": _.partial(this.changeBoolCheckboxField, "fullWidth"),
|
||||
"change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"),
|
||||
"click .mailpoet_field_image_select_another_image": "showMediaManager",
|
||||
"click .mailpoet_done_editing": "close",
|
||||
|
@ -43,10 +43,10 @@ define([
|
||||
inclusionType: 'include', // 'include'|'exclude'
|
||||
displayType: 'excerpt', // 'excerpt'|'full'|'titleOnly'
|
||||
titleFormat: 'h1', // 'h1'|'h2'|'h3'|'ul'
|
||||
titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock',
|
||||
titleAlignment: 'left', // 'left'|'center'|'right'
|
||||
titleIsLink: false, // false|true
|
||||
imagePadded: true, // true|false
|
||||
imageFullWidth: false, // true|false
|
||||
featuredImagePosition: 'belowTitle', // 'aboveTitle'|'belowTitle'|'none'
|
||||
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
|
||||
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
|
||||
authorPrecededBy: 'Author:',
|
||||
@ -88,7 +88,7 @@ define([
|
||||
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.on('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:showDivider', refreshTransformedPosts);
|
||||
this.listenTo(this.get('readMoreButton'), 'change', refreshTransformedPosts);
|
||||
this.listenTo(this.get('divider'), 'change', refreshTransformedPosts);
|
||||
|
||||
@ -101,7 +101,7 @@ define([
|
||||
that.get('_selectedPosts').reset(); // Empty out the collection
|
||||
that.trigger('change:_availablePosts');
|
||||
}).fail(function() {
|
||||
console.log('Posts fetchPosts error', arguments);
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
|
||||
});
|
||||
},
|
||||
_refreshTransformedPosts: function() {
|
||||
@ -111,14 +111,14 @@ define([
|
||||
data.posts = this.get('_selectedPosts').pluck('ID');
|
||||
|
||||
if (data.posts.length === 0) {
|
||||
this.get('_transformedPosts.blocks').reset();
|
||||
this.get('_transformedPosts').get('blocks').reset();
|
||||
return;
|
||||
}
|
||||
|
||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
|
||||
}).fail(function() {
|
||||
console.log('Posts _refreshTransformedPosts error', arguments);
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
|
||||
});
|
||||
},
|
||||
_insertSelectedPosts: function() {
|
||||
@ -134,7 +134,7 @@ define([
|
||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||
collection.add(posts, { at: index });
|
||||
}).fail(function() {
|
||||
console.log('Posts fetchPosts error', arguments);
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
|
||||
});
|
||||
},
|
||||
});
|
||||
@ -394,9 +394,9 @@ define([
|
||||
"keyup .mailpoet_posts_show_amount": _.partial(this.changeField, "amount"),
|
||||
"change .mailpoet_posts_content_type": _.partial(this.changeField, "contentType"),
|
||||
"change .mailpoet_posts_include_or_exclude": _.partial(this.changeField, "inclusionType"),
|
||||
"change .mailpoet_posts_title_position": _.partial(this.changeField, "titlePosition"),
|
||||
"change .mailpoet_posts_title_alignment": _.partial(this.changeField, "titleAlignment"),
|
||||
"change .mailpoet_posts_image_padded": _.partial(this.changeBoolField, "imagePadded"),
|
||||
"change .mailpoet_posts_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
|
||||
"change .mailpoet_posts_featured_image_position": _.partial(this.changeField, "featuredImagePosition"),
|
||||
"change .mailpoet_posts_show_author": _.partial(this.changeField, "showAuthor"),
|
||||
"keyup .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
||||
"change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"),
|
||||
@ -448,11 +448,11 @@ define([
|
||||
changeDisplayType: function(event) {
|
||||
var value = jQuery(event.target).val();
|
||||
if (value == 'titleOnly') {
|
||||
this.$('.mailpoet_posts_title_position_container').addClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_posts_title_as_list').removeClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_posts_image_full_width_option').addClass('mailpoet_hidden');
|
||||
} else {
|
||||
this.$('.mailpoet_posts_title_position_container').removeClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_posts_title_as_list').addClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_posts_image_full_width_option').removeClass('mailpoet_hidden');
|
||||
|
||||
// Reset titleFormat if it was set to List when switching away from displayType=titleOnly
|
||||
if (this.model.get('titleFormat') === 'ul') {
|
||||
@ -461,6 +461,13 @@ define([
|
||||
this.$('.mailpoet_posts_title_as_link').removeClass('mailpoet_hidden');
|
||||
}
|
||||
}
|
||||
|
||||
if (value === 'excerpt') {
|
||||
this.$('.mailpoet_posts_featured_image_position_container').removeClass('mailpoet_hidden');
|
||||
} else {
|
||||
this.$('.mailpoet_posts_featured_image_position_container').addClass('mailpoet_hidden');
|
||||
}
|
||||
|
||||
this.changeField('displayType', event);
|
||||
},
|
||||
changeTitleFormat: function(event) {
|
||||
|
@ -52,21 +52,15 @@ define([
|
||||
inline: true,
|
||||
|
||||
menubar: false,
|
||||
toolbar1: "styleselect bold italic forecolor | link unlink",
|
||||
toolbar1: "formatselect bold italic forecolor | link unlink",
|
||||
toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_custom_fields",
|
||||
|
||||
//forced_root_block: 'p',
|
||||
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]",
|
||||
invalid_elements: "script",
|
||||
style_formats: [
|
||||
{title: 'Heading 1', block: 'h1'},
|
||||
{title: 'Heading 2', block: 'h2'},
|
||||
{title: 'Heading 3', block: 'h3'},
|
||||
block_formats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
|
||||
|
||||
{title: 'Paragraph', block: 'p'},
|
||||
],
|
||||
|
||||
plugins: "link code textcolor mailpoet_custom_fields",
|
||||
plugins: "link code textcolor colorpicker mailpoet_custom_fields",
|
||||
|
||||
setup: function(editor) {
|
||||
editor.on('change', function(e) {
|
||||
@ -83,7 +77,7 @@ define([
|
||||
},
|
||||
|
||||
mailpoet_custom_fields: App.getConfig().get('customFields').toJSON(),
|
||||
mailpoet_custom_fields_window_title: App.getConfig().get('translations.customFieldsWindowTitle'),
|
||||
mailpoet_custom_fields_window_title: MailPoet.I18n.t('customFieldsWindowTitle'),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,6 @@ define([
|
||||
availableStyles: {},
|
||||
socialIcons: {},
|
||||
blockDefaults: {},
|
||||
translations: {},
|
||||
sidepanelWidth: '331px',
|
||||
validation: {},
|
||||
urls: {},
|
||||
|
@ -11,7 +11,7 @@ define([
|
||||
// Does not hold newsletter content nor newsletter styles, those are
|
||||
// handled by other components.
|
||||
Module.NewsletterModel = SuperModel.extend({
|
||||
stale: ['body'],
|
||||
stale: ['body', 'created_at', 'deleted_at', 'updated_at'],
|
||||
initialize: function(options) {
|
||||
this.on('change', function() {
|
||||
App.getChannel().trigger('autoSave');
|
||||
|
@ -67,7 +67,28 @@ define([
|
||||
};
|
||||
|
||||
Module.getThumbnail = function(element, options) {
|
||||
return html2canvas(element, options || {});
|
||||
var promise = html2canvas(element, options || {});
|
||||
|
||||
return promise.then(function(oldCanvas) {
|
||||
// Temporary workaround for html2canvas-alpha2.
|
||||
// Removes 1px left transparent border from resulting canvas.
|
||||
|
||||
var oldContext = oldCanvas.getContext('2d'),
|
||||
newCanvas = document.createElement("canvas"),
|
||||
newContext = newCanvas.getContext("2d"),
|
||||
leftBorderWidth = 1;
|
||||
|
||||
newCanvas.width = oldCanvas.width;
|
||||
newCanvas.height = oldCanvas.height;
|
||||
|
||||
newContext.drawImage(
|
||||
oldCanvas,
|
||||
leftBorderWidth, 0, oldCanvas.width - leftBorderWidth, oldCanvas.height,
|
||||
0, 0, oldCanvas.width, oldCanvas.height
|
||||
);
|
||||
|
||||
return newCanvas;
|
||||
});
|
||||
};
|
||||
|
||||
Module.saveTemplate = function(options) {
|
||||
@ -170,7 +191,7 @@ define([
|
||||
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateNameMissing'),
|
||||
MailPoet.I18n.t('templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
@ -178,30 +199,27 @@ define([
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
||||
MailPoet.I18n.t('templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log('Saving template with ', templateName, templateDescription);
|
||||
Module.saveTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
}).done(function() {
|
||||
console.log('Template saved', arguments);
|
||||
MailPoet.Notice.success(
|
||||
App.getConfig().get('translations.templateSaved'),
|
||||
MailPoet.I18n.t('templateSaved'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
}).fail(function() {
|
||||
console.log('Template save failed', arguments);
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateSaveFailed'),
|
||||
MailPoet.I18n.t('templateSaveFailed'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
@ -226,7 +244,7 @@ define([
|
||||
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateNameMissing'),
|
||||
MailPoet.I18n.t('templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
@ -234,14 +252,13 @@ define([
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
||||
MailPoet.I18n.t('templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log('Exporting template with ', templateName, templateDescription);
|
||||
Module.exportTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
@ -257,7 +274,6 @@ define([
|
||||
next: function() {
|
||||
this.hideOptionContents();
|
||||
if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
|
||||
console.log('Next');
|
||||
window.location.href = App.getConfig().get('urls.send');
|
||||
}
|
||||
},
|
||||
@ -268,8 +284,8 @@ define([
|
||||
}
|
||||
|
||||
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
|
||||
JSON.stringify(jsonObject).indexOf("[unsubscribeUrl]") < 0) {
|
||||
this.showValidationError(App.getConfig().get('translations.unsubscribeLinkMissing'));
|
||||
JSON.stringify(jsonObject).indexOf("[subscription:unsubscribe_url]") < 0) {
|
||||
this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,24 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/components/communication',
|
||||
'mailpoet',
|
||||
'backbone',
|
||||
'backbone.marionette',
|
||||
'backbone.supermodel',
|
||||
'underscore',
|
||||
'jquery',
|
||||
'sticky-kit'
|
||||
], function(App, CommunicationComponent, Backbone, Marionette, SuperModel, _, jQuery, StickyKit) {
|
||||
], function(
|
||||
App,
|
||||
CommunicationComponent,
|
||||
MailPoet,
|
||||
Backbone,
|
||||
Marionette,
|
||||
SuperModel,
|
||||
_,
|
||||
jQuery,
|
||||
StickyKit
|
||||
) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -225,33 +236,50 @@ define([
|
||||
showPreview: function() {
|
||||
var json = App.toJSON();
|
||||
|
||||
// Stringify to enable transmission of primitive non-string value types
|
||||
if (!_.isUndefined(json.body)) {
|
||||
json.body = JSON.stringify(json.body);
|
||||
}
|
||||
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'render',
|
||||
data: json,
|
||||
}).done(function(response){
|
||||
console.log('Should open a new window');
|
||||
window.open('data:text/html,' + encodeURIComponent(response.rendered_body), '_blank');
|
||||
MailPoet.Modal.loading(false);
|
||||
window.open('data:text/html;charset=utf-8,' + encodeURIComponent(response.rendered_body), '_blank');
|
||||
}).fail(function(error) {
|
||||
console.log('Preview error', json);
|
||||
MailPoet.Modal.loading(false);
|
||||
alert('Something went wrong, check console');
|
||||
});
|
||||
},
|
||||
sendPreview: function() {
|
||||
// testing sending method
|
||||
console.log('trying to send a preview');
|
||||
// get form data
|
||||
var $emailField = this.$('#mailpoet_preview_to_email');
|
||||
var data = {
|
||||
subscriber: this.$('#mailpoet_preview_to_email').val(),
|
||||
subscriber: $emailField.val(),
|
||||
id: App.getNewsletter().get('id'),
|
||||
};
|
||||
|
||||
if (data.subscriber.length <= 0) {
|
||||
MailPoet.Notice.error(
|
||||
MailPoet.I18n.t('newsletterPreviewEmailMissing'),
|
||||
{
|
||||
positionAfter: $emailField,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// send test email
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
CommunicationComponent.previewNewsletter(data).done(function(response) {
|
||||
if(response.result !== undefined && response.result === true) {
|
||||
MailPoet.Notice.success(App.getConfig().get('translations.newsletterPreviewSent'), { scroll: true });
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('newsletterPreviewSent'), { scroll: true });
|
||||
} else {
|
||||
if (_.isArray(response.errors)) {
|
||||
response.errors.map(function(error) {
|
||||
@ -259,7 +287,7 @@ define([
|
||||
});
|
||||
} else {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.newsletterPreviewFailedToSend'),
|
||||
MailPoet.I18n.t('newsletterPreviewFailedToSend'),
|
||||
{
|
||||
scroll: true,
|
||||
static: true,
|
||||
|
@ -2,12 +2,14 @@ define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'classnames'
|
||||
'classnames',
|
||||
'mailpoet'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
classNames
|
||||
classNames,
|
||||
MailPoet
|
||||
) {
|
||||
var Link = Router.Link;
|
||||
|
||||
@ -21,20 +23,20 @@ define(
|
||||
steps: [
|
||||
{
|
||||
name: 'type',
|
||||
label: 'Select type',
|
||||
label: MailPoet.I18n.t('selectType'),
|
||||
link: '/new'
|
||||
},
|
||||
{
|
||||
name: 'template',
|
||||
label: 'Template'
|
||||
label: MailPoet.I18n.t('template')
|
||||
},
|
||||
{
|
||||
name: 'editor',
|
||||
label: 'Designer'
|
||||
label: MailPoet.I18n.t('designer')
|
||||
},
|
||||
{
|
||||
name: 'send',
|
||||
label: 'Send'
|
||||
label: MailPoet.I18n.t('send')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -4,104 +4,97 @@ define(
|
||||
'react-router',
|
||||
'listing/listing.jsx',
|
||||
'classnames',
|
||||
'jquery'
|
||||
'jquery',
|
||||
'mailpoet'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
Listing,
|
||||
classNames,
|
||||
jQuery
|
||||
jQuery,
|
||||
MailPoet
|
||||
) {
|
||||
var Link = Router.Link;
|
||||
|
||||
var columns = [
|
||||
{
|
||||
name: 'subject',
|
||||
label: 'Subject',
|
||||
label: MailPoet.I18n.t('subject'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status'
|
||||
label: MailPoet.I18n.t('status')
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists'
|
||||
label: MailPoet.I18n.t('lists')
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
label: MailPoet.I18n.t('createdOn'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'updated_at',
|
||||
label: 'Last modified on',
|
||||
label: MailPoet.I18n.t('lastModifiedOn'),
|
||||
sortable: true
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
onTrash: function(response) {
|
||||
var count = ~~response.newsletters;
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
if(count === 1) {
|
||||
message = (
|
||||
'1 newsletter was moved to the trash.'
|
||||
MailPoet.I18n.t('oneNewsletterTrashed')
|
||||
);
|
||||
} else if(count > 1) {
|
||||
} else {
|
||||
message = (
|
||||
'%$1d newsletters were moved to the trash.'
|
||||
MailPoet.I18n.t('multipleNewslettersTrashed')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
},
|
||||
onDelete: function(response) {
|
||||
var count = ~~response.newsletters;
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
if(count === 1) {
|
||||
message = (
|
||||
'1 newsletter was permanently deleted.'
|
||||
MailPoet.I18n.t('oneNewsletterDeleted')
|
||||
);
|
||||
} else if(count > 1) {
|
||||
} else {
|
||||
message = (
|
||||
'%$1d newsletters were permanently deleted.'
|
||||
MailPoet.I18n.t('multipleNewslettersDeleted')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
},
|
||||
onRestore: function(response) {
|
||||
var count = ~~response.newsletters;
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
if(count === 1) {
|
||||
message = (
|
||||
'1 newsletter has been restored from the trash.'
|
||||
MailPoet.I18n.t('oneNewsletterRestored')
|
||||
);
|
||||
} else if(count > 1) {
|
||||
} else {
|
||||
message = (
|
||||
'%$1d newsletters have been restored from the trash.'
|
||||
MailPoet.I18n.t('multipleNewslettersRestored')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
};
|
||||
|
||||
var bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
label: MailPoet.I18n.t('trash'),
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
@ -112,7 +105,7 @@ define(
|
||||
link: function(item) {
|
||||
return (
|
||||
<a href={ `?page=mailpoet-newsletter-editor&id=${ item.id }` }>
|
||||
Edit
|
||||
{MailPoet.I18n.t('edit')}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@ -144,9 +137,9 @@ define(
|
||||
});
|
||||
},
|
||||
renderStatus: function(item) {
|
||||
if(item.queue === null) {
|
||||
if(!item.queue) {
|
||||
return (
|
||||
<span>Not sent yet.</span>
|
||||
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
||||
);
|
||||
} else {
|
||||
var progressClasses = classNames(
|
||||
@ -164,9 +157,11 @@ define(
|
||||
if(item.queue.status === 'completed') {
|
||||
label = (
|
||||
<span>
|
||||
Sent to {
|
||||
item.queue.count_processed - item.queue.count_failed
|
||||
} out of { item.queue.count_total }.
|
||||
{
|
||||
MailPoet.I18n.t('newsletterQueueCompleted')
|
||||
.replace("%$1d", item.queue.count_processed - item.queue.count_failed)
|
||||
.replace("%$2d", item.queue.count_total)
|
||||
}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
@ -180,14 +175,14 @@ define(
|
||||
style={{ display: (item.queue.status === 'paused') ? 'inline-block': 'none' }}
|
||||
href="javascript:;"
|
||||
onClick={ this.resumeSending.bind(null, item) }
|
||||
>Resume</a>
|
||||
>{MailPoet.I18n.t('resume')}</a>
|
||||
<a
|
||||
id={ 'pause_'+item.id }
|
||||
className="button mailpoet_pause"
|
||||
style={{ display: (item.queue.status === null) ? 'inline-block': 'none' }}
|
||||
href="javascript:;"
|
||||
onClick={ this.pauseSending.bind(null, item) }
|
||||
>Pause</a>
|
||||
>{MailPoet.I18n.t('pause')}</a>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -217,10 +212,8 @@ define(
|
||||
'has-row-actions'
|
||||
);
|
||||
|
||||
var segments = mailpoet_segments.filter(function(segment) {
|
||||
return (jQuery.inArray(segment.id, newsletter.segments) !== -1);
|
||||
}).map(function(segment) {
|
||||
return segment.name;
|
||||
var segments = newsletter.segments.map(function(segment) {
|
||||
return segment.name
|
||||
}).join(', ');
|
||||
|
||||
return (
|
||||
@ -238,10 +231,10 @@ define(
|
||||
{ segments }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed on">
|
||||
<abbr>{ newsletter.created_at }</abbr>
|
||||
<abbr>{ MailPoet.Date.full(newsletter.created_at) }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Last modified on">
|
||||
<abbr>{ newsletter.updated_at }</abbr>
|
||||
<abbr>{ MailPoet.Date.full(newsletter.updated_at) }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
@ -250,7 +243,7 @@ define(
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Newsletters <Link className="add-new-h2" to="/new">New</Link>
|
||||
{MailPoet.I18n.t('pageTitle')} <Link className="add-new-h2" to="/new">{MailPoet.I18n.t('new')}</Link>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
|
@ -21,20 +21,20 @@ define(
|
||||
var fields = [
|
||||
{
|
||||
name: 'subject',
|
||||
label: 'Subject line',
|
||||
tip: "Be creative! It's the first thing your subscribers see."+
|
||||
"Tempt them to open your email.",
|
||||
label: MailPoet.I18n.t('subjectLine'),
|
||||
tip: MailPoet.I18n.t('subjectLineTip'),
|
||||
type: 'text',
|
||||
validation: {
|
||||
'data-parsley-required': true
|
||||
'data-parsley-required': true,
|
||||
'data-parsley-required-message': MailPoet.I18n.t('emptySubjectLineError')
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Segments',
|
||||
tip: "The subscriber segment that will be used for this campaign.",
|
||||
label: MailPoet.I18n.t('segments'),
|
||||
tip: MailPoet.I18n.t('segmentsTip'),
|
||||
type: 'selection',
|
||||
placeholder: "Select a segment",
|
||||
placeholder: MailPoet.I18n.t('selectSegmentPlaceholder'),
|
||||
id: "mailpoet_segments",
|
||||
endpoint: "segments",
|
||||
multiple: true,
|
||||
@ -42,18 +42,19 @@ define(
|
||||
return !!(!segment.deleted_at);
|
||||
},
|
||||
validation: {
|
||||
'data-parsley-required': true
|
||||
'data-parsley-required': true,
|
||||
'data-parsley-required-message': MailPoet.I18n.t('noSegmentsSelectedError')
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'sender',
|
||||
label: 'Sender',
|
||||
tip: "Name & email of yourself or your company.",
|
||||
label: MailPoet.I18n.t('sender'),
|
||||
tip: MailPoet.I18n.t('senderTip'),
|
||||
fields: [
|
||||
{
|
||||
name: 'sender_name',
|
||||
type: 'text',
|
||||
placeholder: 'John Doe',
|
||||
placeholder: MailPoet.I18n.t('senderNamePlaceholder'),
|
||||
defaultValue: (settings.sender !== undefined) ? settings.sender.name : '',
|
||||
validation: {
|
||||
'data-parsley-required': true
|
||||
@ -62,7 +63,7 @@ define(
|
||||
{
|
||||
name: 'sender_address',
|
||||
type: 'text',
|
||||
placeholder: 'john.doe@email.com',
|
||||
placeholder: MailPoet.I18n.t('senderAddressPlaceholder'),
|
||||
defaultValue: (settings.sender !== undefined) ? settings.sender.address : '',
|
||||
validation: {
|
||||
'data-parsley-required': true,
|
||||
@ -73,21 +74,20 @@ define(
|
||||
},
|
||||
{
|
||||
name: 'reply-to',
|
||||
label: 'Reply-to',
|
||||
tip: 'When the subscribers hit "reply" this is who will receive their '+
|
||||
'email.',
|
||||
label: MailPoet.I18n.t('replyTo'),
|
||||
tip: MailPoet.I18n.t('replyToTip'),
|
||||
inline: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'reply_to_name',
|
||||
type: 'text',
|
||||
placeholder: 'John Doe',
|
||||
placeholder: MailPoet.I18n.t('replyToNamePlaceholder'),
|
||||
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '',
|
||||
},
|
||||
{
|
||||
name: 'reply_to_address',
|
||||
type: 'text',
|
||||
placeholder: 'john.doe@email.com',
|
||||
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder'),
|
||||
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : ''
|
||||
},
|
||||
]
|
||||
@ -96,10 +96,10 @@ define(
|
||||
|
||||
var messages = {
|
||||
onUpdate: function() {
|
||||
MailPoet.Notice.success('Newsletter successfully updated!');
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('newsletterUpdated'));
|
||||
},
|
||||
onCreate: function() {
|
||||
MailPoet.Notice.success('Newsletter successfully added!');
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('newsletterAdded'));
|
||||
}
|
||||
};
|
||||
|
||||
@ -107,8 +107,16 @@ define(
|
||||
mixins: [
|
||||
Router.History
|
||||
],
|
||||
componentDidMount: function() {
|
||||
jQuery('#mailpoet_newsletter').parsley();
|
||||
},
|
||||
isValid: function() {
|
||||
return jQuery('#mailpoet_newsletter').parsley().isValid();
|
||||
},
|
||||
handleSend: function() {
|
||||
if(jQuery('#mailpoet_newsletter').parsley().validate() === true) {
|
||||
if(!this.isValid()) {
|
||||
jQuery('#mailpoet_newsletter').parsley().validate();
|
||||
} else {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'sendingQueue',
|
||||
action: 'add',
|
||||
@ -128,27 +136,25 @@ define(
|
||||
if(response.result === true) {
|
||||
this.history.pushState(null, '/');
|
||||
MailPoet.Notice.success(
|
||||
'The newsletter is being sent...'
|
||||
MailPoet.I18n.t('newsletterIsBeingSent')
|
||||
);
|
||||
} else {
|
||||
if(response.errors) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.join("<br />")
|
||||
);
|
||||
MailPoet.Notice.error(response.errors);
|
||||
} else {
|
||||
MailPoet.Notice.error(
|
||||
'An error occurred while trying to send. '+
|
||||
'<a href="?page=mailpoet-settings">Check your settings.</a>'
|
||||
MailPoet.I18n.t('newsletterSendingError').replace("%$1s", '?page=mailpoet-settings')
|
||||
);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Final step: last details</h1>
|
||||
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
|
||||
|
||||
<Breadcrumb step="send" />
|
||||
|
||||
@ -158,24 +164,25 @@ define(
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
isValid={ this.isValid }
|
||||
>
|
||||
<p className="submit">
|
||||
<input
|
||||
className="button button-primary"
|
||||
type="button"
|
||||
onClick={ this.handleSend }
|
||||
value="Send" />
|
||||
value={MailPoet.I18n.t('send')} />
|
||||
|
||||
<input
|
||||
className="button button-secondary"
|
||||
type="submit"
|
||||
value="Save as draft and close" />
|
||||
or simply
|
||||
value={MailPoet.I18n.t('saveDraftAndClose')} />
|
||||
{MailPoet.I18n.t('orSimply')}
|
||||
<a
|
||||
href={
|
||||
'?page=mailpoet-newsletter-editor&id='+this.props.params.id
|
||||
}>
|
||||
go back to design
|
||||
{MailPoet.I18n.t('goBackToDesign')}
|
||||
</a>.
|
||||
</p>
|
||||
</Form>
|
||||
|
@ -24,12 +24,15 @@ define(
|
||||
template.body = JSON.stringify(template.body);
|
||||
}
|
||||
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletterTemplates',
|
||||
action: 'save',
|
||||
data: template
|
||||
}).done(function(response) {
|
||||
if(response === true) {
|
||||
MailPoet.Modal.loading(false);
|
||||
if(response.result === true) {
|
||||
this.props.onImport(template);
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
@ -51,7 +54,7 @@ define(
|
||||
try {
|
||||
saveTemplate(JSON.parse(e.target.result));
|
||||
} catch (err) {
|
||||
MailPoet.Notice.error('This template file appears to be malformed. Please try another one.');
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('templateFileMalformedError'));
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
@ -60,15 +63,15 @@ define(
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2>Import a template</h2>
|
||||
<h2>{MailPoet.I18n.t('importTemplateTitle')}</h2>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<input type="file" placeholder="Select a .json file to upload" ref="templateFile" />
|
||||
<input type="file" placeholder={MailPoet.I18n.t('selectJsonFileToUpload')} ref="templateFile" />
|
||||
|
||||
<p className="submit">
|
||||
<input
|
||||
className="button button-primary"
|
||||
type="submit"
|
||||
value="Upload" />
|
||||
value={MailPoet.I18n.t('upload')} />
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
@ -92,19 +95,22 @@ define(
|
||||
getTemplates: function() {
|
||||
this.setState({ loading: true });
|
||||
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletterTemplates',
|
||||
action: 'getAll',
|
||||
}).done(function(response) {
|
||||
MailPoet.Modal.loading(false);
|
||||
if(this.isMounted()) {
|
||||
|
||||
if(response.length === 0) {
|
||||
response = [
|
||||
{
|
||||
name:
|
||||
"MailPoet's Guide",
|
||||
MailPoet.I18n.t('mailpoetGuideTemplateTitle'),
|
||||
description:
|
||||
"This is the standard template that comes with MailPoet.",
|
||||
MailPoet.I18n.t('mailpoetGuideTemplateDescription'),
|
||||
readonly: "1"
|
||||
}
|
||||
]
|
||||
@ -149,7 +155,9 @@ define(
|
||||
this.setState({ loading: true });
|
||||
if(
|
||||
window.confirm(
|
||||
'You are about to delete the template named "'+ template.name +'"'
|
||||
(
|
||||
MailPoet.I18n.t('confirmTemplateDeletion')
|
||||
).replace("%$1s", template.name)
|
||||
)
|
||||
) {
|
||||
MailPoet.Ajax.post({
|
||||
@ -181,7 +189,7 @@ define(
|
||||
href="javascript:;"
|
||||
onClick={ this.handleDeleteTemplate.bind(null, template) }
|
||||
>
|
||||
Delete
|
||||
{MailPoet.I18n.t('delete')}
|
||||
</a>
|
||||
</div>
|
||||
), thumbnail = '';
|
||||
@ -212,7 +220,7 @@ define(
|
||||
className="button button-primary"
|
||||
onClick={ this.handleSelectTemplate.bind(null, template) }
|
||||
>
|
||||
Select
|
||||
{MailPoet.I18n.t('select')}
|
||||
</a>
|
||||
|
||||
<a
|
||||
@ -220,7 +228,7 @@ define(
|
||||
className="button button-secondary"
|
||||
onClick={ this.handlePreviewTemplate.bind(null, template) }
|
||||
>
|
||||
Preview
|
||||
{MailPoet.I18n.t('preview')}
|
||||
</a>
|
||||
</div>
|
||||
{ (template.readonly === "1") ? false : deleteLink }
|
||||
@ -236,7 +244,7 @@ define(
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Select a template</h1>
|
||||
<h1>{MailPoet.I18n.t('selectTemplateTitle')}</h1>
|
||||
|
||||
<Breadcrumb step="template" />
|
||||
|
||||
|
@ -26,22 +26,24 @@ define(
|
||||
action: 'create',
|
||||
data: {
|
||||
type: type,
|
||||
subject: 'Draft newsletter',
|
||||
subject: MailPoet.I18n.t('draftNewsletterTitle'),
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response.id !== undefined) {
|
||||
this.history.pushState(null, `/template/${response.id}`);
|
||||
if(response.result && response.newsletter.id) {
|
||||
this.history.pushState(null, `/template/${response.newsletter.id}`);
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
if(response.errors.length > 0) {
|
||||
response.errors.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Pick a type of campaign</h1>
|
||||
<h1>{MailPoet.I18n.t('pickCampaignType')}</h1>
|
||||
|
||||
<Breadcrumb step="type" />
|
||||
|
||||
@ -50,10 +52,9 @@ define(
|
||||
<div className="mailpoet_thumbnail"></div>
|
||||
|
||||
<div className="mailpoet_description">
|
||||
<h3>Newsletter</h3>
|
||||
<h3>{MailPoet.I18n.t('regularNewsletterTypeTitle')}</h3>
|
||||
<p>
|
||||
Send a newsletter with images, buttons, dividers,
|
||||
and social bookmarks. Or a simple email.
|
||||
{MailPoet.I18n.t('regularNewsletterTypeDescription')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -62,7 +63,7 @@ define(
|
||||
className="button button-primary"
|
||||
onClick={ this.createNewsletter.bind(null, 'standard') }
|
||||
>
|
||||
Create
|
||||
{MailPoet.I18n.t('create')}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
@ -71,9 +72,9 @@ define(
|
||||
<div className="mailpoet_thumbnail"></div>
|
||||
|
||||
<div className="mailpoet_description">
|
||||
<h3>Welcome email</h3>
|
||||
<h3>{MailPoet.I18n.t('welcomeNewsletterTypeTitle')}</h3>
|
||||
<p>
|
||||
Send an email for new users.
|
||||
{MailPoet.I18n.t('welcomeNewsletterTypeDescription')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -82,7 +83,7 @@ define(
|
||||
className="button button-primary"
|
||||
onClick={ this.setupNewsletter.bind(null, 'welcome') }
|
||||
>
|
||||
Set up
|
||||
{MailPoet.I18n.t('setUp')}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
@ -91,9 +92,9 @@ define(
|
||||
<div className="mailpoet_thumbnail"></div>
|
||||
|
||||
<div className="mailpoet_description">
|
||||
<h3>Post notifications</h3>
|
||||
<h3>{MailPoet.I18n.t('postNotificationNewsletterTypeTitle')}</h3>
|
||||
<p>
|
||||
Automatically send posts immediately, daily, weekly or monthly. Filter by categories, if you like.
|
||||
{MailPoet.I18n.t('postNotificationsNewsletterTypeDescription')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -102,7 +103,7 @@ define(
|
||||
className="button button-primary"
|
||||
onClick={ this.setupNewsletter.bind(null, 'notification') }
|
||||
>
|
||||
Set up
|
||||
{MailPoet.I18n.t('setUp')}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
@ -25,11 +25,11 @@ define(
|
||||
var intervalField = {
|
||||
name: 'interval',
|
||||
values: {
|
||||
'daily': 'Once a day at...',
|
||||
'weekly': 'Weekly on...',
|
||||
'monthly': 'Monthly on the...',
|
||||
'nthWeekDay': 'Monthly every...',
|
||||
'immediately': 'Immediately.',
|
||||
'daily': MailPoet.I18n.t('daily'),
|
||||
'weekly': MailPoet.I18n.t('weekly'),
|
||||
'monthly': MailPoet.I18n.t('monthly'),
|
||||
'nthWeekDay': MailPoet.I18n.t('monthlyEvery'),
|
||||
'immediately': MailPoet.I18n.t('immediately'),
|
||||
},
|
||||
};
|
||||
|
||||
@ -53,13 +53,13 @@ define(
|
||||
var weekDayField = {
|
||||
name: 'weekDay',
|
||||
values: {
|
||||
0: 'Monday',
|
||||
1: 'Tuesday',
|
||||
2: 'Wednesday',
|
||||
3: 'Thursday',
|
||||
4: 'Friday',
|
||||
5: 'Saturday',
|
||||
6: 'Sunday',
|
||||
0: MailPoet.I18n.t('sunday'),
|
||||
1: MailPoet.I18n.t('monday'),
|
||||
2: MailPoet.I18n.t('tuesday'),
|
||||
3: MailPoet.I18n.t('wednesday'),
|
||||
4: MailPoet.I18n.t('thursday'),
|
||||
5: MailPoet.I18n.t('friday'),
|
||||
6: MailPoet.I18n.t('saturday')
|
||||
},
|
||||
};
|
||||
|
||||
@ -69,14 +69,19 @@ define(
|
||||
values: _.object(_.map(
|
||||
_.times(NUMBER_OF_DAYS_IN_MONTH, function(day) { return day; }),
|
||||
function(day) {
|
||||
var suffixes = {
|
||||
0: 'st',
|
||||
1: 'nd',
|
||||
2: 'rd'
|
||||
};
|
||||
var suffix = suffixes[day] || 'th';
|
||||
var labels = {
|
||||
0: MailPoet.I18n.t('first'),
|
||||
1: MailPoet.I18n.t('second'),
|
||||
2: MailPoet.I18n.t('third')
|
||||
},
|
||||
label;
|
||||
if (labels[day] !== undefined) {
|
||||
label = labels[day];
|
||||
} else {
|
||||
label = MailPoet.I18n.t('nth').replace("%$1d", day + 1);
|
||||
}
|
||||
|
||||
return [day, (day + 1).toString() + suffix];
|
||||
return [day, label];
|
||||
},
|
||||
)),
|
||||
};
|
||||
@ -84,10 +89,10 @@ define(
|
||||
var nthWeekDayField = {
|
||||
name: 'nthWeekDay',
|
||||
values: {
|
||||
'0': '1st',
|
||||
'1': '2nd',
|
||||
'2': '3rd',
|
||||
'3': 'last',
|
||||
'1': MailPoet.I18n.t('first'),
|
||||
'2': MailPoet.I18n.t('second'),
|
||||
'3': MailPoet.I18n.t('third'),
|
||||
'L': MailPoet.I18n.t('last'),
|
||||
},
|
||||
};
|
||||
|
||||
@ -99,9 +104,9 @@ define(
|
||||
return {
|
||||
intervalType: 'immediate', // 'immediate'|'daily'|'weekly'|'monthly'
|
||||
timeOfDay: 0,
|
||||
weekDay: 0,
|
||||
weekDay: 1,
|
||||
monthDay: 0,
|
||||
nthWeekDay: 0,
|
||||
nthWeekDay: 1,
|
||||
};
|
||||
},
|
||||
handleIntervalChange: function(event) {
|
||||
@ -138,12 +143,14 @@ define(
|
||||
options: this.state,
|
||||
},
|
||||
}).done(function(response) {
|
||||
if(response.id !== undefined) {
|
||||
this.showTemplateSelection(response.id);
|
||||
if(response.result && response.newsletter.id) {
|
||||
this.showTemplateSelection(response.newsletter.id);
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
if(response.errors.length > 0) {
|
||||
response.errors.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
@ -195,7 +202,7 @@ define(
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Post notifications</h1>
|
||||
<h1>{MailPoet.I18n.t('postNotificationNewsletterTypeTitle')}</h1>
|
||||
<Breadcrumb step="type" />
|
||||
|
||||
<Select
|
||||
@ -213,7 +220,7 @@ define(
|
||||
className="button button-primary"
|
||||
type="button"
|
||||
onClick={ this.handleNext }
|
||||
value="Next" />
|
||||
value={MailPoet.I18n.t('next')} />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
@ -32,19 +32,22 @@ define(
|
||||
type: 'standard',
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response.id !== undefined) {
|
||||
this.showTemplateSelection(response.id);
|
||||
console.log(response);
|
||||
if(response.result && response.newsletter.id) {
|
||||
this.showTemplateSelection(response.newsletter.id);
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
if(response.errors.length > 0) {
|
||||
response.errors.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Newsletter</h1>
|
||||
<h1>{MailPoet.I18n.t('regularNewsletterTypeTitle')}</h1>
|
||||
<Breadcrumb step="type" />
|
||||
</div>
|
||||
);
|
||||
|
@ -28,8 +28,8 @@ define(
|
||||
var events = {
|
||||
name: 'event',
|
||||
values: {
|
||||
'segment': 'When someone subscribes to the list...',
|
||||
'user': 'When a new Wordrpess user is added to your site...',
|
||||
'segment': MailPoet.I18n.t('onSubscriptionToList'),
|
||||
'user': MailPoet.I18n.t('onWordpressUserRegistration'),
|
||||
}
|
||||
};
|
||||
|
||||
@ -57,10 +57,10 @@ define(
|
||||
var afterTimeTypeField = {
|
||||
name: 'afterTimeType',
|
||||
values: {
|
||||
'immediate': 'immediately',
|
||||
'hours': 'hour(s) after',
|
||||
'days': 'day(s) after',
|
||||
'weeks': 'week(s) after',
|
||||
'immediate': MailPoet.I18n.t('delayImmediately'),
|
||||
'hours': MailPoet.I18n.t('delayHoursAfter'),
|
||||
'days': MailPoet.I18n.t('delayDaysAfter'),
|
||||
'weeks': MailPoet.I18n.t('delayWeeksAfter'),
|
||||
}
|
||||
};
|
||||
|
||||
@ -111,12 +111,14 @@ define(
|
||||
options: this.state,
|
||||
},
|
||||
}).done(function(response) {
|
||||
if(response.id !== undefined) {
|
||||
this.showTemplateSelection(response.id);
|
||||
if(response.result && response.newsletter.id) {
|
||||
this.showTemplateSelection(response.newsletter.id);
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
if(response.errors.length > 0) {
|
||||
response.errors.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
@ -150,9 +152,11 @@ define(
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h1>Welcome email</h1>
|
||||
<h1>{MailPoet.I18n.t('welcomeNewsletterTypeTitle')}</h1>
|
||||
<Breadcrumb step="type" />
|
||||
|
||||
<h3>{MailPoet.I18n.t('selectEventToSendWelcomeEmail')}</h3>
|
||||
|
||||
<Select
|
||||
field={events}
|
||||
item={this.state}
|
||||
@ -172,7 +176,7 @@ define(
|
||||
className="button button-primary"
|
||||
type="button"
|
||||
onClick={ this.handleNext }
|
||||
value="Next" />
|
||||
value={MailPoet.I18n.t('next')} />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
@ -192,21 +192,28 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
error: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'error',
|
||||
message: '<p>'+message+'</p>'
|
||||
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||
}, options));
|
||||
},
|
||||
success: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'success',
|
||||
message: '<p>'+message+'</p>'
|
||||
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||
}, options));
|
||||
},
|
||||
system: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'system',
|
||||
static: true,
|
||||
message: message
|
||||
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||
}, options));
|
||||
},
|
||||
formatMessage: function(message) {
|
||||
if(Array.isArray(message)) {
|
||||
return message.join('<br />');
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -20,13 +20,18 @@ function(
|
||||
$('form.mailpoet_form').each(function() {
|
||||
var form = $(this);
|
||||
|
||||
form.parsley().on('form:submit', function(parsley) {
|
||||
|
||||
var data = form.serializeObject() || {};
|
||||
|
||||
form.parsley().on('form:validated', function(parsley) {
|
||||
// clear messages
|
||||
form.find('.mailpoet_message').html('');
|
||||
|
||||
// resize iframe
|
||||
if(window.frameElement !== null) {
|
||||
MailPoet.Iframe.autoSize(window.frameElement);
|
||||
}
|
||||
});
|
||||
|
||||
form.parsley().on('form:submit', function(parsley) {
|
||||
var data = form.serializeObject() || {};
|
||||
// check if we're on the same domain
|
||||
if(isSameDomain(MailPoetForm.ajax_url) === false) {
|
||||
// non ajax post request
|
||||
@ -68,6 +73,11 @@ function(
|
||||
// reset validation
|
||||
parsley.reset();
|
||||
}
|
||||
|
||||
// resize iframe
|
||||
if(window.frameElement !== null) {
|
||||
MailPoet.Iframe.autoSize(window.frameElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
@ -12,29 +12,29 @@ define(
|
||||
Form
|
||||
) {
|
||||
|
||||
var fields = [
|
||||
let fields = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
label: MailPoet.I18n.t('name'),
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
label: 'Description',
|
||||
label: MailPoet.I18n.t('description'),
|
||||
type: 'textarea'
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
const messages = {
|
||||
onUpdate: function() {
|
||||
MailPoet.Notice.success('Segment successfully updated!');
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('segmentUpdated'));
|
||||
},
|
||||
onCreate: function() {
|
||||
MailPoet.Notice.success('Segment successfully added!');
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('segmentAdded'));
|
||||
}
|
||||
};
|
||||
|
||||
var SegmentForm = React.createClass({
|
||||
const SegmentForm = React.createClass({
|
||||
mixins: [
|
||||
Router.History
|
||||
],
|
||||
@ -42,7 +42,7 @@ define(
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Segment
|
||||
{MailPoet.I18n.t('segment')}
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
|
@ -10,101 +10,95 @@ import Listing from 'listing/listing.jsx'
|
||||
var columns = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
label: MailPoet.I18n.t('name'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
label: 'Description',
|
||||
label: MailPoet.I18n.t('description'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'subscribed',
|
||||
label: 'Subscribed',
|
||||
label: MailPoet.I18n.t('subscribed'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'unconfirmed',
|
||||
label: 'Unconfirmed',
|
||||
label: MailPoet.I18n.t('unconfirmed'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'unsubscribed',
|
||||
label: 'Unsubscribed',
|
||||
label: MailPoet.I18n.t('unsubscribed'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
label: MailPoet.I18n.t('createdOn'),
|
||||
sortable: true
|
||||
}
|
||||
];
|
||||
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was moved to the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d segments were moved to the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
if(count === 1) {
|
||||
message = (
|
||||
MailPoet.I18n.t('oneSegmentTrashed')
|
||||
);
|
||||
} else {
|
||||
message = (
|
||||
MailPoet.I18n.t('multipleSegmentsTrashed')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
},
|
||||
onDelete: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was permanently deleted.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d segments were permanently deleted.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
if(count === 1) {
|
||||
message = (
|
||||
MailPoet.I18n.t('oneSegmentDeleted')
|
||||
);
|
||||
} else {
|
||||
message = (
|
||||
MailPoet.I18n.t('multipleSegmentsDeleted')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
},
|
||||
onRestore: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment has been restored from the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d segments have been restored from the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
var count = ~~response;
|
||||
var message = null;
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
if(count === 1) {
|
||||
message = (
|
||||
MailPoet.I18n.t('oneSegmentRestored')
|
||||
);
|
||||
} else {
|
||||
message = (
|
||||
MailPoet.I18n.t('multipleSegmentsRestored')
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
};
|
||||
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
label: MailPoet.I18n.t('edit'),
|
||||
link: function(item) {
|
||||
return (
|
||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
||||
<Link to={ `/edit/${item.id}` }>{MailPoet.I18n.t('edit')}</Link>
|
||||
);
|
||||
},
|
||||
display: function(segment) {
|
||||
return (segment.type !== 'wp_users');
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -117,7 +111,7 @@ const item_actions = [
|
||||
data: item.id
|
||||
}).done(function(response) {
|
||||
MailPoet.Notice.success(
|
||||
('List "%$1s" has been duplicated.').replace('%$1s', response.name)
|
||||
(MailPoet.I18n.t('listDuplicated')).replace('%$1s', response.name)
|
||||
);
|
||||
refresh();
|
||||
});
|
||||
@ -128,7 +122,7 @@ const item_actions = [
|
||||
},
|
||||
{
|
||||
name: 'synchronize_segment',
|
||||
label: 'Update',
|
||||
label: MailPoet.I18n.t('update'),
|
||||
className: 'update',
|
||||
onClick: function(item, refresh) {
|
||||
MailPoet.Modal.loading(true);
|
||||
@ -139,7 +133,7 @@ const item_actions = [
|
||||
MailPoet.Modal.loading(false);
|
||||
if(response === true) {
|
||||
MailPoet.Notice.success(
|
||||
('List "%$1s" has been synchronized.').replace('%$1s', item.name)
|
||||
(MailPoet.I18n.t('listSynchronized')).replace('%$1s', item.name)
|
||||
);
|
||||
refresh();
|
||||
}
|
||||
@ -153,7 +147,7 @@ const item_actions = [
|
||||
name: 'view_subscribers',
|
||||
link: function(item) {
|
||||
return (
|
||||
<a href={ item.subscribers_url }>View subscribers</a>
|
||||
<a href={ item.subscribers_url }>{MailPoet.I18n.t('viewSubscribers')}</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -187,16 +181,16 @@ const SegmentList = React.createClass({
|
||||
<abbr>{ segment.description }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed">
|
||||
<abbr>{ segment.subscribed || 0 }</abbr>
|
||||
<abbr>{ segment.subscribers_count.subscribed || 0 }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Unconfirmed">
|
||||
<abbr>{ segment.unconfirmed || 0 }</abbr>
|
||||
<abbr>{ segment.subscribers_count.unconfirmed || 0 }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Unsubscribed">
|
||||
<abbr>{ segment.unsubscribed || 0 }</abbr>
|
||||
<abbr>{ segment.subscribers_count.unsubscribed || 0 }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Created on">
|
||||
<abbr>{ segment.created_at }</abbr>
|
||||
<abbr>{ MailPoet.Date.full(segment.created_at) }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
@ -205,7 +199,7 @@ const SegmentList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Segments <Link className="add-new-h2" to="/new">New</Link>
|
||||
{MailPoet.I18n.t('pageTitle')} <Link className="add-new-h2" to="/new">{MailPoet.I18n.t('new')}</Link>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
|
@ -11,42 +11,76 @@ define(
|
||||
MailPoet,
|
||||
Form
|
||||
) {
|
||||
|
||||
var fields = [
|
||||
{
|
||||
name: 'email',
|
||||
label: 'E-mail',
|
||||
label: MailPoet.I18n.t('email'),
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'first_name',
|
||||
label: 'Firstname',
|
||||
label: MailPoet.I18n.t('firstname'),
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'last_name',
|
||||
label: 'Lastname',
|
||||
label: MailPoet.I18n.t('lastname'),
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
label: MailPoet.I18n.t('status'),
|
||||
type: 'select',
|
||||
values: {
|
||||
'unconfirmed': 'Unconfirmed',
|
||||
'subscribed': 'Subscribed',
|
||||
'unsubscribed': 'Unsubscribed'
|
||||
'unconfirmed': MailPoet.I18n.t('unconfirmed'),
|
||||
'subscribed': MailPoet.I18n.t('subscribed'),
|
||||
'unsubscribed': MailPoet.I18n.t('unsubscribed')
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
label: MailPoet.I18n.t('lists'),
|
||||
type: 'selection',
|
||||
placeholder: "Select a list",
|
||||
placeholder: MailPoet.I18n.t('selectList'),
|
||||
endpoint: "segments",
|
||||
multiple: true,
|
||||
selected: function(subscriber) {
|
||||
if (Array.isArray(subscriber.subscriptions) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return subscriber.subscriptions.map(function(subscription) {
|
||||
if (subscription.status === 'subscribed') {
|
||||
return subscription.segment_id;
|
||||
}
|
||||
});
|
||||
},
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
},
|
||||
getSearchLabel: function(segment, subscriber) {
|
||||
let label = '';
|
||||
|
||||
if (subscriber.subscriptions !== undefined) {
|
||||
subscriber.subscriptions.map(function(subscription) {
|
||||
if (segment.id === subscription.segment_id) {
|
||||
label = segment.name;
|
||||
|
||||
if (subscription.status === 'unsubscribed') {
|
||||
const unsubscribed_at = MailPoet.Date
|
||||
.format(subscription.updated_at);
|
||||
label += ' (%$1s)'.replace(
|
||||
'%$1s',
|
||||
MailPoet.I18n.t('unsubscribedOn').replace(
|
||||
'%$1s',
|
||||
unsubscribed_at
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -58,11 +92,11 @@ define(
|
||||
label: custom_field.name,
|
||||
type: custom_field.type
|
||||
};
|
||||
if(custom_field.params) {
|
||||
if (custom_field.params) {
|
||||
field.params = custom_field.params;
|
||||
}
|
||||
|
||||
if(custom_field.params.values) {
|
||||
if (custom_field.params.values) {
|
||||
field.values = custom_field.params.values;
|
||||
}
|
||||
|
||||
@ -71,10 +105,10 @@ define(
|
||||
|
||||
var messages = {
|
||||
onUpdate: function() {
|
||||
MailPoet.Notice.success('Subscriber successfully updated!');
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('subscriberUpdated'));
|
||||
},
|
||||
onCreate: function() {
|
||||
MailPoet.Notice.success('Subscriber successfully added!');
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('subscriberAdded'));
|
||||
}
|
||||
};
|
||||
|
||||
@ -88,7 +122,7 @@ define(
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscriber
|
||||
{MailPoet.I18n.t('subscriber')}
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
|
@ -115,7 +115,7 @@ define(
|
||||
exportData.exportConfirmedOption = false;
|
||||
renderSegmentsAndFields(segmentsContainerElement, segments);
|
||||
}
|
||||
segmentsContainerElement.select2('val', selectedSegments);
|
||||
segmentsContainerElement.val(selectedSegments).trigger('change');
|
||||
});
|
||||
|
||||
function toggleNextStepButton(condition) {
|
||||
@ -148,9 +148,9 @@ define(
|
||||
.done(function (response) {
|
||||
MailPoet.Modal.loading(false);
|
||||
if (response.result === false) {
|
||||
MailPoet.Notice.error(response.error);
|
||||
MailPoet.Notice.error(response.errors);
|
||||
} else {
|
||||
resultMessage = MailPoetI18n.exportMessage
|
||||
resultMessage = MailPoet.I18n.t('exportMessage')
|
||||
.replace('%1$s', '<strong>' + response.data.totalExported + '</strong>')
|
||||
.replace('[link]', '<a href="' + response.data.exportFileURL + '" target="_blank" >')
|
||||
.replace('[/link]', '</a>');
|
||||
@ -162,7 +162,7 @@ define(
|
||||
.error(function (error) {
|
||||
MailPoet.Modal.loading(false);
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.'
|
||||
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -6,7 +6,9 @@ define(
|
||||
'mailpoet',
|
||||
'handlebars',
|
||||
'papaparse',
|
||||
'select2'
|
||||
'select2',
|
||||
'asyncqueue',
|
||||
'xss'
|
||||
],
|
||||
function (
|
||||
Backbone,
|
||||
@ -14,12 +16,15 @@ define(
|
||||
jQuery,
|
||||
MailPoet,
|
||||
Handlebars,
|
||||
Papa
|
||||
Papa,
|
||||
AsyncQueue,
|
||||
xss
|
||||
) {
|
||||
if (!jQuery('#mailpoet_subscribers_import').length) {
|
||||
return;
|
||||
}
|
||||
jQuery(document).ready(function () {
|
||||
var noticeTimeout = 3000;
|
||||
jQuery('input[name="select_method"]').attr('checked', false);
|
||||
// configure router
|
||||
router = new (Backbone.Router.extend({
|
||||
@ -123,8 +128,8 @@ define(
|
||||
// get an approximate size of textarea paste in bytes
|
||||
var pasteSize = encodeURI(pasteInputElement.val()).split(/%..|./).length - 1;
|
||||
if (pasteSize > maxPostSizeBytes) {
|
||||
MailPoet.Notice.error(MailPoetI18n.maxPostSizeNotice, {
|
||||
timeout: 3000,
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('maxPostSizeNotice'), {
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -143,8 +148,8 @@ define(
|
||||
var ext = this.value.match(/\.(.+)$/);
|
||||
if (ext === null || ext[1].toLowerCase() !== 'csv') {
|
||||
this.value = '';
|
||||
MailPoet.Notice.error(MailPoetI18n.wrongFileFormat, {
|
||||
timeout: 3000,
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('wrongFileFormat'), {
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
}
|
||||
|
||||
@ -193,8 +198,8 @@ define(
|
||||
}).done(function (response) {
|
||||
if (response.result === false) {
|
||||
MailPoet.Notice.hide();
|
||||
MailPoet.Notice.error(response.error, {
|
||||
timeout: 3000,
|
||||
MailPoet.Notice.error(response.errors, {
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
jQuery('.mailpoet_mailchimp-key-status')
|
||||
.removeClass()
|
||||
@ -207,7 +212,7 @@ define(
|
||||
.removeClass()
|
||||
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-ok');
|
||||
if (!response.data) {
|
||||
jQuery('.mailpoet_mailchimp-key-status').html(MailPoetI18n.noMailChimpLists);
|
||||
jQuery('.mailpoet_mailchimp-key-status').html(MailPoet.I18n.t('noMailChimpLists'));
|
||||
mailChimpListsContainerElement.hide();
|
||||
toggleNextStepButton(mailChimpProcessButtonElement, 'off');
|
||||
} else {
|
||||
@ -218,8 +223,8 @@ define(
|
||||
}).error(function (error) {
|
||||
MailPoet.Modal.loading(false);
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
||||
timeout: 3000,
|
||||
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.', {
|
||||
timeout: noticeTimeout,
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -245,16 +250,16 @@ define(
|
||||
}
|
||||
else {
|
||||
MailPoet.Notice.hide();
|
||||
MailPoet.Notice(response.message, {
|
||||
timeout: 3000,
|
||||
MailPoet.Notice.error(response.errors, {
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
}
|
||||
MailPoet.Modal.loading(false);
|
||||
}).error(function () {
|
||||
MailPoet.Modal.loading(false);
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.serverError + result.statusText.toLowerCase() + '.', {
|
||||
timeout: 3000,
|
||||
MailPoet.I18n.t('serverError') + result.statusText.toLowerCase() + '.', {
|
||||
timeout: noticeTimeout,
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -345,14 +350,14 @@ define(
|
||||
comments: advancedOptionComments,
|
||||
error: function () {
|
||||
MailPoet.Notice.hide();
|
||||
MailPoet.Notice.error(MailPoetI18n.dataProcessingError, {
|
||||
timeout: 3000,
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('dataProcessingError'), {
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
},
|
||||
complete: function (CSV) {
|
||||
for (var rowCount in CSV.data) {
|
||||
var rowData = CSV.data[rowCount].map(function (el) {
|
||||
return el.trim();
|
||||
return filterXSS(el.trim());
|
||||
}),
|
||||
rowColumnCount = rowData.length;
|
||||
// set the number of row elements based on the first non-empty row
|
||||
@ -426,11 +431,11 @@ define(
|
||||
}
|
||||
else {
|
||||
MailPoet.Modal.loading(false);
|
||||
var errorNotice = MailPoetI18n.noValidRecords;
|
||||
errorNotice = errorNotice.replace('[link]', MailPoetI18n.csvKBLink);
|
||||
var errorNotice = MailPoet.I18n.t('noValidRecords');
|
||||
errorNotice = errorNotice.replace('[link]', MailPoet.I18n.t('csvKBLink'));
|
||||
errorNotice = errorNotice.replace('[/link]', '</a>');
|
||||
MailPoet.Notice.error(errorNotice, {
|
||||
timeout: 3000,
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -496,17 +501,17 @@ define(
|
||||
}
|
||||
|
||||
var import_results = {
|
||||
notice: MailPoetI18n.importNoticeSkipped.replace(
|
||||
notice: MailPoet.I18n.t('importNoticeSkipped').replace(
|
||||
'%1$s',
|
||||
'<strong>' + (subscribers.invalid.length + subscribers.duplicate.length) + '</strong>'
|
||||
),
|
||||
invalid: (subscribers.invalid.length)
|
||||
? MailPoetI18n.importNoticeInvalid
|
||||
? MailPoet.I18n.t('importNoticeInvalid')
|
||||
.replace('%1$s', '<strong>' + subscribers.invalid.length + '</strong>')
|
||||
.replace('%2$s', subscribers.invalid.join(', '))
|
||||
: null,
|
||||
duplicate: (subscribers.duplicate.length)
|
||||
? MailPoetI18n.importNoticeDuplicate
|
||||
? MailPoet.I18n.t('importNoticeDuplicate')
|
||||
.replace('%1$s', '<strong>' + subscribers.duplicate.length + '</strong>')
|
||||
.replace('%2$s', subscribers.duplicate.join(', '))
|
||||
: null
|
||||
@ -522,8 +527,8 @@ define(
|
||||
jQuery(details).toggle();
|
||||
this.text =
|
||||
(jQuery(details).is(":visible"))
|
||||
? MailPoetI18n.hideDetails
|
||||
: MailPoetI18n.showDetails;
|
||||
? MailPoet.I18n.t('hideDetails')
|
||||
: MailPoet.I18n.t('showDetails');
|
||||
});
|
||||
|
||||
// show available segments
|
||||
@ -559,9 +564,9 @@ define(
|
||||
var segmentSelectionNotice = jQuery('[data-id="notice_segmentSelection"]');
|
||||
if (!this.value) {
|
||||
if (!segmentSelectionNotice.length) {
|
||||
MailPoet.Notice.error(MailPoetI18n.segmentSelectionRequired, {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('segmentSelectionRequired'), {
|
||||
static: true,
|
||||
timeout: 3000,
|
||||
timeout: noticeTimeout,
|
||||
scroll: true,
|
||||
id: 'segmentSelection',
|
||||
hideClose: true
|
||||
@ -579,7 +584,7 @@ define(
|
||||
|
||||
jQuery('.mailpoet_create_segment').click(function () {
|
||||
MailPoet.Modal.popup({
|
||||
title: MailPoetI18n.addNewList,
|
||||
title: MailPoet.I18n.t('addNewList'),
|
||||
template: jQuery('#new_segment_template').html()
|
||||
})
|
||||
jQuery('#new_segment_name').keypress(function (e) {
|
||||
@ -639,8 +644,8 @@ define(
|
||||
else {
|
||||
MailPoet.Modal.close();
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.segmentCreateError + response.message + '.', {
|
||||
timeout: 3000,
|
||||
MailPoet.I18n.t('segmentCreateError') + response.message + '.', {
|
||||
timeout: noticeTimeout,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -648,8 +653,8 @@ define(
|
||||
.error(function (error) {
|
||||
MailPoet.Modal.close();
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
||||
timeout: 3000
|
||||
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.', {
|
||||
timeout: noticeTimeout
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -765,7 +770,7 @@ define(
|
||||
selectEvent.preventDefault();
|
||||
jQuery(selectElement).select2('close');
|
||||
MailPoet.Modal.popup({
|
||||
title: MailPoetI18n.addNewColumn,
|
||||
title: MailPoet.I18n.t('addNewColumn'),
|
||||
template: jQuery('#new_column_template').html()
|
||||
});
|
||||
jQuery('#new_column_name').keypress(function (e) {
|
||||
@ -829,7 +834,7 @@ define(
|
||||
// if this is the first custom column, create an "optgroup"
|
||||
if (mailpoetColumnsSelect2.length === 2) {
|
||||
mailpoetColumnsSelect2.push({
|
||||
'name': MailPoetI18n.userColumns,
|
||||
'name': MailPoet.I18n.t('userColumns'),
|
||||
'children': []
|
||||
});
|
||||
}
|
||||
@ -855,8 +860,8 @@ define(
|
||||
filterSubscribers();
|
||||
}
|
||||
else {
|
||||
MailPoet.Notice.error(MailPoetI18n.customFieldCreateError, {
|
||||
timeout: 3000,
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('customFieldCreateError'), {
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
}
|
||||
MailPoet.Modal.loading(false);
|
||||
@ -864,8 +869,8 @@ define(
|
||||
.error(function (error) {
|
||||
MailPoet.Modal.loading(false);
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
||||
timeout: 3000,
|
||||
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.', {
|
||||
timeout: noticeTimeout,
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -885,7 +890,7 @@ define(
|
||||
// if another column has the same value and it's not an 'ignore', prompt user
|
||||
if (elementId === selectedOptionId
|
||||
&& elementId !== 'ignore') {
|
||||
if (confirm(MailPoetI18n.selectedValueAlreadyMatched + ' ' + MailPoetI18n.confirmCorrespondingColumn)) {
|
||||
if (confirm(MailPoet.I18n.t('selectedValueAlreadyMatched') + ' ' + MailPoet.I18n.t('confirmCorrespondingColumn'))) {
|
||||
jQuery(element).data('column-id', 'ignore');
|
||||
}
|
||||
else {
|
||||
@ -928,9 +933,9 @@ define(
|
||||
if (!emailRegex.test(subscribersClone.subscribers[0][matchedColumn])) {
|
||||
preventNextStep = true;
|
||||
if (!jQuery('[data-id="notice_invalidEmail"]').length) {
|
||||
MailPoet.Notice.error(MailPoetI18n.columnContainsInvalidElement, {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidElement'), {
|
||||
static: true,
|
||||
timeout: 3000,
|
||||
timeout: noticeTimeout,
|
||||
scroll: true,
|
||||
hideClose: true,
|
||||
id: 'invalidEmail'
|
||||
@ -948,18 +953,18 @@ define(
|
||||
date = new Date(rowData.replace(/-/g, '/')), // IE doesn't like
|
||||
// dashes as date separators
|
||||
month_name = [
|
||||
MailPoetI18n.january,
|
||||
MailPoetI18n.february,
|
||||
MailPoetI18n.march,
|
||||
MailPoetI18n.april,
|
||||
MailPoetI18n.may,
|
||||
MailPoetI18n.june,
|
||||
MailPoetI18n.july,
|
||||
MailPoetI18n.august,
|
||||
MailPoetI18n.september,
|
||||
MailPoetI18n.october,
|
||||
MailPoetI18n.november,
|
||||
MailPoetI18n.december
|
||||
MailPoet.I18n.t('january'),
|
||||
MailPoet.I18n.t('february'),
|
||||
MailPoet.I18n.t('march'),
|
||||
MailPoet.I18n.t('april'),
|
||||
MailPoet.I18n.t('may'),
|
||||
MailPoet.I18n.t('june'),
|
||||
MailPoet.I18n.t('july'),
|
||||
MailPoet.I18n.t('august'),
|
||||
MailPoet.I18n.t('september'),
|
||||
MailPoet.I18n.t('october'),
|
||||
MailPoet.I18n.t('november'),
|
||||
MailPoet.I18n.t('december')
|
||||
];
|
||||
|
||||
if (position !== fillterPosition) {
|
||||
@ -972,8 +977,8 @@ define(
|
||||
if (rowData.trim() === '') {
|
||||
data[matchedColumn] =
|
||||
'<span class="mailpoet_data_match mailpoet_import_error" title="'
|
||||
+ MailPoetI18n.noDateFieldMatch + '">'
|
||||
+ MailPoetI18n.emptyDate
|
||||
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
|
||||
+ MailPoet.I18n.t('emptyDate')
|
||||
+ '</span>';
|
||||
preventNextStep = true;
|
||||
return;
|
||||
@ -990,27 +995,27 @@ define(
|
||||
+ ((date.getMinutes() < 10 ? '0' : '')
|
||||
+ date.getMinutes()) + ' '
|
||||
+ ((date.getHours() >= 12)
|
||||
? MailPoetI18n.pm
|
||||
: MailPoetI18n.am
|
||||
? MailPoet.I18n.t('pm')
|
||||
: MailPoet.I18n.t('am')
|
||||
);
|
||||
data[matchedColumn] +=
|
||||
'<span class="mailpoet_data_match" title="'
|
||||
+ MailPoetI18n.verifyDateMatch + '">'
|
||||
+ MailPoet.I18n.t('verifyDateMatch') + '">'
|
||||
+ date + '</span>';
|
||||
}
|
||||
else {
|
||||
data[matchedColumn] +=
|
||||
'<span class="mailpoet_data_match mailpoet_import_error" title="'
|
||||
+ MailPoetI18n.noDateFieldMatch + '">'
|
||||
+ MailPoetI18n.dateMatchError + '</span>';
|
||||
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
|
||||
+ MailPoet.I18n.t('dateMatchError') + '</span>';
|
||||
preventNextStep = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (preventNextStep && !jQuery('.mailpoet_invalidDate').length) {
|
||||
MailPoet.Notice.error(MailPoetI18n.columnContainsInvalidDate, {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidDate'), {
|
||||
static: true,
|
||||
timeout: 3000,
|
||||
timeout: noticeTimeout,
|
||||
scroll: true,
|
||||
hideClose: true,
|
||||
id: 'invalidDate'
|
||||
@ -1050,64 +1055,98 @@ define(
|
||||
}
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
var subscribers = {};
|
||||
var columns = {},
|
||||
queue = new jQuery.AsyncQueue(),
|
||||
batchNumber = 0,
|
||||
batchSize = 2000,
|
||||
timestamp = Date.now() / 1000,
|
||||
subscribers = [],
|
||||
importResults = {
|
||||
'created': 0,
|
||||
'updated': 0,
|
||||
'errors': [],
|
||||
'segments': []
|
||||
},
|
||||
splitSubscribers = function (subscribers, size) {
|
||||
return subscribers.reduce(function (res, item, index) {
|
||||
if (index % size === 0) {
|
||||
res.push([]);
|
||||
}
|
||||
res[res.length - 1].push(item);
|
||||
return res;
|
||||
}, []);
|
||||
},
|
||||
subscribers = splitSubscribers(importData.step1.subscribers, batchSize);
|
||||
|
||||
_.each(jQuery('select.mailpoet_subscribers_column_data_match'),
|
||||
function (column, index) {
|
||||
var columnId = jQuery(column).data('column-id');
|
||||
if (columnId === 'ignore') {
|
||||
return;
|
||||
}
|
||||
subscribers[columnId] = [];
|
||||
_.each(importData.step1.subscribers, function (subsciber) {
|
||||
subscribers[columnId].push(
|
||||
_.chain(subsciber)
|
||||
.pick(index)
|
||||
.toArray()
|
||||
.flatten()
|
||||
.value()
|
||||
);
|
||||
});
|
||||
subscribers[columnId] = _.flatten(subscribers[columnId]);
|
||||
});
|
||||
function (column, columnIndex) {
|
||||
var columnId = jQuery(column).data('column-id');
|
||||
if (columnId === 'ignore') {
|
||||
return;
|
||||
}
|
||||
columns[columnId] = columnIndex;
|
||||
});
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'ImportExport',
|
||||
action: 'processImport',
|
||||
data: JSON.stringify({
|
||||
subscribers: subscribers,
|
||||
segments: segmentSelectElement.val(),
|
||||
updateSubscribers: (jQuery(':radio[name="subscriber_update_option"]:checked').val() === 'yes') ? true : false
|
||||
_.each(subscribers, function () {
|
||||
queue.add(function (queue) {
|
||||
queue.pause();
|
||||
MailPoet.Ajax
|
||||
.post({
|
||||
endpoint: 'ImportExport',
|
||||
action: 'processImport',
|
||||
data: JSON.stringify({
|
||||
columns: columns,
|
||||
subscribers: subscribers[batchNumber],
|
||||
timestamp: timestamp,
|
||||
segments: segmentSelectElement.val(),
|
||||
updateSubscribers: (jQuery(':radio[name="subscriber_update_option"]:checked').val() === 'yes') ? true : false
|
||||
})
|
||||
})
|
||||
.done(function (response) {
|
||||
if (response.result === false) {
|
||||
importResults.errors.push(response.errors);
|
||||
} else {
|
||||
importResults.created = response.data.created;
|
||||
importResults.updated = response.data.updated;
|
||||
importResults.segments = response.data.segments;
|
||||
}
|
||||
queue.run();
|
||||
})
|
||||
.error(function (error) {
|
||||
importResults.errors.push(
|
||||
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
|
||||
);
|
||||
queue.run();
|
||||
});
|
||||
batchNumber++;
|
||||
})
|
||||
}).done(function (response) {
|
||||
});
|
||||
|
||||
queue.run();
|
||||
|
||||
queue.onComplete(function () {
|
||||
MailPoet.Modal.loading(false);
|
||||
if (response.result === false) {
|
||||
MailPoet.Notice.error(response.error, {
|
||||
timeout: 3000,
|
||||
});
|
||||
} else {
|
||||
mailpoetSegments = response.data.segments;
|
||||
response.data.segments = _.map(segmentSelectElement.select2('data'),
|
||||
function (data) {
|
||||
return data.name;
|
||||
});
|
||||
importData.step2 = response.data;
|
||||
if (importResults.errors.length > 0 && !importResults.updated && !importResults.created) {
|
||||
MailPoet.Notice.error(_.flatten(importResults.errors), {
|
||||
timeout: noticeTimeout,
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
mailpoetSegments = importResults.segments;
|
||||
importResults.segments = _.map(segmentSelectElement.select2('data'),
|
||||
function (data) {
|
||||
return data.name;
|
||||
});
|
||||
importData.step2 = importResults;
|
||||
enableSegmentSelection(mailpoetSegments);
|
||||
router.navigate('step3', {trigger: true});
|
||||
}
|
||||
}).error(function (error) {
|
||||
MailPoet.Modal.loading(false);
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
||||
timeout: 3000,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
filterSubscribers();
|
||||
enableSegmentSelection(mailpoetSegments);
|
||||
|
||||
});
|
||||
|
||||
router.on('route:step3', function () {
|
||||
@ -1118,6 +1157,12 @@ define(
|
||||
|
||||
showCurrentStep();
|
||||
|
||||
if (importData.step2.errors.length > 0) {
|
||||
MailPoet.Notice.error(_.flatten(importData.step2.errors), {
|
||||
timeout: noticeTimeout,
|
||||
});
|
||||
}
|
||||
|
||||
// display statistics
|
||||
var subscribersDataImportResultsTemplate =
|
||||
Handlebars
|
||||
@ -1126,12 +1171,12 @@ define(
|
||||
exportMenuElement = jQuery('span.mailpoet_export'),
|
||||
importResults = {
|
||||
created: (importData.step2.created)
|
||||
? MailPoetI18n.subscribersCreated
|
||||
? MailPoet.I18n.t('subscribersCreated')
|
||||
.replace('%1$s', '<strong>' + importData.step2.created + '</strong>')
|
||||
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
|
||||
: false,
|
||||
updated: (importData.step2.updated)
|
||||
? MailPoetI18n.subscribersUpdated
|
||||
? MailPoet.I18n.t('subscribersUpdated')
|
||||
.replace('%1$s', '<strong>' + importData.step2.updated + '</strong>')
|
||||
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
|
||||
: false,
|
||||
|
@ -11,28 +11,28 @@ import Selection from 'form/fields/selection.jsx'
|
||||
const columns = [
|
||||
{
|
||||
name: 'email',
|
||||
label: 'Subscriber',
|
||||
label: MailPoet.I18n.t('subscriber'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
label: MailPoet.I18n.t('status'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
label: MailPoet.I18n.t('lists'),
|
||||
sortable: false
|
||||
},
|
||||
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Subscribed on',
|
||||
label: MailPoet.I18n.t('subscribedOn'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'updated_at',
|
||||
label: 'Last modified on',
|
||||
label: MailPoet.I18n.t('lastModifiedOn'),
|
||||
sortable: true
|
||||
},
|
||||
];
|
||||
@ -43,11 +43,11 @@ const messages = {
|
||||
var message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 subscriber was moved to the trash.'
|
||||
MailPoet.I18n.t('oneSubscriberTrashed')
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d subscribers were moved to the trash.'
|
||||
MailPoet.I18n.t('multipleSubscribersTrashed')
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
@ -61,11 +61,11 @@ const messages = {
|
||||
var message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 subscriber was permanently deleted.'
|
||||
MailPoet.I18n.t('oneSubscriberDeleted')
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d subscribers were permanently deleted.'
|
||||
MailPoet.I18n.t('multipleSubscribersDeleted')
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
@ -79,11 +79,11 @@ const messages = {
|
||||
var message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 subscriber has been restored from the trash.'
|
||||
MailPoet.I18n.t('oneSubscriberRestored')
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d subscribers have been restored from the trash.'
|
||||
MailPoet.I18n.t('multipleSubscribersRestored')
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ const messages = {
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'moveToList',
|
||||
label: 'Move to list...',
|
||||
label: MailPoet.I18n.t('moveToList'),
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'move_to_segment',
|
||||
@ -120,7 +120,7 @@ const bulk_actions = [
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were moved to list <strong>%$2s</strong>.'
|
||||
MailPoet.I18n.t('multipleSubscribersMovedToList')
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
@ -128,7 +128,7 @@ const bulk_actions = [
|
||||
},
|
||||
{
|
||||
name: 'addToList',
|
||||
label: 'Add to list...',
|
||||
label: MailPoet.I18n.t('addToList'),
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'add_to_segment',
|
||||
@ -151,7 +151,7 @@ const bulk_actions = [
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were added to list <strong>%$2s</strong>.'
|
||||
MailPoet.I18n.t('multipleSubscribersAddedToList')
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
@ -159,7 +159,7 @@ const bulk_actions = [
|
||||
},
|
||||
{
|
||||
name: 'removeFromList',
|
||||
label: 'Remove from list...',
|
||||
label: MailPoet.I18n.t('removeFromList'),
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'remove_from_segment',
|
||||
@ -182,7 +182,7 @@ const bulk_actions = [
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were removed from list <strong>%$2s</strong>.'
|
||||
MailPoet.I18n.t('multipleSubscribersRemovedFromList')
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
@ -190,27 +190,37 @@ const bulk_actions = [
|
||||
},
|
||||
{
|
||||
name: 'removeFromAllLists',
|
||||
label: 'Remove from all lists',
|
||||
label: MailPoet.I18n.t('removeFromAllLists'),
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were removed from all lists.'
|
||||
MailPoet.I18n.t('multipleSubscribersRemovedFromAllLists')
|
||||
.replace('%$1d', ~~response)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'confirmUnconfirmed',
|
||||
label: 'Confirm unconfirmed',
|
||||
label: MailPoet.I18n.t('confirmUnconfirmed'),
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers have been confirmed.'
|
||||
MailPoet.I18n.t('multipleSubscribersConfirmed')
|
||||
.replace('%$1d', ~~response)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'sendConfirmationEmail',
|
||||
label: MailPoet.I18n.t('resendConfirmationEmail'),
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('multipleConfirmationEmailsSent')
|
||||
.replace('%$1d', ~~response)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
label: MailPoet.I18n.t('trash'),
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
@ -218,10 +228,10 @@ const bulk_actions = [
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
label: MailPoet.I18n.t('edit'),
|
||||
link: function(item) {
|
||||
return (
|
||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
||||
<Link to={ `/edit/${item.id}` }>{MailPoet.I18n.t('edit')}</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -231,6 +241,15 @@ const item_actions = [
|
||||
];
|
||||
|
||||
const SubscriberList = React.createClass({
|
||||
getSegmentFromId: function(segment_id) {
|
||||
let result = false;
|
||||
mailpoet_segments.map(function(segment) {
|
||||
if (segment.id === segment_id) {
|
||||
result = segment;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
renderItem: function(subscriber, actions) {
|
||||
let row_classes = classNames(
|
||||
'manage-column',
|
||||
@ -243,23 +262,53 @@ const SubscriberList = React.createClass({
|
||||
|
||||
switch(subscriber.status) {
|
||||
case 'subscribed':
|
||||
status = 'Subscribed';
|
||||
status = MailPoet.I18n.t('subscribed');
|
||||
break;
|
||||
|
||||
case 'unconfirmed':
|
||||
status = 'Unconfirmed';
|
||||
status = MailPoet.I18n.t('unconfirmed');
|
||||
break;
|
||||
|
||||
case 'unsubscribed':
|
||||
status = 'Unsubscribed';
|
||||
status = MailPoet.I18n.t('unsubscribed');
|
||||
break;
|
||||
}
|
||||
|
||||
let segments = mailpoet_segments.filter(function(segment) {
|
||||
return (jQuery.inArray(segment.id, subscriber.segments) !== -1);
|
||||
}).map(function(segment) {
|
||||
return segment.name;
|
||||
}).join(', ');
|
||||
let segments = false;
|
||||
|
||||
if (subscriber.subscriptions.length > 0) {
|
||||
let subscribed_segments = [];
|
||||
let unsubscribed_segments = [];
|
||||
|
||||
subscriber.subscriptions.map((subscription) => {
|
||||
const segment = this.getSegmentFromId(subscription.segment_id);
|
||||
if(segment === false) return;
|
||||
if (subscription.status === 'subscribed') {
|
||||
subscribed_segments.push(segment.name);
|
||||
} else if (subscription.status === 'unsubscribed') {
|
||||
unsubscribed_segments.push(segment.name);
|
||||
}
|
||||
});
|
||||
segments = (
|
||||
<span>
|
||||
<span className="mailpoet_segments_subscribed">
|
||||
{ subscribed_segments.join(', ') }
|
||||
{
|
||||
(
|
||||
subscribed_segments.length > 0
|
||||
&& unsubscribed_segments.length > 0
|
||||
) ? ' / ' : ''
|
||||
}
|
||||
</span>
|
||||
<span
|
||||
className="mailpoet_segments_unsubscribed"
|
||||
title={MailPoet.I18n.t('listsToWhichSubscriberWasSubscribed')}
|
||||
>
|
||||
{ unsubscribed_segments.join(', ') }
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
let avatar = false;
|
||||
if(subscriber.avatar_url) {
|
||||
@ -285,17 +334,17 @@ const SubscriberList = React.createClass({
|
||||
</p>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column" data-colname="Status">
|
||||
<td className="column" data-colname={MailPoet.I18n.t('status')}>
|
||||
{ status }
|
||||
</td>
|
||||
<td className="column" data-colname="Lists">
|
||||
<td className="column" data-colname={MailPoet.I18n.t('lists')}>
|
||||
{ segments }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed on">
|
||||
<abbr>{ subscriber.created_at }</abbr>
|
||||
<td className="column-date" data-colname={MailPoet.I18n.t('subscribedOn')}>
|
||||
<abbr>{ MailPoet.Date.full(subscriber.created_at) }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Last modified on">
|
||||
<abbr>{ subscriber.updated_at }</abbr>
|
||||
<td className="column-date" data-colname={MailPoet.I18n.t('lastModifiedOn')}>
|
||||
<abbr>{ MailPoet.Date.full(subscriber.updated_at) }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
@ -307,12 +356,13 @@ const SubscriberList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscribers <Link className="add-new-h2" to="/new">New</Link>
|
||||
<a className="add-new-h2" href="?page=mailpoet-import#step1">Import</a>
|
||||
<a id="mailpoet_export_button" className="add-new-h2" href="?page=mailpoet-export">Export</a>
|
||||
{MailPoet.I18n.t('pageTitle')} <Link className="add-new-h2" to="/new">{MailPoet.I18n.t('new')}</Link>
|
||||
<a className="add-new-h2" href="?page=mailpoet-import#step1">{MailPoet.I18n.t('import')}</a>
|
||||
<a id="mailpoet_export_button" className="add-new-h2" href="?page=mailpoet-export">{MailPoet.I18n.t('export')}</a>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
limit={ mailpoet_listing_per_page }
|
||||
location={ this.props.location }
|
||||
params={ this.props.params }
|
||||
endpoint="subscribers"
|
||||
|
79
assets/js/src/vendor/jquery.asyncqueue.js
vendored
Normal file
79
assets/js/src/vendor/jquery.asyncqueue.js
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of the jquery plugin "asyncQueue".
|
||||
*
|
||||
* (c) Sebastien Roch <roch.sebastien@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
(function($){
|
||||
$.AsyncQueue = function() {
|
||||
var that = this,
|
||||
queue = [],
|
||||
failureFunc,
|
||||
completeFunc,
|
||||
paused = false,
|
||||
lastCallbackData,
|
||||
_run;
|
||||
|
||||
_run = function() {
|
||||
var f = queue.shift();
|
||||
|
||||
if (f) {
|
||||
f.apply(that, [that]);
|
||||
if (paused === false) {
|
||||
_run();
|
||||
}
|
||||
} else {
|
||||
if(completeFunc){
|
||||
completeFunc.apply(that);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.onFailure = function(func) {
|
||||
failureFunc = func;
|
||||
}
|
||||
|
||||
this.onComplete = function(func) {
|
||||
completeFunc = func;
|
||||
}
|
||||
|
||||
this.add = function(func) {
|
||||
queue.push(func);
|
||||
return this;
|
||||
}
|
||||
|
||||
this.storeData = function(dataObject) {
|
||||
lastCallbackData = dataObject;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.lastCallbackData = function () {
|
||||
return lastCallbackData;
|
||||
}
|
||||
|
||||
this.run = function() {
|
||||
paused = false;
|
||||
_run();
|
||||
}
|
||||
|
||||
this.pause = function () {
|
||||
paused = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.failure = function() {
|
||||
paused = true;
|
||||
if (failureFunc) {
|
||||
var args = [that];
|
||||
for(i = 0; i < arguments.length; i++) {
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
failureFunc.apply(that, args);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
})(jQuery);
|
@ -9,6 +9,7 @@ settings:
|
||||
bootstrap: _bootstrap.php
|
||||
colors: true
|
||||
memory_limit: 1024M
|
||||
log: true
|
||||
extensions:
|
||||
enabled:
|
||||
- Codeception\Extension\RunFailed
|
||||
@ -19,3 +20,12 @@ modules:
|
||||
user: ''
|
||||
password: ''
|
||||
dump: tests/_data/dump.sql
|
||||
coverage:
|
||||
enabled: true
|
||||
whitelist:
|
||||
include:
|
||||
- lib/*
|
||||
exclude:
|
||||
blacklist:
|
||||
include:
|
||||
exclude:
|
@ -9,7 +9,7 @@
|
||||
"j4mie/paris": "1.5.4",
|
||||
"swiftmailer/swiftmailer": "^5.4",
|
||||
"phpseclib/phpseclib": "*",
|
||||
"mtdowling/cron-expression": "^1.0",
|
||||
"mtdowling/cron-expression": "^1.1",
|
||||
"nesbot/carbon": "^1.21",
|
||||
"soundasleep/html2text": "^0.3.0"
|
||||
},
|
||||
|
399
composer.lock
generated
399
composer.lock
generated
@ -4,8 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "db2edea5fb720fcb8013ac470e924c19",
|
||||
"content-hash": "85119d1ccd5193b6b08fda305a2427e7",
|
||||
"hash": "2bed8395d84740d7c0ae644a6c6216fd",
|
||||
"content-hash": "7b66e221814f3d5839ed4faabd2f50ad",
|
||||
"packages": [
|
||||
{
|
||||
"name": "cerdic/css-tidy",
|
||||
@ -160,23 +160,23 @@
|
||||
},
|
||||
{
|
||||
"name": "mtdowling/cron-expression",
|
||||
"version": "v1.0.4",
|
||||
"version": "v1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mtdowling/cron-expression.git",
|
||||
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412"
|
||||
"reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412",
|
||||
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412",
|
||||
"url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
|
||||
"reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*"
|
||||
"phpunit/phpunit": "~4.0|~5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -200,7 +200,7 @@
|
||||
"cron",
|
||||
"schedule"
|
||||
],
|
||||
"time": "2015-01-11 23:07:46"
|
||||
"time": "2016-01-26 21:23:30"
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
@ -401,16 +401,16 @@
|
||||
},
|
||||
{
|
||||
"name": "soundasleep/html2text",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/soundasleep/html2text.git",
|
||||
"reference": "55be17ddbb7234650722f66816ba2b10f66e565f"
|
||||
"reference": "2a5fd94bf58b653a5a9d777ac6a5593f82d087db"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/soundasleep/html2text/zipball/55be17ddbb7234650722f66816ba2b10f66e565f",
|
||||
"reference": "55be17ddbb7234650722f66816ba2b10f66e565f",
|
||||
"url": "https://api.github.com/repos/soundasleep/html2text/zipball/2a5fd94bf58b653a5a9d777ac6a5593f82d087db",
|
||||
"reference": "2a5fd94bf58b653a5a9d777ac6a5593f82d087db",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -447,7 +447,7 @@
|
||||
"php",
|
||||
"text"
|
||||
],
|
||||
"time": "2015-12-18 02:30:26"
|
||||
"time": "2016-02-25 00:00:36"
|
||||
},
|
||||
{
|
||||
"name": "sunra/php-simple-html-dom-parser",
|
||||
@ -547,16 +547,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.0.1",
|
||||
"version": "v1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25"
|
||||
"reference": "1289d16209491b584839022f29257ad859b8532d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/49ff736bd5d41f45240cec77b44967d76e0c3d25",
|
||||
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
|
||||
"reference": "1289d16209491b584839022f29257ad859b8532d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -568,7 +568,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -602,20 +602,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2015-11-20 09:19:13"
|
||||
"time": "2016-01-20 09:13:37"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "bc0b666903944858f4ffec01c4e50c63e5c276c0"
|
||||
"reference": "b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/bc0b666903944858f4ffec01c4e50c63e5c276c0",
|
||||
"reference": "bc0b666903944858f4ffec01c4e50c63e5c276c0",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7",
|
||||
"reference": "b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -666,7 +666,7 @@
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-03 15:33:41"
|
||||
"time": "2016-02-02 09:49:18"
|
||||
},
|
||||
{
|
||||
"name": "tburry/pquery",
|
||||
@ -722,16 +722,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.23.3",
|
||||
"version": "v1.24.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "ae53fc2c312fdee63773b75cb570304f85388b08"
|
||||
"reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ae53fc2c312fdee63773b75cb570304f85388b08",
|
||||
"reference": "ae53fc2c312fdee63773b75cb570304f85388b08",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
|
||||
"reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -744,7 +744,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.23-dev"
|
||||
"dev-master": "1.24-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -779,47 +779,48 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2016-01-11 14:02:19"
|
||||
"time": "2016-01-25 21:22:18"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "codeception/codeception",
|
||||
"version": "2.1.5",
|
||||
"version": "2.1.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codeception/Codeception.git",
|
||||
"reference": "4ee562f421fd404139dd7b73ae46d075396a4baf"
|
||||
"reference": "65971b0dee4972710365b6102154cd412a9bf7b1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/4ee562f421fd404139dd7b73ae46d075396a4baf",
|
||||
"reference": "4ee562f421fd404139dd7b73ae46d075396a4baf",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/65971b0dee4972710365b6102154cd412a9bf7b1",
|
||||
"reference": "65971b0dee4972710365b6102154cd412a9bf7b1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"facebook/webdriver": ">=1.0.1",
|
||||
"facebook/webdriver": ">=1.0.1 <2.0",
|
||||
"guzzlehttp/guzzle": ">=4.1.4 <7.0",
|
||||
"guzzlehttp/psr7": "~1.0",
|
||||
"php": ">=5.4.0",
|
||||
"phpunit/phpunit": "~4.8.0",
|
||||
"symfony/browser-kit": ">=2.4|<3.1",
|
||||
"symfony/console": ">=2.4|<3.1",
|
||||
"symfony/css-selector": ">=2.4|<3.1",
|
||||
"symfony/dom-crawler": ">=2.4|<3.1",
|
||||
"symfony/event-dispatcher": ">=2.4|<3.1",
|
||||
"symfony/finder": ">=2.4|<3.1",
|
||||
"symfony/yaml": ">=2.4|<3.1"
|
||||
"php": ">=5.4.0 <8.0",
|
||||
"phpunit/php-code-coverage": ">=2.1.3",
|
||||
"phpunit/phpunit": ">4.8.20 <6.0",
|
||||
"symfony/browser-kit": ">=2.5 <3.1",
|
||||
"symfony/console": ">=2.5 <3.1",
|
||||
"symfony/css-selector": ">=2.5 <3.1",
|
||||
"symfony/dom-crawler": ">=2.5 <3.1",
|
||||
"symfony/event-dispatcher": ">=2.5 <3.1",
|
||||
"symfony/finder": ">=2.5 <3.1",
|
||||
"symfony/yaml": ">=2.5 <3.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/specify": "~0.3",
|
||||
"facebook/php-sdk-v4": "~4.0",
|
||||
"facebook/php-sdk-v4": "~5.0",
|
||||
"flow/jsonpath": "~0.2",
|
||||
"monolog/monolog": "~1.8",
|
||||
"pda/pheanstalk": "~2.0",
|
||||
"videlalvaro/php-amqplib": "~2.4"
|
||||
"php-amqplib/php-amqplib": "~2.4"
|
||||
},
|
||||
"suggest": {
|
||||
"codeception/phpbuiltinserver": "Extension to start and stop PHP built-in web server for your tests",
|
||||
@ -861,7 +862,7 @@
|
||||
"functional testing",
|
||||
"unit testing"
|
||||
],
|
||||
"time": "2015-12-20 12:11:42"
|
||||
"time": "2016-03-12 01:15:25"
|
||||
},
|
||||
{
|
||||
"name": "codeception/verify",
|
||||
@ -898,33 +899,36 @@
|
||||
},
|
||||
{
|
||||
"name": "codegyre/robo",
|
||||
"version": "0.6.0",
|
||||
"version": "0.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codegyre/Robo.git",
|
||||
"reference": "d18185f0494c854d36aa5ee0ad931ee23bbef552"
|
||||
"reference": "1f4e0621fdc37521e2eaca67f33d1c4e240dc7d8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codegyre/Robo/zipball/d18185f0494c854d36aa5ee0ad931ee23bbef552",
|
||||
"reference": "d18185f0494c854d36aa5ee0ad931ee23bbef552",
|
||||
"url": "https://api.github.com/repos/Codegyre/Robo/zipball/1f4e0621fdc37521e2eaca67f33d1c4e240dc7d8",
|
||||
"reference": "1f4e0621fdc37521e2eaca67f33d1c4e240dc7d8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"henrikbjorn/lurker": "1.0.*@dev",
|
||||
"henrikbjorn/lurker": "~1.0",
|
||||
"php": ">=5.4.0",
|
||||
"symfony/console": "~2.5",
|
||||
"symfony/filesystem": "~2.5",
|
||||
"symfony/finder": "~2.5",
|
||||
"symfony/process": "~2.5"
|
||||
"symfony/console": "~2.5|~3.0",
|
||||
"symfony/filesystem": "~2.5|~3.0",
|
||||
"symfony/finder": "~2.5|~3.0",
|
||||
"symfony/process": "~2.5|~3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/aspect-mock": "0.5.*",
|
||||
"codeception/base": "~2.1",
|
||||
"codeception/codeception": "2.1",
|
||||
"codeception/aspect-mock": "0.5.4",
|
||||
"codeception/base": "~2.1.5",
|
||||
"codeception/verify": "0.2.*",
|
||||
"natxet/cssmin": "~3.0",
|
||||
"patchwork/jsqueeze": "~1.0"
|
||||
"patchwork/jsqueeze": "~1.0",
|
||||
"pear/archive_tar": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively."
|
||||
},
|
||||
"bin": [
|
||||
"robo"
|
||||
@ -946,7 +950,7 @@
|
||||
}
|
||||
],
|
||||
"description": "Modern task runner",
|
||||
"time": "2015-10-30 11:29:52"
|
||||
"time": "2016-02-25 19:28:51"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
@ -1109,16 +1113,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"version": "1.0.3",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/promises.git",
|
||||
"reference": "b1e1c0d55f8083c71eda2c28c12a228d708294ea"
|
||||
"reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/b1e1c0d55f8083c71eda2c28c12a228d708294ea",
|
||||
"reference": "b1e1c0d55f8083c71eda2c28c12a228d708294ea",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/bb9024c526b22f3fe6ae55a561fd70653d470aa8",
|
||||
"reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1156,20 +1160,20 @@
|
||||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"time": "2015-10-15 22:28:00"
|
||||
"time": "2016-03-08 01:15:46"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "f5d04bdd2881ac89abde1fb78cc234bce24327bb"
|
||||
"reference": "2e89629ff057ebb49492ba08e6995d3a6a80021b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/f5d04bdd2881ac89abde1fb78cc234bce24327bb",
|
||||
"reference": "f5d04bdd2881ac89abde1fb78cc234bce24327bb",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/2e89629ff057ebb49492ba08e6995d3a6a80021b",
|
||||
"reference": "2e89629ff057ebb49492ba08e6995d3a6a80021b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1214,20 +1218,20 @@
|
||||
"stream",
|
||||
"uri"
|
||||
],
|
||||
"time": "2016-01-23 01:23:02"
|
||||
"time": "2016-02-18 21:54:00"
|
||||
},
|
||||
{
|
||||
"name": "henrikbjorn/lurker",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/flint/Lurker.git",
|
||||
"reference": "a020d45b3bc37810aeafe27343c51af8a74c9419"
|
||||
"reference": "ab45f9cefe600065cc3137a238217598d3a1d062"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/flint/Lurker/zipball/a020d45b3bc37810aeafe27343c51af8a74c9419",
|
||||
"reference": "a020d45b3bc37810aeafe27343c51af8a74c9419",
|
||||
"url": "https://api.github.com/repos/flint/Lurker/zipball/ab45f9cefe600065cc3137a238217598d3a1d062",
|
||||
"reference": "ab45f9cefe600065cc3137a238217598d3a1d062",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1255,18 +1259,16 @@
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Henrik Bjornskov",
|
||||
"email": "henrik@bjrnskov.dk",
|
||||
"homepage": "http://henrik.bjrnskov.dk"
|
||||
"name": "Yaroslav Kiliba",
|
||||
"email": "om.dattaya@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Konstantin Kudryashov",
|
||||
"email": "ever.zet@gmail.com",
|
||||
"homepage": "http://everzet.com"
|
||||
"email": "ever.zet@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Yaroslav Kiliba",
|
||||
"email": "om.dattaya@gmail.com"
|
||||
"name": "Henrik Bjrnskov",
|
||||
"email": "henrik@bjrnskov.dk"
|
||||
}
|
||||
],
|
||||
"description": "Resource Watcher.",
|
||||
@ -1275,7 +1277,7 @@
|
||||
"resource",
|
||||
"watching"
|
||||
],
|
||||
"time": "2013-05-24 06:47:29"
|
||||
"time": "2015-10-27 09:19:19"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
@ -1328,22 +1330,24 @@
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.5.0",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7"
|
||||
"reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7",
|
||||
"reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
|
||||
"reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": "^5.3|^7.0",
|
||||
"phpdocumentor/reflection-docblock": "~2.0",
|
||||
"sebastian/comparator": "~1.1"
|
||||
"sebastian/comparator": "~1.1",
|
||||
"sebastian/recursion-context": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "~2.0"
|
||||
@ -1351,7 +1355,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
"dev-master": "1.5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -1384,7 +1388,7 @@
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2015-08-13 10:07:40"
|
||||
"time": "2016-02-15 07:46:21"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@ -1628,16 +1632,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.8.21",
|
||||
"version": "4.8.24",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "ea76b17bced0500a28098626b84eda12dbcf119c"
|
||||
"reference": "a1066c562c52900a142a0e2bbf0582994671385e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c",
|
||||
"reference": "ea76b17bced0500a28098626b84eda12dbcf119c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e",
|
||||
"reference": "a1066c562c52900a142a0e2bbf0582994671385e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1696,7 +1700,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-12-12 07:45:58"
|
||||
"time": "2016-03-14 06:16:08"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
@ -1972,16 +1976,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "1.3.3",
|
||||
"version": "1.3.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "6e7133793a8e5a5714a551a8324337374be209df"
|
||||
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e7133793a8e5a5714a551a8324337374be209df",
|
||||
"reference": "6e7133793a8e5a5714a551a8324337374be209df",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
|
||||
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2018,7 +2022,7 @@
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2015-12-02 08:37:27"
|
||||
"time": "2016-02-26 18:40:46"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
@ -2227,16 +2231,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v3.0.1",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "334a58c0def6dfcbe4bb57c6d2a8c06c6cc77679"
|
||||
"reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/334a58c0def6dfcbe4bb57c6d2a8c06c6cc77679",
|
||||
"reference": "334a58c0def6dfcbe4bb57c6d2a8c06c6cc77679",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/dde849a0485b70a24b36f826ed3fb95b904d80c3",
|
||||
"reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2280,26 +2284,29 @@
|
||||
],
|
||||
"description": "Symfony BrowserKit Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-12-26 13:39:53"
|
||||
"time": "2016-01-27 11:34:55"
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "41ee6c70758f40fa1dbf90d019ae0a66c4a09e74"
|
||||
"reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/41ee6c70758f40fa1dbf90d019ae0a66c4a09e74",
|
||||
"reference": "41ee6c70758f40fa1dbf90d019ae0a66c4a09e74",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19",
|
||||
"reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"symfony/filesystem": "~2.3|~3.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/yaml": "To use the yaml reference dumper"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2330,30 +2337,30 @@
|
||||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-03 15:33:41"
|
||||
"time": "2016-02-22 16:12:45"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.8.2",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "d0239fb42f98dd02e7d342f793c5d2cdee0c478d"
|
||||
"reference": "2ed5e2706ce92313d120b8fe50d1063bcfd12e04"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/d0239fb42f98dd02e7d342f793c5d2cdee0c478d",
|
||||
"reference": "d0239fb42f98dd02e7d342f793c5d2cdee0c478d",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/2ed5e2706ce92313d120b8fe50d1063bcfd12e04",
|
||||
"reference": "2ed5e2706ce92313d120b8fe50d1063bcfd12e04",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"php": ">=5.5.9",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/event-dispatcher": "~2.1|~3.0.0",
|
||||
"symfony/process": "~2.1|~3.0.0"
|
||||
"symfony/event-dispatcher": "~2.8|~3.0",
|
||||
"symfony/process": "~2.8|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "For using the console logger",
|
||||
@ -2363,7 +2370,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2390,20 +2397,20 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-14 08:33:16"
|
||||
"time": "2016-02-28 16:24:34"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v3.0.1",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3"
|
||||
"reference": "6605602690578496091ac20ec7a5cbd160d4dff4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/4613311fd46e146f506403ce2f8a0c71d402d2a3",
|
||||
"reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/6605602690578496091ac20ec7a5cbd160d4dff4",
|
||||
"reference": "6605602690578496091ac20ec7a5cbd160d4dff4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2443,20 +2450,20 @@
|
||||
],
|
||||
"description": "Symfony CssSelector Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-12-05 17:45:07"
|
||||
"time": "2016-01-27 05:14:46"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v3.0.1",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d"
|
||||
"reference": "981c8edb4538f88ba976ed44bdcaa683fce3d6c6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d",
|
||||
"reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/981c8edb4538f88ba976ed44bdcaa683fce3d6c6",
|
||||
"reference": "981c8edb4538f88ba976ed44bdcaa683fce3d6c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2499,20 +2506,20 @@
|
||||
],
|
||||
"description": "Symfony DomCrawler Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-12-26 13:42:31"
|
||||
"time": "2016-02-28 16:24:34"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "ee278f7c851533e58ca307f66305ccb9188aceda"
|
||||
"reference": "78c468665c9568c3faaa9c416a7134308f2d85c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ee278f7c851533e58ca307f66305ccb9188aceda",
|
||||
"reference": "ee278f7c851533e58ca307f66305ccb9188aceda",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/78c468665c9568c3faaa9c416a7134308f2d85c3",
|
||||
"reference": "78c468665c9568c3faaa9c416a7134308f2d85c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2559,20 +2566,20 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-13 10:28:07"
|
||||
"time": "2016-01-27 05:14:19"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "637b64d0ee10f44ae98dbad651b1ecdf35a11e8c"
|
||||
"reference": "65cb36b6539b1d446527d60457248f30d045464d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/637b64d0ee10f44ae98dbad651b1ecdf35a11e8c",
|
||||
"reference": "637b64d0ee10f44ae98dbad651b1ecdf35a11e8c",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/65cb36b6539b1d446527d60457248f30d045464d",
|
||||
"reference": "65cb36b6539b1d446527d60457248f30d045464d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2608,29 +2615,29 @@
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-13 10:28:07"
|
||||
"time": "2016-02-22 15:02:30"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.8.2",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "c90fabdd97e431ee19b6383999cf35334dff27da"
|
||||
"reference": "623bda0abd9aa29e529c8e9c08b3b84171914723"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/c90fabdd97e431ee19b6383999cf35334dff27da",
|
||||
"reference": "c90fabdd97e431ee19b6383999cf35334dff27da",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/623bda0abd9aa29e529c8e9c08b3b84171914723",
|
||||
"reference": "623bda0abd9aa29e529c8e9c08b3b84171914723",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2657,20 +2664,20 @@
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-14 08:26:52"
|
||||
"time": "2016-01-27 05:14:46"
|
||||
},
|
||||
{
|
||||
"name": "symfony/form",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/form.git",
|
||||
"reference": "7fd5e4034cb8e215887136f5e176430bbf5ef085"
|
||||
"reference": "25b71aec36879b4a84c2ea06603dbe7498b31f06"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/form/zipball/7fd5e4034cb8e215887136f5e176430bbf5ef085",
|
||||
"reference": "7fd5e4034cb8e215887136f5e176430bbf5ef085",
|
||||
"url": "https://api.github.com/repos/symfony/form/zipball/25b71aec36879b4a84c2ea06603dbe7498b31f06",
|
||||
"reference": "25b71aec36879b4a84c2ea06603dbe7498b31f06",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2731,20 +2738,20 @@
|
||||
],
|
||||
"description": "Symfony Form Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-12 17:46:01"
|
||||
"time": "2016-02-28 15:05:09"
|
||||
},
|
||||
{
|
||||
"name": "symfony/intl",
|
||||
"version": "v3.0.1",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/intl.git",
|
||||
"reference": "9abd5cd590211c35cda87591f0dee856b7a16125"
|
||||
"reference": "cafee6f65148dab9058cdb6de5631222aca820d0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/intl/zipball/9abd5cd590211c35cda87591f0dee856b7a16125",
|
||||
"reference": "9abd5cd590211c35cda87591f0dee856b7a16125",
|
||||
"url": "https://api.github.com/repos/symfony/intl/zipball/cafee6f65148dab9058cdb6de5631222aca820d0",
|
||||
"reference": "cafee6f65148dab9058cdb6de5631222aca820d0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2806,20 +2813,20 @@
|
||||
"l10n",
|
||||
"localization"
|
||||
],
|
||||
"time": "2015-12-05 11:13:14"
|
||||
"time": "2016-02-23 15:16:06"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/options-resolver.git",
|
||||
"reference": "b98ca04f85240531b9ea8a0f00a21f2ecfbdfa51"
|
||||
"reference": "d1e6e9182d9e5af6367bf85175e708f8b4a828c0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/b98ca04f85240531b9ea8a0f00a21f2ecfbdfa51",
|
||||
"reference": "b98ca04f85240531b9ea8a0f00a21f2ecfbdfa51",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/d1e6e9182d9e5af6367bf85175e708f8b4a828c0",
|
||||
"reference": "d1e6e9182d9e5af6367bf85175e708f8b4a828c0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2860,30 +2867,33 @@
|
||||
"configuration",
|
||||
"options"
|
||||
],
|
||||
"time": "2016-01-03 15:33:41"
|
||||
"time": "2016-01-21 09:05:51"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-icu",
|
||||
"version": "v1.0.1",
|
||||
"version": "v1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-icu.git",
|
||||
"reference": "2deb44160e1c886241c06602b12b98779f728177"
|
||||
"reference": "8328069d9f5322f0e7b3c3518485acfdc94c3942"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/2deb44160e1c886241c06602b12b98779f728177",
|
||||
"reference": "2deb44160e1c886241c06602b12b98779f728177",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/8328069d9f5322f0e7b3c3518485acfdc94c3942",
|
||||
"reference": "8328069d9f5322f0e7b3c3518485acfdc94c3942",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/intl": "~2.3|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2915,29 +2925,29 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2015-11-04 20:28:58"
|
||||
"time": "2016-02-26 16:18:12"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.8.2",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac"
|
||||
"reference": "dfecef47506179db2501430e732adbf3793099c8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac",
|
||||
"reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/dfecef47506179db2501430e732adbf3793099c8",
|
||||
"reference": "dfecef47506179db2501430e732adbf3793099c8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2964,20 +2974,20 @@
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-06 09:59:23"
|
||||
"time": "2016-02-02 13:44:19"
|
||||
},
|
||||
{
|
||||
"name": "symfony/property-access",
|
||||
"version": "v3.0.1",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/property-access.git",
|
||||
"reference": "9bb9f79ade13196fadd0b98504117f117d8221ad"
|
||||
"reference": "f138bcc0cdaf6a6aba99ecab20d235b394f46eba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/property-access/zipball/9bb9f79ade13196fadd0b98504117f117d8221ad",
|
||||
"reference": "9bb9f79ade13196fadd0b98504117f117d8221ad",
|
||||
"url": "https://api.github.com/repos/symfony/property-access/zipball/f138bcc0cdaf6a6aba99ecab20d235b394f46eba",
|
||||
"reference": "f138bcc0cdaf6a6aba99ecab20d235b394f46eba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3024,20 +3034,20 @@
|
||||
"property path",
|
||||
"reflection"
|
||||
],
|
||||
"time": "2015-12-23 08:00:11"
|
||||
"time": "2016-02-13 09:23:44"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/routing.git",
|
||||
"reference": "5451a8a1874fd4e6a4dd347ea611d86cd8441735"
|
||||
"reference": "ae38e64bae52753c0f4a1a6583f5ba9bb2b742ab"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/5451a8a1874fd4e6a4dd347ea611d86cd8441735",
|
||||
"reference": "5451a8a1874fd4e6a4dd347ea611d86cd8441735",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/ae38e64bae52753c0f4a1a6583f5ba9bb2b742ab",
|
||||
"reference": "ae38e64bae52753c0f4a1a6583f5ba9bb2b742ab",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3060,6 +3070,7 @@
|
||||
"symfony/config": "For using the all-in-one router or any loader",
|
||||
"symfony/dependency-injection": "For loading routes from a service",
|
||||
"symfony/expression-language": "For using expression matching",
|
||||
"symfony/http-foundation": "For using a Symfony Request object",
|
||||
"symfony/yaml": "For using the YAML loader"
|
||||
},
|
||||
"type": "library",
|
||||
@ -3098,20 +3109,20 @@
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2016-01-11 16:43:36"
|
||||
"time": "2016-02-04 13:53:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/twig-bridge",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/twig-bridge.git",
|
||||
"reference": "e33b512de4b769a1c728cd6775e22668ae89fca9"
|
||||
"reference": "ba898e4714734948dc00c4d776e1d6be165ff8c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e33b512de4b769a1c728cd6775e22668ae89fca9",
|
||||
"reference": "e33b512de4b769a1c728cd6775e22668ae89fca9",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/ba898e4714734948dc00c4d776e1d6be165ff8c4",
|
||||
"reference": "ba898e4714734948dc00c4d776e1d6be165ff8c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3179,20 +3190,20 @@
|
||||
],
|
||||
"description": "Symfony Twig Bridge",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-12 17:46:01"
|
||||
"time": "2016-02-22 15:02:30"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.0.1",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "3df409958a646dad2bc5046c3fb671ee24a1a691"
|
||||
"reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/3df409958a646dad2bc5046c3fb671ee24a1a691",
|
||||
"reference": "3df409958a646dad2bc5046c3fb671ee24a1a691",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/b5ba64cd67ecd6887f63868fa781ca094bd1377c",
|
||||
"reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3228,7 +3239,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-12-26 13:39:53"
|
||||
"time": "2016-02-23 15:16:06"
|
||||
},
|
||||
{
|
||||
"name": "twig/extensions",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,12 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Models\Setting;
|
||||
use \MailPoet\Util\Url;
|
||||
|
||||
class Changelog {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
|
||||
|
||||
@ -42,20 +46,7 @@ class Changelog {
|
||||
// save version number
|
||||
Setting::setValue('version', Env::$version);
|
||||
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
|
||||
if($redirect_url !== $current_url) {
|
||||
wp_safe_redirect(
|
||||
add_query_arg(
|
||||
array(
|
||||
'mailpoet_redirect' => urlencode($current_url)
|
||||
),
|
||||
$redirect_url
|
||||
)
|
||||
);
|
||||
exit;
|
||||
}
|
||||
Url::redirectWithReferer($redirect_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class Env {
|
||||
static $assets_path;
|
||||
static $assets_url;
|
||||
static $temp_path;
|
||||
static $temp_URL;
|
||||
static $temp_url;
|
||||
static $languages_path;
|
||||
static $lib_path;
|
||||
static $plugin_prefix;
|
||||
@ -26,6 +26,7 @@ class Env {
|
||||
static $db_username;
|
||||
static $db_password;
|
||||
static $db_charset;
|
||||
static $db_timezone_offset;
|
||||
|
||||
static function init($file, $version) {
|
||||
global $wpdb;
|
||||
@ -36,8 +37,9 @@ class Env {
|
||||
self::$views_path = self::$path . '/views';
|
||||
self::$assets_path = self::$path . '/assets';
|
||||
self::$assets_url = plugins_url('/assets', $file);
|
||||
self::$temp_path = wp_upload_dir()['path'];
|
||||
self::$temp_URL = wp_upload_dir()['url'];
|
||||
$wp_upload_dir = wp_upload_dir();
|
||||
self::$temp_path = $wp_upload_dir['path'];
|
||||
self::$temp_url = $wp_upload_dir['url'];
|
||||
self::$languages_path = self::$path . '/lang';
|
||||
self::$lib_path = self::$path . '/lib';
|
||||
self::$plugin_prefix = 'mailpoet_';
|
||||
@ -57,6 +59,7 @@ class Env {
|
||||
self::$db_password = DB_PASSWORD;
|
||||
self::$db_charset = $wpdb->get_charset_collate();
|
||||
self::$db_source_name = self::dbSourceName(self::$db_host, self::$db_socket, self::$db_port);
|
||||
self::$db_timezone_offset = self::getDbTimezoneOffset();
|
||||
}
|
||||
|
||||
private static function dbSourceName($host, $socket, $port) {
|
||||
@ -73,18 +76,12 @@ class Env {
|
||||
return implode('', $source_name);
|
||||
}
|
||||
|
||||
static function isPluginActivated() {
|
||||
$activatesPlugins = get_option('active_plugins');
|
||||
$isActivated = (
|
||||
in_array(
|
||||
sprintf('%s/%s.php', basename(self::$path), self::$plugin_name),
|
||||
$activatesPlugins
|
||||
) ||
|
||||
in_array(
|
||||
sprintf('%s/%s.php', explode('/', plugin_basename(__FILE__))[0], self::$plugin_name),
|
||||
$activatesPlugins
|
||||
)
|
||||
);
|
||||
return ($isActivated) ? true : false;
|
||||
private static function getDbTimezoneOffset() {
|
||||
$mins = get_option('gmt_offset') * 60;
|
||||
$sgn = ($mins < 0 ? -1 : 1);
|
||||
$mins = abs($mins);
|
||||
$hrs = floor($mins / 60);
|
||||
$mins -= $hrs * 60;
|
||||
return sprintf('%+d:%02d', $hrs * $sgn, $mins);
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use MailPoet\Cron\Workers\Scheduler;
|
||||
use MailPoet\Cron\Workers\SendingQueue;
|
||||
use \MailPoet\Models\Setting;
|
||||
|
||||
class Hooks {
|
||||
@ -7,12 +9,31 @@ class Hooks {
|
||||
}
|
||||
|
||||
function init() {
|
||||
$this->setupSubscribe();
|
||||
$this->setupWPUsers();
|
||||
$this->setupImageSize();
|
||||
$this->setupListing();
|
||||
}
|
||||
|
||||
function setupSubscribe() {
|
||||
$subscribe = Setting::getValue('subscribe', array());
|
||||
// Subscribe in comments
|
||||
if((bool)Setting::getValue('subscribe.on_comment.enabled')) {
|
||||
add_action(
|
||||
'comment_form_after_fields',
|
||||
'\MailPoet\Subscription\Comment::extendForm'
|
||||
);
|
||||
if(
|
||||
isset($subscribe['on_comment']['enabled'])
|
||||
&&
|
||||
(bool)$subscribe['on_comment']['enabled']
|
||||
) {
|
||||
if(is_user_logged_in()) {
|
||||
add_action(
|
||||
'comment_form_field_comment',
|
||||
'\MailPoet\Subscription\Comment::extendLoggedInForm'
|
||||
);
|
||||
} else {
|
||||
add_action(
|
||||
'comment_form_after_fields',
|
||||
'\MailPoet\Subscription\Comment::extendLoggedOutForm'
|
||||
);
|
||||
}
|
||||
|
||||
add_action(
|
||||
'comment_post',
|
||||
@ -30,7 +51,11 @@ class Hooks {
|
||||
}
|
||||
|
||||
// Subscribe in registration form
|
||||
if((bool)Setting::getValue('subscribe.on_register.enabled')) {
|
||||
if(
|
||||
isset($subscribe['on_register']['enabled'])
|
||||
&&
|
||||
(bool)$subscribe['on_register']['enabled']
|
||||
) {
|
||||
if(is_multisite()) {
|
||||
add_action(
|
||||
'signup_extra_fields',
|
||||
@ -55,7 +80,9 @@ class Hooks {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setupWPUsers() {
|
||||
// WP Users synchronization
|
||||
add_action(
|
||||
'user_register',
|
||||
@ -70,7 +97,7 @@ class Hooks {
|
||||
add_action(
|
||||
'profile_update',
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
1,2
|
||||
);
|
||||
add_action(
|
||||
'delete_user',
|
||||
@ -88,19 +115,35 @@ class Hooks {
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
function setupImageSize() {
|
||||
add_filter(
|
||||
'image_size_names_choose',
|
||||
array(
|
||||
$this,
|
||||
'appendImageSizes'
|
||||
)
|
||||
array($this, 'appendImageSize'),
|
||||
10, 1
|
||||
);
|
||||
}
|
||||
|
||||
function appendImageSizes($sizes) {
|
||||
function appendImageSize($sizes) {
|
||||
return array_merge($sizes, array(
|
||||
'mailpoet_newsletter_max' => __('MailPoet Newsletter'),
|
||||
'mailpoet_newsletter_max' => __('MailPoet Newsletter')
|
||||
));
|
||||
}
|
||||
|
||||
function setupListing() {
|
||||
add_filter(
|
||||
'set-screen-option',
|
||||
array($this, 'setScreenOption'),
|
||||
10, 3
|
||||
);
|
||||
}
|
||||
|
||||
function setScreenOption($status, $option, $value) {
|
||||
if(preg_match('/^mailpoet_(.*)_per_page$/', $option)) {
|
||||
return $value;
|
||||
} else {
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ namespace MailPoet\Config;
|
||||
use MailPoet\Models;
|
||||
use MailPoet\Cron\Supervisor;
|
||||
use MailPoet\Router;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Settings\Pages;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
||||
|
||||
class Initializer {
|
||||
function __construct($params = array(
|
||||
'file' => '',
|
||||
@ -18,22 +18,29 @@ class Initializer {
|
||||
}
|
||||
|
||||
function init() {
|
||||
$this->setupDB();
|
||||
|
||||
register_activation_hook(Env::$file, array($this, 'runMigrator'));
|
||||
register_activation_hook(Env::$file, array($this, 'runPopulator'));
|
||||
|
||||
add_action('plugins_loaded', array($this, 'setup'));
|
||||
add_action('init', array($this, 'onInit'));
|
||||
add_action('widgets_init', array($this, 'setupWidget'));
|
||||
}
|
||||
|
||||
function setup() {
|
||||
try {
|
||||
$this->setupDB();
|
||||
$this->setupRenderer();
|
||||
$this->setupLocalizer();
|
||||
$this->setupMenu();
|
||||
$this->setupRouter();
|
||||
$this->setupWidget();
|
||||
$this->setupAnalytics();
|
||||
$this->setupPermissions();
|
||||
$this->setupAnalytics();
|
||||
$this->setupChangelog();
|
||||
$this->setupPublicAPI();
|
||||
$this->runQueueSupervisor();
|
||||
$this->setupShortcodes();
|
||||
$this->setupHooks();
|
||||
$this->setupPages();
|
||||
$this->setupImages();
|
||||
$this->setupPublicAPI();
|
||||
$this->runQueueSupervisor();
|
||||
} catch(\Exception $e) {
|
||||
// if anything goes wrong during init
|
||||
// automatically deactivate the plugin
|
||||
@ -41,14 +48,25 @@ class Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
$this->setupRouter();
|
||||
$this->setupPages();
|
||||
$this->runQueueSupervisor();
|
||||
}
|
||||
|
||||
function setupDB() {
|
||||
\ORM::configure(Env::$db_source_name);
|
||||
\ORM::configure('username', Env::$db_username);
|
||||
\ORM::configure('password', Env::$db_password);
|
||||
\ORM::configure('logging', WP_DEBUG);
|
||||
\ORM::configure('logger', function($query, $time) {
|
||||
// error_log("\n".$query."\n");
|
||||
});
|
||||
|
||||
\ORM::configure('driver_options', array(
|
||||
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
|
||||
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET TIME_ZONE = "+00:00"'
|
||||
\PDO::MYSQL_ATTR_INIT_COMMAND =>
|
||||
'SET TIME_ZONE = "' . Env::$db_timezone_offset. '"'
|
||||
));
|
||||
|
||||
$subscribers = Env::$db_prefix . 'subscribers';
|
||||
@ -56,8 +74,6 @@ class Initializer {
|
||||
$newsletters = Env::$db_prefix . 'newsletters';
|
||||
$newsletter_templates = Env::$db_prefix . 'newsletter_templates';
|
||||
$segments = Env::$db_prefix . 'segments';
|
||||
$filters = Env::$db_prefix . 'filters';
|
||||
$segment_filter = Env::$db_prefix . 'segment_filter';
|
||||
$forms = Env::$db_prefix . 'forms';
|
||||
$subscriber_segment = Env::$db_prefix . 'subscriber_segment';
|
||||
$newsletter_segment = Env::$db_prefix . 'newsletter_segment';
|
||||
@ -72,8 +88,6 @@ class Initializer {
|
||||
define('MP_SETTINGS_TABLE', $settings);
|
||||
define('MP_NEWSLETTERS_TABLE', $newsletters);
|
||||
define('MP_SEGMENTS_TABLE', $segments);
|
||||
define('MP_FILTERS_TABLE', $filters);
|
||||
define('MP_SEGMENT_FILTER_TABLE', $segment_filter);
|
||||
define('MP_FORMS_TABLE', $forms);
|
||||
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
|
||||
define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates);
|
||||
@ -86,8 +100,12 @@ class Initializer {
|
||||
define('MP_NEWSLETTER_STATISTICS_TABLE', $newsletter_statistics);
|
||||
}
|
||||
|
||||
function runMigrator() {
|
||||
$migrator = new Migrator();
|
||||
$migrator->up();
|
||||
}
|
||||
|
||||
function runPopulator() {
|
||||
$this->init();
|
||||
$populator = new Populator();
|
||||
$populator->up();
|
||||
}
|
||||
@ -103,10 +121,7 @@ class Initializer {
|
||||
}
|
||||
|
||||
function setupMenu() {
|
||||
$menu = new Menu(
|
||||
$this->renderer,
|
||||
Env::$assets_url
|
||||
);
|
||||
$menu = new Menu($this->renderer, Env::$assets_url);
|
||||
$menu->init();
|
||||
}
|
||||
|
||||
@ -116,7 +131,7 @@ class Initializer {
|
||||
}
|
||||
|
||||
function setupWidget() {
|
||||
$widget = new Widget();
|
||||
$widget = new Widget($this->renderer);
|
||||
$widget->init();
|
||||
}
|
||||
|
||||
@ -136,8 +151,11 @@ class Initializer {
|
||||
}
|
||||
|
||||
function setupPages() {
|
||||
$pages = new Pages();
|
||||
$pages = new \MailPoet\Settings\Pages();
|
||||
$pages->init();
|
||||
|
||||
$subscription_pages = new \MailPoet\Subscription\Pages();
|
||||
$subscription_pages->init();
|
||||
}
|
||||
|
||||
function setupShortcodes() {
|
||||
@ -156,9 +174,7 @@ class Initializer {
|
||||
}
|
||||
|
||||
function runQueueSupervisor() {
|
||||
if(php_sapi_name() === 'cli' ||
|
||||
!Env::isPluginActivated()
|
||||
) return;
|
||||
if(php_sapi_name() === 'cli') return;
|
||||
try {
|
||||
$supervisor = new Supervisor();
|
||||
$supervisor->checkDaemon();
|
||||
|
@ -11,8 +11,7 @@ class Localizer {
|
||||
function init() {
|
||||
add_action(
|
||||
'init',
|
||||
array($this, 'setup'),
|
||||
0
|
||||
array($this, 'setup')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ use MailPoet\Settings\Pages;
|
||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||
use MailPoet\Util\DKIM;
|
||||
use MailPoet\Util\Permissions;
|
||||
use MailPoet\Listing;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -67,7 +68,7 @@ class Menu {
|
||||
'forms'
|
||||
)
|
||||
);
|
||||
add_submenu_page(
|
||||
$subscribers_page = add_submenu_page(
|
||||
'mailpoet',
|
||||
__('Subscribers'),
|
||||
__('Subscribers'),
|
||||
@ -78,6 +79,17 @@ class Menu {
|
||||
'subscribers'
|
||||
)
|
||||
);
|
||||
// add limit per page to screen options
|
||||
add_action('load-'.$subscribers_page, function() {
|
||||
add_screen_option('per_page', array(
|
||||
'label' => _x(
|
||||
'Number of subscribers per page',
|
||||
'subscribers per page (screen options)'
|
||||
),
|
||||
'option' => 'mailpoet_subscribers_per_page'
|
||||
));
|
||||
});
|
||||
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
__('Segments'),
|
||||
@ -305,6 +317,14 @@ class Menu {
|
||||
function subscribers() {
|
||||
$data = array();
|
||||
|
||||
// listing: limit per page
|
||||
$listing_per_page = get_user_meta(
|
||||
get_current_user_id(), 'mailpoet_subscribers_per_page', true
|
||||
);
|
||||
$data['per_page'] = (!empty($listing_per_page))
|
||||
? (int)$listing_per_page
|
||||
: Listing\Handler::DEFAULT_LIMIT_PER_PAGE;
|
||||
|
||||
$data['segments'] = Segment::findArray();
|
||||
|
||||
$data['custom_fields'] = array_map(function($field) {
|
||||
@ -347,6 +367,8 @@ class Menu {
|
||||
$data['segments'] = Segment::findArray();
|
||||
$data['settings'] = Setting::getAll();
|
||||
$data['roles'] = $wp_roles->get_names();
|
||||
$data['roles']['mailpoet_all'] = __('In any WordPress role');
|
||||
|
||||
echo $this->renderer->render('newsletters.html', $data);
|
||||
}
|
||||
|
||||
@ -360,11 +382,12 @@ class Menu {
|
||||
|
||||
$data = array(
|
||||
'customFields' => $custom_fields,
|
||||
'settings' => Setting::getAll(),
|
||||
);
|
||||
wp_enqueue_media();
|
||||
wp_enqueue_script('tinymce-wplink', includes_url('js/tinymce/plugins/wplink/plugin.js'));
|
||||
wp_enqueue_style('editor', includes_url('css/editor.css'));
|
||||
echo $this->renderer->render('newsletter/form.html', $data);
|
||||
echo $this->renderer->render('newsletter/editor.html', $data);
|
||||
}
|
||||
|
||||
function import() {
|
||||
|
@ -214,6 +214,9 @@ class Migrator {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'newsletter_id mediumint(9) NOT NULL,',
|
||||
'newsletter_rendered_body longtext,',
|
||||
'newsletter_rendered_body_hash varchar(250) NULL DEFAULT NULL,',
|
||||
'newsletter_rendered_subject varchar(250) NULL DEFAULT NULL,',
|
||||
'subscribers longtext,',
|
||||
'status varchar(12) NULL DEFAULT NULL,',
|
||||
'priority mediumint(9) NOT NULL DEFAULT 0,',
|
||||
@ -221,6 +224,7 @@ class Migrator {
|
||||
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_to_process mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_failed mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'scheduled_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'processed_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
@ -236,10 +240,7 @@ class Migrator {
|
||||
'newsletter_id mediumint(9) NOT NULL,',
|
||||
'subscriber_id mediumint(9) NOT NULL,',
|
||||
'queue_id mediumint(9) NOT NULL,',
|
||||
'sent_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||
'sent_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)',
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
|
@ -70,35 +70,36 @@ class Populator {
|
||||
|
||||
if($page === null) {
|
||||
$mailpoet_page_id = Pages::createMailPoetPage();
|
||||
Setting::setValue('subscription.page', $mailpoet_page_id);
|
||||
} else {
|
||||
$mailpoet_page_id = (int)$page->ID;
|
||||
}
|
||||
|
||||
Setting::setValue('subscription.unsubscribe_page', $mailpoet_page_id);
|
||||
Setting::setValue('subscription.manage_page', $mailpoet_page_id);
|
||||
Setting::setValue('subscription.confirmation_page', $mailpoet_page_id);
|
||||
}
|
||||
|
||||
private function createDefaultSettings() {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
// user name
|
||||
$user_name = '';
|
||||
if($current_user->user_firstname) {
|
||||
$user_name = $current_user->user_firstname;
|
||||
}
|
||||
if($current_user->user_lastname) {
|
||||
if($user_name) {
|
||||
$user_name .= ' '.$current_user->user_lastname;
|
||||
}
|
||||
}
|
||||
if(!$user_name) {
|
||||
$user_name = $current_user->display_name;
|
||||
}
|
||||
// default sender info based on current user
|
||||
$sender = array(
|
||||
'name' => $current_user->display_name,
|
||||
'address' => $current_user->user_email
|
||||
);
|
||||
|
||||
// default from name & address
|
||||
Setting::setValue('sender', array(
|
||||
'name' => $user_name,
|
||||
'address' => $current_user->user_email
|
||||
));
|
||||
Setting::setValue('sender', $sender);
|
||||
|
||||
// enable signup confirmation by default
|
||||
Setting::setValue('signup_confirmation.enabled', true);
|
||||
Setting::setValue('signup_confirmation', array(
|
||||
'enabled' => true,
|
||||
'from' => array(
|
||||
'name' => get_option('blogname'),
|
||||
'address' => get_option('admin_email')
|
||||
),
|
||||
'reply_to' => $sender
|
||||
));
|
||||
}
|
||||
|
||||
private function createDefaultSegments() {
|
||||
@ -175,6 +176,14 @@ class Populator {
|
||||
'name' => 'nthWeekDay',
|
||||
'newsletter_type' => 'notification',
|
||||
),
|
||||
array(
|
||||
'name' => 'schedule',
|
||||
'newsletter_type' => 'notification',
|
||||
),
|
||||
array(
|
||||
'name' => 'segments',
|
||||
'newsletter_type' => 'notification',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ class BlankTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => "<a href=\"[unsubscribeUrl]\">Unsubscribe</a> | <a href=\"[manageSubscriptionUrl]\">Manage subscription</a><br /><b>Add your postal address here!</b>",
|
||||
"text" => "<a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>",
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
|
@ -46,7 +46,7 @@ class FranksRoastHouseTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "header",
|
||||
"text" => __("Display problems? <a href=\"[viewInBrowserUrl]\">View it in your browser</a>"),
|
||||
"text" => __("Display problems? <a href=\"[newsletter:view_in_browser_url]\">View it in your browser</a>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "#ccc6c6"
|
||||
@ -68,7 +68,7 @@ class FranksRoastHouseTemplate {
|
||||
"link" => "http://www.example.com",
|
||||
"src" => $this->template_image_url . "/header-v2.jpg",
|
||||
"alt" => __("Frank's Roast House"),
|
||||
"padded" => false,
|
||||
"fullWidth" => true,
|
||||
"width" => "600px",
|
||||
"height" => "220px",
|
||||
"styles" => array(
|
||||
@ -95,7 +95,7 @@ class FranksRoastHouseTemplate {
|
||||
"link" => "http://example.org",
|
||||
"src" => $this->template_image_url . "/coffee-grain.jpg",
|
||||
"alt" => __("coffee-grain-3-1329675-1599x941"),
|
||||
"padded" => true,
|
||||
"fullWidth" => false,
|
||||
"width" => "1599px",
|
||||
"height" => "777px",
|
||||
"styles" => array(
|
||||
@ -139,7 +139,7 @@ class FranksRoastHouseTemplate {
|
||||
"link" => "http://example.org",
|
||||
"src" => $this->template_image_url . "/sandwich.jpg",
|
||||
"alt" => "sandwich",
|
||||
"padded" => true,
|
||||
"fullWidth" => false,
|
||||
"width" => "640px",
|
||||
"height" => "344px",
|
||||
"styles" => array(
|
||||
@ -168,6 +168,7 @@ class FranksRoastHouseTemplate {
|
||||
"fontColor" => "#ffffff",
|
||||
"fontFamily" => "Arial",
|
||||
"fontSize" => "14px",
|
||||
"fontWeight" => "normal",
|
||||
"textAlign" => "center"
|
||||
)
|
||||
)
|
||||
@ -238,7 +239,7 @@ class FranksRoastHouseTemplate {
|
||||
"link" => "http://example.org",
|
||||
"src" => $this->template_image_url . "/map-v2.jpg",
|
||||
"alt" => __("map-v2"),
|
||||
"padded" => true,
|
||||
"fullWidth" => false,
|
||||
"width" => "636px",
|
||||
"height" => "342px",
|
||||
"styles" => array(
|
||||
@ -279,19 +280,19 @@ class FranksRoastHouseTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => __("<p><span style=\"color: #000000;\"><a href=\"[unsubscribeUrl]\" style=\"color: #000000;\">Unsubscribe</a> | <a href=\"[manageSubscriptionUrl]\" style=\"color: #000000;\">Manage subscription</a></span><br /><span style=\"color: #000000;\">12345 MailPoet Drive, EmailVille, 76543</span></p>"),
|
||||
"text" => __("<p><a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br />12345 MailPoet Drive, EmailVille, 76543</p>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "#a9a7a7"
|
||||
),
|
||||
"text" => array(
|
||||
"fontColor" => "#ffffff",
|
||||
"fontColor" => "#000000",
|
||||
"fontFamily" => "Arial",
|
||||
"fontSize" => "12px",
|
||||
"textAlign" => "center"
|
||||
),
|
||||
"link" => array(
|
||||
"fontColor" => "#ffffff",
|
||||
"fontColor" => "#000000",
|
||||
"textDecoration" => "underline"
|
||||
)
|
||||
)
|
||||
|
@ -90,7 +90,7 @@ class PostNotificationsBlankTemplate {
|
||||
"link" => "http://example.org",
|
||||
"src" => $this->template_image_url . "/ALC-widget-icon.png",
|
||||
"alt" => __("ALC-widget-icon"),
|
||||
"padded" => true,
|
||||
"fullWidth" => false,
|
||||
"width" => "200px",
|
||||
"height" => "134px",
|
||||
"styles" => array(
|
||||
@ -242,7 +242,7 @@ class PostNotificationsBlankTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => __("<a href=\"[unsubscribeUrl]\">Unsubscribe</a> | <a href=\"[manageSubscriptionUrl]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"text" => __("<a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
@ -325,6 +325,7 @@ class PostNotificationsBlankTemplate {
|
||||
"fontColor" => "#ffffff",
|
||||
"fontFamily" => "Arial",
|
||||
"fontSize" => "18px",
|
||||
"fontWeight" => "normal",
|
||||
"textAlign" => "center"
|
||||
)
|
||||
)
|
||||
|
@ -46,7 +46,7 @@ class WelcomeTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "header",
|
||||
"text" => __("Display problems? <a href=\"[viewInBrowserUrl]\">View it in your browser</a>"),
|
||||
"text" => __("Display problems? <a href=\"[newsletter:view_in_browser_url]\">View it in your browser</a>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
@ -68,7 +68,7 @@ class WelcomeTemplate {
|
||||
"link" => "http://example.org",
|
||||
"src" => $this->template_image_url . "/logo-header.gif",
|
||||
"alt" => "logo-header",
|
||||
"padded" => true,
|
||||
"fullWidth" => false,
|
||||
"width" => "233px",
|
||||
"height" => "118px",
|
||||
"styles" => array(
|
||||
@ -224,7 +224,7 @@ class WelcomeTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => __("<a href=\"[unsubscribeUrl]\">Unsubscribe</a> | <a href=\"[manageSubscriptionUrl]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"text" => __("<a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
|
@ -59,7 +59,7 @@ class Renderer {
|
||||
}
|
||||
|
||||
function detectCache() {
|
||||
$cache_path = Env::$views_path . '/cache';
|
||||
$cache_path = Env::$temp_path . '/cache';
|
||||
if(WP_DEBUG === false) {
|
||||
return $cache_path;
|
||||
}
|
||||
|
@ -1,21 +1,82 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Util\Security;
|
||||
use \MailPoet\Models\Form;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Widget {
|
||||
function __construct() {
|
||||
private $renderer = null;
|
||||
|
||||
function __construct($renderer = null) {
|
||||
if($renderer !== null) {
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
add_action('widgets_init', array($this, 'registerWidget'));
|
||||
$this->registerWidget();
|
||||
|
||||
if(!is_admin()) {
|
||||
//$this->setupActions();
|
||||
add_action('widgets_init', array($this, 'setupDependencies'));
|
||||
$this->setupDependencies();
|
||||
$this->setupIframe();
|
||||
} else {
|
||||
add_action('widgets_init', array($this, 'setupAdminDependencies'));
|
||||
$this->setupAdminDependencies();
|
||||
}
|
||||
}
|
||||
|
||||
function setupIframe() {
|
||||
$form_id = (isset($_GET['mailpoet_form_iframe']) ? (int)$_GET['mailpoet_form_iframe'] : 0);
|
||||
if($form_id > 0) {
|
||||
$form = Form::findOne($form_id);
|
||||
|
||||
if($form !== false) {
|
||||
$form_widget = new \MailPoet\Form\Widget();
|
||||
$form_html = $form_widget->widget(array(
|
||||
'form' => $form_id,
|
||||
'form_type' => 'iframe'
|
||||
));
|
||||
|
||||
// capture javascripts
|
||||
ob_start();
|
||||
wp_print_scripts('jquery');
|
||||
wp_print_scripts('mailpoet_vendor');
|
||||
wp_print_scripts('mailpoet_public');
|
||||
$scripts = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
// language attributes
|
||||
$language_attributes = array();
|
||||
$is_rtl = (bool)(function_exists('is_rtl') && is_rtl());
|
||||
|
||||
if($is_rtl) {
|
||||
$language_attributes[] = 'dir="rtl"';
|
||||
}
|
||||
|
||||
if($lang = get_bloginfo('language')) {
|
||||
if(get_option('html_type') === 'text/html') {
|
||||
$language_attributes[] = "lang=\"$lang\"";
|
||||
}
|
||||
}
|
||||
|
||||
$language_attributes = apply_filters(
|
||||
'language_attributes', implode(' ', $language_attributes)
|
||||
);
|
||||
|
||||
$data = array(
|
||||
'language_attributes' => $language_attributes,
|
||||
'scripts' => $scripts,
|
||||
'form' => $form_html,
|
||||
'mailpoet_form' => array(
|
||||
'ajax_url' => admin_url('admin-ajax.php', 'absolute'),
|
||||
'is_rtl' => $is_rtl,
|
||||
'token' => Security::generateToken()
|
||||
)
|
||||
);
|
||||
|
||||
echo $this->renderer->render('form/iframe.html', $data);
|
||||
}
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +130,9 @@ class Widget {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: extract this method into an Initializer
|
||||
// - the "ajax" part might probably be useless
|
||||
// - the "post" (non-ajax) part needs to be redone properly
|
||||
function setupActions() {
|
||||
// ajax requests
|
||||
add_action(
|
||||
|
@ -7,8 +7,9 @@ use MailPoet\Util\Security;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class CronHelper {
|
||||
static $daemon_execution_limit = 30;
|
||||
static $daemon_timeout_limit = 30;
|
||||
const daemon_execution_limit = 20;
|
||||
const daemon_execution_timeout = 35;
|
||||
const daemon_request_timeout = 2;
|
||||
|
||||
static function createDaemon($token) {
|
||||
$daemon = array(
|
||||
@ -36,12 +37,12 @@ class CronHelper {
|
||||
return Security::generateRandomString();
|
||||
}
|
||||
|
||||
static function accessDaemon($token) {
|
||||
static function accessDaemon($token, $timeout = self::daemon_request_timeout) {
|
||||
$payload = serialize(array('token' => $token));
|
||||
$url = '/?mailpoet-api§ion=queue&action=run&request_payload=' .
|
||||
base64_encode($payload);
|
||||
$args = array(
|
||||
'timeout' => 1,
|
||||
'timeout' => $timeout,
|
||||
'user-agent' => 'MailPoet (www.mailpoet.com) Cron'
|
||||
);
|
||||
$result = wp_remote_get(
|
||||
@ -67,4 +68,11 @@ class CronHelper {
|
||||
// throw an error if all connection attempts failed
|
||||
throw new \Exception(__('Site URL is unreachable.'));
|
||||
}
|
||||
|
||||
static function checkExecutionTimer($timer) {
|
||||
$elapsed_time = microtime(true) - $timer;
|
||||
if($elapsed_time >= self::daemon_execution_limit) {
|
||||
throw new \Exception(__('Maximum execution time reached.'));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use MailPoet\Cron\Workers\Scheduler;
|
||||
use MailPoet\Cron\Workers\SendingQueue;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
@ -11,6 +12,7 @@ class Daemon {
|
||||
public $daemon;
|
||||
public $request_payload;
|
||||
public $refreshed_token;
|
||||
const daemon_request_timeout = 5;
|
||||
private $timer;
|
||||
|
||||
function __construct($request_payload = array()) {
|
||||
@ -34,13 +36,15 @@ class Daemon {
|
||||
}
|
||||
$this->abortIfStopped($daemon);
|
||||
try {
|
||||
$sending_queue = new SendingQueue($this->timer);
|
||||
$sending_queue->process();
|
||||
} catch(Exception $e) {
|
||||
$scheduler = new Scheduler();
|
||||
$scheduler->process($this->timer);
|
||||
$queue = new SendingQueue();
|
||||
$queue->process($this->timer);
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
$elapsed_time = microtime(true) - $this->timer;
|
||||
if($elapsed_time < CronHelper::$daemon_execution_limit) {
|
||||
sleep(CronHelper::$daemon_execution_limit - $elapsed_time);
|
||||
if($elapsed_time < CronHelper::daemon_execution_limit) {
|
||||
sleep(CronHelper::daemon_execution_limit - $elapsed_time);
|
||||
}
|
||||
// after each execution, re-read daemon data in case it was deleted or
|
||||
// its status has changed
|
||||
@ -72,7 +76,7 @@ class Daemon {
|
||||
}
|
||||
|
||||
function callSelf() {
|
||||
CronHelper::accessDaemon($this->token);
|
||||
CronHelper::accessDaemon($this->token, self::daemon_request_timeout);
|
||||
exit;
|
||||
}
|
||||
}
|
@ -31,13 +31,13 @@ class Supervisor {
|
||||
$elapsed_time = time() - (int) $daemon['updated_at'];
|
||||
// if it's been less than 40 seconds since last execution and we're not
|
||||
// force-running the daemon, return its status and do nothing
|
||||
if($elapsed_time < CronHelper::$daemon_timeout_limit && !$this->force_run) {
|
||||
if($elapsed_time < CronHelper::daemon_execution_timeout && !$this->force_run) {
|
||||
return $this->formatDaemonStatusMessage($daemon['status']);
|
||||
}
|
||||
// if it's been less than 40 seconds since last execution, we are
|
||||
// force-running the daemon and it's either being started or stopped,
|
||||
// return its status and do nothing
|
||||
elseif($elapsed_time < CronHelper::$daemon_timeout_limit &&
|
||||
elseif($elapsed_time < CronHelper::daemon_execution_timeout &&
|
||||
$this->force_run &&
|
||||
in_array($daemon['status'], array(
|
||||
'stopping',
|
||||
@ -62,7 +62,7 @@ class Supervisor {
|
||||
list(, $message) = explode(':', $status[0]);
|
||||
$message = base64_decode($message);
|
||||
}
|
||||
return $this->formatResult(
|
||||
return $this->formatResultMessage(
|
||||
false,
|
||||
$message
|
||||
);
|
||||
|
139
lib/Cron/Workers/Scheduler.php
Normal file
139
lib/Cron/Workers/Scheduler.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron\Workers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Cron\CronExpression as Cron;
|
||||
use MailPoet\Cron\CronHelper;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Scheduler {
|
||||
public $timer;
|
||||
|
||||
function __construct($timer = false) {
|
||||
$this->timer = ($timer) ? $timer : microtime(true);
|
||||
CronHelper::checkExecutionTimer($this->timer);
|
||||
}
|
||||
|
||||
function process() {
|
||||
$scheduled_queues = SendingQueue::where('status', 'scheduled')
|
||||
->whereLte('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
|
||||
->findMany();
|
||||
if(!count($scheduled_queues)) return;
|
||||
foreach($scheduled_queues as $queue) {
|
||||
$newsletter = Newsletter::filter('filterWithOptions')
|
||||
->findOne($queue->newsletter_id);
|
||||
if(!$newsletter || $newsletter->deleted_at !== null) {
|
||||
$queue->delete();
|
||||
}
|
||||
else if($newsletter->type === 'welcome') {
|
||||
$this->processWelcomeNewsletter($newsletter, $queue);
|
||||
}
|
||||
else if($newsletter->type === 'notification') {
|
||||
$this->processPostNotificationNewsletter($newsletter, $queue);
|
||||
}
|
||||
CronHelper::checkExecutionTimer($this->timer);
|
||||
}
|
||||
}
|
||||
|
||||
function processWelcomeNewsletter($newsletter, $queue) {
|
||||
$subscriber = unserialize($queue->subscribers);
|
||||
$subscriber_id = $subscriber['to_process'][0];
|
||||
$result = false;
|
||||
if($newsletter->event === 'segment') {
|
||||
$result = $this->verifyMailPoetSubscriber($subscriber_id, $newsletter);
|
||||
}
|
||||
else if($newsletter->event === 'user') {
|
||||
$result = $this->verifyWPSubscriber($subscriber_id, $newsletter);
|
||||
}
|
||||
if(!$result) {
|
||||
$queue->delete();
|
||||
return;
|
||||
}
|
||||
$queue->status = null;
|
||||
$queue->save();
|
||||
}
|
||||
|
||||
function processPostNotificationNewsletter($newsletter, $queue) {
|
||||
$next_run_date = $this->getQueueNextRunDate($newsletter->schedule);
|
||||
$segments = unserialize($newsletter->segments);
|
||||
$subscribers = SubscriberSegment::whereIn('segment_id', $segments)
|
||||
->findArray();
|
||||
$subscribers = Helpers::arrayColumn($subscribers, 'subscriber_id');
|
||||
$subscribers = array_unique($subscribers);
|
||||
if(!count($subscribers)) {
|
||||
$queue->delete();
|
||||
return;
|
||||
}
|
||||
if(!$this->checkIfNewsletterChanged($newsletter)) {
|
||||
$queue->scheduled_at = $next_run_date;
|
||||
$queue->save();
|
||||
return;
|
||||
}
|
||||
// update current queue
|
||||
$queue->subscribers = serialize(
|
||||
array(
|
||||
'to_process' => $subscribers
|
||||
)
|
||||
);
|
||||
$queue->count_total = $queue->count_to_process = count($subscribers);
|
||||
$queue->status = null;
|
||||
$queue->save();
|
||||
// schedule newsletter for next delivery
|
||||
$new_queue = SendingQueue::create();
|
||||
$new_queue->newsletter_id = $newsletter->id;
|
||||
$new_queue->scheduled_at = $next_run_date;
|
||||
$new_queue->status = 'scheduled';
|
||||
$new_queue->save();
|
||||
}
|
||||
|
||||
private function verifyMailPoetSubscriber($subscriber_id, $newsletter) {
|
||||
// check if subscriber is in proper segment
|
||||
$subscriber_in_segment =
|
||||
SubscriberSegment::where('subscriber_id', $subscriber_id)
|
||||
->where('segment_id', $newsletter->segment)
|
||||
->where('status', 'subscribed')
|
||||
->findOne();
|
||||
return ($subscriber_in_segment) ? true : false;
|
||||
}
|
||||
|
||||
private function verifyWPSubscriber($subscriber_id, $newsletter) {
|
||||
// check if user has the proper role
|
||||
$subscriber = Subscriber::findOne($subscriber_id);
|
||||
if(!$subscriber || $subscriber->wp_user_id === null) {
|
||||
return false;
|
||||
}
|
||||
$wp_user = (array) get_userdata($subscriber->wp_user_id);
|
||||
if(!in_array($newsletter->role, $wp_user['roles'])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkIfNewsletterChanged($newsletter) {
|
||||
$last_run_queue = SendingQueue::where('status', 'completed')
|
||||
->where('newsletter_id', $newsletter->id)
|
||||
->orderByDesc('id')
|
||||
->findOne();
|
||||
if(!$last_run_queue) return true;
|
||||
$renderer = new Renderer($newsletter->asArray());
|
||||
$rendered_newsletter = $renderer->render();
|
||||
$new_hash = md5($rendered_newsletter['html']);
|
||||
$old_hash = $last_run_queue->newsletter_rendered_body_hash;
|
||||
return $new_hash !== $old_hash;
|
||||
}
|
||||
|
||||
private function getQueueNextRunDate($schedule) {
|
||||
$schedule = Cron::factory($schedule);
|
||||
return $schedule->getNextRunDate(current_time('mysql'))
|
||||
->format('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
@ -5,125 +5,209 @@ use MailPoet\Cron\CronHelper;
|
||||
use MailPoet\Mailer\Mailer;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterStatistics;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SendingQueue {
|
||||
public $mta_config;
|
||||
public $mta_log;
|
||||
public $processing_method;
|
||||
private $timer;
|
||||
const batch_size = 50;
|
||||
|
||||
function __construct($timer = false) {
|
||||
$this->mta_config = $this->getMailerConfig();
|
||||
$this->mta_log = $this->getMailerLog();
|
||||
$this->processing_method = ($this->mta_config['method'] === 'MailPoet') ?
|
||||
'processBulkSubscribers' :
|
||||
'processIndividualSubscriber';
|
||||
$this->timer = ($timer) ? $timer : microtime(true);
|
||||
CronHelper::checkExecutionTimer($this->timer);
|
||||
}
|
||||
|
||||
function process() {
|
||||
// TODO: implement mailer sending frequency limits
|
||||
foreach($this->getQueues() as $queue) {
|
||||
$newsletter = Newsletter::findOne($queue->newsletter_id)
|
||||
->asArray();
|
||||
$newsletter = Newsletter::findOne($queue->newsletter_id);
|
||||
if(!$newsletter) {
|
||||
$queue->delete();
|
||||
continue;
|
||||
};
|
||||
$mailer = $this->configureMailerForNewsletter($newsletter);
|
||||
$subscribers = json_decode($queue->subscribers, true);
|
||||
$subscribers_to_process = $subscribers['to_process'];
|
||||
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
|
||||
if(!isset($subscribers['failed'])) $subscribers['failed'] = array();
|
||||
foreach(array_chunk($subscribers_to_process, 200) as $subscriber_ids) {
|
||||
$db_subscribers = Subscriber::whereIn('id', $subscriber_ids)
|
||||
}
|
||||
$newsletter = $newsletter->asArray();
|
||||
$newsletter['body'] = $this->getNewsletterBodyAndSubject($queue, $newsletter);
|
||||
$queue->subscribers = (object) unserialize($queue->subscribers);
|
||||
if(!isset($queue->subscribers->processed)) {
|
||||
$queue->subscribers->processed = array();
|
||||
}
|
||||
if(!isset($queue->subscribers->failed)) {
|
||||
$queue->subscribers->failed = array();
|
||||
}
|
||||
$mailer = $this->configureMailer($newsletter);
|
||||
foreach(array_chunk($queue->subscribers->to_process, self::batch_size) as
|
||||
$subscribers_ids) {
|
||||
$subscribers = Subscriber::whereIn('id', $subscribers_ids)
|
||||
->findArray();
|
||||
foreach($db_subscribers as $db_subscriber) {
|
||||
$this->checkExecutionTimer();
|
||||
$result = $this->sendNewsletter(
|
||||
$queue->subscribers = call_user_func_array(
|
||||
array(
|
||||
$this,
|
||||
$this->processing_method
|
||||
),
|
||||
array(
|
||||
$mailer,
|
||||
$this->processNewsletter($newsletter, $db_subscriber),
|
||||
$db_subscriber);
|
||||
if($result) {
|
||||
$this->updateStatistics($newsletter['id'], $db_subscriber['id'], $queue->id);
|
||||
$subscribers['processed'][] = $db_subscriber['id'];
|
||||
} else {
|
||||
$subscribers['failed'][] = $db_subscriber['id'];
|
||||
}
|
||||
$this->updateQueue($queue, $subscribers);
|
||||
}
|
||||
$newsletter,
|
||||
$subscribers,
|
||||
$queue
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processNewsletter($newsletter, $subscriber) {
|
||||
$rendered_newsletter = $this->renderNewsletter($newsletter);
|
||||
$shortcodes = new Shortcodes($rendered_newsletter['body']['html'], $newsletter, $subscriber);
|
||||
$processed_newsletter['body']['html'] = $shortcodes->replace();
|
||||
$shortcodes = new Shortcodes($rendered_newsletter['body']['text'], $newsletter, $subscriber);
|
||||
$processed_newsletter['body']['text'] = $shortcodes->replace();
|
||||
$processed_newsletter['subject'] = $rendered_newsletter['subject'];
|
||||
return $processed_newsletter;
|
||||
function getNewsletterBodyAndSubject($queue, $newsletter) {
|
||||
// check if newsletter has been rendered, in which case return its contents
|
||||
// or render & and for future use
|
||||
if($queue->newsletter_rendered_body === null) {
|
||||
$newsletter['body'] = $this->renderNewsletter($newsletter);
|
||||
$queue->newsletter_rendered_body = json_encode($newsletter['body']);
|
||||
$queue->newsletter_rendered_body_hash = md5($newsletter['body']['text']);
|
||||
$queue->save();
|
||||
} else {
|
||||
$newsletter['body'] = json_decode($queue->newsletter_rendered_body);
|
||||
}
|
||||
return (array) $newsletter['body'];
|
||||
}
|
||||
|
||||
function processBulkSubscribers($mailer, $newsletter, $subscribers, $queue) {
|
||||
foreach($subscribers as $subscriber) {
|
||||
$processed_newsletters[] =
|
||||
$this->processNewsletter($newsletter, $subscriber);
|
||||
$transformed_subscribers[] =
|
||||
$mailer->transformSubscriber($subscriber);
|
||||
}
|
||||
$result = $this->sendNewsletter(
|
||||
$mailer,
|
||||
$processed_newsletters,
|
||||
$transformed_subscribers
|
||||
);
|
||||
$subscribers_ids = Helpers::arrayColumn($subscribers, 'id');
|
||||
if(!$result) {
|
||||
$queue->subscribers->failed = array_merge(
|
||||
$queue->subscribers->failed,
|
||||
$subscribers_ids
|
||||
);
|
||||
} else {
|
||||
$newsletter_statistics =
|
||||
array_map(function($data) use ($newsletter, $subscribers_ids, $queue) {
|
||||
return array(
|
||||
$newsletter['id'],
|
||||
$subscribers_ids[$data],
|
||||
$queue->id
|
||||
);
|
||||
}, range(0, count($transformed_subscribers) - 1));
|
||||
$newsletter_statistics = Helpers::flattenArray($newsletter_statistics);
|
||||
$this->updateMailerLog();
|
||||
$this->updateNewsletterStatistics($newsletter_statistics);
|
||||
$queue->subscribers->processed = array_merge(
|
||||
$queue->subscribers->processed,
|
||||
$subscribers_ids
|
||||
);
|
||||
}
|
||||
$this->updateQueue($queue);
|
||||
$this->checkSendingLimit();
|
||||
CronHelper::checkExecutionTimer($this->timer);
|
||||
return $queue->subscribers;
|
||||
}
|
||||
|
||||
function processIndividualSubscriber($mailer, $newsletter, $subscribers, $queue) {
|
||||
foreach($subscribers as $subscriber) {
|
||||
$this->checkSendingLimit();
|
||||
$processed_newsletter = $this->processNewsletter($newsletter, $subscriber);
|
||||
if (!$queue->newsletter_rendered_subject) {
|
||||
$queue->newsletter_rendered_subject = $processed_newsletter['subject'];
|
||||
}
|
||||
$transformed_subscriber = $mailer->transformSubscriber($subscriber);
|
||||
$result = $this->sendNewsletter(
|
||||
$mailer,
|
||||
$processed_newsletter,
|
||||
$transformed_subscriber
|
||||
);
|
||||
if(!$result) {
|
||||
$queue->subscribers->failed[] = $subscriber['id'];
|
||||
} else {
|
||||
$queue->subscribers->processed[] = $subscriber['id'];
|
||||
$newsletter_statistics = array(
|
||||
$newsletter['id'],
|
||||
$subscriber['id'],
|
||||
$queue->id
|
||||
);
|
||||
$this->updateMailerLog();
|
||||
$this->updateNewsletterStatistics($newsletter_statistics);
|
||||
}
|
||||
$this->updateQueue($queue);
|
||||
CronHelper::checkExecutionTimer($this->timer);
|
||||
}
|
||||
return $queue->subscribers;
|
||||
}
|
||||
|
||||
function updateNewsletterStatistics($data) {
|
||||
return NewsletterStatistics::createMultiple($data);
|
||||
}
|
||||
|
||||
function renderNewsletter($newsletter) {
|
||||
$renderer = new Renderer($newsletter);
|
||||
return $renderer->render();
|
||||
}
|
||||
|
||||
function processNewsletter($newsletter, $subscriber = false) {
|
||||
$divider = '***MailPoet***';
|
||||
$data_for_shortcodes =
|
||||
array_merge(array($newsletter['subject']), $newsletter['body']);
|
||||
$body = implode($divider, $data_for_shortcodes);
|
||||
$shortcodes = new Shortcodes(
|
||||
$newsletter,
|
||||
$subscriber
|
||||
);
|
||||
list($newsletter['subject'],
|
||||
$newsletter['body']['html'],
|
||||
$newsletter['body']['text']
|
||||
) = explode($divider, $shortcodes->replace($body));
|
||||
return $newsletter;
|
||||
}
|
||||
|
||||
function sendNewsletter($mailer, $newsletter, $subscriber) {
|
||||
return $mailer->mailer_instance->send(
|
||||
$newsletter,
|
||||
$mailer->transformSubscriber($subscriber)
|
||||
$subscriber
|
||||
);
|
||||
}
|
||||
|
||||
function updateStatistics($newsletter_id, $subscriber_id, $queue_id) {
|
||||
$newsletter_statistic = NewsletterStatistics::create();
|
||||
$newsletter_statistic->subscriber_id = $newsletter_id;
|
||||
$newsletter_statistic->newsletter_id = $subscriber_id;
|
||||
$newsletter_statistic->queue_id = $queue_id;
|
||||
$newsletter_statistic->save();
|
||||
}
|
||||
|
||||
function updateQueue($queue, $subscribers) {
|
||||
$subscribers['to_process'] = array_values(
|
||||
array_diff(
|
||||
$subscribers['to_process'],
|
||||
array_merge($subscribers['processed'], $subscribers['failed'])
|
||||
)
|
||||
);
|
||||
$queue->count_processed =
|
||||
count($subscribers['processed']) + count($subscribers['failed']);
|
||||
$queue->count_to_process = count($subscribers['to_process']);
|
||||
$queue->count_failed = count($subscribers['failed']);
|
||||
$queue->count_total =
|
||||
$queue->count_processed + $queue->count_to_process;
|
||||
if(!$queue->count_to_process) {
|
||||
$queue->processed_at = date('Y-m-d H:i:s');
|
||||
$queue->status = 'completed';
|
||||
}
|
||||
$queue->subscribers = json_encode($subscribers);
|
||||
$queue->save();
|
||||
}
|
||||
|
||||
function configureMailerForNewsletter($newsletter) {
|
||||
if(!empty($newsletter['sender_address']) && !empty($newsletter['sender_name'])) {
|
||||
$sender = array(
|
||||
'name' => $newsletter['sender_name'],
|
||||
'address' => $newsletter['sender_address']
|
||||
);
|
||||
} else {
|
||||
function configureMailer($newsletter) {
|
||||
$sender['address'] = (!empty($newsletter['sender_address'])) ?
|
||||
$newsletter['sender_address'] :
|
||||
false;
|
||||
$sender['name'] = (!empty($newsletter['sender_name'])) ?
|
||||
$newsletter['sender_name'] :
|
||||
false;
|
||||
$reply_to['address'] = (!empty($newsletter['reply_to_address'])) ?
|
||||
$newsletter['reply_to_address'] :
|
||||
false;
|
||||
$reply_to['name'] = (!empty($newsletter['reply_to_name'])) ?
|
||||
$newsletter['reply_to_name'] :
|
||||
false;
|
||||
if(!$sender['address']) {
|
||||
$sender = false;
|
||||
}
|
||||
if(!empty($newsletter['reply_to_address']) && !empty($newsletter['reply_to_name'])) {
|
||||
$reply_to = array(
|
||||
'name' => $newsletter['reply_to_name'],
|
||||
'address' => $newsletter['reply_to_address']
|
||||
);
|
||||
} else {
|
||||
if(!$reply_to['address']) {
|
||||
$reply_to = false;
|
||||
}
|
||||
$mailer = new Mailer($method = false, $sender, $reply_to);
|
||||
return $mailer;
|
||||
}
|
||||
|
||||
function checkExecutionTimer() {
|
||||
$elapsed_time = microtime(true) - $this->timer;
|
||||
if($elapsed_time >= CronHelper::$daemon_execution_limit) throw new \Exception(__('Maximum execution time reached.'));
|
||||
}
|
||||
|
||||
function getQueues() {
|
||||
return \MailPoet\Models\SendingQueue::orderByDesc('priority')
|
||||
->whereNull('deleted_at')
|
||||
@ -131,9 +215,73 @@ class SendingQueue {
|
||||
->findResultSet();
|
||||
}
|
||||
|
||||
function renderNewsletter($newsletter) {
|
||||
$renderer = new Renderer($newsletter);
|
||||
$newsletter['body'] = $renderer->render();
|
||||
return $newsletter;
|
||||
function updateQueue($queue) {
|
||||
$queue = clone($queue);
|
||||
$queue->subscribers->to_process = array_diff(
|
||||
$queue->subscribers->to_process,
|
||||
array_merge(
|
||||
$queue->subscribers->processed,
|
||||
$queue->subscribers->failed
|
||||
)
|
||||
);
|
||||
$queue->subscribers->to_process = array_values(
|
||||
$queue->subscribers->to_process
|
||||
);
|
||||
$queue->count_processed =
|
||||
count($queue->subscribers->processed) + count($queue->subscribers->failed);
|
||||
$queue->count_to_process = count($queue->subscribers->to_process);
|
||||
$queue->count_failed = count($queue->subscribers->failed);
|
||||
$queue->count_total =
|
||||
$queue->count_processed + $queue->count_to_process;
|
||||
if(!$queue->count_to_process) {
|
||||
$queue->processed_at = date('Y-m-d H:i:s');
|
||||
$queue->status = 'completed';
|
||||
}
|
||||
$queue->subscribers = serialize((array) $queue->subscribers);
|
||||
$queue->save();
|
||||
}
|
||||
|
||||
function updateMailerLog() {
|
||||
$this->mta_log['sent']++;
|
||||
return Setting::setValue('mta_log', $this->mta_log);
|
||||
}
|
||||
|
||||
function getMailerConfig() {
|
||||
$mta_config = Setting::getValue('mta');
|
||||
if(!$mta_config) {
|
||||
throw new \Exception(__('Mailer is not configured.'));
|
||||
}
|
||||
return $mta_config;
|
||||
}
|
||||
|
||||
function getMailerLog() {
|
||||
$mta_log = Setting::getValue('mta_log');
|
||||
if(!$mta_log) {
|
||||
$mta_log = array(
|
||||
'sent' => 0,
|
||||
'started' => time()
|
||||
);
|
||||
Setting::setValue('mta_log', $mta_log);
|
||||
}
|
||||
return $mta_log;
|
||||
}
|
||||
|
||||
function checkSendingLimit() {
|
||||
$frequency_interval = (int) $this->mta_config['frequency']['interval'] * 60;
|
||||
$frequency_limit = (int) $this->mta_config['frequency']['emails'];
|
||||
$elapsed_time = time() - (int) $this->mta_log['started'];
|
||||
if($this->mta_log['sent'] === $frequency_limit &&
|
||||
$elapsed_time <= $frequency_interval
|
||||
) {
|
||||
throw new \Exception(__('Sending frequency limit reached.'));
|
||||
}
|
||||
if($elapsed_time > $frequency_interval) {
|
||||
$this->mta_log = array(
|
||||
'sent' => 0,
|
||||
'started' => time()
|
||||
);
|
||||
Setting::setValue('mta_log', $this->mta_log);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
@ -112,4 +112,17 @@ abstract class Base {
|
||||
&& strlen(trim($block['params']['value'])) > 0)
|
||||
? esc_attr(trim($block['params']['value'])) : '';
|
||||
}
|
||||
|
||||
protected static function getInputModifiers($block = array()) {
|
||||
$modifiers = array();
|
||||
|
||||
if(isset($block['params']['readonly'])) {
|
||||
$modifiers[] = 'readonly';
|
||||
}
|
||||
|
||||
if(isset($block['params']['disabled'])) {
|
||||
$modifiers[] = 'disabled';
|
||||
}
|
||||
return join(' ', $modifiers);
|
||||
}
|
||||
}
|
@ -20,18 +20,22 @@ class Checkbox extends Base {
|
||||
|
||||
foreach($options as $option) {
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
|
||||
$html .= '<input type="hidden" name="'.$field_name.'" value="" />';
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
|
||||
$html .= 'name="'.$field_name.'" ';
|
||||
|
||||
$html .= 'value="1" ';
|
||||
|
||||
$html .= (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'checked="checked"' : '';
|
||||
$html .= (
|
||||
(isset($option['is_checked']) && $option['is_checked'])
|
||||
||
|
||||
(self::getFieldValue($block))
|
||||
) ? 'checked="checked"' : '';
|
||||
|
||||
$html .= $field_validation;
|
||||
|
||||
$html .= ' />'.$option['value'];
|
||||
$html .= ' /> '.esc_attr($option['value']);
|
||||
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
@ -33,18 +33,37 @@ class Date extends Base {
|
||||
// generate an array of selectors based on date format
|
||||
$date_selectors = explode('/', $date_format);
|
||||
|
||||
// format value if present
|
||||
$value = self::getFieldValue($block);
|
||||
$day = null;
|
||||
$month = null;
|
||||
$year = null;
|
||||
|
||||
if($value) {
|
||||
$day = (int)strftime('%d', $value);
|
||||
$month = (int)strftime('%m', $value);
|
||||
$year = (int)strftime('%Y', $value);
|
||||
} else if(!empty($block['params']['is_default_today'])) {
|
||||
$day = (int)strftime('%d');
|
||||
$month = (int)strftime('%m');
|
||||
$year = (int)strftime('%Y');
|
||||
}
|
||||
|
||||
foreach($date_selectors as $date_selector) {
|
||||
if($date_selector === 'dd') {
|
||||
$block['selected'] = $day;
|
||||
$html .= '<select class="mailpoet_date_day" ';
|
||||
$html .= 'name="'.$field_name.'[day]" placeholder="'.__('Day').'">';
|
||||
$html .= static::getDays($block);
|
||||
$html .= '</select>';
|
||||
} else if($date_selector === 'mm') {
|
||||
$block['selected'] = $month;
|
||||
$html .= '<select class="mailpoet_date_month" ';
|
||||
$html .= 'name="'.$field_name.'[month]" placeholder="'.__('Month').'">';
|
||||
$html .= static::getMonths($block);
|
||||
$html .= '</select>';
|
||||
} else if($date_selector === 'yyyy') {
|
||||
$block['selected'] = $year;
|
||||
$html .= '<select class="mailpoet_date_year" ';
|
||||
$html .= 'name="'.$field_name.'[year]" placeholder="'.__('Year').'">';
|
||||
$html .= static::getYears($block);
|
||||
@ -84,11 +103,6 @@ class Date extends Base {
|
||||
'selected' => null
|
||||
);
|
||||
|
||||
// is default today
|
||||
if(!empty($block['params']['is_default_today'])) {
|
||||
$defaults['selected'] = (int)strftime('%m');
|
||||
}
|
||||
|
||||
// merge block with defaults
|
||||
$block = array_merge($defaults, $block);
|
||||
|
||||
|
@ -25,14 +25,24 @@ class Radio extends Base {
|
||||
|
||||
$html .= 'name="'.$field_name.'" ';
|
||||
|
||||
$html .= 'value="'.esc_attr($option['value']).'" ';
|
||||
if(is_array($option['value'])) {
|
||||
$value = key($option['value']);
|
||||
$label = reset($option['value']);
|
||||
} else {
|
||||
$value = $option['value'];
|
||||
$label = $option['value'];
|
||||
}
|
||||
|
||||
$html .= 'value="'.esc_attr($value).'" ';
|
||||
|
||||
$html .= (
|
||||
(isset($option['is_checked']) && $option['is_checked'])
|
||||
||
|
||||
(self::getFieldValue($block) === $value)
|
||||
) ? 'checked="checked"' : '';
|
||||
|
||||
$html .= (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'checked="checked"' : '';
|
||||
$html .= $field_validation;
|
||||
|
||||
$html .= ' /> '.esc_attr($option['value']);
|
||||
|
||||
$html .= ' /> '.esc_attr($label);
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ class Segment extends Base {
|
||||
$html .= 'name="'.$field_name.'[]" ';
|
||||
$html .= 'value="'.$option['id'].'" '.$is_checked.' ';
|
||||
$html .= $field_validation;
|
||||
$html .= ' />'.$option['name'];
|
||||
$html .= ' /> '.esc_attr($option['name']);
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,7 @@ class Select extends Base {
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
$html .= '<select class="mailpoet_select" name="'.$field_name.'">';
|
||||
|
||||
if(isset($block['params']['label_within'])
|
||||
@ -20,11 +18,28 @@ class Select extends Base {
|
||||
$html .= '<option value="">'.static::getFieldLabel($block).'</option>';
|
||||
}
|
||||
|
||||
foreach($block['params']['values'] as $option) {
|
||||
$is_selected = (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'selected="selected"' : '';
|
||||
$html .= '<option value="'.$option['value'].'" '.$is_selected.'>';
|
||||
$html .= $option['value'];
|
||||
$options = (!empty($block['params']['values'])
|
||||
? $block['params']['values']
|
||||
: array()
|
||||
);
|
||||
|
||||
foreach($options as $option) {
|
||||
$is_selected = (
|
||||
(isset($option['is_checked']) && $option['is_checked'])
|
||||
||
|
||||
(self::getFieldValue($block) === $option['value'])
|
||||
) ? 'selected="selected"' : '';
|
||||
|
||||
if(is_array($option['value'])) {
|
||||
$value = key($option['value']);
|
||||
$label = reset($option['value']);
|
||||
} else {
|
||||
$value = $option['value'];
|
||||
$label = $option['value'];
|
||||
}
|
||||
|
||||
$html .= '<option value="'.$value.'" '.$is_selected.'>';
|
||||
$html .= esc_attr($label);
|
||||
$html .= '</option>';
|
||||
}
|
||||
$html .= '</select>';
|
||||
|
@ -6,7 +6,7 @@ class Text extends Base {
|
||||
static function render($block) {
|
||||
$type = 'text';
|
||||
if($block['id'] === 'email') {
|
||||
$type = 'email';
|
||||
$type = 'email';
|
||||
}
|
||||
|
||||
$html = '';
|
||||
@ -27,6 +27,8 @@ class Text extends Base {
|
||||
|
||||
$html .= static::getInputValidation($block);
|
||||
|
||||
$html .= static::getInputModifiers($block);
|
||||
|
||||
$html .= '/>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
@ -19,6 +19,8 @@ class Textarea extends Base {
|
||||
|
||||
$html .= static::getInputValidation($block);
|
||||
|
||||
$html .= static::getInputModifiers($block);
|
||||
|
||||
$html .= '></textarea>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
@ -13,9 +13,11 @@ class Renderer {
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function renderStyles($form = array()) {
|
||||
static function renderStyles($form = array(), $prefix = null) {
|
||||
$styles = new Util\Styles(static::getStyles($form));
|
||||
|
||||
$html = '<style type="text/css">';
|
||||
$html .= static::getStyles($form);
|
||||
$html .= $styles->render($prefix);
|
||||
$html .= '</style>';
|
||||
|
||||
return $html;
|
||||
@ -37,8 +39,7 @@ class Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
// private: rendering methods
|
||||
private static function renderBlocks($blocks = array()) {
|
||||
static function renderBlocks($blocks = array()) {
|
||||
$html = '';
|
||||
foreach ($blocks as $key => $block) {
|
||||
$html .= static::renderBlock($block)."\n";
|
||||
@ -47,7 +48,7 @@ class Renderer {
|
||||
return $html;
|
||||
}
|
||||
|
||||
private static function renderBlock($block = array()) {
|
||||
static function renderBlock($block = array()) {
|
||||
$html = '';
|
||||
switch($block['type']) {
|
||||
case 'html':
|
||||
|
@ -17,24 +17,25 @@ class Export {
|
||||
case 'iframe':
|
||||
// generate url to load iframe's content
|
||||
$iframe_url = add_query_arg(array(
|
||||
'mailpoet_page' => 'mailpoet_form_iframe',
|
||||
'mailpoet_form' => $form['id']
|
||||
'mailpoet_form_iframe' => $form['id']
|
||||
), site_url());
|
||||
|
||||
// generate iframe
|
||||
return '<iframe '.
|
||||
'width="100%" '.
|
||||
'scrolling="no" '.
|
||||
'frameborder="0" '.
|
||||
'src="'.$iframe_url.'" '.
|
||||
'class="mailpoet_form_iframe" '.
|
||||
'vspace="0" '.
|
||||
'tabindex="0" '.
|
||||
'onload="javascript:(this.style.height = this.contentWindow.document.body.scrollHeight + \'px\');"'.
|
||||
'marginwidth="0" '.
|
||||
'marginheight="0" '.
|
||||
'hspace="0" '.
|
||||
'allowtransparency="true"></iframe>';
|
||||
return join(' ', array(
|
||||
'<iframe',
|
||||
'width="100%"',
|
||||
'scrolling="no"',
|
||||
'frameborder="0"',
|
||||
'src="'.$iframe_url.'"',
|
||||
'class="mailpoet_form_iframe"',
|
||||
'vspace="0"',
|
||||
'tabindex="0"',
|
||||
'onload="MailPoet.Iframe.autoSize(this);"',
|
||||
'marginwidth="0"',
|
||||
'marginheight="0"',
|
||||
'hspace="0"',
|
||||
'allowtransparency="true"></iframe>'
|
||||
));
|
||||
break;
|
||||
|
||||
case 'php':
|
||||
|
@ -17,7 +17,7 @@ class Styles {
|
||||
}
|
||||
|
||||
/* labels */
|
||||
.mailpoet_input_label,
|
||||
.mailpoet_text_label,
|
||||
.mailpoet_textarea_label,
|
||||
.mailpoet_select_label,
|
||||
.mailpoet_radio_label,
|
||||
@ -28,7 +28,7 @@ class Styles {
|
||||
}
|
||||
|
||||
/* inputs */
|
||||
.mailpoet_input,
|
||||
.mailpoet_text,
|
||||
.mailpoet_textarea,
|
||||
.mailpoet_select,
|
||||
.mailpoet_date {
|
||||
@ -36,9 +36,7 @@ class Styles {
|
||||
}
|
||||
|
||||
.mailpoet_checkbox {
|
||||
display:inline;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
|
||||
}
|
||||
|
||||
.mailpoet_validate_success {
|
||||
@ -101,7 +99,7 @@ EOL;
|
||||
}
|
||||
|
||||
private function stripComments($stylesheet) {
|
||||
// remove comments
|
||||
// remove comments
|
||||
return preg_replace('!/\*.*?\*/!s', '', $stylesheet);
|
||||
}
|
||||
|
||||
@ -111,7 +109,6 @@ EOL;
|
||||
|
||||
private function setStyles($styles) {
|
||||
$this->_styles = $styles;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,8 @@ class Widget extends \WP_Widget {
|
||||
)
|
||||
);
|
||||
|
||||
$form_edit_url = admin_url('admin.php?page=mailpoet-form-editor&id=');
|
||||
|
||||
// set title
|
||||
$title = isset($instance['title']) ? strip_tags($instance['title']) : '';
|
||||
|
||||
@ -102,8 +104,9 @@ class Widget extends \WP_Widget {
|
||||
endpoint: 'forms',
|
||||
action: 'create'
|
||||
}).done(function(response) {
|
||||
if(response !== false) {
|
||||
window.location = response;
|
||||
if(response.result && response.form_id) {
|
||||
window.location =
|
||||
"<?php echo $form_edit_url; ?>" + response.form_id;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
@ -151,12 +154,14 @@ class Widget extends \WP_Widget {
|
||||
$output = '';
|
||||
|
||||
if(!empty($body)) {
|
||||
$form_id = $this->id_base.'_'.$form['id'];
|
||||
|
||||
$data = array(
|
||||
'form_id' => $this->id_base.'_'.$this->number,
|
||||
'form_id' => $form_id,
|
||||
'form_type' => $form_type,
|
||||
'form' => $form,
|
||||
'title' => $title,
|
||||
'styles' => FormRenderer::renderStyles($form),
|
||||
'styles' => FormRenderer::renderStyles($form, '#'.$form_id),
|
||||
'html' => FormRenderer::renderHTML($form),
|
||||
'before_widget' => (!empty($before_widget) ? $before_widget : ''),
|
||||
'after_widget' => (!empty($after_widget) ? $after_widget : ''),
|
||||
|
@ -4,6 +4,8 @@ namespace MailPoet\Listing;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Handler {
|
||||
const DEFAULT_LIMIT_PER_PAGE = 20;
|
||||
|
||||
private $data = array();
|
||||
private $model = null;
|
||||
|
||||
@ -14,7 +16,10 @@ class Handler {
|
||||
$this->data = array(
|
||||
// pagination
|
||||
'offset' => (isset($data['offset']) ? (int)$data['offset'] : 0),
|
||||
'limit' => (isset($data['limit']) ? (int)$data['limit'] : 50),
|
||||
'limit' => (isset($data['limit'])
|
||||
? (int)$data['limit']
|
||||
: self::DEFAULT_LIMIT_PER_PAGE
|
||||
),
|
||||
// searching
|
||||
'search' => (isset($data['search']) ? $data['search'] : null),
|
||||
// sorting
|
||||
@ -84,11 +89,11 @@ class Handler {
|
||||
$items = $this->model
|
||||
->offset($this->data['offset'])
|
||||
->limit($this->data['limit'])
|
||||
->findArray();
|
||||
->findMany();
|
||||
|
||||
return array(
|
||||
'count' => $count,
|
||||
'filters' => $this->model->filter('filters'),
|
||||
'filters' => $this->model->filter('filters', $this->data['group']),
|
||||
'groups' => $this->model->filter('groups'),
|
||||
'items' => $items
|
||||
);
|
||||
|
@ -102,7 +102,7 @@ class Mailer {
|
||||
function getSender($sender = false) {
|
||||
if(!$sender) {
|
||||
$sender = Setting::getValue('sender', null);
|
||||
if(!$sender) throw new \Exception(__('Sender name and email are not configured.'));
|
||||
if(!$sender['address']) throw new \Exception(__('Sender name and email are not configured.'));
|
||||
}
|
||||
return array(
|
||||
'from_name' => $sender['name'],
|
||||
@ -122,7 +122,7 @@ class Mailer {
|
||||
}
|
||||
}
|
||||
if(!$reply_to['address']) {
|
||||
$reply_to['reply_to_email'] = $this->sender['from_email'];
|
||||
$reply_to['address'] = $this->sender['from_email'];
|
||||
}
|
||||
return array(
|
||||
'reply_to_name' => $reply_to['name'],
|
||||
|
@ -25,8 +25,7 @@ class PHPMail {
|
||||
}
|
||||
|
||||
function buildMailer() {
|
||||
$transport = \Swift_SmtpTransport::newInstance();
|
||||
$transport->setTimeout(10);
|
||||
$transport = \Swift_MailTransport::newInstance();
|
||||
return \Swift_Mailer::newInstance($transport);
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,11 @@ class SendGrid {
|
||||
$this->url,
|
||||
$this->request($newsletter, $subscriber)
|
||||
);
|
||||
$result_body = json_decode($result['body'], true);
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
!preg_match('!invalid!', $result['body']) === true &&
|
||||
!isset(json_decode($result['body'], true)['errors']) === true &&
|
||||
!isset($result_body['errors']) === true &&
|
||||
wp_remote_retrieve_response_code($result) === 200
|
||||
);
|
||||
}
|
||||
|
@ -19,20 +19,22 @@ class CustomField extends Model {
|
||||
function asArray() {
|
||||
$model = parent::asArray();
|
||||
|
||||
$model['params'] = (
|
||||
is_serialized($this->params)
|
||||
? unserialize($this->params)
|
||||
: $this->params
|
||||
);
|
||||
|
||||
if(isset($model['params'])) {
|
||||
$model['params'] = (is_array($this->params))
|
||||
? $this->params
|
||||
: unserialize($this->params);
|
||||
}
|
||||
return $model;
|
||||
}
|
||||
|
||||
function save() {
|
||||
if(is_null($this->params)) {
|
||||
$this->params = array();
|
||||
}
|
||||
$this->set('params', (
|
||||
is_serialized($this->params)
|
||||
? $this->params
|
||||
: serialize($this->params)
|
||||
is_array($this->params)
|
||||
? serialize($this->params)
|
||||
: $this->params
|
||||
));
|
||||
return parent::save();
|
||||
}
|
||||
@ -66,12 +68,6 @@ class CustomField extends Model {
|
||||
$custom_field->set($data);
|
||||
}
|
||||
|
||||
try {
|
||||
$custom_field->save();
|
||||
return $custom_field;
|
||||
} catch(Exception $e) {
|
||||
return $custom_field->getValidationErrors();
|
||||
}
|
||||
return false;
|
||||
return $custom_field->save();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user