Compare commits
484 Commits
Author | SHA1 | Date | |
---|---|---|---|
d25070829d | |||
d194502b27 | |||
2cef99de2b | |||
05d3756a1c | |||
b3d9fc54fe | |||
20841eb5e8 | |||
9e23326d45 | |||
f81d639b19 | |||
ab3e272020 | |||
4c265d1339 | |||
da08de0e74 | |||
6074aa927b | |||
046127eeba | |||
0c8a8c6854 | |||
acfcfdd730 | |||
8f935df12a | |||
2784bb7282 | |||
08a8ca4969 | |||
5a03eb9a17 | |||
91bb215e4d | |||
0b3a388a78 | |||
66a93768e1 | |||
61df4899cd | |||
f8b1e153be | |||
f322433875 | |||
be155c38bc | |||
13ee338fb0 | |||
f8628c1f4e | |||
f7c70be5eb | |||
65df28d52e | |||
3e658033da | |||
31e082eb2b | |||
bf1ab3a593 | |||
8540c51679 | |||
d2a6b6bd4e | |||
06417c1e88 | |||
be238f4c67 | |||
343da0fdcc | |||
dbb3c96300 | |||
c8f7bea419 | |||
396ab50fa0 | |||
84e9ecef29 | |||
57472d1a2e | |||
cb4f055263 | |||
3f1bdd2c59 | |||
a6802a1925 | |||
a02b2d3aa0 | |||
607a151c23 | |||
c8748e5e6e | |||
6e45a8e788 | |||
395e95bc54 | |||
a8309b436d | |||
77fe385645 | |||
290f749220 | |||
8cb5b3729d | |||
ce4a3196ee | |||
40ea5a0b84 | |||
af95380a62 | |||
483eaffc0e | |||
7e86ee3266 | |||
65630e6726 | |||
23682011af | |||
00eaa768a6 | |||
bc92d9a61e | |||
a1d8dec047 | |||
ff030068b0 | |||
79e37018c9 | |||
7ae8248339 | |||
30720975ab | |||
b2359258d4 | |||
1bd7639cc2 | |||
2dab89135f | |||
c3368d69fd | |||
751d8e7852 | |||
8a4dec08e1 | |||
8b9f5ad5b1 | |||
fc597a53bb | |||
2f25dc6a20 | |||
fc38ee2f08 | |||
33bebc6629 | |||
14a8e02f99 | |||
0bf6c87ec7 | |||
422fba2835 | |||
f36dbb78e6 | |||
3213dd0d08 | |||
3f2199fd63 | |||
a4477a9bd6 | |||
52790d7bd6 | |||
0b9812210f | |||
756dbb4641 | |||
b38742ddc0 | |||
49e38549ec | |||
afcb0a0d7f | |||
d18f0e50b5 | |||
6868a07ead | |||
cca76d0d97 | |||
70fa77d333 | |||
412201d965 | |||
045a92c7d6 | |||
2ba2e3eca5 | |||
90c294f60e | |||
57b953dd14 | |||
0f81a8db60 | |||
2d6971f8df | |||
0abe8b5371 | |||
5bad682879 | |||
fa9d32c230 | |||
1b3ceca7b2 | |||
9be326b45d | |||
2d2e1298c4 | |||
5dc3a4386e | |||
b617dde266 | |||
962e91f9dc | |||
4047b41a7f | |||
59199140bf | |||
1079c0beae | |||
1694baab7d | |||
335ac9c778 | |||
65efd234f9 | |||
f726d943db | |||
2d1e950097 | |||
ca2f16970b | |||
4a123f8fe9 | |||
7b224328e1 | |||
699dfa19f0 | |||
06d56fe19d | |||
1b7ac62b5c | |||
ae358ce13e | |||
18f35b5e91 | |||
67ca305b7f | |||
cb0908fc70 | |||
42df59076d | |||
ff8be3bdc6 | |||
f7b6dcf409 | |||
940f3848dd | |||
e847ad2df2 | |||
2459a103fd | |||
0dd3f2178e | |||
de873eca71 | |||
ef461da77f | |||
caf6dcddfa | |||
9684c88651 | |||
256bca8ed9 | |||
8d56e8582f | |||
56959f2f49 | |||
bbc7de6898 | |||
0df246da15 | |||
757e18355d | |||
4b29b04bd1 | |||
6cb94bc413 | |||
f624c891ab | |||
b83abf0ac5 | |||
ef1b0036e5 | |||
5efa9f65c6 | |||
a8e3dd424e | |||
26628ba156 | |||
78cabde9e1 | |||
1ec0372c2d | |||
31e2d5e771 | |||
d2dbf86a9c | |||
1c39d39078 | |||
6d0795abba | |||
5f45c6cc74 | |||
d4d806e247 | |||
758a545eb6 | |||
578088d2e5 | |||
e17dba2b07 | |||
7e5cf533f0 | |||
f7c656aed5 | |||
2e42305710 | |||
b3e310652e | |||
6737158130 | |||
906558a772 | |||
d559483c7b | |||
bec3e02285 | |||
9d6d72dd8c | |||
3b76f838d1 | |||
909ad86e33 | |||
dd8f58e35e | |||
4b2061fcfa | |||
8e6ca502b3 | |||
ef85834db5 | |||
2bdcd0eb42 | |||
3b90be4122 | |||
375e70d84b | |||
42d586610e | |||
e4a5438512 | |||
11b22fa63a | |||
45b933d635 | |||
15cf087d40 | |||
ed09c3e5d4 | |||
285a556f21 | |||
dc1ef2af47 | |||
6f17f0d2d1 | |||
91076580ef | |||
d4abaa7150 | |||
d2bc0fd24a | |||
1f26079b5f | |||
87a1211a55 | |||
0ca0a7d029 | |||
cb3d49f200 | |||
c0da428c27 | |||
435cd9b777 | |||
bfde34eb8d | |||
a4c1b24c35 | |||
2cbd2d54f3 | |||
378f6d803a | |||
af4d29ebe6 | |||
599661e028 | |||
84294b7ee6 | |||
a3e6eb5bba | |||
67359980e9 | |||
f1b955d74a | |||
809be415c5 | |||
457a4d1bba | |||
1e16912763 | |||
e2c9971c99 | |||
c1d31ca400 | |||
a011c3aade | |||
e35e97cdbf | |||
49a59d35a1 | |||
9a46640c15 | |||
678a0b3835 | |||
0c008325c4 | |||
ad5441487b | |||
104620a40a | |||
c1a3ba67f5 | |||
c42bbf3dc4 | |||
7d34274fbf | |||
f930b3303b | |||
a25ea3ddf6 | |||
021349caee | |||
89f2958d23 | |||
8c8435766e | |||
40dd1bbb3b | |||
ba40437eb9 | |||
813db1ae33 | |||
9588397e4e | |||
ecf83ca419 | |||
9cc494f0fa | |||
dd4b7e4d1c | |||
738b2f6c17 | |||
33289342d3 | |||
a00f1efcfe | |||
b89897e6d4 | |||
c539837896 | |||
27edf5f71d | |||
32cc5644f9 | |||
8a664aa7f1 | |||
7e5e8a4282 | |||
70d5d609e2 | |||
19160c99e1 | |||
99b2a7457e | |||
945d7edc70 | |||
6a97badfed | |||
5ec8e4ed52 | |||
1569b5f80a | |||
e62ecc5036 | |||
b0150e184b | |||
8b96854f39 | |||
28d8600078 | |||
4f30158722 | |||
4486f9c5b0 | |||
8515dcf29b | |||
d16eb87782 | |||
3c77e5d25e | |||
aa1a2a0da9 | |||
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 |
@ -89,14 +89,14 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makepot() {
|
function makepot() {
|
||||||
$this->_exec('grunt makepot'.
|
$this->_exec('./node_modules/.bin/grunt makepot'.
|
||||||
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
|
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
|
||||||
' --base_path '.__DIR__
|
' --base_path '.__DIR__
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushpot() {
|
function pushpot() {
|
||||||
$this->_exec('grunt pushpot'.
|
$this->_exec('./node_modules/.bin/grunt pushpot'.
|
||||||
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
|
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
|
||||||
' --base_path '.__DIR__
|
' --base_path '.__DIR__
|
||||||
);
|
);
|
||||||
@ -108,11 +108,12 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
$this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : ''));
|
$this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCoverage() {
|
function testCoverage($file = null) {
|
||||||
$this->loadEnv();
|
$this->loadEnv();
|
||||||
$this->_exec('vendor/bin/codecept build');
|
$this->_exec('vendor/bin/codecept build');
|
||||||
$this->_exec(join(' ', array(
|
$this->_exec(join(' ', array(
|
||||||
'vendor/bin/codecept run',
|
'vendor/bin/codecept run',
|
||||||
|
(($file) ? $file : ''),
|
||||||
'--coverage',
|
'--coverage',
|
||||||
'--coverage-html'
|
'--coverage-html'
|
||||||
)));
|
)));
|
||||||
@ -122,7 +123,7 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
$this->compileJs();
|
$this->compileJs();
|
||||||
|
|
||||||
$this->_exec(join(' ', array(
|
$this->_exec(join(' ', array(
|
||||||
'./node_modules/mocha/bin/mocha',
|
'./node_modules/.bin/mocha',
|
||||||
'-r tests/javascript/mochaTestHelper.js',
|
'-r tests/javascript/mochaTestHelper.js',
|
||||||
'tests/javascript/testBundles/**/*.js'
|
'tests/javascript/testBundles/**/*.js'
|
||||||
)));
|
)));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@import 'nib'
|
@import 'nib'
|
||||||
|
|
||||||
@require 'select2/dist/css/select2.css'
|
@require 'select2/dist/css/select2.css'
|
||||||
|
@require 'datepicker/datepicker'
|
||||||
|
|
||||||
@require 'common'
|
@require 'common'
|
||||||
@require 'modal'
|
@require 'modal'
|
||||||
@ -17,3 +18,5 @@
|
|||||||
|
|
||||||
@require 'settings'
|
@require 'settings'
|
||||||
@require 'progress_bar'
|
@require 'progress_bar'
|
||||||
|
|
||||||
|
@require 'subscribers'
|
||||||
|
2
assets/css/src/datepicker/datepicker.styl
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@require 'jquery-ui-1.10.1.css'
|
||||||
|
@require 'melon.datepicker.css'
|
649
assets/css/src/datepicker/jquery-ui-1.10.1.css
vendored
Normal file
@ -0,0 +1,649 @@
|
|||||||
|
/*! jQuery UI - v1.10.1 - 2013-03-10
|
||||||
|
* http://jqueryui.com
|
||||||
|
* Includes: jquery.ui.core.css, jquery.ui.datepicker.css
|
||||||
|
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
|
||||||
|
* Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */
|
||||||
|
|
||||||
|
/* Layout helpers
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-helper-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-helper-hidden-accessible {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
.ui-helper-reset {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
line-height: 1.3;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 100%;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix:before,
|
||||||
|
.ui-helper-clearfix:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix {
|
||||||
|
min-height: 0; /* support: IE7 */
|
||||||
|
}
|
||||||
|
.ui-helper-zfix {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
filter:Alpha(Opacity=0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-front {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Interaction Cues
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-disabled {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Icons
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* states and images */
|
||||||
|
.ui-icon {
|
||||||
|
display: block;
|
||||||
|
text-indent: -99999px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc visuals
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* Overlays */
|
||||||
|
.ui-widget-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-datepicker {
|
||||||
|
width: 17em;
|
||||||
|
padding: .2em .2em 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-header {
|
||||||
|
position: relative;
|
||||||
|
padding: .2em 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev,
|
||||||
|
.ui-datepicker .ui-datepicker-next {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev-hover,
|
||||||
|
.ui-datepicker .ui-datepicker-next-hover {
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev {
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-next {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev-hover {
|
||||||
|
left: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-next-hover {
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev span,
|
||||||
|
.ui-datepicker .ui-datepicker-next span {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -8px;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-title {
|
||||||
|
margin: 0 2.3em;
|
||||||
|
line-height: 1.8em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-title select {
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 1px 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker select.ui-datepicker-month-year {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.ui-datepicker select.ui-datepicker-month,
|
||||||
|
.ui-datepicker select.ui-datepicker-year {
|
||||||
|
width: 49%;
|
||||||
|
}
|
||||||
|
.ui-datepicker table {
|
||||||
|
width: 100%;
|
||||||
|
font-size: .9em;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 0 0 .4em;
|
||||||
|
}
|
||||||
|
.ui-datepicker th {
|
||||||
|
padding: .7em .3em;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker td {
|
||||||
|
border: 0;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker td span,
|
||||||
|
.ui-datepicker td a {
|
||||||
|
display: block;
|
||||||
|
padding: .2em;
|
||||||
|
text-align: right;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-buttonpane {
|
||||||
|
background-image: none;
|
||||||
|
margin: .7em 0 0 0;
|
||||||
|
padding: 0 .2em;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-buttonpane button {
|
||||||
|
float: right;
|
||||||
|
margin: .5em .2em .4em;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: .2em .6em .3em .6em;
|
||||||
|
width: auto;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* with multiple calendars */
|
||||||
|
.ui-datepicker.ui-datepicker-multi {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group table {
|
||||||
|
width: 95%;
|
||||||
|
margin: 0 auto .4em;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi-2 .ui-datepicker-group {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi-3 .ui-datepicker-group {
|
||||||
|
width: 33.3%;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi-4 .ui-datepicker-group {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-buttonpane {
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
.ui-datepicker-row-break {
|
||||||
|
clear: both;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RTL support */
|
||||||
|
.ui-datepicker-rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-prev {
|
||||||
|
right: 2px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-next {
|
||||||
|
left: 2px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-prev:hover {
|
||||||
|
right: 1px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-next:hover {
|
||||||
|
left: 1px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-buttonpane {
|
||||||
|
clear: right;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-buttonpane button {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-group {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
|
||||||
|
border-right-width: 0;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component containers
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-widget {
|
||||||
|
font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
.ui-widget .ui-widget {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.ui-widget input,
|
||||||
|
.ui-widget select,
|
||||||
|
.ui-widget textarea,
|
||||||
|
.ui-widget button {
|
||||||
|
font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.ui-widget-content {
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
background: #eeeeee url(../img/datepicker/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.ui-widget-content a {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.ui-widget-header {
|
||||||
|
border: 1px solid #e78f08;
|
||||||
|
background: #f6a828 url(../img/datepicker/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.ui-widget-header a {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interaction states
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-default,
|
||||||
|
.ui-widget-content .ui-state-default,
|
||||||
|
.ui-widget-header .ui-state-default {
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
background: #f6f6f6 url(../img/datepicker/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1c94c4;
|
||||||
|
}
|
||||||
|
.ui-state-default a,
|
||||||
|
.ui-state-default a:link,
|
||||||
|
.ui-state-default a:visited {
|
||||||
|
color: #1c94c4;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-state-hover,
|
||||||
|
.ui-widget-content .ui-state-hover,
|
||||||
|
.ui-widget-header .ui-state-hover,
|
||||||
|
.ui-state-focus,
|
||||||
|
.ui-widget-content .ui-state-focus,
|
||||||
|
.ui-widget-header .ui-state-focus {
|
||||||
|
border: 1px solid #fbcb09;
|
||||||
|
background: #fdf5ce url(../img/datepicker/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #c77405;
|
||||||
|
}
|
||||||
|
.ui-state-hover a,
|
||||||
|
.ui-state-hover a:hover,
|
||||||
|
.ui-state-hover a:link,
|
||||||
|
.ui-state-hover a:visited {
|
||||||
|
color: #c77405;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-state-active,
|
||||||
|
.ui-widget-content .ui-state-active,
|
||||||
|
.ui-widget-header .ui-state-active {
|
||||||
|
border: 1px solid #fbd850;
|
||||||
|
background: #ffffff url(../img/datepicker/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #eb8f00;
|
||||||
|
}
|
||||||
|
.ui-state-active a,
|
||||||
|
.ui-state-active a:link,
|
||||||
|
.ui-state-active a:visited {
|
||||||
|
color: #eb8f00;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interaction Cues
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-highlight,
|
||||||
|
.ui-widget-content .ui-state-highlight,
|
||||||
|
.ui-widget-header .ui-state-highlight {
|
||||||
|
border: 1px solid #fed22f;
|
||||||
|
background: #ffe45c url(../img/datepicker/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x;
|
||||||
|
color: #363636;
|
||||||
|
}
|
||||||
|
.ui-state-highlight a,
|
||||||
|
.ui-widget-content .ui-state-highlight a,
|
||||||
|
.ui-widget-header .ui-state-highlight a {
|
||||||
|
color: #363636;
|
||||||
|
}
|
||||||
|
.ui-state-error,
|
||||||
|
.ui-widget-content .ui-state-error,
|
||||||
|
.ui-widget-header .ui-state-error {
|
||||||
|
border: 1px solid #cd0a0a;
|
||||||
|
background: #b81900 url(../img/datepicker/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.ui-state-error a,
|
||||||
|
.ui-widget-content .ui-state-error a,
|
||||||
|
.ui-widget-header .ui-state-error a {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.ui-state-error-text,
|
||||||
|
.ui-widget-content .ui-state-error-text,
|
||||||
|
.ui-widget-header .ui-state-error-text {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.ui-priority-primary,
|
||||||
|
.ui-widget-content .ui-priority-primary,
|
||||||
|
.ui-widget-header .ui-priority-primary {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.ui-priority-secondary,
|
||||||
|
.ui-widget-content .ui-priority-secondary,
|
||||||
|
.ui-widget-header .ui-priority-secondary {
|
||||||
|
opacity: .7;
|
||||||
|
filter:Alpha(Opacity=70);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.ui-state-disabled,
|
||||||
|
.ui-widget-content .ui-state-disabled,
|
||||||
|
.ui-widget-header .ui-state-disabled {
|
||||||
|
opacity: .35;
|
||||||
|
filter:Alpha(Opacity=35);
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.ui-state-disabled .ui-icon {
|
||||||
|
filter:Alpha(Opacity=35); /* For IE8 - See #6059 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* states and images */
|
||||||
|
.ui-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-position: 16px 16px;
|
||||||
|
}
|
||||||
|
.ui-icon,
|
||||||
|
.ui-widget-content .ui-icon {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_222222_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-widget-header .ui-icon {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_ffffff_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-default .ui-icon {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_ef8c08_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-hover .ui-icon,
|
||||||
|
.ui-state-focus .ui-icon {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_ef8c08_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-active .ui-icon {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_ef8c08_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-highlight .ui-icon {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_228ef1_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-error .ui-icon,
|
||||||
|
.ui-state-error-text .ui-icon {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_ffd27a_256x240.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* positioning */
|
||||||
|
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||||
|
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||||
|
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||||
|
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||||
|
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||||
|
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||||
|
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||||
|
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||||
|
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||||
|
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||||
|
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||||
|
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||||
|
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||||
|
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||||
|
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||||
|
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||||
|
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||||
|
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||||
|
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||||
|
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||||
|
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||||
|
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||||
|
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||||
|
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||||
|
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||||
|
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||||
|
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||||
|
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||||
|
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||||
|
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||||
|
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||||
|
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||||
|
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||||
|
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||||
|
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||||
|
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||||
|
.ui-icon-extlink { background-position: -32px -80px; }
|
||||||
|
.ui-icon-newwin { background-position: -48px -80px; }
|
||||||
|
.ui-icon-refresh { background-position: -64px -80px; }
|
||||||
|
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||||
|
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||||
|
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||||
|
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||||
|
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||||
|
.ui-icon-document { background-position: -32px -96px; }
|
||||||
|
.ui-icon-document-b { background-position: -48px -96px; }
|
||||||
|
.ui-icon-note { background-position: -64px -96px; }
|
||||||
|
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||||
|
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||||
|
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||||
|
.ui-icon-comment { background-position: -128px -96px; }
|
||||||
|
.ui-icon-person { background-position: -144px -96px; }
|
||||||
|
.ui-icon-print { background-position: -160px -96px; }
|
||||||
|
.ui-icon-trash { background-position: -176px -96px; }
|
||||||
|
.ui-icon-locked { background-position: -192px -96px; }
|
||||||
|
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||||
|
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||||
|
.ui-icon-tag { background-position: -240px -96px; }
|
||||||
|
.ui-icon-home { background-position: 0 -112px; }
|
||||||
|
.ui-icon-flag { background-position: -16px -112px; }
|
||||||
|
.ui-icon-calendar { background-position: -32px -112px; }
|
||||||
|
.ui-icon-cart { background-position: -48px -112px; }
|
||||||
|
.ui-icon-pencil { background-position: -64px -112px; }
|
||||||
|
.ui-icon-clock { background-position: -80px -112px; }
|
||||||
|
.ui-icon-disk { background-position: -96px -112px; }
|
||||||
|
.ui-icon-calculator { background-position: -112px -112px; }
|
||||||
|
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||||
|
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||||
|
.ui-icon-search { background-position: -160px -112px; }
|
||||||
|
.ui-icon-wrench { background-position: -176px -112px; }
|
||||||
|
.ui-icon-gear { background-position: -192px -112px; }
|
||||||
|
.ui-icon-heart { background-position: -208px -112px; }
|
||||||
|
.ui-icon-star { background-position: -224px -112px; }
|
||||||
|
.ui-icon-link { background-position: -240px -112px; }
|
||||||
|
.ui-icon-cancel { background-position: 0 -128px; }
|
||||||
|
.ui-icon-plus { background-position: -16px -128px; }
|
||||||
|
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||||
|
.ui-icon-minus { background-position: -48px -128px; }
|
||||||
|
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||||
|
.ui-icon-close { background-position: -80px -128px; }
|
||||||
|
.ui-icon-closethick { background-position: -96px -128px; }
|
||||||
|
.ui-icon-key { background-position: -112px -128px; }
|
||||||
|
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||||
|
.ui-icon-scissors { background-position: -144px -128px; }
|
||||||
|
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||||
|
.ui-icon-copy { background-position: -176px -128px; }
|
||||||
|
.ui-icon-contact { background-position: -192px -128px; }
|
||||||
|
.ui-icon-image { background-position: -208px -128px; }
|
||||||
|
.ui-icon-video { background-position: -224px -128px; }
|
||||||
|
.ui-icon-script { background-position: -240px -128px; }
|
||||||
|
.ui-icon-alert { background-position: 0 -144px; }
|
||||||
|
.ui-icon-info { background-position: -16px -144px; }
|
||||||
|
.ui-icon-notice { background-position: -32px -144px; }
|
||||||
|
.ui-icon-help { background-position: -48px -144px; }
|
||||||
|
.ui-icon-check { background-position: -64px -144px; }
|
||||||
|
.ui-icon-bullet { background-position: -80px -144px; }
|
||||||
|
.ui-icon-radio-on { background-position: -96px -144px; }
|
||||||
|
.ui-icon-radio-off { background-position: -112px -144px; }
|
||||||
|
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||||
|
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||||
|
.ui-icon-play { background-position: 0 -160px; }
|
||||||
|
.ui-icon-pause { background-position: -16px -160px; }
|
||||||
|
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||||
|
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||||
|
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||||
|
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||||
|
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||||
|
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||||
|
.ui-icon-stop { background-position: -96px -160px; }
|
||||||
|
.ui-icon-eject { background-position: -112px -160px; }
|
||||||
|
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||||
|
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||||
|
.ui-icon-power { background-position: 0 -176px; }
|
||||||
|
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||||
|
.ui-icon-signal { background-position: -32px -176px; }
|
||||||
|
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||||
|
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||||
|
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||||
|
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||||
|
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||||
|
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||||
|
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||||
|
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||||
|
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||||
|
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||||
|
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||||
|
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||||
|
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||||
|
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||||
|
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||||
|
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||||
|
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||||
|
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||||
|
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||||
|
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||||
|
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||||
|
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||||
|
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||||
|
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||||
|
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||||
|
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||||
|
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||||
|
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||||
|
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||||
|
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc visuals
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* Corner radius */
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-top,
|
||||||
|
.ui-corner-left,
|
||||||
|
.ui-corner-tl {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-top,
|
||||||
|
.ui-corner-right,
|
||||||
|
.ui-corner-tr {
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-bottom,
|
||||||
|
.ui-corner-left,
|
||||||
|
.ui-corner-bl {
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-bottom,
|
||||||
|
.ui-corner-right,
|
||||||
|
.ui-corner-br {
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overlays */
|
||||||
|
.ui-widget-overlay {
|
||||||
|
background: #666666 url(../img/datepicker/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat;
|
||||||
|
opacity: .5;
|
||||||
|
filter: Alpha(Opacity=50);
|
||||||
|
}
|
||||||
|
.ui-widget-shadow {
|
||||||
|
margin: -5px 0 0 -5px;
|
||||||
|
padding: 5px;
|
||||||
|
background: #000000 url(../img/datepicker/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x;
|
||||||
|
opacity: .2;
|
||||||
|
filter: Alpha(Opacity=20);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
115
assets/css/src/datepicker/melon.datepicker.css
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* Melon skin from: https://github.com/rtsinani/jquery-datepicker-skins
|
||||||
|
*/
|
||||||
|
|
||||||
|
.wp-admin {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-widget {
|
||||||
|
font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
|
||||||
|
background: #2e3641;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-border-radius: 0;
|
||||||
|
-moz-border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker-header {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker-header .ui-state-hover {
|
||||||
|
background: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-border-radius: 0;
|
||||||
|
-moz-border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-title {
|
||||||
|
margin-top: .4em;
|
||||||
|
margin-bottom: .3em;
|
||||||
|
color: #e9f0f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-prev-hover,
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-next-hover,
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-next,
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-prev {
|
||||||
|
top: .9em;
|
||||||
|
border:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-prev-hover {
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-next-hover {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-next span,
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-prev span {
|
||||||
|
background-image: url(../img/datepicker/ui-icons_ffffff_256x240.png);
|
||||||
|
background-position: -32px 0;
|
||||||
|
margin-top: 0;
|
||||||
|
top: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker .ui-datepicker-prev span {
|
||||||
|
background-position: -96px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker table {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker th {
|
||||||
|
padding: 1em 0;
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: normal;
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid #3a414d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-datepicker td {
|
||||||
|
background: #f97e76;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin td .ui-state-default {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
text-align: center;
|
||||||
|
padding: .5em;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #efefef;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-state-disabled {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin .ui-state-disabled .ui-state-default {
|
||||||
|
color: #fba49e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-admin td .ui-state-active,
|
||||||
|
.wp-admin td .ui-state-hover {
|
||||||
|
background: #2e3641;
|
||||||
|
}
|
||||||
|
|
@ -1,2 +1,5 @@
|
|||||||
|
.mailpoet_form
|
||||||
|
margin: 0 0 20px 0
|
||||||
|
|
||||||
.mailpoet_form td
|
.mailpoet_form td
|
||||||
vertical-align: top !important
|
vertical-align: top !important
|
||||||
|
@ -563,3 +563,6 @@ handle_icon = '../img/handle.png'
|
|||||||
.CodeMirror
|
.CodeMirror
|
||||||
border: 1px solid #eee
|
border: 1px solid #eee
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
#mailpoet_form_segments.parsley-error + span .select2-selection
|
||||||
|
border: 1px solid #b94a48
|
@ -37,3 +37,6 @@
|
|||||||
|
|
||||||
input[type=text]
|
input[type=text]
|
||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
|
|
||||||
|
.mailpoet_form_field_block
|
||||||
|
display: block
|
||||||
|
@ -38,9 +38,7 @@
|
|||||||
content: '\f142'
|
content: '\f142'
|
||||||
|
|
||||||
.mailpoet_save_show_options_icon
|
.mailpoet_save_show_options_icon
|
||||||
width: auto
|
vertical-align: middle
|
||||||
height: auto
|
|
||||||
line-height: auto
|
|
||||||
|
|
||||||
&::before
|
&::before
|
||||||
content: '\f140'
|
content: '\f140'
|
||||||
|
@ -21,3 +21,9 @@
|
|||||||
|
|
||||||
.mailpoet_automated_latest_content_display_options
|
.mailpoet_automated_latest_content_display_options
|
||||||
animation-slide-open-downwards()
|
animation-slide-open-downwards()
|
||||||
|
|
||||||
|
.mailpoet_automated_latest_content_show_amount
|
||||||
|
width: 25px
|
||||||
|
|
||||||
|
.mailpoet_automated_latest_content_content_type
|
||||||
|
width: 180px
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
$block-hover-highlight-color = $primary-active-color
|
$block-hover-highlight-color = $primary-active-color
|
||||||
|
$block-text-line-height = $text-line-height
|
||||||
|
|
||||||
.mailpoet_block
|
.mailpoet_block
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
@ -30,3 +31,34 @@ $block-hover-highlight-color = $primary-active-color
|
|||||||
|
|
||||||
.mailpoet_content
|
.mailpoet_content
|
||||||
position: relative
|
position: relative
|
||||||
|
line-height: $block-text-line-height
|
||||||
|
|
||||||
|
p, h1, h2, h3, h4, h5, h6
|
||||||
|
line-height: $block-text-line-height
|
||||||
|
padding: 0
|
||||||
|
margin: 0
|
||||||
|
font-style: normal
|
||||||
|
font-weight: normal
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6
|
||||||
|
margin-bottom: 0.3em
|
||||||
|
|
||||||
|
p
|
||||||
|
margin-top: 0
|
||||||
|
margin-bottom: 0
|
||||||
|
font-weight: normal
|
||||||
|
|
||||||
|
ul
|
||||||
|
padding: 0
|
||||||
|
margin-top: 10px
|
||||||
|
margin-bottom: 10px
|
||||||
|
|
||||||
|
li
|
||||||
|
margin-top: 0
|
||||||
|
font-weight: normal
|
||||||
|
margin-bottom: 10px
|
||||||
|
|
||||||
|
blockquote
|
||||||
|
margin: 0 0 $block-text-line-height
|
||||||
|
padding-left: 10px
|
||||||
|
border-left: 2px #565656 solid
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
$button-vertical-padding = 13px
|
|
||||||
|
|
||||||
.mailpoet_button_block
|
.mailpoet_button_block
|
||||||
padding-top: $button-vertical-padding
|
|
||||||
padding-bottom: $button-vertical-padding
|
|
||||||
|
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
|
|
||||||
.mailpoet_editor_button
|
.mailpoet_editor_button
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
.mailpoet_footer_block
|
.mailpoet_footer_block
|
||||||
padding-left: 0
|
padding-left: 0
|
||||||
padding-right: 0
|
padding-right: 0
|
||||||
|
margin-bottom: 0
|
||||||
|
|
||||||
.mailpoet_content
|
.mailpoet_content
|
||||||
padding: 5px 20px
|
padding: 10px 20px
|
||||||
|
|
||||||
|
& > *:last-child
|
||||||
|
margin-bottom: 0
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
.mailpoet_header_block
|
.mailpoet_header_block
|
||||||
padding-left: 0
|
padding-left: 0
|
||||||
padding-right: 0
|
padding-right: 0
|
||||||
|
margin-bottom: 0
|
||||||
|
|
||||||
.mailpoet_content
|
.mailpoet_content
|
||||||
padding: 5px 20px
|
padding: 10px 20px
|
||||||
|
|
||||||
|
& > *:last-child
|
||||||
|
margin-bottom: 0
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
padding-right: 0
|
padding-right: 0
|
||||||
margin-bottom: 0
|
margin-bottom: 0
|
||||||
|
|
||||||
img
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
.mailpoet_content a:hover
|
.mailpoet_content a:hover
|
||||||
cursor: all-scroll
|
cursor: all-scroll
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
$social-block-vertical-padding = 11px
|
$social-block-vertical-padding = 0px
|
||||||
|
|
||||||
$social-icon-width = 32px
|
$social-icon-width = 32px
|
||||||
$active-social-icon-set-border-color = #adadad
|
$active-social-icon-set-border-color = #adadad
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
$text-vertical-padding = 3px
|
|
||||||
|
|
||||||
.mailpoet_text_block
|
.mailpoet_text_block
|
||||||
padding-left: 0
|
padding-left: 0
|
||||||
padding-right: 0
|
padding-right: 0
|
||||||
|
|
||||||
& > .mailpoet_content
|
& > .mailpoet_content
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
padding-top: 13px
|
padding-top: 0
|
||||||
padding-bottom: 13px
|
padding-bottom: 0px
|
||||||
padding-left: 20px
|
padding-left: 20px
|
||||||
padding-right: 20px
|
padding-right: 20px
|
||||||
|
|
||||||
blockquote
|
& > *:last-child
|
||||||
margin: 1em
|
margin-bottom: 0
|
||||||
padding-left: 1em
|
|
||||||
border-left: 2px #565656 solid
|
|
||||||
|
@ -133,3 +133,17 @@ body
|
|||||||
.wrap > .mailpoet_notice,
|
.wrap > .mailpoet_notice,
|
||||||
.update-nag
|
.update-nag
|
||||||
margin-left: 2px + 15px !important
|
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
|
||||||
|
|
||||||
|
@ -24,3 +24,5 @@ $error-text-color = #d54e21
|
|||||||
|
|
||||||
// Dimensions
|
// Dimensions
|
||||||
$newsletter-width = 660px
|
$newsletter-width = 660px
|
||||||
|
|
||||||
|
$text-line-height = 1.6em
|
||||||
|
@ -2,3 +2,13 @@
|
|||||||
|
|
||||||
@require 'parsley'
|
@require 'parsley'
|
||||||
@require 'form_validation'
|
@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
@ -0,0 +1,3 @@
|
|||||||
|
#subscribers_container
|
||||||
|
.mailpoet_segments_unsubscribed
|
||||||
|
color: lighten(#555, 33)
|
BIN
assets/img/datepicker/animated-overlay.gif
Executable file
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/img/datepicker/cal_logo.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/img/datepicker/ui-bg_diagonals-thick_18_b81900_40x40.png
Executable file
After Width: | Height: | Size: 418 B |
BIN
assets/img/datepicker/ui-bg_diagonals-thick_20_666666_40x40.png
Executable file
After Width: | Height: | Size: 312 B |
BIN
assets/img/datepicker/ui-bg_flat_10_000000_40x100.png
Executable file
After Width: | Height: | Size: 205 B |
BIN
assets/img/datepicker/ui-bg_glass_100_f6f6f6_1x400.png
Executable file
After Width: | Height: | Size: 262 B |
BIN
assets/img/datepicker/ui-bg_glass_100_fdf5ce_1x400.png
Executable file
After Width: | Height: | Size: 348 B |
BIN
assets/img/datepicker/ui-bg_glass_65_ffffff_1x400.png
Executable file
After Width: | Height: | Size: 207 B |
BIN
assets/img/datepicker/ui-bg_gloss-wave_35_f6a828_500x100.png
Executable file
After Width: | Height: | Size: 5.7 KiB |
BIN
assets/img/datepicker/ui-bg_highlight-soft_100_eeeeee_1x100.png
Executable file
After Width: | Height: | Size: 278 B |
BIN
assets/img/datepicker/ui-bg_highlight-soft_75_ffe45c_1x100.png
Executable file
After Width: | Height: | Size: 328 B |
BIN
assets/img/datepicker/ui-icons_222222_256x240.png
Executable file
After Width: | Height: | Size: 6.8 KiB |
BIN
assets/img/datepicker/ui-icons_228ef1_256x240.png
Executable file
After Width: | Height: | Size: 4.4 KiB |
BIN
assets/img/datepicker/ui-icons_454545_256x240.png
Executable file
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/img/datepicker/ui-icons_ef8c08_256x240.png
Executable file
After Width: | Height: | Size: 4.4 KiB |
BIN
assets/img/datepicker/ui-icons_ffd27a_256x240.png
Executable file
After Width: | Height: | Size: 4.4 KiB |
BIN
assets/img/datepicker/ui-icons_ffffff_256x240.png
Executable file
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 3.8 KiB |
@ -48,28 +48,22 @@ define(
|
|||||||
})
|
})
|
||||||
.done(function(response) {
|
.done(function(response) {
|
||||||
if(!response.result) {
|
if(!response.result) {
|
||||||
MailPoet.Notice.error(MailPoetI18n.daemonControlError);
|
MailPoet.Notice.error(MailPoet.I18n.t('daemonControlError'));
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
if(this.state.status === 'loading') {
|
if(this.state.status === 'loading') {
|
||||||
return(<div>Loading daemon status...</div>);
|
return(<div>{MailPoet.I18n.t('loadingDaemonStatus')}</div>);
|
||||||
}
|
}
|
||||||
switch(this.state.status) {
|
switch(this.state.status) {
|
||||||
case 'started':
|
case 'started':
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
Cron daemon is running.
|
{MailPoet.I18n.t('cronDaemonIsRunning')}
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
It was started
|
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'stop')}>{MailPoet.I18n.t('stop')}</a>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -77,17 +71,17 @@ define(
|
|||||||
case 'stopping':
|
case 'stopping':
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
Daemon is {this.state.status}
|
{MailPoet.I18n.t('cronDaemonState').replace('%$1s', this.state.status)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'stopped':
|
case 'stopped':
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
Daemon is {this.state.status}
|
{MailPoet.I18n.t('cronDaemonState').replace('%$1s', this.state.status)}
|
||||||
<br />
|
<br />
|
||||||
<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>
|
</div>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -103,4 +97,4 @@ define(
|
|||||||
container
|
container
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
145
assets/js/src/date.js
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
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) {
|
||||||
|
options = options || {};
|
||||||
|
this.init(options);
|
||||||
|
|
||||||
|
return Moment(date, this.convertFormat(options.parseFormat))
|
||||||
|
.format(this.convertFormat(this.options.format));
|
||||||
|
},
|
||||||
|
toDate: function(date, options) {
|
||||||
|
options = options || {};
|
||||||
|
this.init(options);
|
||||||
|
|
||||||
|
return Moment(date, this.convertFormat(options.parseFormat)).toDate();
|
||||||
|
},
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!format || format.length <= 0) return format;
|
||||||
|
|
||||||
|
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);
|
return this.props.onValueChange(e);
|
||||||
},
|
},
|
||||||
render: function() {
|
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(
|
const options = Object.keys(this.props.field.values).map(
|
||||||
function(value, index) {
|
(value, index) => {
|
||||||
return (
|
return (
|
||||||
<p key={ 'checkbox-' + index }>
|
<p key={ 'checkbox-' + index }>
|
||||||
<label>
|
<label>
|
||||||
@ -29,7 +32,7 @@ function(
|
|||||||
</label>
|
</label>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
}.bind(this)
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -9,6 +9,13 @@ define([
|
|||||||
render() {
|
render() {
|
||||||
const yearsRange = 100;
|
const yearsRange = 100;
|
||||||
const years = [];
|
const years = [];
|
||||||
|
|
||||||
|
if (this.props.placeholder !== undefined) {
|
||||||
|
years.push((
|
||||||
|
<option value="" key={ 0 }>{ this.props.placeholder }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
const currentYear = Moment().year();
|
const currentYear = Moment().year();
|
||||||
for (let i = currentYear; i >= currentYear - yearsRange; i--) {
|
for (let i = currentYear; i >= currentYear - yearsRange; i--) {
|
||||||
years.push((
|
years.push((
|
||||||
@ -33,6 +40,13 @@ define([
|
|||||||
class FormFieldDateMonth extends React.Component {
|
class FormFieldDateMonth extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const months = [];
|
const months = [];
|
||||||
|
|
||||||
|
if (this.props.placeholder !== undefined) {
|
||||||
|
months.push((
|
||||||
|
<option value="" key={ 0 }>{ this.props.placeholder }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= 12; i++) {
|
for (let i = 1; i <= 12; i++) {
|
||||||
months.push((
|
months.push((
|
||||||
<option
|
<option
|
||||||
@ -56,6 +70,13 @@ define([
|
|||||||
class FormFieldDateDay extends React.Component {
|
class FormFieldDateDay extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
|
if (this.props.placeholder !== undefined) {
|
||||||
|
days.push((
|
||||||
|
<option value="" key={ 0 }>{ this.props.placeholder }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= 31; i++) {
|
for (let i = 1; i <= 31; i++) {
|
||||||
days.push((
|
days.push((
|
||||||
<option
|
<option
|
||||||
@ -81,9 +102,9 @@ define([
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
year: Moment().year(),
|
year: undefined,
|
||||||
month: 1,
|
month: undefined,
|
||||||
day: 1
|
day: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -98,7 +119,6 @@ define([
|
|||||||
}
|
}
|
||||||
extractTimeStamp() {
|
extractTimeStamp() {
|
||||||
const timeStamp = parseInt(this.props.item[this.props.field.name], 10);
|
const timeStamp = parseInt(this.props.item[this.props.field.name], 10);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
year: Moment.unix(timeStamp).year(),
|
year: Moment.unix(timeStamp).year(),
|
||||||
// Moment returns the month as [0..11]
|
// Moment returns the month as [0..11]
|
||||||
@ -112,7 +132,7 @@ define([
|
|||||||
`${this.state.month}/${this.state.day}/${this.state.year}`,
|
`${this.state.month}/${this.state.day}/${this.state.year}`,
|
||||||
'M/D/YYYY'
|
'M/D/YYYY'
|
||||||
).valueOf();
|
).valueOf();
|
||||||
if (!isNaN(newTimeStamp) && parseInt(newTimeStamp, 10) > 0) {
|
if (~~(newTimeStamp) > 0) {
|
||||||
// convert milliseconds to seconds
|
// convert milliseconds to seconds
|
||||||
newTimeStamp /= 1000;
|
newTimeStamp /= 1000;
|
||||||
return this.props.onValueChange({
|
return this.props.onValueChange({
|
||||||
@ -158,6 +178,7 @@ define([
|
|||||||
key={ 'year' }
|
key={ 'year' }
|
||||||
name={ this.props.field.name }
|
name={ this.props.field.name }
|
||||||
year={ this.state.year }
|
year={ this.state.year }
|
||||||
|
placeholder={ this.props.field.year_placeholder }
|
||||||
/>);
|
/>);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -169,6 +190,7 @@ define([
|
|||||||
name={ this.props.field.name }
|
name={ this.props.field.name }
|
||||||
month={ this.state.month }
|
month={ this.state.month }
|
||||||
monthNames={ monthNames }
|
monthNames={ monthNames }
|
||||||
|
placeholder={ this.props.field.month_placeholder }
|
||||||
/>);
|
/>);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -179,6 +201,7 @@ define([
|
|||||||
key={ 'day' }
|
key={ 'day' }
|
||||||
name={ this.props.field.name }
|
name={ this.props.field.name }
|
||||||
day={ this.state.day }
|
day={ this.state.day }
|
||||||
|
placeholder={ this.props.field.day_placeholder }
|
||||||
/>);
|
/>);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,10 @@ function(
|
|||||||
case 'date':
|
case 'date':
|
||||||
field = (<FormFieldDate {...data} />);
|
field = (<FormFieldDate {...data} />);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'reactComponent':
|
||||||
|
field = (<data.field.component {...data} />);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inline === true) {
|
if(inline === true) {
|
||||||
@ -121,4 +125,4 @@ function(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return FormField;
|
return FormField;
|
||||||
});
|
});
|
||||||
|
@ -4,12 +4,15 @@ define([
|
|||||||
function(
|
function(
|
||||||
React
|
React
|
||||||
) {
|
) {
|
||||||
var FormFieldRadio = React.createClass({
|
const FormFieldRadio = React.createClass({
|
||||||
render: function() {
|
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(
|
const selected_value = this.props.item[this.props.field.name];
|
||||||
function(value, index) {
|
const options = Object.keys(this.props.field.values).map(
|
||||||
|
(value, index) => {
|
||||||
return (
|
return (
|
||||||
<p key={ 'radio-' + index }>
|
<p key={ 'radio-' + index }>
|
||||||
<label>
|
<label>
|
||||||
@ -23,7 +26,7 @@ function(
|
|||||||
</label>
|
</label>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
}.bind(this)
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,36 +1,54 @@
|
|||||||
define([
|
import React from 'react'
|
||||||
'react'
|
|
||||||
],
|
|
||||||
function(
|
|
||||||
React
|
|
||||||
) {
|
|
||||||
var FormFieldSelect = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
var options =
|
|
||||||
Object.keys(this.props.field.values).map(function(value, index) {
|
|
||||||
return (
|
|
||||||
<option
|
|
||||||
key={ 'option-' + index }
|
|
||||||
value={ value }>
|
|
||||||
{ this.props.field.values[value] }
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
}.bind(this)
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
const FormFieldSelect = React.createClass({
|
||||||
<select
|
render() {
|
||||||
name={ this.props.field.name }
|
if (this.props.field.values === undefined) {
|
||||||
id={ 'field_'+this.props.field.name }
|
return false;
|
||||||
value={ this.props.item[this.props.field.name] }
|
}
|
||||||
onChange={ this.props.onValueChange }
|
|
||||||
{...this.props.field.validation}
|
let filter = false;
|
||||||
>
|
let placeholder = false;
|
||||||
{options}
|
|
||||||
</select>
|
if (this.props.field.placeholder !== undefined) {
|
||||||
|
placeholder = (
|
||||||
|
<option value="">{ this.props.field.placeholder }</option>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return FormFieldSelect;
|
if (this.props.field['filter'] !== undefined) {
|
||||||
});
|
filter = this.props.field.filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = Object.keys(this.props.field.values).map(
|
||||||
|
(value, index) => {
|
||||||
|
|
||||||
|
if (filter !== false && filter(this.props.item, value) === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<option
|
||||||
|
key={ 'option-' + index }
|
||||||
|
value={ value }>
|
||||||
|
{ this.props.field.values[value] }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={ this.props.field.name }
|
||||||
|
id={ 'field_'+this.props.field.name }
|
||||||
|
value={ this.props.item[this.props.field.name] }
|
||||||
|
onChange={ this.props.onValueChange }
|
||||||
|
{...this.props.field.validation}
|
||||||
|
>
|
||||||
|
{placeholder}
|
||||||
|
{options}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = FormFieldSelect;
|
@ -13,12 +13,22 @@ function(
|
|||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
items: [],
|
items: [],
|
||||||
initialized: false
|
select2: false
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
componentWillMount: function() {
|
||||||
|
this.loadCachedItems();
|
||||||
|
},
|
||||||
|
allowMultipleValues: function() {
|
||||||
|
return (this.props.field.multiple === true);
|
||||||
|
},
|
||||||
|
isSelect2Initialized: function() {
|
||||||
|
return (this.state.select2 === true);
|
||||||
},
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
this.loadCachedItems();
|
if(this.allowMultipleValues()) {
|
||||||
this.setupSelect2();
|
this.setupSelect2();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
componentDidUpdate: function(prevProps, prevState) {
|
componentDidUpdate: function(prevProps, prevState) {
|
||||||
if(
|
if(
|
||||||
@ -26,16 +36,22 @@ function(
|
|||||||
&& (this.props.item.id !== prevProps.item.id)
|
&& (this.props.item.id !== prevProps.item.id)
|
||||||
) {
|
) {
|
||||||
jQuery('#'+this.refs.select.id)
|
jQuery('#'+this.refs.select.id)
|
||||||
.val(this.props.item[this.props.field.name])
|
.val(this.getSelectedValues())
|
||||||
.trigger('change');
|
.trigger('change');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
if(this.allowMultipleValues()) {
|
||||||
|
this.destroySelect2();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroySelect2: function() {
|
||||||
|
if(this.isSelect2Initialized()) {
|
||||||
|
jQuery('#'+this.refs.select.id).select2('destroy');
|
||||||
|
}
|
||||||
|
},
|
||||||
setupSelect2: function() {
|
setupSelect2: function() {
|
||||||
if(
|
if(this.isSelect2Initialized()) {
|
||||||
!this.props.field.multiple
|
|
||||||
|| this.state.initialized === true
|
|
||||||
|| this.refs.select === undefined
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +61,11 @@ function(
|
|||||||
if(item.element && item.element.selected) {
|
if(item.element && item.element.selected) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return item.text;
|
if(item.title) {
|
||||||
|
return item.title;
|
||||||
|
} else {
|
||||||
|
return item.text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -63,17 +83,22 @@ function(
|
|||||||
|
|
||||||
select2.on('change', this.handleChange);
|
select2.on('change', this.handleChange);
|
||||||
|
|
||||||
select2.select2(
|
this.setState({ select2: true });
|
||||||
'val',
|
},
|
||||||
this.props.item[this.props.field.name]
|
getSelectedValues: function() {
|
||||||
);
|
if(this.props.field['selected'] !== undefined) {
|
||||||
|
return this.props.field['selected'](this.props.item);
|
||||||
this.setState({ initialized: true });
|
} else if(this.props.item !== undefined && this.props.field.name !== undefined) {
|
||||||
|
return this.props.item[this.props.field.name];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
loadCachedItems: function() {
|
loadCachedItems: function() {
|
||||||
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
|
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
|
||||||
var items = window['mailpoet_'+this.props.field.endpoint];
|
var items = window['mailpoet_'+this.props.field.endpoint];
|
||||||
|
|
||||||
|
|
||||||
if(this.props.field['filter'] !== undefined) {
|
if(this.props.field['filter'] !== undefined) {
|
||||||
items = items.filter(this.props.field.filter);
|
items = items.filter(this.props.field.filter);
|
||||||
}
|
}
|
||||||
@ -98,31 +123,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() {
|
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 (
|
return (
|
||||||
<option
|
<option
|
||||||
key={ item.id }
|
key={ 'option-'+index }
|
||||||
value={ item.id }
|
value={ value }
|
||||||
|
title={ searchLabel }
|
||||||
>
|
>
|
||||||
{ item.name }
|
{ label }
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
var default_value = (
|
|
||||||
(this.props.item !== undefined && this.props.field.name !== undefined)
|
|
||||||
? this.props.item[this.props.field.name]
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<select
|
<select
|
||||||
id={ this.props.field.id || this.props.field.name }
|
id={ this.props.field.id || this.props.field.name }
|
||||||
ref="select"
|
ref="select"
|
||||||
data-placeholder={ this.props.field.placeholder }
|
data-placeholder={ this.props.field.placeholder }
|
||||||
multiple={ this.props.field.multiple }
|
multiple={ this.props.field.multiple }
|
||||||
defaultValue={ default_value }
|
defaultValue={ this.getSelectedValues() }
|
||||||
{...this.props.field.validation}
|
{...this.props.field.validation}
|
||||||
>{ options }</select>
|
>{ options }</select>
|
||||||
);
|
);
|
||||||
@ -130,4 +172,4 @@ function(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return Selection;
|
return Selection;
|
||||||
});
|
});
|
||||||
|
@ -1,33 +1,35 @@
|
|||||||
define([
|
import React from 'react'
|
||||||
'react'
|
|
||||||
],
|
|
||||||
function(
|
|
||||||
React
|
|
||||||
) {
|
|
||||||
var FormFieldText = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
var value = this.props.item[this.props.field.name];
|
|
||||||
if(!value) { value = null; }
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className={ (this.props.field.size) ? '' : 'regular-text' }
|
|
||||||
size={
|
|
||||||
(this.props.field.size !== 'auto' && this.props.field.size > 0)
|
|
||||||
? this.props.field.size
|
|
||||||
: false
|
|
||||||
}
|
|
||||||
name={ this.props.field.name }
|
|
||||||
id={ 'field_'+this.props.field.name }
|
|
||||||
value={ value }
|
|
||||||
placeholder={ this.props.field.placeholder }
|
|
||||||
defaultValue={ this.props.field.defaultValue }
|
|
||||||
onChange={ this.props.onValueChange }
|
|
||||||
{...this.props.field.validation}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return FormFieldText;
|
const FormFieldText = React.createClass({
|
||||||
});
|
render() {
|
||||||
|
let value = this.props.item[this.props.field.name];
|
||||||
|
if (value === undefined) {
|
||||||
|
value = this.props.field.defaultValue || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
disabled={
|
||||||
|
(this.props.field['disabled'] !== undefined)
|
||||||
|
? this.props.field.disabled(this.props.item)
|
||||||
|
: false
|
||||||
|
}
|
||||||
|
className={ (this.props.field.size) ? '' : 'regular-text' }
|
||||||
|
size={
|
||||||
|
(this.props.field.size !== 'auto' && this.props.field.size > 0)
|
||||||
|
? this.props.field.size
|
||||||
|
: false
|
||||||
|
}
|
||||||
|
name={ this.props.field.name }
|
||||||
|
id={ 'field_'+this.props.field.name }
|
||||||
|
value={ value }
|
||||||
|
placeholder={ this.props.field.placeholder }
|
||||||
|
onChange={ this.props.onValueChange }
|
||||||
|
{...this.props.field.validation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = FormFieldText;
|
@ -13,10 +13,16 @@ define(
|
|||||||
Router,
|
Router,
|
||||||
FormField
|
FormField
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var Form = React.createClass({
|
var Form = React.createClass({
|
||||||
mixins: [
|
contextTypes: {
|
||||||
Router.History
|
router: React.PropTypes.object.isRequired
|
||||||
],
|
},
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
params: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -24,10 +30,20 @@ define(
|
|||||||
item: {}
|
item: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
getValues: function() {
|
||||||
|
return this.props.item ? this.props.item : this.state.item;
|
||||||
|
},
|
||||||
|
getErrors: function() {
|
||||||
|
return this.props.errors ? this.props.errors : this.state.errors;
|
||||||
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
if(this.props.params.id !== undefined) {
|
if(this.isMounted()) {
|
||||||
if(this.isMounted()) {
|
if(this.props.params.id !== undefined) {
|
||||||
this.loadItem(this.props.params.id);
|
this.loadItem(this.props.params.id);
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
item: jQuery('.mailpoet_form').serializeObject()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -37,7 +53,9 @@ define(
|
|||||||
loading: false,
|
loading: false,
|
||||||
item: {}
|
item: {}
|
||||||
});
|
});
|
||||||
this.refs.form.reset();
|
if (props.item === undefined) {
|
||||||
|
this.refs.form.reset();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.loadItem(props.params.id);
|
this.loadItem(props.params.id);
|
||||||
}
|
}
|
||||||
@ -55,7 +73,7 @@ define(
|
|||||||
loading: false,
|
loading: false,
|
||||||
item: {}
|
item: {}
|
||||||
}, function() {
|
}, function() {
|
||||||
this.history.pushState(null, '/new');
|
this.context.router.push('/new');
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -88,7 +106,6 @@ define(
|
|||||||
item[field.name] = this.state.item[field.name];
|
item[field.name] = this.state.item[field.name];
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
// set id if specified
|
// set id if specified
|
||||||
if(this.props.params.id !== undefined) {
|
if(this.props.params.id !== undefined) {
|
||||||
item.id = this.props.params.id;
|
item.id = this.props.params.id;
|
||||||
@ -105,7 +122,7 @@ define(
|
|||||||
if(this.props.onSuccess !== undefined) {
|
if(this.props.onSuccess !== undefined) {
|
||||||
this.props.onSuccess();
|
this.props.onSuccess();
|
||||||
} else {
|
} else {
|
||||||
this.history.pushState(null, '/')
|
this.context.router.push('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.props.params.id !== undefined) {
|
if(this.props.params.id !== undefined) {
|
||||||
@ -123,19 +140,23 @@ define(
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
handleValueChange: function(e) {
|
handleValueChange: function(e) {
|
||||||
var item = this.state.item,
|
if (this.props.onChange) {
|
||||||
field = e.target.name;
|
return this.props.onChange(e);
|
||||||
|
} else {
|
||||||
|
var item = this.state.item,
|
||||||
|
field = e.target.name;
|
||||||
|
|
||||||
item[field] = e.target.value;
|
item[field] = e.target.value;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
item: item
|
item: item
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
if(this.state.errors !== undefined) {
|
if(this.getErrors() !== undefined) {
|
||||||
var errors = this.state.errors.map(function(error, index) {
|
var errors = this.getErrors().map(function(error, index) {
|
||||||
return (
|
return (
|
||||||
<p key={ 'error-'+index } className="mailpoet_error">
|
<p key={ 'error-'+index } className="mailpoet_error">
|
||||||
{ error }
|
{ error }
|
||||||
@ -146,14 +167,25 @@ define(
|
|||||||
|
|
||||||
var formClasses = classNames(
|
var formClasses = classNames(
|
||||||
'mailpoet_form',
|
'mailpoet_form',
|
||||||
{ 'mailpoet_form_loading': this.state.loading }
|
{ 'mailpoet_form_loading': this.state.loading || this.props.loading }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var beforeFormContent = false;
|
||||||
|
var afterFormContent = false;
|
||||||
|
|
||||||
|
if (this.props.beforeFormContent !== undefined) {
|
||||||
|
beforeFormContent = this.props.beforeFormContent(this.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.afterFormContent !== undefined) {
|
||||||
|
afterFormContent = this.props.afterFormContent(this.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
var fields = this.props.fields.map(function(field, i) {
|
var fields = this.props.fields.map(function(field, i) {
|
||||||
return (
|
return (
|
||||||
<FormField
|
<FormField
|
||||||
field={ field }
|
field={ field }
|
||||||
item={ this.state.item }
|
item={ this.getValues() }
|
||||||
onValueChange={ this.handleValueChange }
|
onValueChange={ this.handleValueChange }
|
||||||
key={ 'field-'+i } />
|
key={ 'field-'+i } />
|
||||||
);
|
);
|
||||||
@ -167,36 +199,40 @@ define(
|
|||||||
<input
|
<input
|
||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
value="Save"
|
value={MailPoet.I18n.t('save')}
|
||||||
disabled={this.state.loading} />
|
disabled={this.state.loading} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<div>
|
||||||
id={ this.props.id }
|
{ beforeFormContent }
|
||||||
ref="form"
|
<form
|
||||||
className={ formClasses }
|
id={ this.props.id }
|
||||||
onSubmit={
|
ref="form"
|
||||||
(this.props.onSubmit !== undefined)
|
className={ formClasses }
|
||||||
? this.props.onSubmit
|
onSubmit={
|
||||||
: this.handleSubmit
|
(this.props.onSubmit !== undefined)
|
||||||
}
|
? this.props.onSubmit
|
||||||
>
|
: this.handleSubmit
|
||||||
{ errors }
|
}
|
||||||
|
>
|
||||||
|
{ errors }
|
||||||
|
|
||||||
<table className="form-table">
|
<table className="form-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
{fields}
|
{fields}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{ actions }
|
{ actions }
|
||||||
</form>
|
</form>
|
||||||
|
{ afterFormContent }
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Form;
|
return Form;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -402,11 +402,30 @@ var WysijaForm = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// hide list selection if a list widget has been dragged into the editor
|
var hasSegmentSelection = WysijaForm.hasSegmentSelection();
|
||||||
$('mailpoet_settings_segment_selection')[
|
|
||||||
(($$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0) === true)
|
if(hasSegmentSelection) {
|
||||||
? 'hide' : 'show'
|
$('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) {
|
setBlockPositions: function(event, target) {
|
||||||
// release dragging lock
|
// release dragging lock
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { Router, Route, IndexRoute } from 'react-router'
|
import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
|
||||||
|
import { createHashHistory } from 'history'
|
||||||
import FormList from 'forms/list.jsx'
|
import FormList from 'forms/list.jsx'
|
||||||
import createHashHistory from 'history/lib/createHashHistory'
|
|
||||||
|
|
||||||
let history = createHashHistory({ queryKey: false })
|
const history = useRouterHistory(createHashHistory)({ queryKey: false });
|
||||||
|
|
||||||
const App = React.createClass({
|
const App = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
@ -12,7 +12,7 @@ const App = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let container = document.getElementById('forms_container');
|
const container = document.getElementById('forms_container');
|
||||||
|
|
||||||
if(container) {
|
if(container) {
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
|
@ -8,91 +8,90 @@ import MailPoet from 'mailpoet'
|
|||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: 'Name',
|
label: MailPoet.I18n.t('formName'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'segments',
|
name: 'segments',
|
||||||
label: 'Lists',
|
label: MailPoet.I18n.t('segments'),
|
||||||
sortable: false
|
sortable: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'created_at',
|
name: 'created_at',
|
||||||
label: 'Created on',
|
label: MailPoet.I18n.t('createdOn'),
|
||||||
sortable: true
|
sortable: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
onTrash: function(response) {
|
onTrash: function(response) {
|
||||||
if(response) {
|
var count = ~~response;
|
||||||
let message = null;
|
var 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message !== null) {
|
if(count === 1) {
|
||||||
MailPoet.Notice.success(message);
|
message = (
|
||||||
}
|
MailPoet.I18n.t('oneFormTrashed')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
message = (
|
||||||
|
MailPoet.I18n.t('multipleFormsTrashed')
|
||||||
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
},
|
},
|
||||||
onDelete: function(response) {
|
onDelete: function(response) {
|
||||||
if(response) {
|
var count = ~~response;
|
||||||
let message = null;
|
var message = null;
|
||||||
if(~~response === 1) {
|
|
||||||
message = (
|
|
||||||
'1 form was permanently deleted.'
|
|
||||||
);
|
|
||||||
} else if(~~response > 1) {
|
|
||||||
message = (
|
|
||||||
'%$1d forms were permanently deleted.'
|
|
||||||
).replace('%$1d', ~~response);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message !== null) {
|
if(count === 1) {
|
||||||
MailPoet.Notice.success(message);
|
message = (
|
||||||
}
|
MailPoet.I18n.t('oneFormDeleted')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
message = (
|
||||||
|
MailPoet.I18n.t('multipleFormsDeleted')
|
||||||
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
},
|
},
|
||||||
onRestore: function(response) {
|
onRestore: function(response) {
|
||||||
if(response) {
|
var count = ~~response;
|
||||||
let message = null;
|
var 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message !== null) {
|
if(count === 1) {
|
||||||
MailPoet.Notice.success(message);
|
message = (
|
||||||
}
|
MailPoet.I18n.t('oneFormRestored')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
message = (
|
||||||
|
MailPoet.I18n.t('multipleFormsRestored')
|
||||||
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const bulk_actions = [
|
||||||
|
{
|
||||||
|
name: 'trash',
|
||||||
|
label: MailPoet.I18n.t('trash'),
|
||||||
|
onSuccess: messages.onTrash
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const item_actions = [
|
const item_actions = [
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
label: 'Edit',
|
label: MailPoet.I18n.t('edit'),
|
||||||
link: function(item) {
|
link: function(item) {
|
||||||
return (
|
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',
|
name: 'duplicate_form',
|
||||||
label: 'Duplicate',
|
label: MailPoet.I18n.t('duplicate'),
|
||||||
onClick: function(item, refresh) {
|
onClick: function(item, refresh) {
|
||||||
return MailPoet.Ajax.post({
|
return MailPoet.Ajax.post({
|
||||||
endpoint: 'forms',
|
endpoint: 'forms',
|
||||||
@ -100,7 +99,7 @@ const item_actions = [
|
|||||||
data: item.id
|
data: item.id
|
||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
('Form "%$1s" has been duplicated.').replace('%$1s', response.name)
|
(MailPoet.I18n.t('formDuplicated')).replace('%$1s', response.name)
|
||||||
);
|
);
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
@ -111,14 +110,6 @@ const item_actions = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const bulk_actions = [
|
|
||||||
{
|
|
||||||
name: 'trash',
|
|
||||||
label: 'Trash',
|
|
||||||
onSuccess: messages.onTrash
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const FormList = React.createClass({
|
const FormList = React.createClass({
|
||||||
createForm() {
|
createForm() {
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
@ -147,15 +138,18 @@ const FormList = React.createClass({
|
|||||||
<div>
|
<div>
|
||||||
<td className={ row_classes }>
|
<td className={ row_classes }>
|
||||||
<strong>
|
<strong>
|
||||||
<a>{ form.name }</a>
|
<a
|
||||||
|
className="row-title"
|
||||||
|
href={ `admin.php?page=mailpoet-form-editor&id=${form.id}` }
|
||||||
|
>{ form.name }</a>
|
||||||
</strong>
|
</strong>
|
||||||
{ actions }
|
{ actions }
|
||||||
</td>
|
</td>
|
||||||
<td className="column-format" data-colname="Lists">
|
<td className="column-format" data-colname={MailPoet.I18n.t('segments')}>
|
||||||
{ segments }
|
{ segments }
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Created on">
|
<td className="column-date" data-colname={MailPoet.I18n.t('createdOn')}>
|
||||||
<abbr>{ form.created_at }</abbr>
|
<abbr>{ MailPoet.Date.format(form.created_at) }</abbr>
|
||||||
</td>
|
</td>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -163,20 +157,20 @@ const FormList = React.createClass({
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="title">
|
<h1 className="title">
|
||||||
Forms <a
|
{MailPoet.I18n.t('pageTitle')} <a
|
||||||
className="add-new-h2"
|
className="page-title-action"
|
||||||
href="javascript:;"
|
href="javascript:;"
|
||||||
onClick={ this.createForm }
|
onClick={ this.createForm }
|
||||||
>New</a>
|
>{MailPoet.I18n.t('new')}</a>
|
||||||
</h2>
|
</h1>
|
||||||
|
|
||||||
<Listing
|
<Listing
|
||||||
|
limit={ mailpoet_listing_per_page }
|
||||||
location={ this.props.location }
|
location={ this.props.location }
|
||||||
params={ this.props.params }
|
params={ this.props.params }
|
||||||
messages={ messages }
|
messages={ messages }
|
||||||
search={ false }
|
search={ false }
|
||||||
limit={ 1000 }
|
|
||||||
endpoint="forms"
|
endpoint="forms"
|
||||||
onRenderItem={ this.renderItem }
|
onRenderItem={ this.renderItem }
|
||||||
columns={ columns }
|
columns={ columns }
|
||||||
@ -188,4 +182,4 @@ const FormList = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = FormList;
|
module.exports = FormList;
|
||||||
|
@ -140,5 +140,20 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
|||||||
return parseInt(string, 10);
|
return parseInt(string, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper('fontWithFallback', function(font) {
|
||||||
|
switch(font) {
|
||||||
|
case 'Arial': return new Handlebars.SafeString("Arial, 'Helvetica Neue', Helvetica, sans-serif");
|
||||||
|
case 'Comic Sans MS': return new Handlebars.SafeString("'Comic Sans MS', 'Marker Felt-Thin', Arial, sans-serif");
|
||||||
|
case 'Courier New': return new Handlebars.SafeString("'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace");
|
||||||
|
case 'Georgia': return new Handlebars.SafeString("Georgia, Times, 'Times New Roman', serif");
|
||||||
|
case 'Lucida': return new Handlebars.SafeString("'Lucida Sans Unicode', 'Lucida Grande', sans-serif");
|
||||||
|
case 'Tahoma': return new Handlebars.SafeString("Tahoma, Verdana, Segoe, sans-serif");
|
||||||
|
case 'Times New Roman': return new Handlebars.SafeString("'Times New Roman', Times, Baskerville, Georgia, serif");
|
||||||
|
case 'Trebuchet MS': return new Handlebars.SafeString("'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif");
|
||||||
|
case 'Verdana': return new Handlebars.SafeString("Verdana, Geneva, sans-serif");
|
||||||
|
default: return font;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
window.Handlebars = Handlebars;
|
window.Handlebars = Handlebars;
|
||||||
});
|
});
|
||||||
|
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
@ -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([
|
define([
|
||||||
'react'
|
'react',
|
||||||
|
'mailpoet'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React
|
React,
|
||||||
|
MailPoet
|
||||||
) {
|
) {
|
||||||
var ListingBulkActions = React.createClass({
|
var ListingBulkActions = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
@ -82,7 +84,7 @@ function(
|
|||||||
<label
|
<label
|
||||||
className="screen-reader-text"
|
className="screen-reader-text"
|
||||||
htmlFor="bulk-action-selector-top">
|
htmlFor="bulk-action-selector-top">
|
||||||
Select bulk action
|
{MailPoet.I18n.t('selectBulkAction')}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
@ -91,7 +93,7 @@ function(
|
|||||||
value={ this.state.action }
|
value={ this.state.action }
|
||||||
onChange={this.handleChangeAction}
|
onChange={this.handleChangeAction}
|
||||||
>
|
>
|
||||||
<option value="">Bulk Actions</option>
|
<option value="">{MailPoet.I18n.t('bulkActions')}</option>
|
||||||
{ this.props.bulk_actions.map(function(action, index) {
|
{ this.props.bulk_actions.map(function(action, index) {
|
||||||
return (
|
return (
|
||||||
<option
|
<option
|
||||||
@ -104,7 +106,7 @@ function(
|
|||||||
<input
|
<input
|
||||||
onClick={ this.handleApplyAction }
|
onClick={ this.handleApplyAction }
|
||||||
type="submit"
|
type="submit"
|
||||||
defaultValue="Apply"
|
defaultValue={MailPoet.I18n.t('apply')}
|
||||||
className="button action" />
|
className="button action" />
|
||||||
|
|
||||||
{ this.state.extra }
|
{ this.state.extra }
|
||||||
@ -114,4 +116,4 @@ function(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return ListingBulkActions;
|
return ListingBulkActions;
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
define([
|
define([
|
||||||
'react',
|
'react',
|
||||||
'jquery'
|
'jquery',
|
||||||
|
'mailpoet'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React,
|
||||||
jQuery
|
jQuery,
|
||||||
|
MailPoet
|
||||||
) {
|
) {
|
||||||
var ListingFilters = React.createClass({
|
var ListingFilters = React.createClass({
|
||||||
handleFilterAction: function() {
|
handleFilterAction: function() {
|
||||||
@ -14,6 +16,9 @@ function(
|
|||||||
})
|
})
|
||||||
return this.props.onSelectFilter(filters);
|
return this.props.onSelectFilter(filters);
|
||||||
},
|
},
|
||||||
|
handleEmptyTrash: function() {
|
||||||
|
return this.props.onEmptyTrash();
|
||||||
|
},
|
||||||
getAvailableFilters: function() {
|
getAvailableFilters: function() {
|
||||||
let filters = this.props.filters;
|
let filters = this.props.filters;
|
||||||
|
|
||||||
@ -34,7 +39,7 @@ function(
|
|||||||
const available_filters = this.getAvailableFilters()
|
const available_filters = this.getAvailableFilters()
|
||||||
.map(function(filter, i) {
|
.map(function(filter, i) {
|
||||||
let default_value = false;
|
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]
|
default_value = selected_filters[filter]
|
||||||
} else {
|
} else {
|
||||||
jQuery(`select[name="${filter}"]`).val('');
|
jQuery(`select[name="${filter}"]`).val('');
|
||||||
@ -60,20 +65,34 @@ function(
|
|||||||
|
|
||||||
let button = false;
|
let button = false;
|
||||||
|
|
||||||
if(available_filters.length > 0) {
|
if (available_filters.length > 0) {
|
||||||
button = (
|
button = (
|
||||||
<input
|
<input
|
||||||
|
id="post-query-submit"
|
||||||
onClick={ this.handleFilterAction }
|
onClick={ this.handleFilterAction }
|
||||||
type="submit"
|
type="submit"
|
||||||
defaultValue="Filter"
|
defaultValue={MailPoet.I18n.t('filter')}
|
||||||
className="button" />
|
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 (
|
return (
|
||||||
<div className="alignleft actions actions">
|
<div className="alignleft actions actions">
|
||||||
{ available_filters }
|
{ available_filters }
|
||||||
{ button }
|
{ button }
|
||||||
|
{ empty_trash }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
href="javascript:;"
|
href="javascript:;"
|
||||||
className={classes}
|
className={classes}
|
||||||
onClick={this.handleSelect.bind(this, group.name)} >
|
onClick={this.handleSelect.bind(this, group.name)} >
|
||||||
{group.label} <span className="count">({ group.count })</span>
|
{group.label} <span className="count">({ group.count.toLocaleString() })</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
define(['react', 'classnames'], function(React, classNames) {
|
define([
|
||||||
|
'react',
|
||||||
|
'classnames',
|
||||||
|
'mailpoet'
|
||||||
|
], function(
|
||||||
|
React,
|
||||||
|
classNames,
|
||||||
|
MailPoet
|
||||||
|
) {
|
||||||
|
|
||||||
var ListingHeader = React.createClass({
|
var ListingHeader = React.createClass({
|
||||||
handleSelectItems: function() {
|
handleSelectItems: function() {
|
||||||
@ -28,7 +36,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
<th
|
<th
|
||||||
className="manage-column column-cb check-column">
|
className="manage-column column-cb check-column">
|
||||||
<label className="screen-reader-text">
|
<label className="screen-reader-text">
|
||||||
{ 'Select All' }
|
{MailPoet.I18n.t('selectAll')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@ -87,4 +95,4 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return ListingHeader;
|
return ListingHeader;
|
||||||
});
|
});
|
||||||
|
@ -74,10 +74,11 @@ define(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var custom_actions = this.props.item_actions;
|
const custom_actions = this.props.item_actions;
|
||||||
var item_actions = false;
|
let item_actions = false;
|
||||||
|
|
||||||
if(custom_actions.length > 0) {
|
if(custom_actions.length > 0) {
|
||||||
|
let is_first = true;
|
||||||
item_actions = custom_actions.map(function(action, index) {
|
item_actions = custom_actions.map(function(action, index) {
|
||||||
if(action.display !== undefined) {
|
if(action.display !== undefined) {
|
||||||
if(action.display(this.props.item) === false) {
|
if(action.display(this.props.item) === false) {
|
||||||
@ -85,42 +86,44 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let custom_action = null;
|
||||||
|
|
||||||
if(action.name === 'trash') {
|
if(action.name === 'trash') {
|
||||||
return (
|
custom_action = (
|
||||||
<span key={ 'action-'+index } className="trash">
|
<span key={ 'action-'+index } className="trash">
|
||||||
{(index > 0) ? ' | ' : ''}
|
{(!is_first) ? ' | ' : ''}
|
||||||
<a
|
<a
|
||||||
href="javascript:;"
|
href="javascript:;"
|
||||||
onClick={ this.handleTrashItem.bind(
|
onClick={ this.handleTrashItem.bind(
|
||||||
null,
|
null,
|
||||||
this.props.item.id
|
this.props.item.id
|
||||||
) }>
|
) }>
|
||||||
Trash
|
{MailPoet.I18n.t('trash')}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else if(action.refresh) {
|
} else if(action.refresh) {
|
||||||
return (
|
custom_action = (
|
||||||
<span
|
<span
|
||||||
onClick={ this.props.onRefreshItems }
|
onClick={ this.props.onRefreshItems }
|
||||||
key={ 'action-'+index } className={ action.name }>
|
key={ 'action-'+index } className={ action.name }>
|
||||||
{(index > 0) ? ' | ' : ''}
|
{(!is_first) ? ' | ' : ''}
|
||||||
{ action.link(this.props.item) }
|
{ action.link(this.props.item) }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else if(action.link) {
|
} else if(action.link) {
|
||||||
return (
|
custom_action = (
|
||||||
<span
|
<span
|
||||||
key={ 'action-'+index } className={ action.name }>
|
key={ 'action-'+index } className={ action.name }>
|
||||||
{(index > 0) ? ' | ' : ''}
|
{(!is_first) ? ' | ' : ''}
|
||||||
{ action.link(this.props.item) }
|
{ action.link(this.props.item) }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
custom_action = (
|
||||||
<span
|
<span
|
||||||
key={ 'action-'+index } className={ action.name }>
|
key={ 'action-'+index } className={ action.name }>
|
||||||
{(index > 0) ? ' | ' : ''}
|
{(!is_first) ? ' | ' : ''}
|
||||||
<a href="javascript:;" onClick={
|
<a href="javascript:;" onClick={
|
||||||
(action.onClick !== undefined)
|
(action.onClick !== undefined)
|
||||||
? action.onClick.bind(null,
|
? action.onClick.bind(null,
|
||||||
@ -132,11 +135,17 @@ define(
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(custom_action !== null && is_first === true) {
|
||||||
|
is_first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return custom_action;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
} else {
|
} else {
|
||||||
item_actions = (
|
item_actions = (
|
||||||
<span className="edit">
|
<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>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -152,7 +161,7 @@ define(
|
|||||||
null,
|
null,
|
||||||
this.props.item.id
|
this.props.item.id
|
||||||
)}
|
)}
|
||||||
>Restore</a>
|
>{MailPoet.I18n.t('restore')}</a>
|
||||||
</span>
|
</span>
|
||||||
{ ' | ' }
|
{ ' | ' }
|
||||||
<span className="delete">
|
<span className="delete">
|
||||||
@ -163,13 +172,13 @@ define(
|
|||||||
null,
|
null,
|
||||||
this.props.item.id
|
this.props.item.id
|
||||||
)}
|
)}
|
||||||
>Delete permanently</a>
|
>{MailPoet.I18n.t('deletePermanently')}</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
||||||
className="toggle-row" type="button">
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -182,7 +191,7 @@ define(
|
|||||||
<button
|
<button
|
||||||
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
||||||
className="toggle-row" type="button">
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -214,8 +223,8 @@ define(
|
|||||||
className="colspanchange">
|
className="colspanchange">
|
||||||
{
|
{
|
||||||
(this.props.loading === true)
|
(this.props.loading === true)
|
||||||
? MailPoetI18n.loadingItems
|
? MailPoet.I18n.t('loadingItems')
|
||||||
: MailPoetI18n.noItemsFound
|
: MailPoet.I18n.t('noItemsFound')
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -241,8 +250,8 @@ define(
|
|||||||
}>
|
}>
|
||||||
{
|
{
|
||||||
(this.props.selection !== 'all')
|
(this.props.selection !== 'all')
|
||||||
? MailPoetI18n.selectAllLabel
|
? MailPoet.I18n.t('selectAllLabel')
|
||||||
: MailPoetI18n.selectedAllLabel.replace(
|
: MailPoet.I18n.t('selectedAllLabel').replace(
|
||||||
'%d',
|
'%d',
|
||||||
this.props.count
|
this.props.count
|
||||||
)
|
)
|
||||||
@ -252,8 +261,8 @@ define(
|
|||||||
onClick={ this.props.onSelectAll }
|
onClick={ this.props.onSelectAll }
|
||||||
href="javascript:;">{
|
href="javascript:;">{
|
||||||
(this.props.selection !== 'all')
|
(this.props.selection !== 'all')
|
||||||
? MailPoetI18n.selectAllLink
|
? MailPoet.I18n.t('selectAllLink')
|
||||||
: MailPoetI18n.clearSelection
|
: MailPoet.I18n.t('clearSelection')
|
||||||
}</a>
|
}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -286,9 +295,9 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
var Listing = React.createClass({
|
var Listing = React.createClass({
|
||||||
mixins: [
|
contextTypes: {
|
||||||
Router.History
|
router: React.PropTypes.object.isRequired
|
||||||
],
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -350,9 +359,12 @@ define(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default overrides
|
||||||
if(this.props.limit !== undefined) {
|
if(this.props.limit !== undefined) {
|
||||||
state.limit = Math.abs(~~this.props.limit);
|
state.limit = Math.abs(~~this.props.limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(state, function() {
|
this.setState(state, function() {
|
||||||
this.getItems();
|
this.getItems();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
@ -389,7 +401,7 @@ define(
|
|||||||
|
|
||||||
if(this.props.location) {
|
if(this.props.location) {
|
||||||
if(this.props.location.pathname !== params) {
|
if(this.props.location.pathname !== params) {
|
||||||
this.history.pushState(null, `${params}`)
|
this.context.router.push(`${params}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -504,10 +516,21 @@ define(
|
|||||||
this.getItems();
|
this.getItems();
|
||||||
}.bind(this));
|
}.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) {
|
handleBulkAction: function(selected_ids, params, callback) {
|
||||||
if(
|
if(
|
||||||
this.state.selection === false
|
this.state.selection === false
|
||||||
&& this.state.selected_ids.length === 0
|
&& this.state.selected_ids.length === 0
|
||||||
|
&& selected_ids !== 'all'
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -520,8 +543,10 @@ define(
|
|||||||
limit: 0,
|
limit: 0,
|
||||||
filter: this.state.filter,
|
filter: this.state.filter,
|
||||||
group: this.state.group,
|
group: this.state.group,
|
||||||
search: this.state.search,
|
search: this.state.search
|
||||||
selection: selected_ids
|
}
|
||||||
|
if(selected_ids !== 'all') {
|
||||||
|
data.listing.selection = selected_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
@ -656,12 +681,12 @@ define(
|
|||||||
bulk_actions = [
|
bulk_actions = [
|
||||||
{
|
{
|
||||||
name: 'restore',
|
name: 'restore',
|
||||||
label: 'Restore',
|
label: MailPoet.I18n.t('restore'),
|
||||||
onSuccess: this.props.messages.onRestore
|
onSuccess: this.props.messages.onRestore
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'delete',
|
name: 'delete',
|
||||||
label: 'Delete permanently',
|
label: MailPoet.I18n.t('deletePermanently'),
|
||||||
onSuccess: this.props.messages.onDelete
|
onSuccess: this.props.messages.onDelete
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -708,6 +733,7 @@ define(
|
|||||||
{ search }
|
{ search }
|
||||||
<div className="tablenav top clearfix">
|
<div className="tablenav top clearfix">
|
||||||
<ListingBulkActions
|
<ListingBulkActions
|
||||||
|
count={ this.state.count }
|
||||||
bulk_actions={ bulk_actions }
|
bulk_actions={ bulk_actions }
|
||||||
selection={ this.state.selection }
|
selection={ this.state.selection }
|
||||||
selected_ids={ this.state.selected_ids }
|
selected_ids={ this.state.selected_ids }
|
||||||
@ -715,7 +741,10 @@ define(
|
|||||||
<ListingFilters
|
<ListingFilters
|
||||||
filters={ this.state.filters }
|
filters={ this.state.filters }
|
||||||
filter={ this.state.filter }
|
filter={ this.state.filter }
|
||||||
onSelectFilter={ this.handleFilter } />
|
group={ this.state.group }
|
||||||
|
onSelectFilter={ this.handleFilter }
|
||||||
|
onEmptyTrash={ this.handleEmptyTrash }
|
||||||
|
/>
|
||||||
<ListingPages
|
<ListingPages
|
||||||
count={ this.state.count }
|
count={ this.state.count }
|
||||||
page={ this.state.page }
|
page={ this.state.page }
|
||||||
@ -728,8 +757,8 @@ define(
|
|||||||
onSort={ this.handleSort }
|
onSort={ this.handleSort }
|
||||||
onSelectItems={ this.handleSelectItems }
|
onSelectItems={ this.handleSelectItems }
|
||||||
selection={ this.state.selection }
|
selection={ this.state.selection }
|
||||||
sort_by={ this.state.sort_by }
|
sort_by={ sort_by }
|
||||||
sort_order={ this.state.sort_order }
|
sort_order={ sort_order }
|
||||||
columns={ this.props.columns }
|
columns={ this.props.columns }
|
||||||
is_selectable={ bulk_actions.length > 0 } />
|
is_selectable={ bulk_actions.length > 0 } />
|
||||||
</thead>
|
</thead>
|
||||||
@ -758,8 +787,8 @@ define(
|
|||||||
onSort={ this.handleSort }
|
onSort={ this.handleSort }
|
||||||
onSelectItems={ this.handleSelectItems }
|
onSelectItems={ this.handleSelectItems }
|
||||||
selection={ this.state.selection }
|
selection={ this.state.selection }
|
||||||
sort_by={ this.state.sort_by }
|
sort_by={ sort_by }
|
||||||
sort_order={ this.state.sort_order }
|
sort_order={ sort_order }
|
||||||
columns={ this.props.columns }
|
columns={ this.props.columns }
|
||||||
is_selectable={ bulk_actions.length > 0 } />
|
is_selectable={ bulk_actions.length > 0 } />
|
||||||
</tfoot>
|
</tfoot>
|
||||||
@ -767,6 +796,7 @@ define(
|
|||||||
</table>
|
</table>
|
||||||
<div className="tablenav bottom">
|
<div className="tablenav bottom">
|
||||||
<ListingBulkActions
|
<ListingBulkActions
|
||||||
|
count={ this.state.count }
|
||||||
bulk_actions={ bulk_actions }
|
bulk_actions={ bulk_actions }
|
||||||
selection={ this.state.selection }
|
selection={ this.state.selection }
|
||||||
selected_ids={ this.state.selected_ids }
|
selected_ids={ this.state.selected_ids }
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
define(['react', 'classnames'], function(React, classNames) {
|
define([
|
||||||
|
'react',
|
||||||
|
'classnames',
|
||||||
|
'mailpoet'
|
||||||
|
], function(
|
||||||
|
React,
|
||||||
|
classNames,
|
||||||
|
MailPoet
|
||||||
|
) {
|
||||||
|
|
||||||
var ListingPages = React.createClass({
|
var ListingPages = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
@ -7,7 +15,11 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setPage: function(page) {
|
setPage: function(page) {
|
||||||
this.props.onSetPage(page);
|
this.setState({
|
||||||
|
page: null
|
||||||
|
}, function () {
|
||||||
|
this.props.onSetPage(this.constrainPage(page));
|
||||||
|
}.bind(this));
|
||||||
},
|
},
|
||||||
setFirstPage: function() {
|
setFirstPage: function() {
|
||||||
this.setPage(1);
|
this.setPage(1);
|
||||||
@ -16,10 +28,14 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
this.setPage(this.getLastPage());
|
this.setPage(this.getLastPage());
|
||||||
},
|
},
|
||||||
setPreviousPage: function() {
|
setPreviousPage: function() {
|
||||||
this.setPage(this.constrainPage(this.props.page - 1));
|
this.setPage(this.constrainPage(
|
||||||
|
parseInt(this.props.page, 10) - 1)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
setNextPage: function() {
|
setNextPage: function() {
|
||||||
this.setPage(this.constrainPage(this.props.page + 1));
|
this.setPage(this.constrainPage(
|
||||||
|
parseInt(this.props.page, 10) + 1)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
constrainPage: function(page) {
|
constrainPage: function(page) {
|
||||||
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
|
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
|
||||||
@ -27,14 +43,16 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
handleSetManualPage: function(e) {
|
handleSetManualPage: function(e) {
|
||||||
if(e.which === 13) {
|
if(e.which === 13) {
|
||||||
this.setPage(this.state.page);
|
this.setPage(this.state.page);
|
||||||
this.setState({ page: null });
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleChangeManualPage: function(e) {
|
handleChangeManualPage: function(e) {
|
||||||
this.setState({
|
this.setState({
|
||||||
page: this.constrainPage(e.target.value)
|
page: e.target.value
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleBlurManualPage: function(e) {
|
||||||
|
this.setPage(e.target.value);
|
||||||
|
},
|
||||||
getLastPage: function() {
|
getLastPage: function() {
|
||||||
return Math.ceil(this.props.count / this.props.limit);
|
return Math.ceil(this.props.count / this.props.limit);
|
||||||
},
|
},
|
||||||
@ -62,7 +80,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
<a href="javascript:;"
|
<a href="javascript:;"
|
||||||
onClick={ this.setPreviousPage }
|
onClick={ this.setPreviousPage }
|
||||||
className="prev-page">
|
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>
|
<span aria-hidden="true">‹</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
@ -73,7 +91,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
<a href="javascript:;"
|
<a href="javascript:;"
|
||||||
onClick={ this.setFirstPage }
|
onClick={ this.setFirstPage }
|
||||||
className="first-page">
|
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>
|
<span aria-hidden="true">«</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
@ -84,7 +102,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
<a href="javascript:;"
|
<a href="javascript:;"
|
||||||
onClick={ this.setNextPage }
|
onClick={ this.setNextPage }
|
||||||
className="next-page">
|
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>
|
<span aria-hidden="true">›</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
@ -95,12 +113,17 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
<a href="javascript:;"
|
<a href="javascript:;"
|
||||||
onClick={ this.setLastPage }
|
onClick={ this.setLastPage }
|
||||||
className="last-page">
|
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>
|
<span aria-hidden="true">»</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pageValue = this.props.page;
|
||||||
|
if(this.state.page !== null) {
|
||||||
|
pageValue = this.state.page;
|
||||||
|
}
|
||||||
|
|
||||||
pagination = (
|
pagination = (
|
||||||
<span className="pagination-links">
|
<span className="pagination-links">
|
||||||
{firstPage}
|
{firstPage}
|
||||||
@ -110,21 +133,22 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
<span className="paging-input">
|
<span className="paging-input">
|
||||||
<label
|
<label
|
||||||
className="screen-reader-text"
|
className="screen-reader-text"
|
||||||
htmlFor="current-page-selector">Current Page</label>
|
htmlFor="current-page-selector">{MailPoet.I18n.t('currentPage')}</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={ this.handleChangeManualPage }
|
onChange={ this.handleChangeManualPage }
|
||||||
onKeyUp={ this.handleSetManualPage }
|
onKeyUp={ this.handleSetManualPage }
|
||||||
|
onBlur={ this.handleBlurManualPage }
|
||||||
aria-describedby="table-paging"
|
aria-describedby="table-paging"
|
||||||
size="1"
|
size="2"
|
||||||
ref="page"
|
ref="page"
|
||||||
value={ this.state.page || this.props.page }
|
value={ pageValue }
|
||||||
name="paged"
|
name="paged"
|
||||||
id="current-page-selector"
|
id="current-page-selector"
|
||||||
className="current-page" />
|
className="current-page" />
|
||||||
of
|
{MailPoet.I18n.t('pageOutOf')}
|
||||||
<span className="total-pages">
|
<span className="total-pages">
|
||||||
{Math.ceil(this.props.count / this.props.limit)}
|
{Math.ceil(this.props.count / this.props.limit).toLocaleString()}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@ -142,7 +166,9 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ classes }>
|
<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.toLocaleString())
|
||||||
|
}</span>
|
||||||
{ pagination }
|
{ pagination }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -151,4 +177,4 @@ define(['react', 'classnames'], function(React, classNames) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return ListingPages;
|
return ListingPages;
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
define(['react'], function(React) {
|
define([
|
||||||
|
'mailpoet',
|
||||||
|
'react'
|
||||||
|
], function(
|
||||||
|
MailPoet,
|
||||||
|
React
|
||||||
|
) {
|
||||||
|
|
||||||
var ListingSearch = React.createClass({
|
var ListingSearch = React.createClass({
|
||||||
handleSearch: function(e) {
|
handleSearch: function(e) {
|
||||||
@ -18,7 +24,7 @@ define(['react'], function(React) {
|
|||||||
<form name="search" onSubmit={this.handleSearch}>
|
<form name="search" onSubmit={this.handleSearch}>
|
||||||
<p className="search-box">
|
<p className="search-box">
|
||||||
<label htmlFor="search_input" className="screen-reader-text">
|
<label htmlFor="search_input" className="screen-reader-text">
|
||||||
Search
|
{MailPoet.I18n.t('searchLabel')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
@ -28,7 +34,7 @@ define(['react'], function(React) {
|
|||||||
defaultValue={this.props.search} />
|
defaultValue={this.props.search} />
|
||||||
<input
|
<input
|
||||||
type="submit"
|
type="submit"
|
||||||
defaultValue={MailPoetI18n.searchLabel}
|
defaultValue={MailPoet.I18n.t('searchLabel')}
|
||||||
className="button" />
|
className="button" />
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
@ -12,9 +12,19 @@ define([
|
|||||||
'newsletter_editor/blocks/button',
|
'newsletter_editor/blocks/button',
|
||||||
'newsletter_editor/blocks/divider',
|
'newsletter_editor/blocks/divider',
|
||||||
'newsletter_editor/components/communication',
|
'newsletter_editor/components/communication',
|
||||||
|
'mailpoet',
|
||||||
'underscore',
|
'underscore',
|
||||||
'jquery'
|
'jquery'
|
||||||
], function(App, BaseBlock, ButtonBlock, DividerBlock, CommunicationComponent, _, jQuery) {
|
], function(
|
||||||
|
App,
|
||||||
|
BaseBlock,
|
||||||
|
ButtonBlock,
|
||||||
|
DividerBlock,
|
||||||
|
CommunicationComponent,
|
||||||
|
MailPoet,
|
||||||
|
_,
|
||||||
|
jQuery
|
||||||
|
) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -32,10 +42,10 @@ define([
|
|||||||
inclusionType: 'include', // 'include'|'exclude'
|
inclusionType: 'include', // 'include'|'exclude'
|
||||||
displayType: 'excerpt', // 'excerpt'|'full'|'titleOnly'
|
displayType: 'excerpt', // 'excerpt'|'full'|'titleOnly'
|
||||||
titleFormat: 'h1', // 'h1'|'h2'|'h3'|'ul'
|
titleFormat: 'h1', // 'h1'|'h2'|'h3'|'ul'
|
||||||
titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock',
|
|
||||||
titleAlignment: 'left', // 'left'|'center'|'right'
|
titleAlignment: 'left', // 'left'|'center'|'right'
|
||||||
titleIsLink: false, // false|true
|
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'
|
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
|
||||||
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
|
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
|
||||||
authorPrecededBy: 'Author:',
|
authorPrecededBy: 'Author:',
|
||||||
@ -63,7 +73,7 @@ define([
|
|||||||
initialize: function() {
|
initialize: function() {
|
||||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||||
this.fetchPosts();
|
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('readMoreButton'), 'change', this._scheduleFetchPosts);
|
||||||
this.listenTo(this.get('divider'), '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.get('_container').get('blocks').reset(content, {parse: true});
|
||||||
that.trigger('postsChanged');
|
that.trigger('postsChanged');
|
||||||
}).fail(function(error) {
|
}).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
|
* ALC posts on each model change
|
||||||
*/
|
*/
|
||||||
_scheduleFetchPosts: function() {
|
_scheduleFetchPosts: function() {
|
||||||
var timeout = 2000,
|
var timeout = 500,
|
||||||
that = this;
|
that = this;
|
||||||
if (this._fetchPostsTimer !== undefined) {
|
if (this._fetchPostsTimer !== undefined) {
|
||||||
clearTimeout(this._fetchPostsTimer);
|
clearTimeout(this._fetchPostsTimer);
|
||||||
@ -142,9 +152,9 @@ define([
|
|||||||
"keyup .mailpoet_automated_latest_content_show_amount": _.partial(this.changeField, "amount"),
|
"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_content_type": _.partial(this.changeField, "contentType"),
|
||||||
"change .mailpoet_automated_latest_content_include_or_exclude": _.partial(this.changeField, "inclusionType"),
|
"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_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"),
|
"change .mailpoet_automated_latest_content_show_author": _.partial(this.changeField, "showAuthor"),
|
||||||
"keyup .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
"keyup .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
||||||
"change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"),
|
"change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"),
|
||||||
@ -273,12 +283,13 @@ define([
|
|||||||
},
|
},
|
||||||
changeDisplayType: function(event) {
|
changeDisplayType: function(event) {
|
||||||
var value = jQuery(event.target).val();
|
var value = jQuery(event.target).val();
|
||||||
|
|
||||||
if (value == 'titleOnly') {
|
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_title_as_list').removeClass('mailpoet_hidden');
|
||||||
|
this.$('.mailpoet_automated_latest_content_image_full_width_option').addClass('mailpoet_hidden');
|
||||||
} else {
|
} 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_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
|
// Reset titleFormat if it was set to List when switching away from displayType=titleOnly
|
||||||
if (this.model.get('titleFormat') === 'ul') {
|
if (this.model.get('titleFormat') === 'ul') {
|
||||||
@ -287,6 +298,12 @@ define([
|
|||||||
this.$('.mailpoet_automated_latest_content_title_as_link').removeClass('mailpoet_hidden');
|
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);
|
this.changeField('displayType', event);
|
||||||
},
|
},
|
||||||
changeTitleFormat: function(event) {
|
changeTitleFormat: function(event) {
|
||||||
|
@ -32,6 +32,7 @@ define([
|
|||||||
fontColor: '#000000',
|
fontColor: '#000000',
|
||||||
fontFamily: 'Arial',
|
fontFamily: 'Arial',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
|
fontWeight: 'normal', // 'normal'|'bold'
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -72,6 +73,7 @@ define([
|
|||||||
"change .mailpoet_field_button_font_size": _.partial(this.changeField, "styles.block.fontSize"),
|
"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_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||||
"change .mailpoet_field_button_border_color": _.partial(this.changeColorField, "styles.block.borderColor"),
|
"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)),
|
"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)),
|
"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());
|
this.$(fieldToUpdate).val(jQuery(event.target).val());
|
||||||
callable(event);
|
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({
|
Module.ButtonWidgetView = base.WidgetView.extend({
|
||||||
|
@ -16,7 +16,7 @@ define([
|
|||||||
defaults: function() {
|
defaults: function() {
|
||||||
return this._getDefaults({
|
return this._getDefaults({
|
||||||
type: 'footer',
|
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="[link:subscription_unsubscribe_url]">Unsubscribe</a> | <a href="[link:subscription_manage_url]">Manage subscription</a><br /><b>Add your postal address here!</b>',
|
||||||
styles: {
|
styles: {
|
||||||
block: {
|
block: {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
@ -41,7 +41,7 @@ define([
|
|||||||
getTemplate: function() { return templates.footerBlock; },
|
getTemplate: function() { return templates.footerBlock; },
|
||||||
modelEvents: _.extend({
|
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',
|
'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; },
|
onDragSubstituteBy: function() { return Module.FooterWidgetView; },
|
||||||
onRender: function() {
|
onRender: function() {
|
||||||
this.toolsView = new Module.FooterBlockToolsView({ model: this.model });
|
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",
|
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",
|
invalid_elements: "script",
|
||||||
style_formats: [
|
block_formats: 'Paragraph=p',
|
||||||
{title: 'Paragraph', block: 'p'},
|
|
||||||
],
|
|
||||||
|
|
||||||
plugins: "link textcolor mailpoet_custom_fields",
|
plugins: "link textcolor colorpicker mailpoet_custom_fields",
|
||||||
|
|
||||||
setup: function(editor) {
|
setup: function(editor) {
|
||||||
editor.on('change', function(e) {
|
editor.on('change', function(e) {
|
||||||
@ -81,7 +79,7 @@ define([
|
|||||||
},
|
},
|
||||||
|
|
||||||
mailpoet_custom_fields: App.getConfig().get('customFields').toJSON(),
|
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() {
|
defaults: function() {
|
||||||
return this._getDefaults({
|
return this._getDefaults({
|
||||||
type: 'header',
|
type: 'header',
|
||||||
text: 'Display problems? <a href="[viewInBrowserUrl]">View it in your browser</a>',
|
text: 'Display problems? <a href="[link:newsletter_view_in_browser_url]">View it in your browser</a>',
|
||||||
styles: {
|
styles: {
|
||||||
block: {
|
block: {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
@ -41,7 +41,7 @@ define([
|
|||||||
getTemplate: function() { return templates.headerBlock; },
|
getTemplate: function() { return templates.headerBlock; },
|
||||||
modelEvents: _.extend({
|
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',
|
'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; },
|
onDragSubstituteBy: function() { return Module.HeaderWidgetView; },
|
||||||
onRender: function() {
|
onRender: function() {
|
||||||
this.toolsView = new Module.HeaderBlockToolsView({ model: this.model });
|
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",
|
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",
|
invalid_elements: "script",
|
||||||
style_formats: [
|
block_formats: 'Paragraph=p',
|
||||||
{title: 'Paragraph', block: 'p'},
|
|
||||||
],
|
|
||||||
|
|
||||||
plugins: "link textcolor mailpoet_custom_fields",
|
plugins: "link textcolor colorpicker mailpoet_custom_fields",
|
||||||
|
|
||||||
setup: function(editor) {
|
setup: function(editor) {
|
||||||
editor.on('change', function(e) {
|
editor.on('change', function(e) {
|
||||||
@ -81,7 +79,7 @@ define([
|
|||||||
},
|
},
|
||||||
|
|
||||||
mailpoet_custom_fields: App.getConfig().get('customFields').toJSON(),
|
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',
|
link: 'http://example.org',
|
||||||
src: 'no-image.png',
|
src: 'no-image.png',
|
||||||
alt: 'An image of...',
|
alt: 'An image of...',
|
||||||
padded: true, // true | false - Padded or full width
|
fullWidth: true, // true | false
|
||||||
width: '64px',
|
width: '64px',
|
||||||
height: '64px',
|
height: '64px',
|
||||||
styles: {
|
styles: {
|
||||||
@ -45,10 +45,10 @@ define([
|
|||||||
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
|
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
|
||||||
this.toolsRegion.show(this.toolsView);
|
this.toolsRegion.show(this.toolsView);
|
||||||
|
|
||||||
if (this.model.get('padded')) {
|
if (this.model.get('fullWidth')) {
|
||||||
this.$el.removeClass('mailpoet_full_image');
|
|
||||||
} else {
|
|
||||||
this.$el.addClass('mailpoet_full_image');
|
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_link": _.partial(this.changeField, "link"),
|
||||||
"keyup .mailpoet_field_image_address": _.partial(this.changeField, "src"),
|
"keyup .mailpoet_field_image_address": _.partial(this.changeField, "src"),
|
||||||
"keyup .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
|
"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"),
|
"change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"),
|
||||||
"click .mailpoet_field_image_select_another_image": "showMediaManager",
|
"click .mailpoet_field_image_select_another_image": "showMediaManager",
|
||||||
"click .mailpoet_done_editing": "close",
|
"click .mailpoet_done_editing": "close",
|
||||||
|
@ -43,10 +43,10 @@ define([
|
|||||||
inclusionType: 'include', // 'include'|'exclude'
|
inclusionType: 'include', // 'include'|'exclude'
|
||||||
displayType: 'excerpt', // 'excerpt'|'full'|'titleOnly'
|
displayType: 'excerpt', // 'excerpt'|'full'|'titleOnly'
|
||||||
titleFormat: 'h1', // 'h1'|'h2'|'h3'|'ul'
|
titleFormat: 'h1', // 'h1'|'h2'|'h3'|'ul'
|
||||||
titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock',
|
|
||||||
titleAlignment: 'left', // 'left'|'center'|'right'
|
titleAlignment: 'left', // 'left'|'center'|'right'
|
||||||
titleIsLink: false, // false|true
|
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'
|
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
|
||||||
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
|
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
|
||||||
authorPrecededBy: 'Author:',
|
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.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.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('readMoreButton'), 'change', refreshTransformedPosts);
|
||||||
this.listenTo(this.get('divider'), 'change', refreshTransformedPosts);
|
this.listenTo(this.get('divider'), 'change', refreshTransformedPosts);
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ define([
|
|||||||
that.get('_selectedPosts').reset(); // Empty out the collection
|
that.get('_selectedPosts').reset(); // Empty out the collection
|
||||||
that.trigger('change:_availablePosts');
|
that.trigger('change:_availablePosts');
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log('Posts fetchPosts error', arguments);
|
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_refreshTransformedPosts: function() {
|
_refreshTransformedPosts: function() {
|
||||||
@ -111,14 +111,14 @@ define([
|
|||||||
data.posts = this.get('_selectedPosts').pluck('ID');
|
data.posts = this.get('_selectedPosts').pluck('ID');
|
||||||
|
|
||||||
if (data.posts.length === 0) {
|
if (data.posts.length === 0) {
|
||||||
this.get('_transformedPosts.blocks').reset();
|
this.get('_transformedPosts').get('blocks').reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||||
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
|
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log('Posts _refreshTransformedPosts error', arguments);
|
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_insertSelectedPosts: function() {
|
_insertSelectedPosts: function() {
|
||||||
@ -134,7 +134,7 @@ define([
|
|||||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||||
collection.add(posts, { at: index });
|
collection.add(posts, { at: index });
|
||||||
}).fail(function() {
|
}).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"),
|
"keyup .mailpoet_posts_show_amount": _.partial(this.changeField, "amount"),
|
||||||
"change .mailpoet_posts_content_type": _.partial(this.changeField, "contentType"),
|
"change .mailpoet_posts_content_type": _.partial(this.changeField, "contentType"),
|
||||||
"change .mailpoet_posts_include_or_exclude": _.partial(this.changeField, "inclusionType"),
|
"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_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"),
|
"change .mailpoet_posts_show_author": _.partial(this.changeField, "showAuthor"),
|
||||||
"keyup .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
"keyup .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
||||||
"change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"),
|
"change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"),
|
||||||
@ -448,11 +448,11 @@ define([
|
|||||||
changeDisplayType: function(event) {
|
changeDisplayType: function(event) {
|
||||||
var value = jQuery(event.target).val();
|
var value = jQuery(event.target).val();
|
||||||
if (value == 'titleOnly') {
|
if (value == 'titleOnly') {
|
||||||
this.$('.mailpoet_posts_title_position_container').addClass('mailpoet_hidden');
|
|
||||||
this.$('.mailpoet_posts_title_as_list').removeClass('mailpoet_hidden');
|
this.$('.mailpoet_posts_title_as_list').removeClass('mailpoet_hidden');
|
||||||
|
this.$('.mailpoet_posts_image_full_width_option').addClass('mailpoet_hidden');
|
||||||
} else {
|
} else {
|
||||||
this.$('.mailpoet_posts_title_position_container').removeClass('mailpoet_hidden');
|
|
||||||
this.$('.mailpoet_posts_title_as_list').addClass('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
|
// Reset titleFormat if it was set to List when switching away from displayType=titleOnly
|
||||||
if (this.model.get('titleFormat') === 'ul') {
|
if (this.model.get('titleFormat') === 'ul') {
|
||||||
@ -461,6 +461,13 @@ define([
|
|||||||
this.$('.mailpoet_posts_title_as_link').removeClass('mailpoet_hidden');
|
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);
|
this.changeField('displayType', event);
|
||||||
},
|
},
|
||||||
changeTitleFormat: function(event) {
|
changeTitleFormat: function(event) {
|
||||||
|
@ -52,21 +52,15 @@ define([
|
|||||||
inline: true,
|
inline: true,
|
||||||
|
|
||||||
menubar: false,
|
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",
|
toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_custom_fields",
|
||||||
|
|
||||||
//forced_root_block: 'p',
|
//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]",
|
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",
|
invalid_elements: "script",
|
||||||
style_formats: [
|
block_formats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
|
||||||
{title: 'Heading 1', block: 'h1'},
|
|
||||||
{title: 'Heading 2', block: 'h2'},
|
|
||||||
{title: 'Heading 3', block: 'h3'},
|
|
||||||
|
|
||||||
{title: 'Paragraph', block: 'p'},
|
plugins: "link code textcolor colorpicker mailpoet_custom_fields",
|
||||||
],
|
|
||||||
|
|
||||||
plugins: "link code textcolor mailpoet_custom_fields",
|
|
||||||
|
|
||||||
setup: function(editor) {
|
setup: function(editor) {
|
||||||
editor.on('change', function(e) {
|
editor.on('change', function(e) {
|
||||||
@ -83,7 +77,7 @@ define([
|
|||||||
},
|
},
|
||||||
|
|
||||||
mailpoet_custom_fields: App.getConfig().get('customFields').toJSON(),
|
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: {},
|
availableStyles: {},
|
||||||
socialIcons: {},
|
socialIcons: {},
|
||||||
blockDefaults: {},
|
blockDefaults: {},
|
||||||
translations: {},
|
|
||||||
sidepanelWidth: '331px',
|
sidepanelWidth: '331px',
|
||||||
validation: {},
|
validation: {},
|
||||||
urls: {},
|
urls: {},
|
||||||
|
@ -67,7 +67,28 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
Module.getThumbnail = function(element, options) {
|
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) {
|
Module.saveTemplate = function(options) {
|
||||||
@ -170,7 +191,7 @@ define([
|
|||||||
|
|
||||||
if (templateName === '') {
|
if (templateName === '') {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
App.getConfig().get('translations.templateNameMissing'),
|
MailPoet.I18n.t('templateNameMissing'),
|
||||||
{
|
{
|
||||||
positionAfter: that.$el,
|
positionAfter: that.$el,
|
||||||
scroll: true,
|
scroll: true,
|
||||||
@ -178,30 +199,27 @@ define([
|
|||||||
);
|
);
|
||||||
} else if (templateDescription === '') {
|
} else if (templateDescription === '') {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
MailPoet.I18n.t('templateDescriptionMissing'),
|
||||||
{
|
{
|
||||||
positionAfter: that.$el,
|
positionAfter: that.$el,
|
||||||
scroll: true,
|
scroll: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('Saving template with ', templateName, templateDescription);
|
|
||||||
Module.saveTemplate({
|
Module.saveTemplate({
|
||||||
name: templateName,
|
name: templateName,
|
||||||
description: templateDescription,
|
description: templateDescription,
|
||||||
}).done(function() {
|
}).done(function() {
|
||||||
console.log('Template saved', arguments);
|
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
App.getConfig().get('translations.templateSaved'),
|
MailPoet.I18n.t('templateSaved'),
|
||||||
{
|
{
|
||||||
positionAfter: that.$el,
|
positionAfter: that.$el,
|
||||||
scroll: true,
|
scroll: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log('Template save failed', arguments);
|
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
App.getConfig().get('translations.templateSaveFailed'),
|
MailPoet.I18n.t('templateSaveFailed'),
|
||||||
{
|
{
|
||||||
positionAfter: that.$el,
|
positionAfter: that.$el,
|
||||||
scroll: true,
|
scroll: true,
|
||||||
@ -226,7 +244,7 @@ define([
|
|||||||
|
|
||||||
if (templateName === '') {
|
if (templateName === '') {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
App.getConfig().get('translations.templateNameMissing'),
|
MailPoet.I18n.t('templateNameMissing'),
|
||||||
{
|
{
|
||||||
positionAfter: that.$el,
|
positionAfter: that.$el,
|
||||||
scroll: true,
|
scroll: true,
|
||||||
@ -234,14 +252,13 @@ define([
|
|||||||
);
|
);
|
||||||
} else if (templateDescription === '') {
|
} else if (templateDescription === '') {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
MailPoet.I18n.t('templateDescriptionMissing'),
|
||||||
{
|
{
|
||||||
positionAfter: that.$el,
|
positionAfter: that.$el,
|
||||||
scroll: true,
|
scroll: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('Exporting template with ', templateName, templateDescription);
|
|
||||||
Module.exportTemplate({
|
Module.exportTemplate({
|
||||||
name: templateName,
|
name: templateName,
|
||||||
description: templateDescription,
|
description: templateDescription,
|
||||||
@ -257,7 +274,6 @@ define([
|
|||||||
next: function() {
|
next: function() {
|
||||||
this.hideOptionContents();
|
this.hideOptionContents();
|
||||||
if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
|
if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
|
||||||
console.log('Next');
|
|
||||||
window.location.href = App.getConfig().get('urls.send');
|
window.location.href = App.getConfig().get('urls.send');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -268,8 +284,8 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
|
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
|
||||||
JSON.stringify(jsonObject).indexOf("[unsubscribeUrl]") < 0) {
|
JSON.stringify(jsonObject).indexOf("[link:subscription_unsubscribe_url]") < 0) {
|
||||||
this.showValidationError(App.getConfig().get('translations.unsubscribeLinkMissing'));
|
this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,24 @@
|
|||||||
define([
|
define([
|
||||||
'newsletter_editor/App',
|
'newsletter_editor/App',
|
||||||
'newsletter_editor/components/communication',
|
'newsletter_editor/components/communication',
|
||||||
|
'mailpoet',
|
||||||
'backbone',
|
'backbone',
|
||||||
'backbone.marionette',
|
'backbone.marionette',
|
||||||
'backbone.supermodel',
|
'backbone.supermodel',
|
||||||
'underscore',
|
'underscore',
|
||||||
'jquery',
|
'jquery',
|
||||||
'sticky-kit'
|
'sticky-kit'
|
||||||
], function(App, CommunicationComponent, Backbone, Marionette, SuperModel, _, jQuery, StickyKit) {
|
], function(
|
||||||
|
App,
|
||||||
|
CommunicationComponent,
|
||||||
|
MailPoet,
|
||||||
|
Backbone,
|
||||||
|
Marionette,
|
||||||
|
SuperModel,
|
||||||
|
_,
|
||||||
|
jQuery,
|
||||||
|
StickyKit
|
||||||
|
) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -225,33 +236,56 @@ define([
|
|||||||
showPreview: function() {
|
showPreview: function() {
|
||||||
var json = App.toJSON();
|
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({
|
MailPoet.Ajax.post({
|
||||||
endpoint: 'newsletters',
|
endpoint: 'newsletters',
|
||||||
action: 'render',
|
action: 'showPreview',
|
||||||
data: json,
|
data: json,
|
||||||
}).done(function(response){
|
}).done(function(response){
|
||||||
console.log('Should open a new window');
|
MailPoet.Modal.loading(false);
|
||||||
window.open('data:text/html,' + encodeURIComponent(response.rendered_body), '_blank');
|
|
||||||
|
if (response.result === true) {
|
||||||
|
window.open(response.data.url, '_blank')
|
||||||
|
}
|
||||||
|
MailPoet.Notice.error(response.errors);
|
||||||
}).fail(function(error) {
|
}).fail(function(error) {
|
||||||
console.log('Preview error', json);
|
MailPoet.Modal.loading(false);
|
||||||
alert('Something went wrong, check console');
|
MailPoet.Notice.error(
|
||||||
|
MailPoet.I18n.t('newsletterPreviewFailed')
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
sendPreview: function() {
|
sendPreview: function() {
|
||||||
// testing sending method
|
|
||||||
console.log('trying to send a preview');
|
|
||||||
// get form data
|
// get form data
|
||||||
|
var $emailField = this.$('#mailpoet_preview_to_email');
|
||||||
var data = {
|
var data = {
|
||||||
subscriber: this.$('#mailpoet_preview_to_email').val(),
|
subscriber: $emailField.val(),
|
||||||
id: App.getNewsletter().get('id'),
|
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
|
// send test email
|
||||||
MailPoet.Modal.loading(true);
|
MailPoet.Modal.loading(true);
|
||||||
|
|
||||||
CommunicationComponent.previewNewsletter(data).done(function(response) {
|
CommunicationComponent.previewNewsletter(data).done(function(response) {
|
||||||
if(response.result !== undefined && response.result === true) {
|
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 {
|
} else {
|
||||||
if (_.isArray(response.errors)) {
|
if (_.isArray(response.errors)) {
|
||||||
response.errors.map(function(error) {
|
response.errors.map(function(error) {
|
||||||
@ -259,7 +293,7 @@ define([
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
App.getConfig().get('translations.newsletterPreviewFailedToSend'),
|
MailPoet.I18n.t('newsletterPreviewFailedToSend'),
|
||||||
{
|
{
|
||||||
scroll: true,
|
scroll: true,
|
||||||
static: true,
|
static: true,
|
||||||
|
@ -2,39 +2,38 @@ define(
|
|||||||
[
|
[
|
||||||
'react',
|
'react',
|
||||||
'react-router',
|
'react-router',
|
||||||
'classnames'
|
'classnames',
|
||||||
|
'mailpoet'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React,
|
||||||
Router,
|
Router,
|
||||||
classNames
|
classNames,
|
||||||
|
MailPoet
|
||||||
) {
|
) {
|
||||||
var Link = Router.Link;
|
var Link = Router.Link;
|
||||||
|
|
||||||
var Breadcrumb = React.createClass({
|
var Breadcrumb = React.createClass({
|
||||||
mixins: [
|
|
||||||
Router.History
|
|
||||||
],
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
step: null,
|
step: null,
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
name: 'type',
|
name: 'type',
|
||||||
label: 'Select type',
|
label: MailPoet.I18n.t('selectType'),
|
||||||
link: '/new'
|
link: '/new'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'template',
|
name: 'template',
|
||||||
label: 'Template'
|
label: MailPoet.I18n.t('template')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'editor',
|
name: 'editor',
|
||||||
label: 'Designer'
|
label: MailPoet.I18n.t('designer')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'send',
|
name: 'send',
|
||||||
label: 'Send'
|
label: MailPoet.I18n.t('send')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@ -73,4 +72,4 @@ define(
|
|||||||
|
|
||||||
return Breadcrumb;
|
return Breadcrumb;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -4,104 +4,101 @@ define(
|
|||||||
'react-router',
|
'react-router',
|
||||||
'listing/listing.jsx',
|
'listing/listing.jsx',
|
||||||
'classnames',
|
'classnames',
|
||||||
'jquery'
|
'jquery',
|
||||||
|
'mailpoet'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React,
|
||||||
Router,
|
Router,
|
||||||
Listing,
|
Listing,
|
||||||
classNames,
|
classNames,
|
||||||
jQuery
|
jQuery,
|
||||||
|
MailPoet
|
||||||
) {
|
) {
|
||||||
var Link = Router.Link;
|
var Link = Router.Link;
|
||||||
|
|
||||||
var columns = [
|
var columns = [
|
||||||
{
|
{
|
||||||
name: 'subject',
|
name: 'subject',
|
||||||
label: 'Subject',
|
label: MailPoet.I18n.t('subject'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'status',
|
name: 'status',
|
||||||
label: 'Status'
|
label: MailPoet.I18n.t('status')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'segments',
|
name: 'segments',
|
||||||
label: 'Lists'
|
label: MailPoet.I18n.t('lists')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'statistics',
|
||||||
|
label: MailPoet.I18n.t('statistics')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'created_at',
|
name: 'created_at',
|
||||||
label: 'Created on',
|
label: MailPoet.I18n.t('createdOn'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'updated_at',
|
name: 'updated_at',
|
||||||
label: 'Last modified on',
|
label: MailPoet.I18n.t('lastModifiedOn'),
|
||||||
sortable: true
|
sortable: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
var messages = {
|
var messages = {
|
||||||
onTrash: function(response) {
|
onTrash: function(response) {
|
||||||
var count = ~~response.newsletters;
|
var count = ~~response;
|
||||||
var message = null;
|
var message = null;
|
||||||
|
|
||||||
if(count === 1 || response === true) {
|
if(count === 1) {
|
||||||
message = (
|
message = (
|
||||||
'1 newsletter was moved to the trash.'
|
MailPoet.I18n.t('oneNewsletterTrashed')
|
||||||
);
|
);
|
||||||
} else if(count > 1) {
|
} else {
|
||||||
message = (
|
message = (
|
||||||
'%$1d newsletters were moved to the trash.'
|
MailPoet.I18n.t('multipleNewslettersTrashed')
|
||||||
).replace('%$1d', count);
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
if(message !== null) {
|
|
||||||
MailPoet.Notice.success(message);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onDelete: function(response) {
|
onDelete: function(response) {
|
||||||
var count = ~~response.newsletters;
|
var count = ~~response;
|
||||||
var message = null;
|
var message = null;
|
||||||
|
|
||||||
if(count === 1 || response === true) {
|
if(count === 1) {
|
||||||
message = (
|
message = (
|
||||||
'1 newsletter was permanently deleted.'
|
MailPoet.I18n.t('oneNewsletterDeleted')
|
||||||
);
|
);
|
||||||
} else if(count > 1) {
|
} else {
|
||||||
message = (
|
message = (
|
||||||
'%$1d newsletters were permanently deleted.'
|
MailPoet.I18n.t('multipleNewslettersDeleted')
|
||||||
).replace('%$1d', count);
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
if(message !== null) {
|
|
||||||
MailPoet.Notice.success(message);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onRestore: function(response) {
|
onRestore: function(response) {
|
||||||
var count = ~~response.newsletters;
|
var count = ~~response;
|
||||||
var message = null;
|
var message = null;
|
||||||
|
|
||||||
if(count === 1 || response === true) {
|
if(count === 1) {
|
||||||
message = (
|
message = (
|
||||||
'1 newsletter has been restored from the trash.'
|
MailPoet.I18n.t('oneNewsletterRestored')
|
||||||
);
|
);
|
||||||
} else if(count > 1) {
|
} else {
|
||||||
message = (
|
message = (
|
||||||
'%$1d newsletters have been restored from the trash.'
|
MailPoet.I18n.t('multipleNewslettersRestored')
|
||||||
).replace('%$1d', count);
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
if(message !== null) {
|
|
||||||
MailPoet.Notice.success(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var bulk_actions = [
|
var bulk_actions = [
|
||||||
{
|
{
|
||||||
name: 'trash',
|
name: 'trash',
|
||||||
label: 'Trash',
|
label: MailPoet.I18n.t('trash'),
|
||||||
onSuccess: messages.onTrash
|
onSuccess: messages.onTrash
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -112,7 +109,7 @@ define(
|
|||||||
link: function(item) {
|
link: function(item) {
|
||||||
return (
|
return (
|
||||||
<a href={ `?page=mailpoet-newsletter-editor&id=${ item.id }` }>
|
<a href={ `?page=mailpoet-newsletter-editor&id=${ item.id }` }>
|
||||||
Edit
|
{MailPoet.I18n.t('edit')}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -144,11 +141,16 @@ define(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
renderStatus: function(item) {
|
renderStatus: function(item) {
|
||||||
if(item.queue === null) {
|
if(!item.queue) {
|
||||||
return (
|
return (
|
||||||
<span>Not sent yet.</span>
|
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
if (item.queue.status === 'scheduled') {
|
||||||
|
return (
|
||||||
|
<span>{MailPoet.I18n.t('scheduledFor')} { MailPoet.Date.format(item.queue.scheduled_at) } </span>
|
||||||
|
)
|
||||||
|
}
|
||||||
var progressClasses = classNames(
|
var progressClasses = classNames(
|
||||||
'mailpoet_progress',
|
'mailpoet_progress',
|
||||||
{ 'mailpoet_progress_complete': item.queue.status === 'completed'}
|
{ 'mailpoet_progress_complete': item.queue.status === 'completed'}
|
||||||
@ -164,9 +166,11 @@ define(
|
|||||||
if(item.queue.status === 'completed') {
|
if(item.queue.status === 'completed') {
|
||||||
label = (
|
label = (
|
||||||
<span>
|
<span>
|
||||||
Sent to {
|
{
|
||||||
item.queue.count_processed - item.queue.count_failed
|
MailPoet.I18n.t('newsletterQueueCompleted')
|
||||||
} out of { item.queue.count_total }.
|
.replace("%$1d", item.queue.count_processed - item.queue.count_failed)
|
||||||
|
.replace("%$2d", item.queue.count_total)
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -180,14 +184,14 @@ define(
|
|||||||
style={{ display: (item.queue.status === 'paused') ? 'inline-block': 'none' }}
|
style={{ display: (item.queue.status === 'paused') ? 'inline-block': 'none' }}
|
||||||
href="javascript:;"
|
href="javascript:;"
|
||||||
onClick={ this.resumeSending.bind(null, item) }
|
onClick={ this.resumeSending.bind(null, item) }
|
||||||
>Resume</a>
|
>{MailPoet.I18n.t('resume')}</a>
|
||||||
<a
|
<a
|
||||||
id={ 'pause_'+item.id }
|
id={ 'pause_'+item.id }
|
||||||
className="button mailpoet_pause"
|
className="button mailpoet_pause"
|
||||||
style={{ display: (item.queue.status === null) ? 'inline-block': 'none' }}
|
style={{ display: (item.queue.status === null) ? 'inline-block': 'none' }}
|
||||||
href="javascript:;"
|
href="javascript:;"
|
||||||
onClick={ this.pauseSending.bind(null, item) }
|
onClick={ this.pauseSending.bind(null, item) }
|
||||||
>Pause</a>
|
>{MailPoet.I18n.t('pause')}</a>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -210,6 +214,31 @@ define(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
renderStatistics: function(item) {
|
||||||
|
if(!item.statistics || !item.queue || item.queue.count_processed == 0 || item.queue.status === 'scheduled') {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{MailPoet.I18n.t('notSentYet')}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var percentage_clicked = Math.round(
|
||||||
|
(item.statistics.clicked * 100) / (item.queue.count_processed)
|
||||||
|
);
|
||||||
|
var percentage_opened = Math.round(
|
||||||
|
(item.statistics.opened * 100) / (item.queue.count_processed)
|
||||||
|
);
|
||||||
|
var percentage_unsubscribed = Math.round(
|
||||||
|
(item.statistics.unsubscribed * 100) / (item.queue.count_processed)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{ percentage_opened }%, { percentage_clicked }%, { percentage_unsubscribed }%
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
renderItem: function(newsletter, actions) {
|
renderItem: function(newsletter, actions) {
|
||||||
var rowClasses = classNames(
|
var rowClasses = classNames(
|
||||||
'manage-column',
|
'manage-column',
|
||||||
@ -217,12 +246,17 @@ define(
|
|||||||
'has-row-actions'
|
'has-row-actions'
|
||||||
);
|
);
|
||||||
|
|
||||||
var segments = mailpoet_segments.filter(function(segment) {
|
var segments = newsletter.segments.map(function(segment) {
|
||||||
return (jQuery.inArray(segment.id, newsletter.segments) !== -1);
|
return segment.name
|
||||||
}).map(function(segment) {
|
|
||||||
return segment.name;
|
|
||||||
}).join(', ');
|
}).join(', ');
|
||||||
|
|
||||||
|
var statistics_column =
|
||||||
|
(!mailpoet_settings.tracking || !mailpoet_settings.tracking.enabled) ?
|
||||||
|
false :
|
||||||
|
<td className="column {statistics_class}" data-colname={ MailPoet.I18n.t('statistics') }>
|
||||||
|
{ this.renderStatistics(newsletter) }
|
||||||
|
</td>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<td className={ rowClasses }>
|
<td className={ rowClasses }>
|
||||||
@ -231,29 +265,34 @@ define(
|
|||||||
</strong>
|
</strong>
|
||||||
{ actions }
|
{ actions }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname="Lists">
|
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
||||||
{ this.renderStatus(newsletter) }
|
{ this.renderStatus(newsletter) }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname="Lists">
|
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
||||||
{ segments }
|
{ segments }
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Subscribed on">
|
{ statistics_column }
|
||||||
<abbr>{ newsletter.created_at }</abbr>
|
<td className="column-date" data-colname={ MailPoet.I18n.t('createdOn') }>
|
||||||
|
<abbr>{ MailPoet.Date.format(newsletter.created_at) }</abbr>
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Last modified on">
|
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
|
||||||
<abbr>{ newsletter.updated_at }</abbr>
|
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
|
||||||
</td>
|
</td>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
|
if (!mailpoet_settings.tracking || !mailpoet_settings.tracking.enabled) {
|
||||||
|
columns = _.without(columns, _.findWhere(columns, {name: 'statistics'}));
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="title">
|
<h1 className="title">
|
||||||
Newsletters <Link className="add-new-h2" to="/new">New</Link>
|
{MailPoet.I18n.t('pageTitle')} <Link className="page-title-action" to="/new">{MailPoet.I18n.t('new')}</Link>
|
||||||
</h2>
|
</h1>
|
||||||
|
|
||||||
<Listing
|
<Listing
|
||||||
|
limit={ mailpoet_listing_per_page }
|
||||||
params={ this.props.params }
|
params={ this.props.params }
|
||||||
endpoint="newsletters"
|
endpoint="newsletters"
|
||||||
onRenderItem={this.renderItem}
|
onRenderItem={this.renderItem}
|
||||||
@ -269,4 +308,4 @@ define(
|
|||||||
|
|
||||||
return NewsletterList;
|
return NewsletterList;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { Router, Route, IndexRoute, Link } from 'react-router'
|
import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
|
||||||
|
import { createHashHistory } from 'history'
|
||||||
import NewsletterList from 'newsletters/list.jsx'
|
import NewsletterList from 'newsletters/list.jsx'
|
||||||
import NewsletterTypes from 'newsletters/types.jsx'
|
import NewsletterTypes from 'newsletters/types.jsx'
|
||||||
import NewsletterTemplates from 'newsletters/templates.jsx'
|
import NewsletterTemplates from 'newsletters/templates.jsx'
|
||||||
import NewsletterSend from 'newsletters/send.jsx'
|
import NewsletterSend from 'newsletters/send.jsx'
|
||||||
import NewsletterStandard from 'newsletters/types/standard.jsx'
|
import NewsletterStandard from 'newsletters/types/standard.jsx'
|
||||||
import NewsletterWelcome from 'newsletters/types/welcome.jsx'
|
import NewsletterWelcome from 'newsletters/types/welcome/welcome.jsx'
|
||||||
import NewsletterNotification from 'newsletters/types/notification.jsx'
|
import NewsletterNotification from 'newsletters/types/notification/notification.jsx'
|
||||||
import createHashHistory from 'history/lib/createHashHistory'
|
|
||||||
|
|
||||||
let history = createHashHistory({ queryKey: false })
|
const history = useRouterHistory(createHashHistory)({ queryKey: false });
|
||||||
|
|
||||||
const App = React.createClass({
|
const App = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
@ -18,7 +18,7 @@ const App = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let container = document.getElementById('newsletters_container');
|
const container = document.getElementById('newsletters_container');
|
||||||
|
|
||||||
if(container) {
|
if(container) {
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
|
@ -2,180 +2,194 @@ define(
|
|||||||
[
|
[
|
||||||
'react',
|
'react',
|
||||||
'react-router',
|
'react-router',
|
||||||
|
'underscore',
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
'form/form.jsx',
|
'form/form.jsx',
|
||||||
'form/fields/selection.jsx',
|
'newsletters/send/standard.jsx',
|
||||||
|
'newsletters/send/notification.jsx',
|
||||||
|
'newsletters/send/welcome.jsx',
|
||||||
'newsletters/breadcrumb.jsx'
|
'newsletters/breadcrumb.jsx'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React,
|
||||||
Router,
|
Router,
|
||||||
|
_,
|
||||||
MailPoet,
|
MailPoet,
|
||||||
Form,
|
Form,
|
||||||
Selection,
|
StandardNewsletterFields,
|
||||||
|
NotificationNewsletterFields,
|
||||||
|
WelcomeNewsletterFields,
|
||||||
Breadcrumb
|
Breadcrumb
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var settings = window.mailpoet_settings || {};
|
|
||||||
|
|
||||||
var fields = [
|
|
||||||
{
|
|
||||||
name: 'subject',
|
|
||||||
label: 'Subject line',
|
|
||||||
tip: "Be creative! It's the first thing your subscribers see."+
|
|
||||||
"Tempt them to open your email.",
|
|
||||||
type: 'text',
|
|
||||||
validation: {
|
|
||||||
'data-parsley-required': true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'segments',
|
|
||||||
label: 'Segments',
|
|
||||||
tip: "The subscriber segment that will be used for this campaign.",
|
|
||||||
type: 'selection',
|
|
||||||
placeholder: "Select a segment",
|
|
||||||
id: "mailpoet_segments",
|
|
||||||
endpoint: "segments",
|
|
||||||
multiple: true,
|
|
||||||
filter: function(segment) {
|
|
||||||
return !!(!segment.deleted_at);
|
|
||||||
},
|
|
||||||
validation: {
|
|
||||||
'data-parsley-required': true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'sender',
|
|
||||||
label: 'Sender',
|
|
||||||
tip: "Name & email of yourself or your company.",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'sender_name',
|
|
||||||
type: 'text',
|
|
||||||
placeholder: 'John Doe',
|
|
||||||
defaultValue: (settings.sender !== undefined) ? settings.sender.name : '',
|
|
||||||
validation: {
|
|
||||||
'data-parsley-required': true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'sender_address',
|
|
||||||
type: 'text',
|
|
||||||
placeholder: 'john.doe@email.com',
|
|
||||||
defaultValue: (settings.sender !== undefined) ? settings.sender.address : '',
|
|
||||||
validation: {
|
|
||||||
'data-parsley-required': true,
|
|
||||||
'data-parsley-type': 'email'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'reply-to',
|
|
||||||
label: 'Reply-to',
|
|
||||||
tip: 'When the subscribers hit "reply" this is who will receive their '+
|
|
||||||
'email.',
|
|
||||||
inline: true,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'reply_to_name',
|
|
||||||
type: 'text',
|
|
||||||
placeholder: 'John Doe',
|
|
||||||
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'reply_to_address',
|
|
||||||
type: 'text',
|
|
||||||
placeholder: 'john.doe@email.com',
|
|
||||||
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : ''
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
var messages = {
|
|
||||||
onUpdate: function() {
|
|
||||||
MailPoet.Notice.success('Newsletter successfully updated!');
|
|
||||||
},
|
|
||||||
onCreate: function() {
|
|
||||||
MailPoet.Notice.success('Newsletter successfully added!');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var NewsletterSend = React.createClass({
|
var NewsletterSend = React.createClass({
|
||||||
mixins: [
|
contextTypes: {
|
||||||
Router.History
|
router: React.PropTypes.object.isRequired
|
||||||
],
|
},
|
||||||
handleSend: function() {
|
getInitialState: function() {
|
||||||
if(jQuery('#mailpoet_newsletter').parsley().validate() === true) {
|
return {
|
||||||
|
fields: [],
|
||||||
|
item: {},
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getFieldsByNewsletter: function(newsletter) {
|
||||||
|
switch(newsletter.type) {
|
||||||
|
case 'notification': return NotificationNewsletterFields;
|
||||||
|
case 'welcome': return WelcomeNewsletterFields;
|
||||||
|
default: return StandardNewsletterFields;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isAutomatedNewsletter: function() {
|
||||||
|
return this.state.item.type !== 'standard';
|
||||||
|
},
|
||||||
|
isValid: function() {
|
||||||
|
return jQuery('#mailpoet_newsletter').parsley().isValid();
|
||||||
|
},
|
||||||
|
componentDidMount: function() {
|
||||||
|
if(this.isMounted()) {
|
||||||
|
this.loadItem(this.props.params.id);
|
||||||
|
}
|
||||||
|
jQuery('#mailpoet_newsletter').parsley();
|
||||||
|
},
|
||||||
|
componentWillReceiveProps: function(props) {
|
||||||
|
this.loadItem(props.params.id);
|
||||||
|
},
|
||||||
|
loadItem: function(id) {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'newsletters',
|
||||||
|
action: 'get',
|
||||||
|
data: id
|
||||||
|
}).done((response) => {
|
||||||
|
if(response === false) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
item: {},
|
||||||
|
}, function() {
|
||||||
|
this.context.router.push('/new');
|
||||||
|
}.bind(this));
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
item: response,
|
||||||
|
fields: this.getFieldsByNewsletter(response),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSend: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if(!this.isValid()) {
|
||||||
|
jQuery('#mailpoet_newsletter').parsley().validate();
|
||||||
|
} else {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
endpoint: 'sendingQueue',
|
endpoint: 'newsletters',
|
||||||
action: 'add',
|
action: 'save',
|
||||||
data: {
|
data: this.state.item,
|
||||||
newsletter_id: this.props.params.id,
|
}).then((response) => {
|
||||||
segments: jQuery('#mailpoet_segments').val(),
|
if (response.result === true) {
|
||||||
sender: {
|
return MailPoet.Ajax.post({
|
||||||
'name': jQuery('#mailpoet_newsletter [name="sender_name"]').val(),
|
endpoint: 'sendingQueue',
|
||||||
'address': jQuery('#mailpoet_newsletter [name="sender_address"]').val()
|
action: 'add',
|
||||||
},
|
data: _.extend({}, this.state.item, {
|
||||||
reply_to: {
|
newsletter_id: this.props.params.id,
|
||||||
'name': jQuery('#mailpoet_newsletter [name="reply_to_name"]').val(),
|
}),
|
||||||
'address': jQuery('#mailpoet_newsletter [name="reply_to_address"]').val()
|
});
|
||||||
}
|
} else {
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
}).done(function(response) {
|
}).done((response) => {
|
||||||
|
this.setState({ loading: false });
|
||||||
if(response.result === true) {
|
if(response.result === true) {
|
||||||
this.history.pushState(null, '/');
|
this.context.router.push('/');
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(response.data.message);
|
||||||
'The newsletter is being sent...'
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
if(response.errors) {
|
if(response.errors) {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(response.errors);
|
||||||
response.errors.join("<br />")
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
'An error occurred while trying to send. '+
|
MailPoet.I18n.t('newsletterSendingError').replace("%$1s", '?page=mailpoet-settings')
|
||||||
'<a href="?page=mailpoet-settings">Check your settings.</a>'
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.bind(this));
|
});
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
handleSave: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'newsletters',
|
||||||
|
action: 'save',
|
||||||
|
data: this.state.item,
|
||||||
|
}).done((response) => {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
|
||||||
|
if(response.result === true) {
|
||||||
|
this.context.router.push('/');
|
||||||
|
MailPoet.Notice.success(
|
||||||
|
MailPoet.I18n.t('newsletterUpdated')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if(response.errors) {
|
||||||
|
MailPoet.Notice.error(response.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleFormChange: function(e) {
|
||||||
|
var item = this.state.item,
|
||||||
|
field = e.target.name;
|
||||||
|
|
||||||
|
item[field] = e.target.value;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
item: item
|
||||||
|
});
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Final step: last details</h1>
|
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
|
||||||
|
|
||||||
<Breadcrumb step="send" />
|
<Breadcrumb step="send" />
|
||||||
|
|
||||||
<Form
|
<Form
|
||||||
id="mailpoet_newsletter"
|
id="mailpoet_newsletter"
|
||||||
endpoint="newsletters"
|
fields={ this.state.fields }
|
||||||
fields={ fields }
|
item={ this.state.item }
|
||||||
params={ this.props.params }
|
loading={ this.state.loading }
|
||||||
messages={ messages }
|
onChange={this.handleFormChange}
|
||||||
|
onSubmit={this.handleSave}
|
||||||
>
|
>
|
||||||
<p className="submit">
|
<p className="submit">
|
||||||
<input
|
<input
|
||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={ this.handleSend }
|
onClick={ this.handleSend }
|
||||||
value="Send" />
|
value={
|
||||||
|
this.isAutomatedNewsletter()
|
||||||
|
? MailPoet.I18n.t('activate')
|
||||||
|
: MailPoet.I18n.t('send')} />
|
||||||
|
|
||||||
<input
|
<input
|
||||||
className="button button-secondary"
|
className="button button-secondary"
|
||||||
type="submit"
|
type="submit"
|
||||||
value="Save as draft and close" />
|
value={MailPoet.I18n.t('saveDraftAndClose')} />
|
||||||
or simply
|
{MailPoet.I18n.t('orSimply')}
|
||||||
<a
|
<a
|
||||||
href={
|
href={
|
||||||
'?page=mailpoet-newsletter-editor&id='+this.props.params.id
|
'?page=mailpoet-newsletter-editor&id='+this.props.params.id
|
||||||
}>
|
}>
|
||||||
go back to design
|
{MailPoet.I18n.t('goBackToDesign')}
|
||||||
</a>.
|
</a>.
|
||||||
</p>
|
</p>
|
||||||
</Form>
|
</Form>
|
||||||
@ -186,4 +200,4 @@ define(
|
|||||||
|
|
||||||
return NewsletterSend;
|
return NewsletterSend;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
100
assets/js/src/newsletters/send/notification.jsx
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'mailpoet',
|
||||||
|
'newsletters/types/notification/scheduling.jsx'
|
||||||
|
],
|
||||||
|
function(
|
||||||
|
MailPoet,
|
||||||
|
Scheduling
|
||||||
|
) {
|
||||||
|
|
||||||
|
var settings = window.mailpoet_settings || {};
|
||||||
|
|
||||||
|
var fields = [
|
||||||
|
{
|
||||||
|
name: 'subject',
|
||||||
|
label: MailPoet.I18n.t('subjectLine'),
|
||||||
|
tip: MailPoet.I18n.t('postNotificationSubjectLineTip'),
|
||||||
|
type: 'text',
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-required-message': MailPoet.I18n.t('emptySubjectLineError')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'options',
|
||||||
|
label: MailPoet.I18n.t('selectPeriodicity'),
|
||||||
|
type: 'reactComponent',
|
||||||
|
component: Scheduling,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'segments',
|
||||||
|
label: MailPoet.I18n.t('segments'),
|
||||||
|
tip: MailPoet.I18n.t('segmentsTip'),
|
||||||
|
type: 'selection',
|
||||||
|
placeholder: MailPoet.I18n.t('selectSegmentPlaceholder'),
|
||||||
|
id: "mailpoet_segments",
|
||||||
|
endpoint: "segments",
|
||||||
|
multiple: true,
|
||||||
|
filter: function(segment) {
|
||||||
|
return !!(!segment.deleted_at);
|
||||||
|
},
|
||||||
|
getLabel: function(segment) {
|
||||||
|
var name = segment.name;
|
||||||
|
if (segment.subscribers > 0) {
|
||||||
|
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
},
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-required-message': MailPoet.I18n.t('noSegmentsSelectedError')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sender',
|
||||||
|
label: MailPoet.I18n.t('sender'),
|
||||||
|
tip: MailPoet.I18n.t('senderTip'),
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'sender_name',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('senderNamePlaceholder'),
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sender_address',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('senderAddressPlaceholder'),
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-type': 'email'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reply-to',
|
||||||
|
label: MailPoet.I18n.t('replyTo'),
|
||||||
|
tip: MailPoet.I18n.t('replyToTip'),
|
||||||
|
inline: true,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'reply_to_name',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('replyToNamePlaceholder')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reply_to_address',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
);
|
406
assets/js/src/newsletters/send/standard.jsx
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'react',
|
||||||
|
'jquery',
|
||||||
|
'underscore',
|
||||||
|
'mailpoet',
|
||||||
|
'form/fields/checkbox.jsx',
|
||||||
|
'form/fields/select.jsx',
|
||||||
|
'form/fields/text.jsx',
|
||||||
|
],
|
||||||
|
function(
|
||||||
|
React,
|
||||||
|
jQuery,
|
||||||
|
_,
|
||||||
|
MailPoet,
|
||||||
|
Checkbox,
|
||||||
|
Select,
|
||||||
|
Text
|
||||||
|
) {
|
||||||
|
|
||||||
|
var settings = window.mailpoet_settings || {},
|
||||||
|
currentTime = window.mailpoet_current_time || '00:00',
|
||||||
|
defaultDateTime = window.mailpoet_current_date + ' ' + '00:00:00';
|
||||||
|
timeOfDayItems = window.mailpoet_schedule_time_of_day,
|
||||||
|
dateDisplayFormat = window.mailpoet_date_display_format,
|
||||||
|
dateStorageFormat = window.mailpoet_date_storage_format;
|
||||||
|
|
||||||
|
var datepickerTranslations = {
|
||||||
|
closeText: MailPoet.I18n.t('close'),
|
||||||
|
currentText: MailPoet.I18n.t('today'),
|
||||||
|
nextText: MailPoet.I18n.t('next'),
|
||||||
|
prevText: MailPoet.I18n.t('previous'),
|
||||||
|
monthNames: [
|
||||||
|
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')
|
||||||
|
],
|
||||||
|
monthNamesShort: [
|
||||||
|
MailPoet.I18n.t('januaryShort'),
|
||||||
|
MailPoet.I18n.t('februaryShort'),
|
||||||
|
MailPoet.I18n.t('marchShort'),
|
||||||
|
MailPoet.I18n.t('aprilShort'),
|
||||||
|
MailPoet.I18n.t('mayShort'),
|
||||||
|
MailPoet.I18n.t('juneShort'),
|
||||||
|
MailPoet.I18n.t('julyShort'),
|
||||||
|
MailPoet.I18n.t('augustShort'),
|
||||||
|
MailPoet.I18n.t('septemberShort'),
|
||||||
|
MailPoet.I18n.t('octoberShort'),
|
||||||
|
MailPoet.I18n.t('novemberShort'),
|
||||||
|
MailPoet.I18n.t('decemberShort')
|
||||||
|
],
|
||||||
|
dayNames: [
|
||||||
|
MailPoet.I18n.t('sunday'),
|
||||||
|
MailPoet.I18n.t('monday'),
|
||||||
|
MailPoet.I18n.t('tuesday'),
|
||||||
|
MailPoet.I18n.t('wednesday'),
|
||||||
|
MailPoet.I18n.t('thursday'),
|
||||||
|
MailPoet.I18n.t('friday'),
|
||||||
|
MailPoet.I18n.t('saturday')
|
||||||
|
],
|
||||||
|
dayNamesShort: [
|
||||||
|
MailPoet.I18n.t('sundayShort'),
|
||||||
|
MailPoet.I18n.t('mondayShort'),
|
||||||
|
MailPoet.I18n.t('tuesdayShort'),
|
||||||
|
MailPoet.I18n.t('wednesdayShort'),
|
||||||
|
MailPoet.I18n.t('thursdayShort'),
|
||||||
|
MailPoet.I18n.t('fridayShort'),
|
||||||
|
MailPoet.I18n.t('saturdayShort')
|
||||||
|
],
|
||||||
|
dayNamesMin: [
|
||||||
|
MailPoet.I18n.t('sundayMin'),
|
||||||
|
MailPoet.I18n.t('mondayMin'),
|
||||||
|
MailPoet.I18n.t('tuesdayMin'),
|
||||||
|
MailPoet.I18n.t('wednesdayMin'),
|
||||||
|
MailPoet.I18n.t('thursdayMin'),
|
||||||
|
MailPoet.I18n.t('fridayMin'),
|
||||||
|
MailPoet.I18n.t('saturdayMin')
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
var DateText = React.createClass({
|
||||||
|
onChange: function(event) {
|
||||||
|
// Swap display format to storage format
|
||||||
|
var displayDate = event.target.value,
|
||||||
|
storageDate = this.getStorageDate(displayDate);
|
||||||
|
|
||||||
|
event.target.value = storageDate;
|
||||||
|
this.props.onChange(event);
|
||||||
|
},
|
||||||
|
componentDidMount: function() {
|
||||||
|
var $element = jQuery(this.refs.dateInput),
|
||||||
|
that = this;
|
||||||
|
if ($element.datepicker) {
|
||||||
|
// Override jQuery UI datepicker Date parsing and formatting
|
||||||
|
jQuery.datepicker.parseDate = function(format, value) {
|
||||||
|
// Transform string format to Date object
|
||||||
|
return MailPoet.Date.toDate(value, {
|
||||||
|
parseFormat: dateDisplayFormat,
|
||||||
|
format: format
|
||||||
|
});
|
||||||
|
};
|
||||||
|
jQuery.datepicker.formatDate = function(format, value) {
|
||||||
|
// Transform Date object to string format
|
||||||
|
var newValue = MailPoet.Date.format(value, {
|
||||||
|
format: format
|
||||||
|
});
|
||||||
|
return newValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
$element.datepicker(_.extend({
|
||||||
|
dateFormat: this.props.displayFormat,
|
||||||
|
isRTL: false,
|
||||||
|
onSelect: function(value) {
|
||||||
|
that.onChange({
|
||||||
|
target: {
|
||||||
|
name: that.getFieldName(),
|
||||||
|
value: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, datepickerTranslations));
|
||||||
|
|
||||||
|
this.datepickerInitialized = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
if (this.datepickerInitialized) {
|
||||||
|
jQuery(this.refs.dateInput).datepicker('destroy');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getFieldName: function() {
|
||||||
|
return this.props.name || 'date';
|
||||||
|
},
|
||||||
|
getDisplayDate: function(date) {
|
||||||
|
return MailPoet.Date.format(date, {
|
||||||
|
parseFormat: this.props.storageFormat,
|
||||||
|
format: this.props.displayFormat
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getStorageDate: function(date) {
|
||||||
|
return MailPoet.Date.format(date, {
|
||||||
|
parseFormat: this.props.displayFormat,
|
||||||
|
format: this.props.storageFormat
|
||||||
|
});
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
size="10"
|
||||||
|
name={this.getFieldName()}
|
||||||
|
value={this.getDisplayDate(this.props.value)}
|
||||||
|
readOnly={ true }
|
||||||
|
onChange={this.onChange}
|
||||||
|
ref="dateInput"
|
||||||
|
{...this.props.validation} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var TimeSelect = React.createClass({
|
||||||
|
render: function() {
|
||||||
|
const options = Object.keys(timeOfDayItems).map(
|
||||||
|
(value, index) => {
|
||||||
|
return (
|
||||||
|
<option
|
||||||
|
key={ 'option-' + index }
|
||||||
|
value={ value }>
|
||||||
|
{ timeOfDayItems[value] }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={this.props.name || 'time'}
|
||||||
|
value={this.props.value}
|
||||||
|
onChange={this.props.onChange}
|
||||||
|
{...this.props.validation}
|
||||||
|
>
|
||||||
|
{options}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var DateTime = React.createClass({
|
||||||
|
_DATE_TIME_SEPARATOR: " ",
|
||||||
|
getInitialState: function() {
|
||||||
|
return this._buildStateFromProps(this.props);
|
||||||
|
},
|
||||||
|
componentWillReceiveProps: function(nextProps) {
|
||||||
|
this.setState(this._buildStateFromProps(nextProps));
|
||||||
|
},
|
||||||
|
_buildStateFromProps: function(props) {
|
||||||
|
let value = props.value || defaultDateTime;
|
||||||
|
const [date, time] = value.split(this._DATE_TIME_SEPARATOR)
|
||||||
|
return {
|
||||||
|
date: date,
|
||||||
|
time: time,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleChange: function(event) {
|
||||||
|
var newState = {};
|
||||||
|
newState[event.target.name] = event.target.value;
|
||||||
|
|
||||||
|
this.setState(newState, function() {
|
||||||
|
this.propagateChange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
propagateChange: function() {
|
||||||
|
if (this.props.onChange) {
|
||||||
|
return this.props.onChange({
|
||||||
|
target: {
|
||||||
|
name: this.props.name || '',
|
||||||
|
value: this.getDateTime(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDateTime: function() {
|
||||||
|
return [this.state.date, this.state.time].join(this._DATE_TIME_SEPARATOR);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<DateText
|
||||||
|
name="date"
|
||||||
|
value={this.state.date}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
displayFormat={dateDisplayFormat}
|
||||||
|
storageFormat={dateStorageFormat}
|
||||||
|
validation={this.props.dateValidation}/>
|
||||||
|
<TimeSelect
|
||||||
|
name="time"
|
||||||
|
value={this.state.time}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
validation={this.props.timeValidation} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var StandardScheduling = React.createClass({
|
||||||
|
_getCurrentValue: function() {
|
||||||
|
return this.props.item[this.props.field.name] || {};
|
||||||
|
},
|
||||||
|
handleValueChange: function(event) {
|
||||||
|
var oldValue = this._getCurrentValue(),
|
||||||
|
newValue = {};
|
||||||
|
newValue[event.target.name] = event.target.value;
|
||||||
|
|
||||||
|
return this.props.onValueChange({
|
||||||
|
target: {
|
||||||
|
name: this.props.field.name,
|
||||||
|
value: _.extend({}, oldValue, newValue)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleCheckboxChange: function(event) {
|
||||||
|
event.target.value = this.refs.isScheduled.checked ? '1' : '0';
|
||||||
|
return this.handleValueChange(event);
|
||||||
|
},
|
||||||
|
isScheduled: function() {
|
||||||
|
return this._getCurrentValue().isScheduled === '1';
|
||||||
|
},
|
||||||
|
getDateValidation: function() {
|
||||||
|
return {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-required-message': MailPoet.I18n.t('noScheduledDateError'),
|
||||||
|
'data-parsley-errors-container': '#mailpoet_scheduling',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var schedulingOptions;
|
||||||
|
|
||||||
|
if (this.isScheduled()) {
|
||||||
|
schedulingOptions = (
|
||||||
|
<span id="mailpoet_scheduling">
|
||||||
|
<DateTime
|
||||||
|
name="scheduledAt"
|
||||||
|
value={this._getCurrentValue().scheduledAt}
|
||||||
|
onChange={this.handleValueChange}
|
||||||
|
dateValidation={this.getDateValidation()} />
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{MailPoet.I18n.t('websiteTimeIs')} <code>{currentTime}</code>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
ref="isScheduled"
|
||||||
|
type="checkbox"
|
||||||
|
value="1"
|
||||||
|
checked={this.isScheduled()}
|
||||||
|
name="isScheduled"
|
||||||
|
onChange={this.handleCheckboxChange} />
|
||||||
|
|
||||||
|
{schedulingOptions}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var fields = [
|
||||||
|
{
|
||||||
|
name: 'subject',
|
||||||
|
label: MailPoet.I18n.t('subjectLine'),
|
||||||
|
tip: MailPoet.I18n.t('subjectLineTip'),
|
||||||
|
type: 'text',
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-required-message': MailPoet.I18n.t('emptySubjectLineError')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'segments',
|
||||||
|
label: MailPoet.I18n.t('segments'),
|
||||||
|
tip: MailPoet.I18n.t('segmentsTip'),
|
||||||
|
type: 'selection',
|
||||||
|
placeholder: MailPoet.I18n.t('selectSegmentPlaceholder'),
|
||||||
|
id: "mailpoet_segments",
|
||||||
|
endpoint: "segments",
|
||||||
|
multiple: true,
|
||||||
|
filter: function(segment) {
|
||||||
|
return !!(!segment.deleted_at);
|
||||||
|
},
|
||||||
|
getLabel: function(segment) {
|
||||||
|
var name = segment.name;
|
||||||
|
if (segment.subscribers > 0) {
|
||||||
|
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
},
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-required-message': MailPoet.I18n.t('noSegmentsSelectedError')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sender',
|
||||||
|
label: MailPoet.I18n.t('sender'),
|
||||||
|
tip: MailPoet.I18n.t('senderTip'),
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'sender_name',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('senderNamePlaceholder'),
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sender_address',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('senderAddressPlaceholder'),
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-type': 'email'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reply-to',
|
||||||
|
label: MailPoet.I18n.t('replyTo'),
|
||||||
|
tip: MailPoet.I18n.t('replyToTip'),
|
||||||
|
inline: true,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'reply_to_name',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('replyToNamePlaceholder')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reply_to_address',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'options',
|
||||||
|
label: MailPoet.I18n.t('scheduleIt'),
|
||||||
|
type: 'reactComponent',
|
||||||
|
component: StandardScheduling,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
);
|
77
assets/js/src/newsletters/send/welcome.jsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'mailpoet',
|
||||||
|
'newsletters/types/welcome/scheduling.jsx'
|
||||||
|
],
|
||||||
|
function(
|
||||||
|
MailPoet,
|
||||||
|
Scheduling
|
||||||
|
) {
|
||||||
|
|
||||||
|
var settings = window.mailpoet_settings || {};
|
||||||
|
|
||||||
|
var fields = [
|
||||||
|
{
|
||||||
|
name: 'subject',
|
||||||
|
label: MailPoet.I18n.t('subjectLine'),
|
||||||
|
tip: MailPoet.I18n.t('subjectLineTip'),
|
||||||
|
type: 'text',
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-required-message': MailPoet.I18n.t('emptySubjectLineError')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'options',
|
||||||
|
label: MailPoet.I18n.t('sendWelcomeEmailWhen'),
|
||||||
|
type: 'reactComponent',
|
||||||
|
component: Scheduling,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sender',
|
||||||
|
label: MailPoet.I18n.t('sender'),
|
||||||
|
tip: MailPoet.I18n.t('senderTip'),
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'sender_name',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('senderNamePlaceholder'),
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sender_address',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('senderAddressPlaceholder'),
|
||||||
|
validation: {
|
||||||
|
'data-parsley-required': true,
|
||||||
|
'data-parsley-type': 'email'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reply-to',
|
||||||
|
label: MailPoet.I18n.t('replyTo'),
|
||||||
|
tip: MailPoet.I18n.t('replyToTip'),
|
||||||
|
inline: true,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'reply_to_name',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('replyToNamePlaceholder')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reply_to_address',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
@ -24,11 +24,14 @@ define(
|
|||||||
template.body = JSON.stringify(template.body);
|
template.body = JSON.stringify(template.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MailPoet.Modal.loading(true);
|
||||||
|
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
endpoint: 'newsletterTemplates',
|
endpoint: 'newsletterTemplates',
|
||||||
action: 'save',
|
action: 'save',
|
||||||
data: template
|
data: template
|
||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
|
MailPoet.Modal.loading(false);
|
||||||
if(response.result === true) {
|
if(response.result === true) {
|
||||||
this.props.onImport(template);
|
this.props.onImport(template);
|
||||||
} else {
|
} else {
|
||||||
@ -51,7 +54,7 @@ define(
|
|||||||
try {
|
try {
|
||||||
saveTemplate(JSON.parse(e.target.result));
|
saveTemplate(JSON.parse(e.target.result));
|
||||||
} catch (err) {
|
} 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);
|
}.bind(this);
|
||||||
|
|
||||||
@ -60,15 +63,15 @@ define(
|
|||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>Import a template</h2>
|
<h2>{MailPoet.I18n.t('importTemplateTitle')}</h2>
|
||||||
<form onSubmit={this.handleSubmit}>
|
<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">
|
<p className="submit">
|
||||||
<input
|
<input
|
||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
value="Upload" />
|
value={MailPoet.I18n.t('upload')} />
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -77,9 +80,6 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
var NewsletterTemplates = React.createClass({
|
var NewsletterTemplates = React.createClass({
|
||||||
mixins: [
|
|
||||||
Router.History
|
|
||||||
],
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -92,19 +92,22 @@ define(
|
|||||||
getTemplates: function() {
|
getTemplates: function() {
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
MailPoet.Modal.loading(true);
|
||||||
|
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
endpoint: 'newsletterTemplates',
|
endpoint: 'newsletterTemplates',
|
||||||
action: 'getAll',
|
action: 'getAll',
|
||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
|
MailPoet.Modal.loading(false);
|
||||||
if(this.isMounted()) {
|
if(this.isMounted()) {
|
||||||
|
|
||||||
if(response.length === 0) {
|
if(response.length === 0) {
|
||||||
response = [
|
response = [
|
||||||
{
|
{
|
||||||
name:
|
name:
|
||||||
"MailPoet's Guide",
|
MailPoet.I18n.t('mailpoetGuideTemplateTitle'),
|
||||||
description:
|
description:
|
||||||
"This is the standard template that comes with MailPoet.",
|
MailPoet.I18n.t('mailpoetGuideTemplateDescription'),
|
||||||
readonly: "1"
|
readonly: "1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -149,7 +152,9 @@ define(
|
|||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
if(
|
if(
|
||||||
window.confirm(
|
window.confirm(
|
||||||
'You are about to delete the template named "'+ template.name +'"'
|
(
|
||||||
|
MailPoet.I18n.t('confirmTemplateDeletion')
|
||||||
|
).replace("%$1s", template.name)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
@ -181,7 +186,7 @@ define(
|
|||||||
href="javascript:;"
|
href="javascript:;"
|
||||||
onClick={ this.handleDeleteTemplate.bind(null, template) }
|
onClick={ this.handleDeleteTemplate.bind(null, template) }
|
||||||
>
|
>
|
||||||
Delete
|
{MailPoet.I18n.t('delete')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
), thumbnail = '';
|
), thumbnail = '';
|
||||||
@ -212,7 +217,7 @@ define(
|
|||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
onClick={ this.handleSelectTemplate.bind(null, template) }
|
onClick={ this.handleSelectTemplate.bind(null, template) }
|
||||||
>
|
>
|
||||||
Select
|
{MailPoet.I18n.t('select')}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
@ -220,7 +225,7 @@ define(
|
|||||||
className="button button-secondary"
|
className="button button-secondary"
|
||||||
onClick={ this.handlePreviewTemplate.bind(null, template) }
|
onClick={ this.handlePreviewTemplate.bind(null, template) }
|
||||||
>
|
>
|
||||||
Preview
|
{MailPoet.I18n.t('preview')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{ (template.readonly === "1") ? false : deleteLink }
|
{ (template.readonly === "1") ? false : deleteLink }
|
||||||
@ -236,7 +241,7 @@ define(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Select a template</h1>
|
<h1>{MailPoet.I18n.t('selectTemplateTitle')}</h1>
|
||||||
|
|
||||||
<Breadcrumb step="template" />
|
<Breadcrumb step="template" />
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@ define(
|
|||||||
Breadcrumb
|
Breadcrumb
|
||||||
) {
|
) {
|
||||||
var NewsletterTypes = React.createClass({
|
var NewsletterTypes = React.createClass({
|
||||||
mixins: [
|
contextTypes: {
|
||||||
Router.History
|
router: React.PropTypes.object.isRequired
|
||||||
],
|
},
|
||||||
setupNewsletter: function(type) {
|
setupNewsletter: function(type) {
|
||||||
if(type !== undefined) {
|
if(type !== undefined) {
|
||||||
this.history.pushState(null, `/new/${type}`);
|
this.context.router.push(`/new/${type}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createNewsletter: function(type) {
|
createNewsletter: function(type) {
|
||||||
@ -26,11 +26,11 @@ define(
|
|||||||
action: 'create',
|
action: 'create',
|
||||||
data: {
|
data: {
|
||||||
type: type,
|
type: type,
|
||||||
subject: 'Draft newsletter',
|
subject: MailPoet.I18n.t('draftNewsletterTitle'),
|
||||||
}
|
}
|
||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
if(response.result && response.newsletter.id) {
|
if(response.result && response.newsletter.id) {
|
||||||
this.history.pushState(null, `/template/${response.newsletter.id}`);
|
this.context.router.push(`/template/${response.newsletter.id}`);
|
||||||
} else {
|
} else {
|
||||||
if(response.errors.length > 0) {
|
if(response.errors.length > 0) {
|
||||||
response.errors.map(function(error) {
|
response.errors.map(function(error) {
|
||||||
@ -43,7 +43,7 @@ define(
|
|||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Pick a type of campaign</h1>
|
<h1>{MailPoet.I18n.t('pickCampaignType')}</h1>
|
||||||
|
|
||||||
<Breadcrumb step="type" />
|
<Breadcrumb step="type" />
|
||||||
|
|
||||||
@ -52,10 +52,9 @@ define(
|
|||||||
<div className="mailpoet_thumbnail"></div>
|
<div className="mailpoet_thumbnail"></div>
|
||||||
|
|
||||||
<div className="mailpoet_description">
|
<div className="mailpoet_description">
|
||||||
<h3>Newsletter</h3>
|
<h3>{MailPoet.I18n.t('regularNewsletterTypeTitle')}</h3>
|
||||||
<p>
|
<p>
|
||||||
Send a newsletter with images, buttons, dividers,
|
{MailPoet.I18n.t('regularNewsletterTypeDescription')}
|
||||||
and social bookmarks. Or a simple email.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -64,7 +63,7 @@ define(
|
|||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
onClick={ this.createNewsletter.bind(null, 'standard') }
|
onClick={ this.createNewsletter.bind(null, 'standard') }
|
||||||
>
|
>
|
||||||
Create
|
{MailPoet.I18n.t('create')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -73,9 +72,9 @@ define(
|
|||||||
<div className="mailpoet_thumbnail"></div>
|
<div className="mailpoet_thumbnail"></div>
|
||||||
|
|
||||||
<div className="mailpoet_description">
|
<div className="mailpoet_description">
|
||||||
<h3>Welcome email</h3>
|
<h3>{MailPoet.I18n.t('welcomeNewsletterTypeTitle')}</h3>
|
||||||
<p>
|
<p>
|
||||||
Send an email for new users.
|
{MailPoet.I18n.t('welcomeNewsletterTypeDescription')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -84,7 +83,7 @@ define(
|
|||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
onClick={ this.setupNewsletter.bind(null, 'welcome') }
|
onClick={ this.setupNewsletter.bind(null, 'welcome') }
|
||||||
>
|
>
|
||||||
Set up
|
{MailPoet.I18n.t('setUp')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -93,9 +92,9 @@ define(
|
|||||||
<div className="mailpoet_thumbnail"></div>
|
<div className="mailpoet_thumbnail"></div>
|
||||||
|
|
||||||
<div className="mailpoet_description">
|
<div className="mailpoet_description">
|
||||||
<h3>Post notifications</h3>
|
<h3>{MailPoet.I18n.t('postNotificationNewsletterTypeTitle')}</h3>
|
||||||
<p>
|
<p>
|
||||||
Automatically send posts immediately, daily, weekly or monthly. Filter by categories, if you like.
|
{MailPoet.I18n.t('postNotificationsNewsletterTypeDescription')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -104,7 +103,7 @@ define(
|
|||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
onClick={ this.setupNewsletter.bind(null, 'notification') }
|
onClick={ this.setupNewsletter.bind(null, 'notification') }
|
||||||
>
|
>
|
||||||
Set up
|
{MailPoet.I18n.t('setUp')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -1,227 +0,0 @@
|
|||||||
define(
|
|
||||||
[
|
|
||||||
'underscore',
|
|
||||||
'react',
|
|
||||||
'react-router',
|
|
||||||
'mailpoet',
|
|
||||||
'form/form.jsx',
|
|
||||||
'form/fields/select.jsx',
|
|
||||||
'form/fields/selection.jsx',
|
|
||||||
'form/fields/text.jsx',
|
|
||||||
'newsletters/breadcrumb.jsx'
|
|
||||||
],
|
|
||||||
function(
|
|
||||||
_,
|
|
||||||
React,
|
|
||||||
Router,
|
|
||||||
MailPoet,
|
|
||||||
Form,
|
|
||||||
Select,
|
|
||||||
Selection,
|
|
||||||
Text,
|
|
||||||
Breadcrumb
|
|
||||||
) {
|
|
||||||
|
|
||||||
var intervalField = {
|
|
||||||
name: 'interval',
|
|
||||||
values: {
|
|
||||||
'daily': 'Once a day at...',
|
|
||||||
'weekly': 'Weekly on...',
|
|
||||||
'monthly': 'Monthly on the...',
|
|
||||||
'nthWeekDay': 'Monthly every...',
|
|
||||||
'immediately': 'Immediately.',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var SECONDS_IN_DAY = 86400;
|
|
||||||
var TIME_STEP_SECONDS = 3600; // Default: 3600
|
|
||||||
var numberOfTimeSteps = SECONDS_IN_DAY / TIME_STEP_SECONDS;
|
|
||||||
var timeOfDayValues = _.object(_.map(
|
|
||||||
_.times(numberOfTimeSteps, function(step) { return step * TIME_STEP_SECONDS; }),
|
|
||||||
function(seconds) {
|
|
||||||
var date = new Date(null);
|
|
||||||
date.setSeconds(seconds);
|
|
||||||
var timeLabel = date.toISOString().substr(11, 5);
|
|
||||||
return [seconds, timeLabel];
|
|
||||||
}
|
|
||||||
));
|
|
||||||
var timeOfDayField = {
|
|
||||||
name: 'timeOfDay',
|
|
||||||
values: timeOfDayValues,
|
|
||||||
};
|
|
||||||
|
|
||||||
var weekDayField = {
|
|
||||||
name: 'weekDay',
|
|
||||||
values: {
|
|
||||||
0: 'Monday',
|
|
||||||
1: 'Tuesday',
|
|
||||||
2: 'Wednesday',
|
|
||||||
3: 'Thursday',
|
|
||||||
4: 'Friday',
|
|
||||||
5: 'Saturday',
|
|
||||||
6: 'Sunday',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var NUMBER_OF_DAYS_IN_MONTH = 28; // 28 for compatibility with MP2
|
|
||||||
var monthDayField = {
|
|
||||||
name: 'monthDay',
|
|
||||||
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';
|
|
||||||
|
|
||||||
return [day, (day + 1).toString() + suffix];
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
|
|
||||||
var nthWeekDayField = {
|
|
||||||
name: 'nthWeekDay',
|
|
||||||
values: {
|
|
||||||
'0': '1st',
|
|
||||||
'1': '2nd',
|
|
||||||
'2': '3rd',
|
|
||||||
'3': 'last',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var NewsletterWelcome = React.createClass({
|
|
||||||
mixins: [
|
|
||||||
Router.History
|
|
||||||
],
|
|
||||||
getInitialState: function() {
|
|
||||||
return {
|
|
||||||
intervalType: 'immediate', // 'immediate'|'daily'|'weekly'|'monthly'
|
|
||||||
timeOfDay: 0,
|
|
||||||
weekDay: 0,
|
|
||||||
monthDay: 0,
|
|
||||||
nthWeekDay: 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
handleIntervalChange: function(event) {
|
|
||||||
this.setState({
|
|
||||||
intervalType: event.target.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleTimeOfDayChange: function(event) {
|
|
||||||
this.setState({
|
|
||||||
timeOfDay: event.target.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleWeekDayChange: function(event) {
|
|
||||||
this.setState({
|
|
||||||
weekDay: event.target.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleMonthDayChange: function(event) {
|
|
||||||
this.setState({
|
|
||||||
monthDay: event.target.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleNthWeekDayChange: function(event) {
|
|
||||||
this.setState({
|
|
||||||
nthWeekDay: event.target.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleNext: function() {
|
|
||||||
MailPoet.Ajax.post({
|
|
||||||
endpoint: 'newsletters',
|
|
||||||
action: 'create',
|
|
||||||
data: {
|
|
||||||
type: 'notification',
|
|
||||||
options: this.state,
|
|
||||||
},
|
|
||||||
}).done(function(response) {
|
|
||||||
if(response.result && response.newsletter.id) {
|
|
||||||
this.showTemplateSelection(response.newsletter.id);
|
|
||||||
} else {
|
|
||||||
if(response.errors.length > 0) {
|
|
||||||
response.errors.map(function(error) {
|
|
||||||
MailPoet.Notice.error(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
showTemplateSelection: function(newsletterId) {
|
|
||||||
this.history.pushState(null, `/template/${newsletterId}`);
|
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
var timeOfDaySelection,
|
|
||||||
weekDaySelection,
|
|
||||||
monthDaySelection,
|
|
||||||
nthWeekDaySelection;
|
|
||||||
|
|
||||||
if (this.state.intervalType !== 'immediately') {
|
|
||||||
timeOfDaySelection = (
|
|
||||||
<Select
|
|
||||||
field={timeOfDayField}
|
|
||||||
item={this.state}
|
|
||||||
onValueChange={this.handleTimeOfDayChange} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.intervalType === 'weekly'
|
|
||||||
|| this.state.intervalType === 'nthWeekDay') {
|
|
||||||
weekDaySelection = (
|
|
||||||
<Select
|
|
||||||
field={weekDayField}
|
|
||||||
item={this.state}
|
|
||||||
onValueChange={this.handleWeekDayChange} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.intervalType === 'monthly') {
|
|
||||||
monthDaySelection = (
|
|
||||||
<Select
|
|
||||||
field={monthDayField}
|
|
||||||
item={this.state}
|
|
||||||
onValueChange={this.handleMonthDayChange} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.intervalType === 'nthWeekDay') {
|
|
||||||
nthWeekDaySelection = (
|
|
||||||
<Select
|
|
||||||
field={nthWeekDayField}
|
|
||||||
item={this.state}
|
|
||||||
onValueChange={this.handleNthWeekDayChange} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>Post notifications</h1>
|
|
||||||
<Breadcrumb step="type" />
|
|
||||||
|
|
||||||
<Select
|
|
||||||
field={intervalField}
|
|
||||||
item={this.state}
|
|
||||||
onValueChange={this.handleIntervalChange} />
|
|
||||||
|
|
||||||
{nthWeekDaySelection}
|
|
||||||
{monthDaySelection}
|
|
||||||
{weekDaySelection}
|
|
||||||
{timeOfDaySelection}
|
|
||||||
|
|
||||||
<p className="submit">
|
|
||||||
<input
|
|
||||||
className="button button-primary"
|
|
||||||
type="button"
|
|
||||||
onClick={ this.handleNext }
|
|
||||||
value="Next" />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NewsletterWelcome;
|
|
||||||
}
|
|
||||||
);
|
|
@ -0,0 +1,96 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'underscore',
|
||||||
|
'react',
|
||||||
|
'react-router',
|
||||||
|
'mailpoet',
|
||||||
|
'newsletters/types/notification/scheduling.jsx',
|
||||||
|
'newsletters/breadcrumb.jsx'
|
||||||
|
],
|
||||||
|
function(
|
||||||
|
_,
|
||||||
|
React,
|
||||||
|
Router,
|
||||||
|
MailPoet,
|
||||||
|
Scheduling,
|
||||||
|
Breadcrumb
|
||||||
|
) {
|
||||||
|
|
||||||
|
var field = {
|
||||||
|
name: 'options',
|
||||||
|
label: 'Periodicity',
|
||||||
|
type: 'reactComponent',
|
||||||
|
component: Scheduling,
|
||||||
|
};
|
||||||
|
|
||||||
|
var NewsletterNotification = React.createClass({
|
||||||
|
contextTypes: {
|
||||||
|
router: React.PropTypes.object.isRequired
|
||||||
|
},
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
intervalType: 'daily',
|
||||||
|
timeOfDay: 0,
|
||||||
|
weekDay: 1,
|
||||||
|
monthDay: 0,
|
||||||
|
nthWeekDay: 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleValueChange: function(event) {
|
||||||
|
var state = this.state;
|
||||||
|
state[event.target.name] = event.target.value;
|
||||||
|
this.setState(state);
|
||||||
|
},
|
||||||
|
handleNext: function() {
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'newsletters',
|
||||||
|
action: 'create',
|
||||||
|
data: _.extend({}, this.state, {
|
||||||
|
type: 'notification',
|
||||||
|
subject: MailPoet.I18n.t('draftNewsletterTitle'),
|
||||||
|
}),
|
||||||
|
}).done(function(response) {
|
||||||
|
if(response.result && response.newsletter.id) {
|
||||||
|
this.showTemplateSelection(response.newsletter.id);
|
||||||
|
} else {
|
||||||
|
if(response.errors.length > 0) {
|
||||||
|
response.errors.map(function(error) {
|
||||||
|
MailPoet.Notice.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
showTemplateSelection: function(newsletterId) {
|
||||||
|
this.context.router.push(`/template/${newsletterId}`);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{MailPoet.I18n.t('postNotificationNewsletterTypeTitle')}</h1>
|
||||||
|
<Breadcrumb step="type" />
|
||||||
|
|
||||||
|
<h3>{MailPoet.I18n.t('selectPeriodicity')}</h3>
|
||||||
|
|
||||||
|
<Scheduling
|
||||||
|
item={this.state}
|
||||||
|
field={field}
|
||||||
|
onValueChange={this.handleValueChange} />
|
||||||
|
|
||||||
|
<p className="submit">
|
||||||
|
<input
|
||||||
|
className="button button-primary"
|
||||||
|
type="button"
|
||||||
|
onClick={ this.handleNext }
|
||||||
|
value={MailPoet.I18n.t('next')} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return NewsletterNotification;
|
||||||
|
}
|
||||||
|
);
|
200
assets/js/src/newsletters/types/notification/scheduling.jsx
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'underscore',
|
||||||
|
'react',
|
||||||
|
'react-router',
|
||||||
|
'mailpoet',
|
||||||
|
'form/fields/select.jsx'
|
||||||
|
],
|
||||||
|
function(
|
||||||
|
_,
|
||||||
|
React,
|
||||||
|
Router,
|
||||||
|
MailPoet,
|
||||||
|
Select
|
||||||
|
) {
|
||||||
|
|
||||||
|
var intervalField = {
|
||||||
|
name: 'intervalType',
|
||||||
|
values: {
|
||||||
|
'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'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var SECONDS_IN_DAY = 86400;
|
||||||
|
var TIME_STEP_SECONDS = 3600; // Default: 3600
|
||||||
|
var numberOfTimeSteps = SECONDS_IN_DAY / TIME_STEP_SECONDS;
|
||||||
|
var timeOfDayValues = _.object(_.map(
|
||||||
|
_.times(numberOfTimeSteps, function(step) { return step * TIME_STEP_SECONDS; }),
|
||||||
|
function(seconds) {
|
||||||
|
var date = new Date(null);
|
||||||
|
date.setSeconds(seconds);
|
||||||
|
var timeLabel = date.toISOString().substr(11, 5);
|
||||||
|
return [seconds, timeLabel];
|
||||||
|
}
|
||||||
|
));
|
||||||
|
var timeOfDayField = {
|
||||||
|
name: 'timeOfDay',
|
||||||
|
values: timeOfDayValues,
|
||||||
|
};
|
||||||
|
|
||||||
|
var weekDayField = {
|
||||||
|
name: 'weekDay',
|
||||||
|
values: {
|
||||||
|
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')
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var NUMBER_OF_DAYS_IN_MONTH = 28; // 28 for compatibility with MP2
|
||||||
|
var monthDayField = {
|
||||||
|
name: 'monthDay',
|
||||||
|
values: _.object(_.map(
|
||||||
|
_.times(NUMBER_OF_DAYS_IN_MONTH, function(day) { return day; }),
|
||||||
|
function(day) {
|
||||||
|
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, label];
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
|
var nthWeekDayField = {
|
||||||
|
name: 'nthWeekDay',
|
||||||
|
values: {
|
||||||
|
'1': MailPoet.I18n.t('first'),
|
||||||
|
'2': MailPoet.I18n.t('second'),
|
||||||
|
'3': MailPoet.I18n.t('third'),
|
||||||
|
'L': MailPoet.I18n.t('last'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var NotificationScheduling = React.createClass({
|
||||||
|
_getCurrentValue: function() {
|
||||||
|
return this.props.item[this.props.field.name] || {};
|
||||||
|
},
|
||||||
|
handleValueChange: function(name, value) {
|
||||||
|
var oldValue = this._getCurrentValue(),
|
||||||
|
newValue = {};
|
||||||
|
newValue[name] = value;
|
||||||
|
|
||||||
|
return this.props.onValueChange({
|
||||||
|
target: {
|
||||||
|
name: this.props.field.name,
|
||||||
|
value: _.extend({}, oldValue, newValue)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleIntervalChange: function(event) {
|
||||||
|
return this.handleValueChange(
|
||||||
|
'intervalType',
|
||||||
|
event.target.value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handleTimeOfDayChange: function(event) {
|
||||||
|
return this.handleValueChange(
|
||||||
|
'timeOfDay',
|
||||||
|
event.target.value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handleWeekDayChange: function(event) {
|
||||||
|
return this.handleValueChange(
|
||||||
|
'weekDay',
|
||||||
|
event.target.value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handleMonthDayChange: function(event) {
|
||||||
|
return this.handleValueChange(
|
||||||
|
'monthDay',
|
||||||
|
event.target.value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handleNthWeekDayChange: function(event) {
|
||||||
|
return this.handleValueChange(
|
||||||
|
'nthWeekDay',
|
||||||
|
event.target.value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var value = this._getCurrentValue(),
|
||||||
|
timeOfDaySelection,
|
||||||
|
weekDaySelection,
|
||||||
|
monthDaySelection,
|
||||||
|
nthWeekDaySelection;
|
||||||
|
|
||||||
|
|
||||||
|
if (value.intervalType !== 'immediately') {
|
||||||
|
timeOfDaySelection = (
|
||||||
|
<Select
|
||||||
|
field={timeOfDayField}
|
||||||
|
item={this._getCurrentValue()}
|
||||||
|
onValueChange={this.handleTimeOfDayChange} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.intervalType === 'weekly'
|
||||||
|
|| value.intervalType === 'nthWeekDay') {
|
||||||
|
weekDaySelection = (
|
||||||
|
<Select
|
||||||
|
field={weekDayField}
|
||||||
|
item={this._getCurrentValue()}
|
||||||
|
onValueChange={this.handleWeekDayChange} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.intervalType === 'monthly') {
|
||||||
|
monthDaySelection = (
|
||||||
|
<Select
|
||||||
|
field={monthDayField}
|
||||||
|
item={this._getCurrentValue()}
|
||||||
|
onValueChange={this.handleMonthDayChange} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.intervalType === 'nthWeekDay') {
|
||||||
|
nthWeekDaySelection = (
|
||||||
|
<Select
|
||||||
|
field={nthWeekDayField}
|
||||||
|
item={this._getCurrentValue()}
|
||||||
|
onValueChange={this.handleNthWeekDayChange} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
field={intervalField}
|
||||||
|
item={this._getCurrentValue()}
|
||||||
|
onValueChange={this.handleIntervalChange} />
|
||||||
|
|
||||||
|
{nthWeekDaySelection}
|
||||||
|
{monthDaySelection}
|
||||||
|
{weekDaySelection}
|
||||||
|
{timeOfDaySelection}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return NotificationScheduling;
|
||||||
|
}
|
||||||
|
);
|
@ -3,25 +3,21 @@ define(
|
|||||||
'react',
|
'react',
|
||||||
'react-router',
|
'react-router',
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
'form/form.jsx',
|
|
||||||
'form/fields/selection.jsx',
|
|
||||||
'newsletters/breadcrumb.jsx'
|
'newsletters/breadcrumb.jsx'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React,
|
||||||
Router,
|
Router,
|
||||||
MailPoet,
|
MailPoet,
|
||||||
Form,
|
|
||||||
Selection,
|
|
||||||
Breadcrumb
|
Breadcrumb
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var NewsletterStandard = React.createClass({
|
var NewsletterStandard = React.createClass({
|
||||||
mixins: [
|
contextTypes: {
|
||||||
Router.History
|
router: React.PropTypes.object.isRequired
|
||||||
],
|
},
|
||||||
showTemplateSelection: function(newsletterId) {
|
showTemplateSelection: function(newsletterId) {
|
||||||
this.history.pushState(null, `/template/${newsletterId}`);
|
this.context.router.push(`/template/${newsletterId}`);
|
||||||
},
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
// No options for this type, create a newsletter upon mounting
|
// No options for this type, create a newsletter upon mounting
|
||||||
@ -32,7 +28,6 @@ define(
|
|||||||
type: 'standard',
|
type: 'standard',
|
||||||
}
|
}
|
||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
console.log(response);
|
|
||||||
if(response.result && response.newsletter.id) {
|
if(response.result && response.newsletter.id) {
|
||||||
this.showTemplateSelection(response.newsletter.id);
|
this.showTemplateSelection(response.newsletter.id);
|
||||||
} else {
|
} else {
|
||||||
@ -47,7 +42,7 @@ define(
|
|||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Newsletter</h1>
|
<h1>{MailPoet.I18n.t('regularNewsletterTypeTitle')}</h1>
|
||||||
<Breadcrumb step="type" />
|
<Breadcrumb step="type" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -4,9 +4,7 @@ define(
|
|||||||
'react',
|
'react',
|
||||||
'react-router',
|
'react-router',
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
'form/form.jsx',
|
|
||||||
'form/fields/select.jsx',
|
'form/fields/select.jsx',
|
||||||
'form/fields/selection.jsx',
|
|
||||||
'form/fields/text.jsx',
|
'form/fields/text.jsx',
|
||||||
'newsletters/breadcrumb.jsx'
|
'newsletters/breadcrumb.jsx'
|
||||||
],
|
],
|
||||||
@ -15,9 +13,7 @@ define(
|
|||||||
React,
|
React,
|
||||||
Router,
|
Router,
|
||||||
MailPoet,
|
MailPoet,
|
||||||
Form,
|
|
||||||
Select,
|
Select,
|
||||||
Selection,
|
|
||||||
Text,
|
Text,
|
||||||
Breadcrumb
|
Breadcrumb
|
||||||
) {
|
) {
|
||||||
@ -28,15 +24,19 @@ define(
|
|||||||
var events = {
|
var events = {
|
||||||
name: 'event',
|
name: 'event',
|
||||||
values: {
|
values: {
|
||||||
'segment': 'When someone subscribes to the list...',
|
'segment': MailPoet.I18n.t('onSubscriptionToList'),
|
||||||
'user': 'When a new Wordrpess user is added to your site...',
|
'user': MailPoet.I18n.t('onWordpressUserRegistration'),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var availableSegmentValues = _.object(_.map(
|
var availableSegmentValues = _.object(_.map(
|
||||||
availableSegments,
|
availableSegments,
|
||||||
function(segment) {
|
function(segment) {
|
||||||
return [segment.id, segment.name];
|
var name = segment.name;
|
||||||
|
if (segment.subscribers > 0) {
|
||||||
|
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
|
||||||
|
}
|
||||||
|
return [segment.id, name];
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
var segmentField = {
|
var segmentField = {
|
||||||
@ -57,50 +57,61 @@ define(
|
|||||||
var afterTimeTypeField = {
|
var afterTimeTypeField = {
|
||||||
name: 'afterTimeType',
|
name: 'afterTimeType',
|
||||||
values: {
|
values: {
|
||||||
'immediate': 'immediately',
|
'immediate': MailPoet.I18n.t('delayImmediately'),
|
||||||
'hours': 'hour(s) after',
|
'hours': MailPoet.I18n.t('delayHoursAfter'),
|
||||||
'days': 'day(s) after',
|
'days': MailPoet.I18n.t('delayDaysAfter'),
|
||||||
'weeks': 'week(s) after',
|
'weeks': MailPoet.I18n.t('delayWeeksAfter'),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var NewsletterWelcome = React.createClass({
|
var WelcomeScheduling = React.createClass({
|
||||||
mixins: [
|
contextTypes: {
|
||||||
Router.History
|
router: React.PropTypes.object.isRequired
|
||||||
],
|
},
|
||||||
getInitialState: function() {
|
_getCurrentValue: function() {
|
||||||
return {
|
return this.props.item[this.props.field.name] || {};
|
||||||
event: 'segment',
|
},
|
||||||
segment: 1,
|
handleValueChange: function(name, value) {
|
||||||
role: 'subscriber',
|
var oldValue = this._getCurrentValue(),
|
||||||
afterTimeNumber: 1,
|
newValue = {};
|
||||||
afterTimeType: 'immediate',
|
newValue[name] = value;
|
||||||
};
|
|
||||||
|
return this.props.onValueChange({
|
||||||
|
target: {
|
||||||
|
name: this.props.field.name,
|
||||||
|
value: _.extend({}, oldValue, newValue)
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
handleEventChange: function(event) {
|
handleEventChange: function(event) {
|
||||||
this.setState({
|
return this.handleValueChange(
|
||||||
event: event.target.value,
|
'event',
|
||||||
});
|
event.target.value
|
||||||
|
);
|
||||||
},
|
},
|
||||||
handleSegmentChange: function(event) {
|
handleSegmentChange: function(event) {
|
||||||
this.setState({
|
return this.handleValueChange(
|
||||||
segment: event.target.value,
|
'segment',
|
||||||
});
|
event.target.value
|
||||||
|
);
|
||||||
},
|
},
|
||||||
handleRoleChange: function(event) {
|
handleRoleChange: function(event) {
|
||||||
this.setState({
|
return this.handleValueChange(
|
||||||
role: event.target.value,
|
'role',
|
||||||
});
|
event.target.value
|
||||||
|
);
|
||||||
},
|
},
|
||||||
handleAfterTimeNumberChange: function(event) {
|
handleAfterTimeNumberChange: function(event) {
|
||||||
this.setState({
|
return this.handleValueChange(
|
||||||
afterTimeNumber: event.target.value,
|
'afterTimeNumber',
|
||||||
});
|
event.target.value
|
||||||
|
);
|
||||||
},
|
},
|
||||||
handleAfterTimeTypeChange: function(event) {
|
handleAfterTimeTypeChange: function(event) {
|
||||||
this.setState({
|
return this.handleValueChange(
|
||||||
afterTimeType: event.target.value,
|
'afterTimeType',
|
||||||
});
|
event.target.value
|
||||||
|
);
|
||||||
},
|
},
|
||||||
handleNext: function() {
|
handleNext: function() {
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
@ -123,41 +134,41 @@ define(
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
showTemplateSelection: function(newsletterId) {
|
showTemplateSelection: function(newsletterId) {
|
||||||
this.history.pushState(null, `/template/${newsletterId}`);
|
this.context.router.push(`/template/${newsletterId}`);
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var roleSegmentSelection, timeNumber;
|
var value = this._getCurrentValue(),
|
||||||
if (this.state.event === 'user') {
|
roleSegmentSelection, timeNumber;
|
||||||
|
|
||||||
|
if (value.event === 'user') {
|
||||||
roleSegmentSelection = (
|
roleSegmentSelection = (
|
||||||
<Select
|
<Select
|
||||||
field={roleField}
|
field={roleField}
|
||||||
item={this.state}
|
item={this._getCurrentValue()}
|
||||||
onValueChange={this.handleRoleChange} />
|
onValueChange={this.handleRoleChange} />
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
roleSegmentSelection = (
|
roleSegmentSelection = (
|
||||||
<Select
|
<Select
|
||||||
field={segmentField}
|
field={segmentField}
|
||||||
item={this.state}
|
item={this._getCurrentValue()}
|
||||||
onValueChange={this.handleSegmentChange} />
|
onValueChange={this.handleSegmentChange} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.state.afterTimeType !== 'immediate') {
|
if (value.afterTimeType !== 'immediate') {
|
||||||
timeNumber = (
|
timeNumber = (
|
||||||
<Text
|
<Text
|
||||||
field={afterTimeNumberField}
|
field={afterTimeNumberField}
|
||||||
item={this.state}
|
item={this._getCurrentValue()}
|
||||||
onValueChange={this.handleAfterTimeNumberChange} />
|
onValueChange={this.handleAfterTimeNumberChange} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Welcome email</h1>
|
|
||||||
<Breadcrumb step="type" />
|
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
field={events}
|
field={events}
|
||||||
item={this.state}
|
item={this._getCurrentValue()}
|
||||||
onValueChange={this.handleEventChange} />
|
onValueChange={this.handleEventChange} />
|
||||||
|
|
||||||
{roleSegmentSelection}
|
{roleSegmentSelection}
|
||||||
@ -166,21 +177,14 @@ define(
|
|||||||
|
|
||||||
<Select
|
<Select
|
||||||
field={afterTimeTypeField}
|
field={afterTimeTypeField}
|
||||||
item={this.state}
|
item={this._getCurrentValue()}
|
||||||
onValueChange={this.handleAfterTimeTypeChange}/>
|
onValueChange={this.handleAfterTimeTypeChange}/>
|
||||||
|
|
||||||
<p className="submit">
|
|
||||||
<input
|
|
||||||
className="button button-primary"
|
|
||||||
type="button"
|
|
||||||
onClick={ this.handleNext }
|
|
||||||
value="Next" />
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return NewsletterWelcome;
|
return WelcomeScheduling;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
103
assets/js/src/newsletters/types/welcome/welcome.jsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'underscore',
|
||||||
|
'react',
|
||||||
|
'react-router',
|
||||||
|
'mailpoet',
|
||||||
|
'newsletters/types/welcome/scheduling.jsx',
|
||||||
|
'newsletters/breadcrumb.jsx'
|
||||||
|
],
|
||||||
|
function(
|
||||||
|
_,
|
||||||
|
React,
|
||||||
|
Router,
|
||||||
|
MailPoet,
|
||||||
|
Scheduling,
|
||||||
|
Breadcrumb
|
||||||
|
) {
|
||||||
|
|
||||||
|
var field = {
|
||||||
|
name: 'options',
|
||||||
|
label: 'Event',
|
||||||
|
type: 'reactComponent',
|
||||||
|
component: Scheduling,
|
||||||
|
};
|
||||||
|
|
||||||
|
var availableSegments = window.mailpoet_segments || {},
|
||||||
|
defaultSegment = 1;
|
||||||
|
|
||||||
|
if (_.size(availableSegments) > 0) {
|
||||||
|
defaultSegment = _.first(availableSegments).id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var NewsletterWelcome = React.createClass({
|
||||||
|
contextTypes: {
|
||||||
|
router: React.PropTypes.object.isRequired
|
||||||
|
},
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
event: 'segment',
|
||||||
|
segment: defaultSegment,
|
||||||
|
role: 'subscriber',
|
||||||
|
afterTimeNumber: 1,
|
||||||
|
afterTimeType: 'immediate',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleValueChange: function(event) {
|
||||||
|
var state = this.state;
|
||||||
|
state[event.target.name] = event.target.value;
|
||||||
|
this.setState(state);
|
||||||
|
},
|
||||||
|
handleNext: function() {
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'newsletters',
|
||||||
|
action: 'create',
|
||||||
|
data: _.extend({}, this.state, {
|
||||||
|
type: 'welcome',
|
||||||
|
subject: MailPoet.I18n.t('draftNewsletterTitle'),
|
||||||
|
}),
|
||||||
|
}).done(function(response) {
|
||||||
|
if(response.result && response.newsletter.id) {
|
||||||
|
this.showTemplateSelection(response.newsletter.id);
|
||||||
|
} else {
|
||||||
|
if(response.errors.length > 0) {
|
||||||
|
response.errors.map(function(error) {
|
||||||
|
MailPoet.Notice.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
showTemplateSelection: function(newsletterId) {
|
||||||
|
this.context.router.push(`/template/${newsletterId}`);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{MailPoet.I18n.t('welcomeNewsletterTypeTitle')}</h1>
|
||||||
|
<Breadcrumb step="type" />
|
||||||
|
|
||||||
|
<h3>{MailPoet.I18n.t('selectEventToSendWelcomeEmail')}</h3>
|
||||||
|
|
||||||
|
<Scheduling
|
||||||
|
item={this.state}
|
||||||
|
field={field}
|
||||||
|
onValueChange={this.handleValueChange} />
|
||||||
|
|
||||||
|
<p className="submit">
|
||||||
|
<input
|
||||||
|
className="button button-primary"
|
||||||
|
type="button"
|
||||||
|
onClick={ this.handleNext }
|
||||||
|
value={MailPoet.I18n.t('next')} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return NewsletterWelcome;
|
||||||
|
}
|
||||||
|
);
|
@ -51,7 +51,7 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
id: null,
|
id: null,
|
||||||
positionAfter: false,
|
positionAfter: false,
|
||||||
scroll: false,
|
scroll: false,
|
||||||
timeout: 2000,
|
timeout: 5000,
|
||||||
onOpen: null,
|
onOpen: null,
|
||||||
onClose: null
|
onClose: null
|
||||||
},
|
},
|
||||||
@ -192,21 +192,28 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
error: function(message, options) {
|
error: function(message, options) {
|
||||||
this.show(jQuery.extend({}, {
|
this.show(jQuery.extend({}, {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: '<p>'+message+'</p>'
|
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||||
}, options));
|
}, options));
|
||||||
},
|
},
|
||||||
success: function(message, options) {
|
success: function(message, options) {
|
||||||
this.show(jQuery.extend({}, {
|
this.show(jQuery.extend({}, {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: '<p>'+message+'</p>'
|
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||||
}, options));
|
}, options));
|
||||||
},
|
},
|
||||||
system: function(message, options) {
|
system: function(message, options) {
|
||||||
this.show(jQuery.extend({}, {
|
this.show(jQuery.extend({}, {
|
||||||
type: 'system',
|
type: 'system',
|
||||||
static: true,
|
static: true,
|
||||||
message: message
|
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||||
}, options));
|
}, 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() {
|
$('form.mailpoet_form').each(function() {
|
||||||
var form = $(this);
|
var form = $(this);
|
||||||
|
|
||||||
form.parsley().on('form:submit', function(parsley) {
|
form.parsley().on('form:validated', function(parsley) {
|
||||||
|
|
||||||
var data = form.serializeObject() || {};
|
|
||||||
|
|
||||||
// clear messages
|
// clear messages
|
||||||
form.find('.mailpoet_message').html('');
|
form.find('.mailpoet_message > p').hide();
|
||||||
|
|
||||||
|
// 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
|
// check if we're on the same domain
|
||||||
if(isSameDomain(MailPoetForm.ajax_url) === false) {
|
if(isSameDomain(MailPoetForm.ajax_url) === false) {
|
||||||
// non ajax post request
|
// non ajax post request
|
||||||
@ -40,27 +45,18 @@ function(
|
|||||||
action: 'subscribe',
|
action: 'subscribe',
|
||||||
data: data
|
data: data
|
||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
if(response.result !== true) {
|
if(response.result === false) {
|
||||||
// errors
|
form.find('.mailpoet_validate_error').html(
|
||||||
$.each(response.errors, function(index, error) {
|
response.errors.join('<br />')
|
||||||
form
|
).show();
|
||||||
.find('.mailpoet_message')
|
|
||||||
.append('<p class="mailpoet_validate_error">'+
|
|
||||||
error+
|
|
||||||
'</p>');
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// successfully subscribed
|
// successfully subscribed
|
||||||
if(response.page !== undefined) {
|
if(response.page !== undefined) {
|
||||||
// go to page
|
// go to page
|
||||||
window.location.href = response.page;
|
window.location.href = response.page;
|
||||||
} else if(response.message !== undefined) {
|
} else {
|
||||||
// display success message
|
// display success message
|
||||||
form
|
form.find('.mailpoet_validate_success').show();
|
||||||
.find('.mailpoet_message')
|
|
||||||
.html('<p class="mailpoet_validate_success">'+
|
|
||||||
response.message+
|
|
||||||
'</p>');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset form
|
// reset form
|
||||||
@ -68,6 +64,11 @@ function(
|
|||||||
// reset validation
|
// reset validation
|
||||||
parsley.reset();
|
parsley.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resize iframe
|
||||||
|
if(window.frameElement !== null) {
|
||||||
|
MailPoet.Iframe.autoSize(window.frameElement);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -12,38 +12,39 @@ define(
|
|||||||
Form
|
Form
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var fields = [
|
let fields = [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: 'Name',
|
label: MailPoet.I18n.t('name'),
|
||||||
type: 'text'
|
type: 'text'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'description',
|
name: 'description',
|
||||||
label: 'Description',
|
label: MailPoet.I18n.t('description'),
|
||||||
type: 'textarea'
|
type: 'textarea',
|
||||||
|
tip: MailPoet.I18n.t('segmentDescriptionTip')
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
var messages = {
|
const messages = {
|
||||||
onUpdate: function() {
|
onUpdate: function() {
|
||||||
MailPoet.Notice.success('Segment successfully updated!');
|
MailPoet.Notice.success(MailPoet.I18n.t('segmentUpdated'));
|
||||||
},
|
},
|
||||||
onCreate: function() {
|
onCreate: function() {
|
||||||
MailPoet.Notice.success('Segment successfully added!');
|
MailPoet.Notice.success(MailPoet.I18n.t('segmentAdded'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var SegmentForm = React.createClass({
|
var Link = Router.Link;
|
||||||
mixins: [
|
|
||||||
Router.History
|
const SegmentForm = React.createClass({
|
||||||
],
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="title">
|
<h1 className="title">
|
||||||
Segment
|
{MailPoet.I18n.t('segment')}
|
||||||
</h2>
|
<Link className="page-title-action" to="/">{MailPoet.I18n.t('backToList')}</Link>
|
||||||
|
</h1>
|
||||||
|
|
||||||
<Form
|
<Form
|
||||||
endpoint="segments"
|
endpoint="segments"
|
||||||
|
@ -10,106 +10,107 @@ import Listing from 'listing/listing.jsx'
|
|||||||
var columns = [
|
var columns = [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: 'Name',
|
label: MailPoet.I18n.t('name'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'description',
|
name: 'description',
|
||||||
label: 'Description',
|
label: MailPoet.I18n.t('description'),
|
||||||
sortable: false
|
sortable: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'subscribed',
|
name: 'subscribed',
|
||||||
label: 'Subscribed',
|
label: MailPoet.I18n.t('subscribed'),
|
||||||
sortable: false
|
sortable: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'unconfirmed',
|
name: 'unconfirmed',
|
||||||
label: 'Unconfirmed',
|
label: MailPoet.I18n.t('unconfirmed'),
|
||||||
sortable: false
|
sortable: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'unsubscribed',
|
name: 'unsubscribed',
|
||||||
label: 'Unsubscribed',
|
label: MailPoet.I18n.t('unsubscribed'),
|
||||||
sortable: false
|
sortable: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'created_at',
|
name: 'created_at',
|
||||||
label: 'Created on',
|
label: MailPoet.I18n.t('createdOn'),
|
||||||
sortable: true
|
sortable: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
onTrash: function(response) {
|
onTrash: function(response) {
|
||||||
if(response) {
|
var count = ~~response;
|
||||||
let message = null;
|
var 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message !== null) {
|
if(count === 1) {
|
||||||
MailPoet.Notice.success(message);
|
message = (
|
||||||
}
|
MailPoet.I18n.t('oneSegmentTrashed')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
message = (
|
||||||
|
MailPoet.I18n.t('multipleSegmentsTrashed')
|
||||||
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
},
|
},
|
||||||
onDelete: function(response) {
|
onDelete: function(response) {
|
||||||
if(response) {
|
var count = ~~response;
|
||||||
let message = null;
|
var message = null;
|
||||||
if(~~response === 1) {
|
|
||||||
message = (
|
|
||||||
'1 segment was permanently deleted.'
|
|
||||||
);
|
|
||||||
} else if(~~response > 1) {
|
|
||||||
message = (
|
|
||||||
'%$1d segments were permanently deleted.'
|
|
||||||
).replace('%$1d', ~~response);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message !== null) {
|
if(count === 1) {
|
||||||
MailPoet.Notice.success(message);
|
message = (
|
||||||
}
|
MailPoet.I18n.t('oneSegmentDeleted')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
message = (
|
||||||
|
MailPoet.I18n.t('multipleSegmentsDeleted')
|
||||||
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
},
|
},
|
||||||
onRestore: function(response) {
|
onRestore: function(response) {
|
||||||
if(response) {
|
var count = ~~response;
|
||||||
let message = null;
|
var 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message !== null) {
|
if(count === 1) {
|
||||||
MailPoet.Notice.success(message);
|
message = (
|
||||||
}
|
MailPoet.I18n.t('oneSegmentRestored')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
message = (
|
||||||
|
MailPoet.I18n.t('multipleSegmentsRestored')
|
||||||
|
).replace('%$1d', count);
|
||||||
}
|
}
|
||||||
|
MailPoet.Notice.success(message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const bulk_actions = [
|
||||||
|
{
|
||||||
|
name: 'trash',
|
||||||
|
label: MailPoet.I18n.t('trash'),
|
||||||
|
onSuccess: messages.onTrash
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const item_actions = [
|
const item_actions = [
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
label: 'Edit',
|
|
||||||
link: function(item) {
|
link: function(item) {
|
||||||
return (
|
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');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'duplicate_segment',
|
name: 'duplicate_segment',
|
||||||
label: 'Duplicate',
|
label: MailPoet.I18n.t('duplicate'),
|
||||||
onClick: function(item, refresh) {
|
onClick: function(item, refresh) {
|
||||||
return MailPoet.Ajax.post({
|
return MailPoet.Ajax.post({
|
||||||
endpoint: 'segments',
|
endpoint: 'segments',
|
||||||
@ -117,7 +118,7 @@ const item_actions = [
|
|||||||
data: item.id
|
data: item.id
|
||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
('List "%$1s" has been duplicated.').replace('%$1s', response.name)
|
(MailPoet.I18n.t('listDuplicated')).replace('%$1s', response.name)
|
||||||
);
|
);
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
@ -126,10 +127,23 @@ const item_actions = [
|
|||||||
return (segment.type !== 'wp_users');
|
return (segment.type !== 'wp_users');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'read_more',
|
||||||
|
link: function(item) {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href="https://www.mailpoet.com/#TODO"
|
||||||
|
target="_blank"
|
||||||
|
>{MailPoet.I18n.t('readMore')}</a>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
display: function(segment) {
|
||||||
|
return (segment.type === 'wp_users');
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'synchronize_segment',
|
name: 'synchronize_segment',
|
||||||
label: 'Update',
|
label: MailPoet.I18n.t('forceSync'),
|
||||||
className: 'update',
|
|
||||||
onClick: function(item, refresh) {
|
onClick: function(item, refresh) {
|
||||||
MailPoet.Modal.loading(true);
|
MailPoet.Modal.loading(true);
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
@ -139,7 +153,7 @@ const item_actions = [
|
|||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
if(response === true) {
|
if(response === true) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
('List "%$1s" has been synchronized.').replace('%$1s', item.name)
|
(MailPoet.I18n.t('listSynchronized')).replace('%$1s', item.name)
|
||||||
);
|
);
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
@ -153,7 +167,7 @@ const item_actions = [
|
|||||||
name: 'view_subscribers',
|
name: 'view_subscribers',
|
||||||
link: function(item) {
|
link: function(item) {
|
||||||
return (
|
return (
|
||||||
<a href={ item.subscribers_url }>View subscribers</a>
|
<a href={ item.subscribers_url }>{MailPoet.I18n.t('viewSubscribers')}</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -165,9 +179,6 @@ const item_actions = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const bulk_actions = [
|
|
||||||
];
|
|
||||||
|
|
||||||
const SegmentList = React.createClass({
|
const SegmentList = React.createClass({
|
||||||
renderItem: function(segment, actions) {
|
renderItem: function(segment, actions) {
|
||||||
var rowClasses = classNames(
|
var rowClasses = classNames(
|
||||||
@ -175,28 +186,42 @@ const SegmentList = React.createClass({
|
|||||||
'column-primary',
|
'column-primary',
|
||||||
'has-row-actions'
|
'has-row-actions'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const subscribed = ~~(segment.subscribers_count.subscribed || 0);
|
||||||
|
const unconfirmed = ~~(segment.subscribers_count.unconfirmed || 0);
|
||||||
|
const unsubscribed = ~~(segment.subscribers_count.unsubscribed || 0);
|
||||||
|
|
||||||
|
let segment_name = (
|
||||||
|
<Link to={ `/edit/${segment.id}` }>{ segment.name }</Link>
|
||||||
|
);
|
||||||
|
|
||||||
|
// the WP users segment is not editable so just display its name
|
||||||
|
if (segment.type === 'wp_users') {
|
||||||
|
segment_name = segment.name;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<td className={ rowClasses }>
|
<td className={ rowClasses }>
|
||||||
<strong>
|
<strong>
|
||||||
<a>{ segment.name }</a>
|
{ segment_name }
|
||||||
</strong>
|
</strong>
|
||||||
{ actions }
|
{ actions }
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Description">
|
<td className="column-date" data-colname={ MailPoet.I18n.t('description') }>
|
||||||
<abbr>{ segment.description }</abbr>
|
<abbr>{ segment.description }</abbr>
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Subscribed">
|
<td className="column-date" data-colname={ MailPoet.I18n.t('subscribed') }>
|
||||||
<abbr>{ segment.subscribed || 0 }</abbr>
|
<abbr>{ subscribed.toLocaleString() }</abbr>
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Unconfirmed">
|
<td className="column-date" data-colname={ MailPoet.I18n.t('unconfirmed') }>
|
||||||
<abbr>{ segment.unconfirmed || 0 }</abbr>
|
<abbr>{ unconfirmed.toLocaleString() }</abbr>
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Unsubscribed">
|
<td className="column-date" data-colname={ MailPoet.I18n.t('unsubscribed') }>
|
||||||
<abbr>{ segment.unsubscribed || 0 }</abbr>
|
<abbr>{ unsubscribed.toLocaleString() }</abbr>
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Created on">
|
<td className="column-date" data-colname={ MailPoet.I18n.t('createdOn') }>
|
||||||
<abbr>{ segment.created_at }</abbr>
|
<abbr>{ MailPoet.Date.format(segment.created_at) }</abbr>
|
||||||
</td>
|
</td>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -204,16 +229,16 @@ const SegmentList = React.createClass({
|
|||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="title">
|
<h1 className="title">
|
||||||
Segments <Link className="add-new-h2" to="/new">New</Link>
|
{MailPoet.I18n.t('pageTitle')} <Link className="page-title-action" to="/new">{MailPoet.I18n.t('new')}</Link>
|
||||||
</h2>
|
</h1>
|
||||||
|
|
||||||
<Listing
|
<Listing
|
||||||
|
limit={ mailpoet_listing_per_page }
|
||||||
location={ this.props.location }
|
location={ this.props.location }
|
||||||
params={ this.props.params }
|
params={ this.props.params }
|
||||||
messages={ messages }
|
messages={ messages }
|
||||||
search={ false }
|
search={ false }
|
||||||
limit={ 1000 }
|
|
||||||
endpoint="segments"
|
endpoint="segments"
|
||||||
onRenderItem={ this.renderItem }
|
onRenderItem={ this.renderItem }
|
||||||
columns={ columns }
|
columns={ columns }
|
||||||
@ -225,4 +250,4 @@ const SegmentList = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = SegmentList;
|
module.exports = SegmentList;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { Router, Route, IndexRoute, Link } from 'react-router'
|
import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
|
||||||
|
import { createHashHistory } from 'history'
|
||||||
import SegmentList from 'segments/list.jsx'
|
import SegmentList from 'segments/list.jsx'
|
||||||
import SegmentForm from 'segments/form.jsx'
|
import SegmentForm from 'segments/form.jsx'
|
||||||
import createHashHistory from 'history/lib/createHashHistory'
|
|
||||||
|
|
||||||
let history = createHashHistory({ queryKey: false })
|
const history = useRouterHistory(createHashHistory)({ queryKey: false });
|
||||||
|
|
||||||
const App = React.createClass({
|
const App = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
@ -13,7 +13,7 @@ const App = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let container = document.getElementById('segments_container');
|
const container = document.getElementById('segments_container');
|
||||||
|
|
||||||
if(container) {
|
if(container) {
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
|
@ -34,13 +34,16 @@ define(
|
|||||||
// show sending methods
|
// show sending methods
|
||||||
jQuery('.mailpoet_sending_methods').fadeIn();
|
jQuery('.mailpoet_sending_methods').fadeIn();
|
||||||
} else {
|
} else {
|
||||||
// hide DKIM option when using MailPoet's API
|
// toggle SPF/DKIM (hidden if the sending method is MailPoet)
|
||||||
jQuery('#mailpoet_mta_dkim')[
|
jQuery('#mailpoet_mta_spf')[
|
||||||
(group === 'mailpoet')
|
(group === 'mailpoet')
|
||||||
? 'hide'
|
? 'hide'
|
||||||
: 'show'
|
: 'show'
|
||||||
]();
|
]();
|
||||||
|
|
||||||
|
// (HIDDEN FOR BETA)
|
||||||
|
jQuery('#mailpoet_mta_dkim').hide();
|
||||||
|
|
||||||
// hide sending methods
|
// hide sending methods
|
||||||
jQuery('.mailpoet_sending_methods').hide();
|
jQuery('.mailpoet_sending_methods').hide();
|
||||||
|
|
||||||
|
@ -3,50 +3,101 @@ define(
|
|||||||
'react',
|
'react',
|
||||||
'react-router',
|
'react-router',
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
'form/form.jsx'
|
'form/form.jsx',
|
||||||
|
'react-string-replace'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React,
|
||||||
Router,
|
Router,
|
||||||
MailPoet,
|
MailPoet,
|
||||||
Form
|
Form,
|
||||||
|
ReactStringReplace
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var fields = [
|
var fields = [
|
||||||
{
|
{
|
||||||
name: 'email',
|
name: 'email',
|
||||||
label: 'E-mail',
|
label: MailPoet.I18n.t('email'),
|
||||||
type: 'text'
|
type: 'text',
|
||||||
|
disabled: function(subscriber) {
|
||||||
|
return ~~(subscriber.wp_user_id > 0);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'first_name',
|
name: 'first_name',
|
||||||
label: 'Firstname',
|
label: MailPoet.I18n.t('firstname'),
|
||||||
type: 'text'
|
type: 'text',
|
||||||
|
disabled: function(subscriber) {
|
||||||
|
return ~~(subscriber.wp_user_id > 0);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'last_name',
|
name: 'last_name',
|
||||||
label: 'Lastname',
|
label: MailPoet.I18n.t('lastname'),
|
||||||
type: 'text'
|
type: 'text',
|
||||||
|
disabled: function(subscriber) {
|
||||||
|
return ~~(subscriber.wp_user_id > 0);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'status',
|
name: 'status',
|
||||||
label: 'Status',
|
label: MailPoet.I18n.t('status'),
|
||||||
type: 'select',
|
type: 'select',
|
||||||
values: {
|
values: {
|
||||||
'unconfirmed': 'Unconfirmed',
|
'subscribed': MailPoet.I18n.t('subscribed'),
|
||||||
'subscribed': 'Subscribed',
|
'unconfirmed': MailPoet.I18n.t('unconfirmed'),
|
||||||
'unsubscribed': 'Unsubscribed'
|
'unsubscribed': MailPoet.I18n.t('unsubscribed')
|
||||||
|
},
|
||||||
|
filter: function(subscriber, value) {
|
||||||
|
if (~~(subscriber.wp_user_id) > 0 && value === 'unconfirmed') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'segments',
|
name: 'segments',
|
||||||
label: 'Lists',
|
label: MailPoet.I18n.t('lists'),
|
||||||
type: 'selection',
|
type: 'selection',
|
||||||
placeholder: "Select a list",
|
placeholder: MailPoet.I18n.t('selectList'),
|
||||||
endpoint: "segments",
|
endpoint: "segments",
|
||||||
multiple: true,
|
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) {
|
filter: function(segment) {
|
||||||
return !!(!segment.deleted_at);
|
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,44 +109,87 @@ define(
|
|||||||
label: custom_field.name,
|
label: custom_field.name,
|
||||||
type: custom_field.type
|
type: custom_field.type
|
||||||
};
|
};
|
||||||
if(custom_field.params) {
|
if (custom_field.params) {
|
||||||
field.params = custom_field.params;
|
field.params = custom_field.params;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(custom_field.params.values) {
|
if (custom_field.params.values) {
|
||||||
field.values = custom_field.params.values;
|
field.values = custom_field.params.values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add placeholders for selects (date, select)
|
||||||
|
switch(custom_field.type) {
|
||||||
|
case 'date':
|
||||||
|
field.year_placeholder = MailPoet.I18n.t('year');
|
||||||
|
field.month_placeholder = MailPoet.I18n.t('month');
|
||||||
|
field.day_placeholder = MailPoet.I18n.t('day');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'select':
|
||||||
|
field.placeholder = '-';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
fields.push(field);
|
fields.push(field);
|
||||||
});
|
});
|
||||||
|
|
||||||
var messages = {
|
var messages = {
|
||||||
onUpdate: function() {
|
onUpdate: function() {
|
||||||
MailPoet.Notice.success('Subscriber successfully updated!');
|
MailPoet.Notice.success(MailPoet.I18n.t('subscriberUpdated'));
|
||||||
},
|
},
|
||||||
onCreate: function() {
|
onCreate: function() {
|
||||||
MailPoet.Notice.success('Subscriber successfully added!');
|
MailPoet.Notice.success(MailPoet.I18n.t('subscriberAdded'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var beforeFormContent = function(subscriber) {
|
||||||
|
if (~~(subscriber.wp_user_id) > 0) {
|
||||||
|
return (
|
||||||
|
<p className="description">
|
||||||
|
{ ReactStringReplace(
|
||||||
|
MailPoet.I18n.t('WPUserEditNotice'),
|
||||||
|
/\[link\](.*?)\[\/link\]/g,
|
||||||
|
(match, i) => (
|
||||||
|
<a
|
||||||
|
key={ i }
|
||||||
|
href={`user-edit.php?user_id=${ subscriber.wp_user_id }`}
|
||||||
|
>{ match }</a>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var afterFormContent = function(subscriber) {
|
||||||
|
return (
|
||||||
|
<p className="description">
|
||||||
|
<strong>
|
||||||
|
{ MailPoet.I18n.t('tip') }
|
||||||
|
</strong> { MailPoet.I18n.t('customFieldsTip') }
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
var Link = Router.Link;
|
var Link = Router.Link;
|
||||||
|
|
||||||
var SubscriberForm = React.createClass({
|
var SubscriberForm = React.createClass({
|
||||||
mixins: [
|
|
||||||
Router.History
|
|
||||||
],
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="title">
|
<h1 className="title">
|
||||||
Subscriber
|
{MailPoet.I18n.t('subscriber')}
|
||||||
</h2>
|
<Link className="page-title-action" to="/">{MailPoet.I18n.t('backToList')}</Link>
|
||||||
|
</h1>
|
||||||
|
|
||||||
<Form
|
<Form
|
||||||
endpoint="subscribers"
|
endpoint="subscribers"
|
||||||
fields={ fields }
|
fields={ fields }
|
||||||
params={ this.props.params }
|
params={ this.props.params }
|
||||||
messages={ messages }
|
messages={ messages }
|
||||||
|
beforeFormContent={ beforeFormContent }
|
||||||
|
afterFormContent={ afterFormContent }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -43,12 +43,12 @@ define(
|
|||||||
width: '20em',
|
width: '20em',
|
||||||
templateResult: function (item) {
|
templateResult: function (item) {
|
||||||
return (item.subscriberCount > 0)
|
return (item.subscriberCount > 0)
|
||||||
? item.name + ' (' + item.subscriberCount + ')'
|
? item.name + ' (' + parseInt(item.subscriberCount).toLocaleString() + ')'
|
||||||
: item.name;
|
: item.name;
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
templateSelection: function (item) {
|
||||||
return (item.subscriberCount > 0)
|
return (item.subscriberCount > 0)
|
||||||
? item.name + ' (' + item.subscriberCount + ')'
|
? item.name + ' (' + parseInt(item.subscriberCount).toLocaleString() + ')'
|
||||||
: item.name;
|
: item.name;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -115,7 +115,7 @@ define(
|
|||||||
exportData.exportConfirmedOption = false;
|
exportData.exportConfirmedOption = false;
|
||||||
renderSegmentsAndFields(segmentsContainerElement, segments);
|
renderSegmentsAndFields(segmentsContainerElement, segments);
|
||||||
}
|
}
|
||||||
segmentsContainerElement.select2('val', selectedSegments);
|
segmentsContainerElement.val(selectedSegments).trigger('change');
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleNextStepButton(condition) {
|
function toggleNextStepButton(condition) {
|
||||||
@ -148,10 +148,10 @@ define(
|
|||||||
.done(function (response) {
|
.done(function (response) {
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
if (response.result === false) {
|
if (response.result === false) {
|
||||||
MailPoet.Notice.error(response.error);
|
MailPoet.Notice.error(response.errors);
|
||||||
} else {
|
} else {
|
||||||
resultMessage = MailPoetI18n.exportMessage
|
resultMessage = MailPoet.I18n.t('exportMessage')
|
||||||
.replace('%1$s', '<strong>' + response.data.totalExported + '</strong>')
|
.replace('%1$s', '<strong>' + parseInt(response.data.totalExported).toLocaleString() + '</strong>')
|
||||||
.replace('[link]', '<a href="' + response.data.exportFileURL + '" target="_blank" >')
|
.replace('[link]', '<a href="' + response.data.exportFileURL + '" target="_blank" >')
|
||||||
.replace('[/link]', '</a>');
|
.replace('[/link]', '</a>');
|
||||||
jQuery('#export_result_notice > ul > li').html(resultMessage);
|
jQuery('#export_result_notice > ul > li').html(resultMessage);
|
||||||
@ -162,9 +162,9 @@ define(
|
|||||||
.error(function (error) {
|
.error(function (error) {
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.'
|
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,9 @@ define(
|
|||||||
'mailpoet',
|
'mailpoet',
|
||||||
'handlebars',
|
'handlebars',
|
||||||
'papaparse',
|
'papaparse',
|
||||||
'select2'
|
'select2',
|
||||||
|
'asyncqueue',
|
||||||
|
'xss'
|
||||||
],
|
],
|
||||||
function (
|
function (
|
||||||
Backbone,
|
Backbone,
|
||||||
@ -14,7 +16,9 @@ define(
|
|||||||
jQuery,
|
jQuery,
|
||||||
MailPoet,
|
MailPoet,
|
||||||
Handlebars,
|
Handlebars,
|
||||||
Papa
|
Papa,
|
||||||
|
AsyncQueue,
|
||||||
|
xss
|
||||||
) {
|
) {
|
||||||
if (!jQuery('#mailpoet_subscribers_import').length) {
|
if (!jQuery('#mailpoet_subscribers_import').length) {
|
||||||
return;
|
return;
|
||||||
@ -123,9 +127,7 @@ define(
|
|||||||
// get an approximate size of textarea paste in bytes
|
// get an approximate size of textarea paste in bytes
|
||||||
var pasteSize = encodeURI(pasteInputElement.val()).split(/%..|./).length - 1;
|
var pasteSize = encodeURI(pasteInputElement.val()).split(/%..|./).length - 1;
|
||||||
if (pasteSize > maxPostSizeBytes) {
|
if (pasteSize > maxPostSizeBytes) {
|
||||||
MailPoet.Notice.error(MailPoetI18n.maxPostSizeNotice, {
|
MailPoet.Notice.error(MailPoet.I18n.t('maxPostSizeNotice'));
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// delay loading indicator for 10ms or else it's just too fast :)
|
// delay loading indicator for 10ms or else it's just too fast :)
|
||||||
@ -143,9 +145,7 @@ define(
|
|||||||
var ext = this.value.match(/\.(.+)$/);
|
var ext = this.value.match(/\.(.+)$/);
|
||||||
if (ext === null || ext[1].toLowerCase() !== 'csv') {
|
if (ext === null || ext[1].toLowerCase() !== 'csv') {
|
||||||
this.value = '';
|
this.value = '';
|
||||||
MailPoet.Notice.error(MailPoetI18n.wrongFileFormat, {
|
MailPoet.Notice.error(MailPoet.I18n.t('wrongFileFormat'));
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleNextStepButton(
|
toggleNextStepButton(
|
||||||
@ -193,9 +193,7 @@ define(
|
|||||||
}).done(function (response) {
|
}).done(function (response) {
|
||||||
if (response.result === false) {
|
if (response.result === false) {
|
||||||
MailPoet.Notice.hide();
|
MailPoet.Notice.hide();
|
||||||
MailPoet.Notice.error(response.error, {
|
MailPoet.Notice.error(response.errors);
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
jQuery('.mailpoet_mailchimp-key-status')
|
jQuery('.mailpoet_mailchimp-key-status')
|
||||||
.removeClass()
|
.removeClass()
|
||||||
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-error');
|
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-error');
|
||||||
@ -207,7 +205,7 @@ define(
|
|||||||
.removeClass()
|
.removeClass()
|
||||||
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-ok');
|
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-ok');
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
jQuery('.mailpoet_mailchimp-key-status').html(MailPoetI18n.noMailChimpLists);
|
jQuery('.mailpoet_mailchimp-key-status').html(MailPoet.I18n.t('noMailChimpLists'));
|
||||||
mailChimpListsContainerElement.hide();
|
mailChimpListsContainerElement.hide();
|
||||||
toggleNextStepButton(mailChimpProcessButtonElement, 'off');
|
toggleNextStepButton(mailChimpProcessButtonElement, 'off');
|
||||||
} else {
|
} else {
|
||||||
@ -218,9 +216,7 @@ define(
|
|||||||
}).error(function (error) {
|
}).error(function (error) {
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
|
||||||
timeout: 3000,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
@ -245,17 +241,13 @@ define(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MailPoet.Notice.hide();
|
MailPoet.Notice.hide();
|
||||||
MailPoet.Notice(response.message, {
|
MailPoet.Notice.error(response.errors);
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
}).error(function () {
|
}).error(function () {
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
MailPoetI18n.serverError + result.statusText.toLowerCase() + '.', {
|
MailPoet.I18n.t('serverError') + result.statusText.toLowerCase() + '.'
|
||||||
timeout: 3000,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -345,14 +337,12 @@ define(
|
|||||||
comments: advancedOptionComments,
|
comments: advancedOptionComments,
|
||||||
error: function () {
|
error: function () {
|
||||||
MailPoet.Notice.hide();
|
MailPoet.Notice.hide();
|
||||||
MailPoet.Notice.error(MailPoetI18n.dataProcessingError, {
|
MailPoet.Notice.error(MailPoet.I18n.t('dataProcessingError'));
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
complete: function (CSV) {
|
complete: function (CSV) {
|
||||||
for (var rowCount in CSV.data) {
|
for (var rowCount in CSV.data) {
|
||||||
var rowData = CSV.data[rowCount].map(function (el) {
|
var rowData = CSV.data[rowCount].map(function (el) {
|
||||||
return el.trim();
|
return filterXSS(el.trim());
|
||||||
}),
|
}),
|
||||||
rowColumnCount = rowData.length;
|
rowColumnCount = rowData.length;
|
||||||
// set the number of row elements based on the first non-empty row
|
// set the number of row elements based on the first non-empty row
|
||||||
@ -426,12 +416,10 @@ define(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
var errorNotice = MailPoetI18n.noValidRecords;
|
var errorNotice = MailPoet.I18n.t('noValidRecords');
|
||||||
errorNotice = errorNotice.replace('[link]', MailPoetI18n.csvKBLink);
|
errorNotice = errorNotice.replace('[link]', MailPoet.I18n.t('csvKBLink'));
|
||||||
errorNotice = errorNotice.replace('[/link]', '</a>');
|
errorNotice = errorNotice.replace('[/link]', '</a>');
|
||||||
MailPoet.Notice.error(errorNotice, {
|
MailPoet.Notice.error(errorNotice);
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -496,17 +484,17 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var import_results = {
|
var import_results = {
|
||||||
notice: MailPoetI18n.importNoticeSkipped.replace(
|
notice: MailPoet.I18n.t('importNoticeSkipped').replace(
|
||||||
'%1$s',
|
'%1$s',
|
||||||
'<strong>' + (subscribers.invalid.length + subscribers.duplicate.length) + '</strong>'
|
'<strong>' + (subscribers.invalid.length + subscribers.duplicate.length) + '</strong>'
|
||||||
),
|
),
|
||||||
invalid: (subscribers.invalid.length)
|
invalid: (subscribers.invalid.length)
|
||||||
? MailPoetI18n.importNoticeInvalid
|
? MailPoet.I18n.t('importNoticeInvalid')
|
||||||
.replace('%1$s', '<strong>' + subscribers.invalid.length + '</strong>')
|
.replace('%1$s', '<strong>' + subscribers.invalid.length.toLocaleString() + '</strong>')
|
||||||
.replace('%2$s', subscribers.invalid.join(', '))
|
.replace('%2$s', subscribers.invalid.join(', '))
|
||||||
: null,
|
: null,
|
||||||
duplicate: (subscribers.duplicate.length)
|
duplicate: (subscribers.duplicate.length)
|
||||||
? MailPoetI18n.importNoticeDuplicate
|
? MailPoet.I18n.t('importNoticeDuplicate')
|
||||||
.replace('%1$s', '<strong>' + subscribers.duplicate.length + '</strong>')
|
.replace('%1$s', '<strong>' + subscribers.duplicate.length + '</strong>')
|
||||||
.replace('%2$s', subscribers.duplicate.join(', '))
|
.replace('%2$s', subscribers.duplicate.join(', '))
|
||||||
: null
|
: null
|
||||||
@ -522,8 +510,8 @@ define(
|
|||||||
jQuery(details).toggle();
|
jQuery(details).toggle();
|
||||||
this.text =
|
this.text =
|
||||||
(jQuery(details).is(":visible"))
|
(jQuery(details).is(":visible"))
|
||||||
? MailPoetI18n.hideDetails
|
? MailPoet.I18n.t('hideDetails')
|
||||||
: MailPoetI18n.showDetails;
|
: MailPoet.I18n.t('showDetails');
|
||||||
});
|
});
|
||||||
|
|
||||||
// show available segments
|
// show available segments
|
||||||
@ -545,13 +533,15 @@ define(
|
|||||||
data: segments,
|
data: segments,
|
||||||
width: '20em',
|
width: '20em',
|
||||||
templateResult: function (item) {
|
templateResult: function (item) {
|
||||||
|
item.subscriberCount = parseInt(item.subscriberCount);
|
||||||
return (item.subscriberCount > 0)
|
return (item.subscriberCount > 0)
|
||||||
? item.name + ' (' + item.subscriberCount + ')'
|
? item.name + ' (' + item.subscriberCount.toLocaleString() + ')'
|
||||||
: item.name;
|
: item.name;
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
templateSelection: function (item) {
|
||||||
|
item.subscriberCount = parseInt(item.subscriberCount);
|
||||||
return (item.subscriberCount > 0)
|
return (item.subscriberCount > 0)
|
||||||
? item.name + ' (' + item.subscriberCount + ')'
|
? item.name + ' (' + item.subscriberCount.toLocaleString() + ')'
|
||||||
: item.name;
|
: item.name;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -559,9 +549,8 @@ define(
|
|||||||
var segmentSelectionNotice = jQuery('[data-id="notice_segmentSelection"]');
|
var segmentSelectionNotice = jQuery('[data-id="notice_segmentSelection"]');
|
||||||
if (!this.value) {
|
if (!this.value) {
|
||||||
if (!segmentSelectionNotice.length) {
|
if (!segmentSelectionNotice.length) {
|
||||||
MailPoet.Notice.error(MailPoetI18n.segmentSelectionRequired, {
|
MailPoet.Notice.error(MailPoet.I18n.t('segmentSelectionRequired'), {
|
||||||
static: true,
|
static: true,
|
||||||
timeout: 3000,
|
|
||||||
scroll: true,
|
scroll: true,
|
||||||
id: 'segmentSelection',
|
id: 'segmentSelection',
|
||||||
hideClose: true
|
hideClose: true
|
||||||
@ -579,7 +568,7 @@ define(
|
|||||||
|
|
||||||
jQuery('.mailpoet_create_segment').click(function () {
|
jQuery('.mailpoet_create_segment').click(function () {
|
||||||
MailPoet.Modal.popup({
|
MailPoet.Modal.popup({
|
||||||
title: MailPoetI18n.addNewList,
|
title: MailPoet.I18n.t('addNewList'),
|
||||||
template: jQuery('#new_segment_template').html()
|
template: jQuery('#new_segment_template').html()
|
||||||
})
|
})
|
||||||
jQuery('#new_segment_name').keypress(function (e) {
|
jQuery('#new_segment_name').keypress(function (e) {
|
||||||
@ -639,18 +628,14 @@ define(
|
|||||||
else {
|
else {
|
||||||
MailPoet.Modal.close();
|
MailPoet.Modal.close();
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
MailPoetI18n.segmentCreateError + response.message + '.', {
|
MailPoet.I18n.t('segmentCreateError') + response.message + '.'
|
||||||
timeout: 3000,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.error(function (error) {
|
.error(function (error) {
|
||||||
MailPoet.Modal.close();
|
MailPoet.Modal.close();
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
|
||||||
timeout: 3000
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -728,7 +713,7 @@ define(
|
|||||||
}
|
}
|
||||||
// if we're on the last line, show the total count of subscribers data
|
// if we're on the last line, show the total count of subscribers data
|
||||||
else if (index === (subscribers.subscribers.length - 1)) {
|
else if (index === (subscribers.subscribers.length - 1)) {
|
||||||
return subscribers.subscribersCount;
|
return subscribers.subscribersCount.toLocaleString();
|
||||||
} else {
|
} else {
|
||||||
return index + 1;
|
return index + 1;
|
||||||
}
|
}
|
||||||
@ -765,7 +750,7 @@ define(
|
|||||||
selectEvent.preventDefault();
|
selectEvent.preventDefault();
|
||||||
jQuery(selectElement).select2('close');
|
jQuery(selectElement).select2('close');
|
||||||
MailPoet.Modal.popup({
|
MailPoet.Modal.popup({
|
||||||
title: MailPoetI18n.addNewColumn,
|
title: MailPoet.I18n.t('addNewColumn'),
|
||||||
template: jQuery('#new_column_template').html()
|
template: jQuery('#new_column_template').html()
|
||||||
});
|
});
|
||||||
jQuery('#new_column_name').keypress(function (e) {
|
jQuery('#new_column_name').keypress(function (e) {
|
||||||
@ -829,7 +814,7 @@ define(
|
|||||||
// if this is the first custom column, create an "optgroup"
|
// if this is the first custom column, create an "optgroup"
|
||||||
if (mailpoetColumnsSelect2.length === 2) {
|
if (mailpoetColumnsSelect2.length === 2) {
|
||||||
mailpoetColumnsSelect2.push({
|
mailpoetColumnsSelect2.push({
|
||||||
'name': MailPoetI18n.userColumns,
|
'name': MailPoet.I18n.t('userColumns'),
|
||||||
'children': []
|
'children': []
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -855,18 +840,14 @@ define(
|
|||||||
filterSubscribers();
|
filterSubscribers();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MailPoet.Notice.error(MailPoetI18n.customFieldCreateError, {
|
MailPoet.Notice.error(MailPoet.I18n.t('customFieldCreateError'));
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
})
|
})
|
||||||
.error(function (error) {
|
.error(function (error) {
|
||||||
MailPoet.Modal.loading(false);
|
MailPoet.Modal.loading(false);
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
|
||||||
timeout: 3000,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -885,7 +866,7 @@ define(
|
|||||||
// if another column has the same value and it's not an 'ignore', prompt user
|
// if another column has the same value and it's not an 'ignore', prompt user
|
||||||
if (elementId === selectedOptionId
|
if (elementId === selectedOptionId
|
||||||
&& elementId !== 'ignore') {
|
&& elementId !== 'ignore') {
|
||||||
if (confirm(MailPoetI18n.selectedValueAlreadyMatched + ' ' + MailPoetI18n.confirmCorrespondingColumn)) {
|
if (confirm(MailPoet.I18n.t('selectedValueAlreadyMatched') + ' ' + MailPoet.I18n.t('confirmCorrespondingColumn'))) {
|
||||||
jQuery(element).data('column-id', 'ignore');
|
jQuery(element).data('column-id', 'ignore');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -928,9 +909,8 @@ define(
|
|||||||
if (!emailRegex.test(subscribersClone.subscribers[0][matchedColumn])) {
|
if (!emailRegex.test(subscribersClone.subscribers[0][matchedColumn])) {
|
||||||
preventNextStep = true;
|
preventNextStep = true;
|
||||||
if (!jQuery('[data-id="notice_invalidEmail"]').length) {
|
if (!jQuery('[data-id="notice_invalidEmail"]').length) {
|
||||||
MailPoet.Notice.error(MailPoetI18n.columnContainsInvalidElement, {
|
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidElement'), {
|
||||||
static: true,
|
static: true,
|
||||||
timeout: 3000,
|
|
||||||
scroll: true,
|
scroll: true,
|
||||||
hideClose: true,
|
hideClose: true,
|
||||||
id: 'invalidEmail'
|
id: 'invalidEmail'
|
||||||
@ -948,18 +928,18 @@ define(
|
|||||||
date = new Date(rowData.replace(/-/g, '/')), // IE doesn't like
|
date = new Date(rowData.replace(/-/g, '/')), // IE doesn't like
|
||||||
// dashes as date separators
|
// dashes as date separators
|
||||||
month_name = [
|
month_name = [
|
||||||
MailPoetI18n.january,
|
MailPoet.I18n.t('january'),
|
||||||
MailPoetI18n.february,
|
MailPoet.I18n.t('february'),
|
||||||
MailPoetI18n.march,
|
MailPoet.I18n.t('march'),
|
||||||
MailPoetI18n.april,
|
MailPoet.I18n.t('april'),
|
||||||
MailPoetI18n.may,
|
MailPoet.I18n.t('may'),
|
||||||
MailPoetI18n.june,
|
MailPoet.I18n.t('june'),
|
||||||
MailPoetI18n.july,
|
MailPoet.I18n.t('july'),
|
||||||
MailPoetI18n.august,
|
MailPoet.I18n.t('august'),
|
||||||
MailPoetI18n.september,
|
MailPoet.I18n.t('september'),
|
||||||
MailPoetI18n.october,
|
MailPoet.I18n.t('october'),
|
||||||
MailPoetI18n.november,
|
MailPoet.I18n.t('november'),
|
||||||
MailPoetI18n.december
|
MailPoet.I18n.t('december')
|
||||||
];
|
];
|
||||||
|
|
||||||
if (position !== fillterPosition) {
|
if (position !== fillterPosition) {
|
||||||
@ -972,8 +952,8 @@ define(
|
|||||||
if (rowData.trim() === '') {
|
if (rowData.trim() === '') {
|
||||||
data[matchedColumn] =
|
data[matchedColumn] =
|
||||||
'<span class="mailpoet_data_match mailpoet_import_error" title="'
|
'<span class="mailpoet_data_match mailpoet_import_error" title="'
|
||||||
+ MailPoetI18n.noDateFieldMatch + '">'
|
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
|
||||||
+ MailPoetI18n.emptyDate
|
+ MailPoet.I18n.t('emptyDate')
|
||||||
+ '</span>';
|
+ '</span>';
|
||||||
preventNextStep = true;
|
preventNextStep = true;
|
||||||
return;
|
return;
|
||||||
@ -990,27 +970,26 @@ define(
|
|||||||
+ ((date.getMinutes() < 10 ? '0' : '')
|
+ ((date.getMinutes() < 10 ? '0' : '')
|
||||||
+ date.getMinutes()) + ' '
|
+ date.getMinutes()) + ' '
|
||||||
+ ((date.getHours() >= 12)
|
+ ((date.getHours() >= 12)
|
||||||
? MailPoetI18n.pm
|
? MailPoet.I18n.t('pm')
|
||||||
: MailPoetI18n.am
|
: MailPoet.I18n.t('am')
|
||||||
);
|
);
|
||||||
data[matchedColumn] +=
|
data[matchedColumn] +=
|
||||||
'<span class="mailpoet_data_match" title="'
|
'<span class="mailpoet_data_match" title="'
|
||||||
+ MailPoetI18n.verifyDateMatch + '">'
|
+ MailPoet.I18n.t('verifyDateMatch') + '">'
|
||||||
+ date + '</span>';
|
+ MailPoet.Date.format(date) + '</span>';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
data[matchedColumn] +=
|
data[matchedColumn] +=
|
||||||
'<span class="mailpoet_data_match mailpoet_import_error" title="'
|
'<span class="mailpoet_data_match mailpoet_import_error" title="'
|
||||||
+ MailPoetI18n.noDateFieldMatch + '">'
|
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
|
||||||
+ MailPoetI18n.dateMatchError + '</span>';
|
+ MailPoet.I18n.t('dateMatchError') + '</span>';
|
||||||
preventNextStep = true;
|
preventNextStep = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (preventNextStep && !jQuery('.mailpoet_invalidDate').length) {
|
if (preventNextStep && !jQuery('.mailpoet_invalidDate').length) {
|
||||||
MailPoet.Notice.error(MailPoetI18n.columnContainsInvalidDate, {
|
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidDate'), {
|
||||||
static: true,
|
static: true,
|
||||||
timeout: 3000,
|
|
||||||
scroll: true,
|
scroll: true,
|
||||||
hideClose: true,
|
hideClose: true,
|
||||||
id: 'invalidDate'
|
id: 'invalidDate'
|
||||||
@ -1050,64 +1029,97 @@ define(
|
|||||||
}
|
}
|
||||||
MailPoet.Modal.loading(true);
|
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'),
|
_.each(jQuery('select.mailpoet_subscribers_column_data_match'),
|
||||||
function (column, index) {
|
function (column, columnIndex) {
|
||||||
var columnId = jQuery(column).data('column-id');
|
var columnId = jQuery(column).data('column-id');
|
||||||
if (columnId === 'ignore') {
|
if (columnId === 'ignore') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
subscribers[columnId] = [];
|
columns[columnId] = columnIndex;
|
||||||
_.each(importData.step1.subscribers, function (subsciber) {
|
});
|
||||||
subscribers[columnId].push(
|
|
||||||
_.chain(subsciber)
|
|
||||||
.pick(index)
|
|
||||||
.toArray()
|
|
||||||
.flatten()
|
|
||||||
.value()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
subscribers[columnId] = _.flatten(subscribers[columnId]);
|
|
||||||
});
|
|
||||||
|
|
||||||
MailPoet.Ajax.post({
|
_.each(subscribers, function () {
|
||||||
endpoint: 'ImportExport',
|
queue.add(function (queue) {
|
||||||
action: 'processImport',
|
queue.pause();
|
||||||
data: JSON.stringify({
|
MailPoet.Ajax
|
||||||
subscribers: subscribers,
|
.post({
|
||||||
segments: segmentSelectElement.val(),
|
endpoint: 'ImportExport',
|
||||||
updateSubscribers: (jQuery(':radio[name="subscriber_update_option"]:checked').val() === 'yes') ? true : false
|
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);
|
MailPoet.Modal.loading(false);
|
||||||
if (response.result === false) {
|
if (importResults.errors.length > 0 && !importResults.updated && !importResults.created) {
|
||||||
MailPoet.Notice.error(response.error, {
|
MailPoet.Notice.error(_.flatten(importResults.errors)
|
||||||
timeout: 3000,
|
);
|
||||||
});
|
}
|
||||||
} else {
|
else {
|
||||||
mailpoetSegments = response.data.segments;
|
mailpoetSegments = importResults.segments;
|
||||||
response.data.segments = _.map(segmentSelectElement.select2('data'),
|
importResults.segments = _.map(segmentSelectElement.select2('data'),
|
||||||
function (data) {
|
function (data) {
|
||||||
return data.name;
|
return data.name;
|
||||||
});
|
});
|
||||||
importData.step2 = response.data;
|
importData.step2 = importResults;
|
||||||
enableSegmentSelection(mailpoetSegments);
|
enableSegmentSelection(mailpoetSegments);
|
||||||
|
toggleNextStepButton('off');
|
||||||
router.navigate('step3', {trigger: true});
|
router.navigate('step3', {trigger: true});
|
||||||
}
|
}
|
||||||
}).error(function (error) {
|
|
||||||
MailPoet.Modal.loading(false);
|
|
||||||
MailPoet.Notice.error(
|
|
||||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.', {
|
|
||||||
timeout: 3000,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
filterSubscribers();
|
filterSubscribers();
|
||||||
enableSegmentSelection(mailpoetSegments);
|
enableSegmentSelection(mailpoetSegments);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.on('route:step3', function () {
|
router.on('route:step3', function () {
|
||||||
@ -1118,6 +1130,10 @@ define(
|
|||||||
|
|
||||||
showCurrentStep();
|
showCurrentStep();
|
||||||
|
|
||||||
|
if (importData.step2.errors.length > 0) {
|
||||||
|
MailPoet.Notice.error(_.flatten(importData.step2.errors));
|
||||||
|
}
|
||||||
|
|
||||||
// display statistics
|
// display statistics
|
||||||
var subscribersDataImportResultsTemplate =
|
var subscribersDataImportResultsTemplate =
|
||||||
Handlebars
|
Handlebars
|
||||||
@ -1126,13 +1142,13 @@ define(
|
|||||||
exportMenuElement = jQuery('span.mailpoet_export'),
|
exportMenuElement = jQuery('span.mailpoet_export'),
|
||||||
importResults = {
|
importResults = {
|
||||||
created: (importData.step2.created)
|
created: (importData.step2.created)
|
||||||
? MailPoetI18n.subscribersCreated
|
? MailPoet.I18n.t('subscribersCreated')
|
||||||
.replace('%1$s', '<strong>' + importData.step2.created + '</strong>')
|
.replace('%1$s', '<strong>' + importData.step2.created.toLocaleString() + '</strong>')
|
||||||
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
|
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
|
||||||
: false,
|
: false,
|
||||||
updated: (importData.step2.updated)
|
updated: (importData.step2.updated)
|
||||||
? MailPoetI18n.subscribersUpdated
|
? MailPoet.I18n.t('subscribersUpdated')
|
||||||
.replace('%1$s', '<strong>' + importData.step2.updated + '</strong>')
|
.replace('%1$s', '<strong>' + importData.step2.updated.toLocaleString() + '</strong>')
|
||||||
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
|
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
|
||||||
: false,
|
: false,
|
||||||
noaction: (!importData.step2.updated && !importData.step2.created)
|
noaction: (!importData.step2.updated && !importData.step2.created)
|
||||||
@ -1167,4 +1183,4 @@ define(
|
|||||||
Backbone.history.start();
|
Backbone.history.start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -11,28 +11,28 @@ import Selection from 'form/fields/selection.jsx'
|
|||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
name: 'email',
|
name: 'email',
|
||||||
label: 'Subscriber',
|
label: MailPoet.I18n.t('subscriber'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'status',
|
name: 'status',
|
||||||
label: 'Status',
|
label: MailPoet.I18n.t('status'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'segments',
|
name: 'segments',
|
||||||
label: 'Lists',
|
label: MailPoet.I18n.t('lists'),
|
||||||
sortable: false
|
sortable: false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'created_at',
|
name: 'created_at',
|
||||||
label: 'Subscribed on',
|
label: MailPoet.I18n.t('subscribedOn'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'updated_at',
|
name: 'updated_at',
|
||||||
label: 'Last modified on',
|
label: MailPoet.I18n.t('lastModifiedOn'),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -43,11 +43,11 @@ const messages = {
|
|||||||
var message = null;
|
var message = null;
|
||||||
if(~~response === 1) {
|
if(~~response === 1) {
|
||||||
message = (
|
message = (
|
||||||
'1 subscriber was moved to the trash.'
|
MailPoet.I18n.t('oneSubscriberTrashed')
|
||||||
);
|
);
|
||||||
} else if(~~response > 1) {
|
} else if(~~response > 1) {
|
||||||
message = (
|
message = (
|
||||||
'%$1d subscribers were moved to the trash.'
|
MailPoet.I18n.t('multipleSubscribersTrashed')
|
||||||
).replace('%$1d', ~~response);
|
).replace('%$1d', ~~response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,11 +61,11 @@ const messages = {
|
|||||||
var message = null;
|
var message = null;
|
||||||
if(~~response === 1) {
|
if(~~response === 1) {
|
||||||
message = (
|
message = (
|
||||||
'1 subscriber was permanently deleted.'
|
MailPoet.I18n.t('oneSubscriberDeleted')
|
||||||
);
|
);
|
||||||
} else if(~~response > 1) {
|
} else if(~~response > 1) {
|
||||||
message = (
|
message = (
|
||||||
'%$1d subscribers were permanently deleted.'
|
MailPoet.I18n.t('multipleSubscribersDeleted')
|
||||||
).replace('%$1d', ~~response);
|
).replace('%$1d', ~~response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,11 +79,11 @@ const messages = {
|
|||||||
var message = null;
|
var message = null;
|
||||||
if(~~response === 1) {
|
if(~~response === 1) {
|
||||||
message = (
|
message = (
|
||||||
'1 subscriber has been restored from the trash.'
|
MailPoet.I18n.t('oneSubscriberRestored')
|
||||||
);
|
);
|
||||||
} else if(~~response > 1) {
|
} else if(~~response > 1) {
|
||||||
message = (
|
message = (
|
||||||
'%$1d subscribers have been restored from the trash.'
|
MailPoet.I18n.t('multipleSubscribersRestored')
|
||||||
).replace('%$1d', ~~response);
|
).replace('%$1d', ~~response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ const messages = {
|
|||||||
const bulk_actions = [
|
const bulk_actions = [
|
||||||
{
|
{
|
||||||
name: 'moveToList',
|
name: 'moveToList',
|
||||||
label: 'Move to list...',
|
label: MailPoet.I18n.t('moveToList'),
|
||||||
onSelect: function() {
|
onSelect: function() {
|
||||||
let field = {
|
let field = {
|
||||||
id: 'move_to_segment',
|
id: 'move_to_segment',
|
||||||
@ -106,6 +106,11 @@ const bulk_actions = [
|
|||||||
return !!(
|
return !!(
|
||||||
!segment.deleted_at && segment.type === 'default'
|
!segment.deleted_at && segment.type === 'default'
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
getLabel: function (segment) {
|
||||||
|
return (segment.subscribers > 0) ?
|
||||||
|
segment.name + ' (' + parseInt(segment.subscribers).toLocaleString() + ')' :
|
||||||
|
segment.name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,7 +125,7 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
onSuccess: function(response) {
|
onSuccess: function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
'%$1d subscribers were moved to list <strong>%$2s</strong>.'
|
MailPoet.I18n.t('multipleSubscribersMovedToList')
|
||||||
.replace('%$1d', ~~response.subscribers)
|
.replace('%$1d', ~~response.subscribers)
|
||||||
.replace('%$2s', response.segment)
|
.replace('%$2s', response.segment)
|
||||||
);
|
);
|
||||||
@ -128,7 +133,7 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'addToList',
|
name: 'addToList',
|
||||||
label: 'Add to list...',
|
label: MailPoet.I18n.t('addToList'),
|
||||||
onSelect: function() {
|
onSelect: function() {
|
||||||
let field = {
|
let field = {
|
||||||
id: 'add_to_segment',
|
id: 'add_to_segment',
|
||||||
@ -137,6 +142,11 @@ const bulk_actions = [
|
|||||||
return !!(
|
return !!(
|
||||||
!segment.deleted_at && segment.type === 'default'
|
!segment.deleted_at && segment.type === 'default'
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
getLabel: function (segment) {
|
||||||
|
return (segment.subscribers > 0) ?
|
||||||
|
segment.name + ' (' + parseInt(segment.subscribers).toLocaleString() + ')' :
|
||||||
|
segment.name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -151,7 +161,7 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
onSuccess: function(response) {
|
onSuccess: function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
'%$1d subscribers were added to list <strong>%$2s</strong>.'
|
MailPoet.I18n.t('multipleSubscribersAddedToList')
|
||||||
.replace('%$1d', ~~response.subscribers)
|
.replace('%$1d', ~~response.subscribers)
|
||||||
.replace('%$2s', response.segment)
|
.replace('%$2s', response.segment)
|
||||||
);
|
);
|
||||||
@ -159,7 +169,7 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'removeFromList',
|
name: 'removeFromList',
|
||||||
label: 'Remove from list...',
|
label: MailPoet.I18n.t('removeFromList'),
|
||||||
onSelect: function() {
|
onSelect: function() {
|
||||||
let field = {
|
let field = {
|
||||||
id: 'remove_from_segment',
|
id: 'remove_from_segment',
|
||||||
@ -168,6 +178,11 @@ const bulk_actions = [
|
|||||||
return !!(
|
return !!(
|
||||||
segment.type === 'default'
|
segment.type === 'default'
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
getLabel: function (segment) {
|
||||||
|
return (segment.subscribers > 0) ?
|
||||||
|
segment.name + ' (' + parseInt(segment.subscribers).toLocaleString() + ')' :
|
||||||
|
segment.name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -182,7 +197,7 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
onSuccess: function(response) {
|
onSuccess: function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
'%$1d subscribers were removed from list <strong>%$2s</strong>.'
|
MailPoet.I18n.t('multipleSubscribersRemovedFromList')
|
||||||
.replace('%$1d', ~~response.subscribers)
|
.replace('%$1d', ~~response.subscribers)
|
||||||
.replace('%$2s', response.segment)
|
.replace('%$2s', response.segment)
|
||||||
);
|
);
|
||||||
@ -190,27 +205,27 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'removeFromAllLists',
|
name: 'removeFromAllLists',
|
||||||
label: 'Remove from all lists',
|
label: MailPoet.I18n.t('removeFromAllLists'),
|
||||||
onSuccess: function(response) {
|
onSuccess: function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
'%$1d subscribers were removed from all lists.'
|
MailPoet.I18n.t('multipleSubscribersRemovedFromAllLists')
|
||||||
.replace('%$1d', ~~response)
|
.replace('%$1d', ~~response)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'confirmUnconfirmed',
|
name: 'sendConfirmationEmail',
|
||||||
label: 'Confirm unconfirmed',
|
label: MailPoet.I18n.t('resendConfirmationEmail'),
|
||||||
onSuccess: function(response) {
|
onSuccess: function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
'%$1d subscribers have been confirmed.'
|
MailPoet.I18n.t('multipleConfirmationEmailsSent')
|
||||||
.replace('%$1d', ~~response)
|
.replace('%$1d', ~~response)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'trash',
|
name: 'trash',
|
||||||
label: 'Trash',
|
label: MailPoet.I18n.t('trash'),
|
||||||
onSuccess: messages.onTrash
|
onSuccess: messages.onTrash
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -218,10 +233,10 @@ const bulk_actions = [
|
|||||||
const item_actions = [
|
const item_actions = [
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
label: 'Edit',
|
label: MailPoet.I18n.t('edit'),
|
||||||
link: function(item) {
|
link: function(item) {
|
||||||
return (
|
return (
|
||||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
<Link to={ `/edit/${item.id}` }>{MailPoet.I18n.t('edit')}</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -231,6 +246,15 @@ const item_actions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const SubscriberList = React.createClass({
|
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) {
|
renderItem: function(subscriber, actions) {
|
||||||
let row_classes = classNames(
|
let row_classes = classNames(
|
||||||
'manage-column',
|
'manage-column',
|
||||||
@ -243,23 +267,42 @@ const SubscriberList = React.createClass({
|
|||||||
|
|
||||||
switch(subscriber.status) {
|
switch(subscriber.status) {
|
||||||
case 'subscribed':
|
case 'subscribed':
|
||||||
status = 'Subscribed';
|
status = MailPoet.I18n.t('subscribed');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'unconfirmed':
|
case 'unconfirmed':
|
||||||
status = 'Unconfirmed';
|
status = MailPoet.I18n.t('unconfirmed');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'unsubscribed':
|
case 'unsubscribed':
|
||||||
status = 'Unsubscribed';
|
status = MailPoet.I18n.t('unsubscribed');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let segments = mailpoet_segments.filter(function(segment) {
|
let segments = false;
|
||||||
return (jQuery.inArray(segment.id, subscriber.segments) !== -1);
|
let subscribed_segments = [];
|
||||||
}).map(function(segment) {
|
|
||||||
return segment.name;
|
// WordPress Users
|
||||||
}).join(', ');
|
if (~~(subscriber.wp_user_id) > 0) {
|
||||||
|
subscribed_segments.push(MailPoet.I18n.t('WPUsersSegment'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscriptions
|
||||||
|
if (subscriber.subscriptions.length > 0) {
|
||||||
|
subscriber.subscriptions.map((subscription) => {
|
||||||
|
const segment = this.getSegmentFromId(subscription.segment_id);
|
||||||
|
if(segment === false) return;
|
||||||
|
if (subscription.status === 'subscribed') {
|
||||||
|
subscribed_segments.push(segment.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
segments = (
|
||||||
|
<span>
|
||||||
|
{ subscribed_segments.join(', ') }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
let avatar = false;
|
let avatar = false;
|
||||||
if(subscriber.avatar_url) {
|
if(subscriber.avatar_url) {
|
||||||
@ -285,17 +328,17 @@ const SubscriberList = React.createClass({
|
|||||||
</p>
|
</p>
|
||||||
{ actions }
|
{ actions }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname="Status">
|
<td className="column" data-colname={MailPoet.I18n.t('status')}>
|
||||||
{ status }
|
{ status }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname="Lists">
|
<td className="column" data-colname={MailPoet.I18n.t('lists')}>
|
||||||
{ segments }
|
{ segments }
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Subscribed on">
|
<td className="column-date" data-colname={MailPoet.I18n.t('subscribedOn')}>
|
||||||
<abbr>{ subscriber.created_at }</abbr>
|
<abbr>{ MailPoet.Date.format(subscriber.created_at) }</abbr>
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname="Last modified on">
|
<td className="column-date" data-colname={MailPoet.I18n.t('lastModifiedOn')}>
|
||||||
<abbr>{ subscriber.updated_at }</abbr>
|
<abbr>{ MailPoet.Date.format(subscriber.updated_at) }</abbr>
|
||||||
</td>
|
</td>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -306,13 +349,14 @@ const SubscriberList = React.createClass({
|
|||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="title">
|
<h1 className="title">
|
||||||
Subscribers <Link className="add-new-h2" to="/new">New</Link>
|
{MailPoet.I18n.t('pageTitle')} <Link className="page-title-action" to="/new">{MailPoet.I18n.t('new')}</Link>
|
||||||
<a className="add-new-h2" href="?page=mailpoet-import#step1">Import</a>
|
<a className="page-title-action" href="?page=mailpoet-import#step1">{MailPoet.I18n.t('import')}</a>
|
||||||
<a id="mailpoet_export_button" className="add-new-h2" href="?page=mailpoet-export">Export</a>
|
<a id="mailpoet_export_button" className="page-title-action" href="?page=mailpoet-export">{MailPoet.I18n.t('export')}</a>
|
||||||
</h2>
|
</h1>
|
||||||
|
|
||||||
<Listing
|
<Listing
|
||||||
|
limit={ mailpoet_listing_per_page }
|
||||||
location={ this.props.location }
|
location={ this.props.location }
|
||||||
params={ this.props.params }
|
params={ this.props.params }
|
||||||
endpoint="subscribers"
|
endpoint="subscribers"
|
||||||
@ -328,4 +372,4 @@ const SubscriberList = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = SubscriberList;
|
module.exports = SubscriberList;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { Router, Route, IndexRoute, Link } from 'react-router'
|
import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
|
||||||
|
import { createHashHistory } from 'history'
|
||||||
import SubscriberList from 'subscribers/list.jsx'
|
import SubscriberList from 'subscribers/list.jsx'
|
||||||
import SubscriberForm from 'subscribers/form.jsx'
|
import SubscriberForm from 'subscribers/form.jsx'
|
||||||
import createHashHistory from 'history/lib/createHashHistory'
|
|
||||||
|
|
||||||
const history = createHashHistory({ queryKey: false })
|
const history = useRouterHistory(createHashHistory)({ queryKey: false });
|
||||||
|
|
||||||
const App = React.createClass({
|
const App = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
|
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
|
bootstrap: _bootstrap.php
|
||||||
colors: true
|
colors: true
|
||||||
memory_limit: 1024M
|
memory_limit: 1024M
|
||||||
|
log: true
|
||||||
extensions:
|
extensions:
|
||||||
enabled:
|
enabled:
|
||||||
- Codeception\Extension\RunFailed
|
- Codeception\Extension\RunFailed
|
||||||
|