Compare commits
996 Commits
3.0.0-beta
...
3.0.0-rc.2
Author | SHA1 | Date | |
---|---|---|---|
856c636089 | |||
8f9e8ea185 | |||
b0b88693f1 | |||
9916eb9da8 | |||
79b5426e01 | |||
5807fd2e02 | |||
0ee39143f4 | |||
10c39bd650 | |||
20593cc5a5 | |||
cb4b599d97 | |||
53f7953566 | |||
61ae2da1e3 | |||
36abd8e5e6 | |||
7e9de1fd07 | |||
7ac5e65963 | |||
cf992852b5 | |||
59482b2bfa | |||
053f9e0cdf | |||
e1cc25239b | |||
2f4452ad36 | |||
f453d685d6 | |||
2d2b4ca7f0 | |||
546e012fbf | |||
83adf089c5 | |||
2f45bb05d7 | |||
9ef8ab3e28 | |||
f4db4f05c4 | |||
e7e08dbb3a | |||
02e2f0c07a | |||
c75b6bd7eb | |||
b74be8777a | |||
7463e0d1f1 | |||
a378880cf8 | |||
33fa496913 | |||
eff996e1f8 | |||
28b894b26b | |||
c914aedc0d | |||
1745b67d64 | |||
2d25974fdc | |||
51a02784e2 | |||
b9bdc86fd9 | |||
e580e6b92b | |||
96f77498f7 | |||
62ce7c0437 | |||
c1e542cb5a | |||
544bf0ddfd | |||
609f1b5e67 | |||
4616cf67bf | |||
cc5227ca0d | |||
26bccd95d4 | |||
af58814fe7 | |||
7d9b4b31aa | |||
8a8108b41d | |||
d92b1f57bd | |||
52ef7bece4 | |||
dc11046ad1 | |||
01f41b9798 | |||
9c0d9c31f8 | |||
df499095c4 | |||
05dca3d2ce | |||
ec35b90f3e | |||
1b7e3a997f | |||
c598537025 | |||
6f149e3ec4 | |||
d181bde0e9 | |||
2985705b14 | |||
6ce925fbe8 | |||
b8aceff61f | |||
cd091c2af6 | |||
510cacf2fd | |||
eac6b1b414 | |||
316fa91a10 | |||
7c23415d26 | |||
28320cdbb6 | |||
48f3ae4ea1 | |||
e47c8bc701 | |||
78429d8f91 | |||
80c4eeed5e | |||
5985d659f9 | |||
638de3cf55 | |||
967fa09f4f | |||
a15e1200b5 | |||
a15b46cbab | |||
dcb0b45c21 | |||
14810a22b5 | |||
1b756ef0b2 | |||
5553817f9a | |||
4b7fb3ae3d | |||
efa231b08f | |||
8d8dfaa11f | |||
5ba2c4bc3a | |||
788494ec47 | |||
5e7f9e3edf | |||
2e5554a3af | |||
51fbf29031 | |||
c3c6ce989c | |||
a241d0c7bc | |||
632bce7894 | |||
1151354278 | |||
c12752403f | |||
d3ff174e9f | |||
03df7e723c | |||
6c8fe8413a | |||
89b0b51980 | |||
fa1ab733f8 | |||
127022645e | |||
b1d26b8cee | |||
f07b90adde | |||
b3884d06a8 | |||
abf1d817f4 | |||
c7b7b0abad | |||
8540e5eea9 | |||
09ed3d4fa6 | |||
b96dc8b3f7 | |||
0a4dc3eb38 | |||
a78af28943 | |||
f035d12aaf | |||
6353075f1e | |||
6c91ca9d31 | |||
6f8634570c | |||
0efcfad3d1 | |||
5d7b54ab22 | |||
ad1f6e2a8e | |||
d844b7e47f | |||
36d4e3eb15 | |||
853f686dde | |||
d17486bac4 | |||
4226684c5a | |||
364dd1b2a3 | |||
eaf10e8a96 | |||
bac494ac0d | |||
acd2b9f51e | |||
27c6fa5ff4 | |||
89b51b6215 | |||
7725391eff | |||
a37117cfa3 | |||
856331caa4 | |||
9117ae1a27 | |||
4aae8d56e5 | |||
033d527db9 | |||
b2b1f7ff71 | |||
de261d6179 | |||
a587b0a966 | |||
441aa14bcb | |||
4b4b5dd556 | |||
df9ba7e6c8 | |||
ca4f1c9387 | |||
8c151d2d11 | |||
78fb9ba46f | |||
3a0669e1a2 | |||
c466e53681 | |||
d02aed870e | |||
fad7ff0018 | |||
84a3f98725 | |||
1c3e968ec4 | |||
c090a8260b | |||
65726de7de | |||
33fe302f0d | |||
2d702dd5d3 | |||
18f208cf47 | |||
f7b1016e63 | |||
223fedba72 | |||
bf7e7e414f | |||
618d0c0c9d | |||
49318791fc | |||
a5abdd28e1 | |||
70860a676c | |||
469e9fd8e1 | |||
715b48df8d | |||
27ae0a9f16 | |||
b92329a6b5 | |||
6fe5b7e0c5 | |||
7e0c500e4f | |||
eec35c8ab6 | |||
4096c4b31b | |||
40cbefd1f4 | |||
fb5d43e975 | |||
f35b66b3cf | |||
7900e7eb8d | |||
849a24ced7 | |||
f7e73b06be | |||
52cbb9fcb2 | |||
966ec0cb7a | |||
2ff0d40d10 | |||
bb249ebe09 | |||
5a57029b38 | |||
84d427cc4c | |||
22efd2109b | |||
f044db5745 | |||
0865995d21 | |||
7c30192a03 | |||
334c3ff420 | |||
6d738ddb3b | |||
440052cf2c | |||
ccb751b44a | |||
7cf3d0960d | |||
6e45856622 | |||
9859df98b7 | |||
1071688924 | |||
4f3b0234a4 | |||
3e2bbeac11 | |||
08f81bd816 | |||
f0c59ff635 | |||
66c6f52646 | |||
4988aaf14f | |||
5773d46f1c | |||
f3a1e1b447 | |||
6de746162e | |||
60b3c066a5 | |||
63158dc2d5 | |||
dede6e56c4 | |||
dd366dde18 | |||
2fedafe483 | |||
feae98ac3f | |||
6fb18ad321 | |||
6c843e35b0 | |||
cfdb86eb6e | |||
41fb93e453 | |||
19813b5dad | |||
321393f119 | |||
ab3f41302c | |||
9dff4539e6 | |||
6520d5eca3 | |||
f5b152cdfa | |||
1d2cab1249 | |||
90b93bd76e | |||
563ca3e605 | |||
08bbfcb5e8 | |||
5572a7f1e5 | |||
9dd326e7db | |||
cf00813c7f | |||
4c898b76b2 | |||
81a2ba8e03 | |||
7e6d900b53 | |||
1a522794d6 | |||
197537d6ca | |||
b212ca801b | |||
db8f3216d7 | |||
78f9945296 | |||
0cebcd3965 | |||
4062e0662d | |||
20b7e82d3c | |||
9ab8a80567 | |||
f98d02121b | |||
e68e212ad0 | |||
cb1a1e51ba | |||
b42d8e68d9 | |||
e88d130ebb | |||
c924778d50 | |||
a9051c6d09 | |||
f6243b5d79 | |||
68c0b93586 | |||
0e8be8040c | |||
f3ea548d65 | |||
1ab6be8acd | |||
c413acd93d | |||
7614a4d8dc | |||
4a94c29b85 | |||
b5b9531ff3 | |||
e2a048a65f | |||
c28726f118 | |||
7c74885669 | |||
5f74f34cba | |||
d6ef526a9d | |||
0da0507e0a | |||
3f03c985bf | |||
77f6e13aa3 | |||
213d0e8627 | |||
1d019bc11e | |||
ca12487416 | |||
c5d42a5033 | |||
3b079440b5 | |||
419697991f | |||
d119a1e5fa | |||
1bd4264dd5 | |||
21ee60b7d7 | |||
849ca27d1f | |||
a4dad46fb7 | |||
fac4c8fb41 | |||
cdc87c23ea | |||
34d09ce0c9 | |||
fe9ae392f2 | |||
9501640f4f | |||
ad028ab55d | |||
74cb8d9735 | |||
381608df22 | |||
6aca598dc3 | |||
acbe2e383a | |||
55d3b67a2a | |||
c02394b576 | |||
6a9b8d88c2 | |||
b24c51d800 | |||
d3a3d3b277 | |||
3dcff8eb8a | |||
401339244c | |||
653ecdc4d0 | |||
88d5952684 | |||
c4d6c19c67 | |||
0554a84f77 | |||
c01b57a383 | |||
65f4f493f1 | |||
8a7ea791b0 | |||
1823985172 | |||
e735b5f3e0 | |||
cd5c57b7e9 | |||
fbf59723d8 | |||
2e166a233b | |||
1608ba5893 | |||
9d7eb8038d | |||
c9c78a7160 | |||
53df10dc2b | |||
a746c124a3 | |||
ca5a5301a8 | |||
7a2aaa86cf | |||
b626c7ea3c | |||
695152e947 | |||
a36fe400ed | |||
22bb971db5 | |||
b88452c5a2 | |||
4a2f9ad1f9 | |||
593a7de9fe | |||
e5ecf870c7 | |||
11cc97b201 | |||
e352b5bfad | |||
334448c964 | |||
7d8d535cb3 | |||
68988edd7e | |||
f164e9bb95 | |||
fe83435d14 | |||
453b7683bc | |||
25625b1ce1 | |||
048d71164a | |||
24e682e92e | |||
23d90c9f73 | |||
a9f190661f | |||
c1e56e5fa1 | |||
e2bb2679e4 | |||
d49530da0f | |||
0bc28ef3c7 | |||
563b7eccb0 | |||
94a9b63136 | |||
91ff008485 | |||
cb8fa23c3f | |||
3499de05e8 | |||
77ed4d34e8 | |||
cfc5f5a88d | |||
2514d87a00 | |||
23c6750ccc | |||
bb2af5176b | |||
95b5206e8b | |||
394118f113 | |||
b691fb5a48 | |||
1ba2492929 | |||
d08243b0ce | |||
189656fdc8 | |||
0be872eea9 | |||
22c39c0092 | |||
1b54e356b2 | |||
9079d7d4db | |||
160b28a632 | |||
03ebb30ac2 | |||
56eac1ae86 | |||
89da4c9aae | |||
b510071857 | |||
4bbec4700d | |||
29a2af2555 | |||
94d57b5287 | |||
6b7bc8a731 | |||
3dd0f00b7f | |||
b58f6cc4e0 | |||
7c942147ec | |||
6fca2061e6 | |||
0acc41c887 | |||
20d1ac81e2 | |||
cdb7b99728 | |||
54cb838d71 | |||
0b9ea23f0b | |||
3e40f768b4 | |||
6e929dcf79 | |||
7be01f0e4e | |||
9cb08734a3 | |||
55fda047f6 | |||
4706c5fc25 | |||
3ba857d03f | |||
f39cbe6b55 | |||
6dc1bf4e95 | |||
5b65a8f0ac | |||
583adf86da | |||
3b4a1b686d | |||
5390dd8421 | |||
fe8452711f | |||
f7cb53de2c | |||
1ac6dd8ccb | |||
b1425198b6 | |||
00a45f3214 | |||
8e46451337 | |||
b0d0cc09c8 | |||
af559a6fac | |||
67acceb968 | |||
703ee7ff71 | |||
29491dfd3e | |||
a49a230983 | |||
b8d285a1d9 | |||
d5227a9f2c | |||
693117eb40 | |||
f3aab6095e | |||
d70587a550 | |||
82226f2c36 | |||
2774101380 | |||
ee0e3ff95e | |||
17584dde43 | |||
3ac416de56 | |||
1e4c00169f | |||
11bbf54aad | |||
688e78560e | |||
5ca577a718 | |||
605df7dff1 | |||
fb1a3a80ff | |||
d3db755489 | |||
a4282b6a3e | |||
bc17984030 | |||
b823991867 | |||
04e238634d | |||
eba482cc67 | |||
e6663f0f3e | |||
7fa94a67c9 | |||
b4be9e1d28 | |||
a7504136a2 | |||
43fa12ec08 | |||
6723a563ed | |||
15e3e93c99 | |||
cbce789ac8 | |||
97607993fb | |||
334b119bb3 | |||
ed0b2e6231 | |||
ad7ad05ec7 | |||
bfba6d459c | |||
344eecbf11 | |||
14dc022d2d | |||
eff75cce94 | |||
51084fc57d | |||
298270f86c | |||
fe6d5d1523 | |||
3cceb32ec1 | |||
c8251a3bcd | |||
58888505b5 | |||
558c493dd7 | |||
8cdb7d77f6 | |||
539e6d3ee1 | |||
c9a0939ddd | |||
2add301b9f | |||
2d217e416a | |||
77e0ace951 | |||
933749f8f0 | |||
7b13babf3f | |||
8c673f78d7 | |||
2285c08c01 | |||
836b7179e9 | |||
f89a728c38 | |||
58f2c32362 | |||
99c4fc71c4 | |||
ce456af962 | |||
faa035a7c3 | |||
9066be6544 | |||
81c3e2facf | |||
3fafe2bd6a | |||
2f6fe8c804 | |||
ec3e88e658 | |||
b346a8846a | |||
6ff3895940 | |||
0e5401dd68 | |||
ea059ac0e4 | |||
f874ae6ca8 | |||
5bd6c6533a | |||
f539860922 | |||
536267c8f5 | |||
5b905a60e8 | |||
5e152ebaa1 | |||
2c35c7061e | |||
2515dcf4ce | |||
9458bf7418 | |||
44bf4b98b8 | |||
ff46784adf | |||
088d4f800d | |||
bb73e257db | |||
53fd3fe07c | |||
27a734d005 | |||
fb059f585e | |||
c99f990dbf | |||
5600d8087f | |||
cac3c30833 | |||
454a00c3cb | |||
156d05b4cf | |||
be63aa727d | |||
6c270ab095 | |||
bb7c9d2667 | |||
570b9dfb8f | |||
5f9baed195 | |||
45e6e0e9e6 | |||
08395d4365 | |||
167fb86927 | |||
64dbf158a4 | |||
89e57479cc | |||
fccd7f4054 | |||
1d6cdfe2cc | |||
812c6634ba | |||
419871a6bf | |||
823cd3cd07 | |||
24fa8c1d79 | |||
868f860e26 | |||
cbcd9fb22f | |||
eeb2fcb2e3 | |||
dde0b16cca | |||
01eaf1ef2d | |||
43c2908a2b | |||
6f64b9faa2 | |||
8d496e7aa3 | |||
25485a366a | |||
8aabc783e3 | |||
f72ceb2dbe | |||
af3d971154 | |||
2d3aae9dd0 | |||
11af014d9d | |||
6653327f7f | |||
3a2adde6c5 | |||
1aba3112e9 | |||
181d7b9876 | |||
ebe3f0bd00 | |||
1b69fe50ff | |||
fa3ba609f3 | |||
fe9aa03de1 | |||
cdd8e51ef9 | |||
1da06bd46a | |||
32b24a83ab | |||
5293589eea | |||
07f4c0bc1e | |||
7d9a072545 | |||
67ffcb5485 | |||
02098a3cf0 | |||
eab8065154 | |||
fb8ecef1c3 | |||
14955e5022 | |||
e83c0ff0bd | |||
09db1aac22 | |||
5fa1eb643a | |||
898913a517 | |||
3a4b364bcd | |||
d373d10f6c | |||
c07e1eff3c | |||
f5e985baa4 | |||
2c93a105cc | |||
cbf0a7684f | |||
2632feba31 | |||
c96bc755c7 | |||
bbad772d7a | |||
520a3c43be | |||
eb70df1466 | |||
5977b8b4bc | |||
2bb7d95e37 | |||
c64959dce0 | |||
ead0792b32 | |||
7bd52d456c | |||
8517896660 | |||
c78933f7c4 | |||
707d5efec1 | |||
acfb3aefba | |||
cb6f4046a2 | |||
667aa91581 | |||
b7f7dc6728 | |||
ad1e8feb23 | |||
486b382c88 | |||
472be3b071 | |||
37a9fd9e1b | |||
c984ac7a66 | |||
a1ea56f505 | |||
dd7f959731 | |||
09f4f2e78a | |||
502250a1a3 | |||
48e37f6797 | |||
420058a86d | |||
6c777ca074 | |||
a481debb77 | |||
c91f8ccc7a | |||
6a2b5e28c2 | |||
bc51b6efc8 | |||
152edda03f | |||
5029b73027 | |||
35c25d3337 | |||
ae25e95d51 | |||
5b8d0c63a1 | |||
94fb8c6096 | |||
93ef1d0197 | |||
501d00b0cc | |||
9af3dc1f9d | |||
3705ed7da0 | |||
5b99e66d8d | |||
cbedd5ff40 | |||
bfcd6f10fc | |||
79362e9955 | |||
fcf272b44a | |||
b80683a9a1 | |||
5349f3a59a | |||
95072a9ac5 | |||
8c372b0909 | |||
580dd38b3a | |||
47d4e98aae | |||
7ebb7bac17 | |||
6cbce2fc97 | |||
e8a950f32c | |||
4f722ecd8a | |||
478359f9ff | |||
a1720a5cf1 | |||
3f0ef3ded7 | |||
dcb25c1a6b | |||
c5dd575324 | |||
6eca26a4e2 | |||
e10fa065bd | |||
49673fabbd | |||
1c1a210542 | |||
30277d92cd | |||
fb940065ea | |||
afa06342a5 | |||
03d2ff5f26 | |||
ec71dff40d | |||
58faf64a5c | |||
65ff14a81d | |||
f7efe44f09 | |||
cf22e81ae1 | |||
7aa0f21d11 | |||
2e31e3d37c | |||
3e988b7a56 | |||
ce3eb06924 | |||
a37ff8d398 | |||
d0bdb1a47b | |||
855f2a55d4 | |||
fc7ec9bded | |||
028de860a2 | |||
5af91d028d | |||
a4bcf870bb | |||
e06f2f5f0b | |||
c101645d93 | |||
b8904c2d51 | |||
099db4e1c8 | |||
cdf36ccb20 | |||
79b6ab1d15 | |||
95114774da | |||
7f566fb672 | |||
d27968a215 | |||
344990d59e | |||
ea831ef160 | |||
8314b05fce | |||
fd33cc7068 | |||
92e4cc6a24 | |||
dd4bebb570 | |||
99aed2cb01 | |||
92616063ec | |||
c56b56f4aa | |||
33d6533c64 | |||
55d7a0dd01 | |||
8b2ac99eda | |||
dba21c68fd | |||
5b40652737 | |||
7f0396747d | |||
e9dfff8e66 | |||
040c4da6c3 | |||
80a237504d | |||
4e2e09ea24 | |||
87b9fbdc16 | |||
a071a14eec | |||
5ae006b10f | |||
9d21ebd26e | |||
fcff6de3c3 | |||
3d2168856d | |||
a6eb1b06da | |||
21d0c3518e | |||
3532a3c8e9 | |||
79cba4cace | |||
a5dee8da12 | |||
3783384ea6 | |||
766c0dfcfc | |||
83e9de8e95 | |||
0a512f6349 | |||
a4c1095db7 | |||
87a6c7100e | |||
fc51d5f98c | |||
a1b3aaf1f8 | |||
3a1bf88c22 | |||
bd39c34f03 | |||
73121c2ca5 | |||
5e23fa4295 | |||
5e34bbf9d5 | |||
cedd94550f | |||
8b13889c7a | |||
3c7ac5488a | |||
398d7d3d80 | |||
b727ba423e | |||
45b9550293 | |||
d2e520e2fd | |||
b9c3ae97cd | |||
b90c0b173b | |||
f498f4df0c | |||
2f10f89fc5 | |||
a49f9d9c80 | |||
e71e23bbb5 | |||
adc86ef247 | |||
765b2bad21 | |||
2354cac719 | |||
7f509f66ff | |||
d8ff251c71 | |||
12979cc2c0 | |||
e974c06a89 | |||
f2ceff8252 | |||
cd5f3165c7 | |||
6e700b0cfa | |||
5b41fc212c | |||
2b7a5452b8 | |||
cfed133fb6 | |||
0beff9a090 | |||
d6e707fb85 | |||
a3e8d47199 | |||
cab3f3a96e | |||
5f0d4abe7f | |||
ff5f87eeca | |||
e85b969e11 | |||
2eb98905b6 | |||
ac1274c6fd | |||
94f91afce1 | |||
73d5fb8cff | |||
90b2b46db4 | |||
f2bf61240a | |||
3f151fd235 | |||
7598363cae | |||
4b1f216cd3 | |||
3d5f13a2b8 | |||
98eab956e9 | |||
a7260cba3d | |||
787e022382 | |||
d8e1c76155 | |||
3cb08e3c09 | |||
0474985866 | |||
8d15ef6d06 | |||
0fbc7fb7eb | |||
1379bdbbeb | |||
64d3e659a4 | |||
19458546a0 | |||
bba7460423 | |||
956fdd5cff | |||
a0289775cb | |||
4c785902bc | |||
e29ae4d7c9 | |||
1ea915017a | |||
6441c781a5 | |||
589c54e205 | |||
e10b99eaac | |||
0316f3ea3e | |||
166fef899f | |||
4e850408fc | |||
6e2494831c | |||
38a7d8f80a | |||
abfebc8643 | |||
40a3487d3d | |||
a93865e594 | |||
4e76286b44 | |||
fbe57e96c6 | |||
950bfb04d6 | |||
6d43b7b6a9 | |||
e1991deafd | |||
2f1b31aeb2 | |||
ca29eefd7f | |||
1421407a23 | |||
36e4bf468d | |||
5cd3917f4d | |||
586470e8f9 | |||
b02e9f5ab3 | |||
4a538e677d | |||
cc2fdbe5be | |||
3833688115 | |||
1639741e55 | |||
ab0d573a66 | |||
26c582b19f | |||
3bc53f9f09 | |||
bb220baf6a | |||
121a78f42a | |||
4257aa634e | |||
95ff83557f | |||
e9070de9c4 | |||
72aa087411 | |||
fbc0a3ad8d | |||
afedc409f5 | |||
0360f16dc8 | |||
f4800dbbae | |||
15ddc8454e | |||
f8df4de711 | |||
a0cb18e1a1 | |||
509ec7d3d3 | |||
aa2416f353 | |||
167a605658 | |||
592f11bd5f | |||
92b128039a | |||
5efe611b2d | |||
477e2737b1 | |||
dc8bacc27d | |||
0b8c787cda | |||
4f5c464659 | |||
4f432645b1 | |||
5fa7930896 | |||
f9efd536d9 | |||
6a65ff5e5d | |||
b549f83422 | |||
a9c80c031f | |||
405bea3049 | |||
6954acd0b3 | |||
efd15d5d18 | |||
6566622167 | |||
8157780b68 | |||
975546915e | |||
319d591662 | |||
1dd6c91529 | |||
c4f0426775 | |||
53f5a122bd | |||
a7142ed21b | |||
771a1bfc44 | |||
53169bba78 | |||
e3b8c1836b | |||
a4b091dc32 | |||
448c9ddaa8 | |||
ac574acf8e | |||
aa15b9420a | |||
2b7f5c321e | |||
bee9bfcfcc | |||
b7d73dcfaa | |||
5b4fa4ea2b | |||
12e5fe77de | |||
2dca10c539 | |||
ceba5b3d0b | |||
c05cf3cad4 | |||
d6f5a39829 | |||
30d67508cb | |||
63b8d892f7 | |||
10137d8551 | |||
9ef74e0951 | |||
89ff93958f | |||
8d870e85eb | |||
0cdb426712 | |||
b9f7a5673f | |||
7ffbf6c378 | |||
3a9c006cf9 | |||
a9edb383b4 | |||
ec23a73edb | |||
10a164ee0c | |||
37fcd5699b | |||
66d969cc2f | |||
9d358f74dd | |||
57e00e3097 | |||
53afbea6ec | |||
2c2c0b3db4 | |||
e235ee66eb | |||
0ef430567b | |||
74aef73f75 | |||
99eb72428f | |||
065b160155 | |||
6811d8e38d | |||
5f75efddf1 | |||
822a7ac5f5 | |||
06e1ac9bb5 | |||
a3530c3367 | |||
ec35bfb2d4 | |||
ed3e46bebb | |||
87b270482b | |||
d22ba55858 | |||
835f25cc82 | |||
11944283b0 | |||
dc704a92de | |||
dca1e9e1a7 | |||
00781be077 | |||
ac80148f5b | |||
ff36833270 | |||
612c7d76a0 | |||
32097b4512 | |||
d686f75222 | |||
bcc01df0b8 | |||
ee12f4d304 | |||
16c1607850 | |||
e2864e2243 | |||
16dc81150d | |||
ed4d3d52ed | |||
37a6a74b6e | |||
136a531047 | |||
bef0097f5b | |||
a0d2be50e8 | |||
18e2d26587 | |||
810a7bf544 | |||
1010c6f4f0 | |||
8dd698ec75 | |||
95e66f1f29 | |||
ac0460ab04 | |||
2d059debb7 | |||
df0ad2df37 | |||
0f7725e6af | |||
eda346c582 | |||
94060a6443 | |||
1cd7c5e876 | |||
b369cadde0 | |||
5321a136e7 | |||
d4c04f29bf | |||
20798d8957 | |||
3cde437628 | |||
8db7af48cd | |||
d05d033727 | |||
ccba1925b1 | |||
b590586d4c | |||
44c742402c | |||
3a9db95c37 | |||
5d88938d94 | |||
67e0f1776d | |||
5b68febb05 | |||
9bf65ca798 | |||
d95aa40502 | |||
a59bf76fb4 | |||
51fdc7f1df | |||
aa51b751d0 | |||
aff522c5cd | |||
66d039ace3 | |||
ed5e6cdd8c | |||
47f5e1e7b4 | |||
626d6c0fa9 | |||
2b45d64695 | |||
c27446666e | |||
7f0195378c | |||
6caa3a069b | |||
baaf73b584 | |||
b2a92feb50 | |||
c11b9677d5 | |||
0e5a26ce1f | |||
40ec5569d0 | |||
d14ecc982b | |||
9c27384ba3 | |||
2268f0ffa6 | |||
bfc04bfa87 | |||
37ac31cdac | |||
15096d483f | |||
16724affad | |||
384d59abe0 | |||
027414b7a2 | |||
a1cd56c419 | |||
6ee1c23f9a | |||
44a223eba1 | |||
7c66754541 | |||
bb80fc0860 | |||
6c7cc5de0d | |||
063cc9edc3 | |||
76c283502e | |||
554add0882 | |||
689c340081 | |||
01e4ed7efc | |||
59f408846a | |||
64606e69cf | |||
e8e0c1e0b3 | |||
953c124ef0 | |||
2e1be55bf9 | |||
33125f2ce7 | |||
e99d2b380c | |||
bcf89f0dfe | |||
3d64a42126 | |||
97eb772ab8 | |||
bc40bbb44b | |||
ed117e53d9 | |||
b74f40c7a8 | |||
bf4023c0ad | |||
c98cdb3e57 | |||
a01b094f9f | |||
e75bb7ee59 | |||
563c62855a | |||
8a15424a62 | |||
8eb04534bc | |||
b3abf46604 | |||
6f19a1593e | |||
883711698e | |||
bdcfd77d42 | |||
2cd503e0e0 | |||
c9519f0b3d | |||
0daa3057e7 | |||
0ac5129e0e | |||
a3aa347fdf | |||
a40d1122a5 | |||
9955b8fda1 | |||
c994438fa8 | |||
3085ae575a | |||
793b8ce29e | |||
5d447cdec3 | |||
e7698b0131 | |||
f86121b656 | |||
45c223c14b | |||
66990d62c2 | |||
4439111a44 | |||
440b7e4e6c |
@ -1,8 +0,0 @@
|
||||
#!/usr/bin/ruby
|
||||
path = "/tmp"
|
||||
Dir.mkdir(path) if !File.exists?(path)
|
||||
File.open("#{path}/mailpoet-#{Time.now.to_f}.txt", "w") do |f|
|
||||
sleep 5
|
||||
f.puts ARGV.inspect
|
||||
$stdin.each_line { |line| f.puts line }
|
||||
end
|
@ -1,3 +0,0 @@
|
||||
; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
|
||||
; http://php.net/sendmail-path
|
||||
sendmail_path = /home/ubuntu/mailpoet/.circle_ci/fake-sendmail.rb
|
@ -3,11 +3,11 @@ Listen 8080
|
||||
<VirtualHost *:8080>
|
||||
UseCanonicalName Off
|
||||
ServerName mailpoet.loc
|
||||
DocumentRoot /home/ubuntu/mailpoet/wordpress
|
||||
DocumentRoot /home/circleci/mailpoet/wordpress
|
||||
DirectoryIndex index.php
|
||||
LogLevel notice
|
||||
|
||||
<Directory /home/ubuntu/mailpoet/wordpress>
|
||||
<Directory /home/circleci/mailpoet/wordpress>
|
||||
Require all granted
|
||||
</Directory>
|
||||
</VirtualHost>
|
137
.circleci/config.yml
Normal file
137
.circleci/config.yml
Normal file
@ -0,0 +1,137 @@
|
||||
version: 2
|
||||
jobs:
|
||||
qa_js_php5:
|
||||
working_directory: /home/circleci/mailpoet
|
||||
docker:
|
||||
- image: circleci/php:5.6.30-apache-browsers
|
||||
- image: circleci/mysql:5.7
|
||||
environment:
|
||||
TZ: /usr/share/zoneinfo/Etc/UTC
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Set up virtual host"
|
||||
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
|
||||
- restore_cache:
|
||||
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
|
||||
- restore_cache:
|
||||
key: npm-{{ checksum "package.json" }}
|
||||
- run:
|
||||
name: "Set up test environment"
|
||||
command: source ./.circleci/setup.bash && setup php5
|
||||
- save_cache:
|
||||
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
|
||||
paths:
|
||||
- vendor
|
||||
- save_cache:
|
||||
key: npm-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- node_modules
|
||||
- run:
|
||||
name: "QA Scripts"
|
||||
command: ./do qa
|
||||
- run:
|
||||
name: "Preparing test results folder"
|
||||
command: mkdir test-results
|
||||
- run:
|
||||
name: "JS tests"
|
||||
command: |
|
||||
mkdir test-results/mocha
|
||||
./do t:j test-results/mocha/junit.xml
|
||||
- run:
|
||||
name: "PHP Unit tests"
|
||||
command: |
|
||||
WP_TEST_PATH="/home/circleci/mailpoet/wordpress" ./do t:u --xml
|
||||
- store_test_results:
|
||||
path: test-results/mocha
|
||||
- store_artifacts:
|
||||
path: test-results/mocha
|
||||
destination: mocha
|
||||
- store_test_results:
|
||||
path: tests/_output
|
||||
- store_artifacts:
|
||||
path: tests/_output
|
||||
destination: codeception
|
||||
- store_artifacts:
|
||||
path: /tmp/fake-mailer/
|
||||
destination: fake-mailer
|
||||
acceptance_tests:
|
||||
working_directory: /home/circleci/mailpoet
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Set up virtual host"
|
||||
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
|
||||
- restore_cache:
|
||||
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
|
||||
- restore_cache:
|
||||
key: npm-{{ checksum "package.json" }}
|
||||
- run:
|
||||
name: "Set up test environment"
|
||||
command: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install circleci-php-5.6.23
|
||||
sudo rm /usr/bin/php
|
||||
sudo ln -s /opt/circleci/php/5.6.23/bin/php /usr/bin/php
|
||||
# Install NodeJS+NPM
|
||||
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
|
||||
sudo apt-get install nodejs build-essential
|
||||
# install plugin dependencies
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
php composer.phar install
|
||||
./do install
|
||||
- save_cache:
|
||||
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
|
||||
paths:
|
||||
- vendor
|
||||
- save_cache:
|
||||
key: npm-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- node_modules
|
||||
- run:
|
||||
name: Run acceptance tests
|
||||
command: |
|
||||
docker-compose run codeception --steps --debug -vvv --html --xml
|
||||
- store_artifacts:
|
||||
path: ~/mailpoet/tests/acceptance-tests/_output
|
||||
- store_test_results:
|
||||
path: ~/mailpoet/tests/acceptance-tests/_output
|
||||
php7:
|
||||
working_directory: /home/circleci/mailpoet
|
||||
docker:
|
||||
- image: circleci/php:7.1-apache-browsers
|
||||
- image: circleci/mysql:5.7
|
||||
environment:
|
||||
TZ: /usr/share/zoneinfo/Etc/UTC
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Set up virtual host"
|
||||
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
|
||||
- restore_cache:
|
||||
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
|
||||
- restore_cache:
|
||||
key: npm-{{ checksum "package.json" }}
|
||||
- run:
|
||||
name: "Set up test environment"
|
||||
command: source ./.circleci/setup.bash && setup php7
|
||||
- run:
|
||||
name: "PHP Unit tests"
|
||||
command: |
|
||||
WP_TEST_PATH="/home/circleci/mailpoet/wordpress" ./do t:u --xml
|
||||
- store_test_results:
|
||||
path: tests/_output
|
||||
- store_artifacts:
|
||||
path: tests/_output
|
||||
destination: codeception
|
||||
- store_artifacts:
|
||||
path: /tmp/fake-mailer/
|
||||
destination: fake-mailer
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- qa_js_php5
|
||||
- php7
|
||||
- acceptance_tests
|
17
.circleci/fake-sendmail.php
Executable file
17
.circleci/fake-sendmail.php
Executable file
@ -0,0 +1,17 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
$path = "/tmp/fake-mailer";
|
||||
if(!file_exists($path)) {
|
||||
mkdir($path);
|
||||
}
|
||||
$filename = $path . '/mailpoet-' . microtime(true) . '.txt';
|
||||
$file_handle = fopen($filename, "w");
|
||||
|
||||
$call_arguments = print_r($argv, true) . "\n";
|
||||
fwrite($file_handle, $call_arguments);
|
||||
|
||||
while($line = fgets(STDIN)) {
|
||||
fwrite($file_handle, $line);
|
||||
}
|
||||
|
||||
fclose($file_handle);
|
9
.circleci/mailpoet_php.ini
Normal file
9
.circleci/mailpoet_php.ini
Normal file
@ -0,0 +1,9 @@
|
||||
; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
|
||||
; http://php.net/sendmail-path
|
||||
sendmail_path = /usr/local/bin/fake-sendmail.php
|
||||
|
||||
[Date]
|
||||
; Defines the default timezone used by the date functions
|
||||
; http://php.net/date.timezone
|
||||
date.timezone = UTC
|
||||
|
48
.circleci/setup.bash
Normal file
48
.circleci/setup.bash
Normal file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function setup {
|
||||
local version=$1
|
||||
# install PHP dependencies for WordPress
|
||||
if [[ $version == "php7" ]]; then
|
||||
echo "deb http://packages.dotdeb.org jessie all" | sudo tee -a /etc/apt/sources.list.d/dotdeb.list
|
||||
echo "deb-src http://packages.dotdeb.org jessie all" | sudo tee -a /etc/apt/sources.list.d/dotdeb.list
|
||||
wget -qO - http://www.dotdeb.org/dotdeb.gpg | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install mysql-client php7.0-mysql zlib1g-dev
|
||||
sudo docker-php-ext-install mysqli pdo pdo_mysql zip
|
||||
else
|
||||
sudo apt-get update
|
||||
sudo apt-get install mysql-client php5-mysql zlib1g-dev
|
||||
sudo docker-php-ext-install mysql mysqli pdo pdo_mysql zip
|
||||
fi
|
||||
# Add a fake sendmail mailer
|
||||
sudo cp ./.circleci/fake-sendmail.php /usr/local/bin/
|
||||
# configure Apache
|
||||
sudo cp ./.circleci/mailpoet_php.ini /usr/local/etc/php/conf.d/
|
||||
sudo cp ./.circleci/apache/mailpoet.loc.conf /etc/apache2/sites-available
|
||||
sudo a2ensite mailpoet.loc
|
||||
sudo a2enmod rewrite
|
||||
sudo service apache2 restart
|
||||
# Install NodeJS+NPM
|
||||
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
|
||||
sudo apt-get install nodejs build-essential
|
||||
# install plugin dependencies
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
./composer.phar install
|
||||
./do install
|
||||
# Set up Wordpress
|
||||
mysql -h 127.0.0.1 -u root -e "create database wordpress"
|
||||
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
|
||||
chmod +x wp-cli.phar
|
||||
./wp-cli.phar core download --allow-root --path=wordpress
|
||||
# Generate `wp-config.php` file with debugging enabled
|
||||
echo "define(\"WP_DEBUG\", true);" | ./wp-cli.phar core config --allow-root --dbname=wordpress --dbuser=root --dbhost=127.0.0.1 --path=wordpress --extra-php
|
||||
# Install WordPress
|
||||
./wp-cli.phar core install --allow-root --admin_name=admin --admin_password=admin --admin_email=admin@mailpoet.loc --url=http://mailpoet.loc:8080 --title=WordPress --path=wordpress
|
||||
# Softlink plugin to plugin path
|
||||
ln -s ../../.. wordpress/wp-content/plugins/mailpoet
|
||||
./wp-cli.phar plugin activate mailpoet --path=wordpress
|
||||
# Create .env file with correct path to WP installation
|
||||
# TODO: Remove this line after PR gets merged and CircleCI env variables change
|
||||
echo "WP_TEST_PATH=\"/home/circleci/mailpoet/wordpress\"" > .env
|
||||
}
|
@ -16,3 +16,4 @@ WP_TEST_MAILER_SMTP_LOGIN=""
|
||||
WP_TEST_MAILER_SMTP_PASSWORD=""
|
||||
WP_SVN_USERNAME=""
|
||||
WP_SVN_PASSWORD=""
|
||||
WP_TRANSIFEX_API_TOKEN=""
|
3
.eslintignore
Normal file
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
**/vendor/**
|
||||
**/testBundles/**
|
||||
assets/js/src/newsletter_editor/tinymce/wplink/plugin.js
|
87
.eslintrc.es5.json
Normal file
87
.eslintrc.es5.json
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
"extends": "airbnb/legacy",
|
||||
"env": {
|
||||
"amd": true,
|
||||
"browser": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 5
|
||||
},
|
||||
"rules": {
|
||||
"import/no-amd": 0,
|
||||
"space-before-function-paren": 0,
|
||||
"prefer-arrow-callback": 0,
|
||||
"no-undef": 0,
|
||||
"key-spacing": 0,
|
||||
"radix": 0,
|
||||
"no-alert": 0,
|
||||
"block-scoped-var": 0,
|
||||
"guard-for-in": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"no-restricted-syntax": 0,
|
||||
"newline-per-chained-call": 0,
|
||||
"no-useless-concat": 0,
|
||||
"no-multi-spaces": 0,
|
||||
"no-nested-ternary": 0,
|
||||
"semi-spacing": 0,
|
||||
"no-sequences": 0,
|
||||
"no-useless-return": 0,
|
||||
"array-callback-return": 0,
|
||||
"new-cap": 0,
|
||||
"no-continue": 0,
|
||||
"no-new": 0,
|
||||
"space-unary-ops": 0,
|
||||
"no-redeclare": 0,
|
||||
"no-console": 0,
|
||||
"no-empty": 0,
|
||||
"no-extra-semi": 0,
|
||||
"no-useless-escape": 0,
|
||||
"wrap-iife": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"block-spacing": 0,
|
||||
"computed-property-spacing": 0,
|
||||
"no-plusplus": 0,
|
||||
"array-bracket-spacing": 0,
|
||||
"lines-around-directive": 0,
|
||||
"no-unreachable": 0,
|
||||
"default-case": 0,
|
||||
"no-lonely-if": 0,
|
||||
"space-before-blocks": 0,
|
||||
"no-unneeded-ternary": 0,
|
||||
"no-mixed-operators": 0,
|
||||
"eqeqeq": 0,
|
||||
"space-in-parens": 0,
|
||||
"semi": 0,
|
||||
"max-len": 0,
|
||||
"no-trailing-spaces": 0,
|
||||
"global-require": 0,
|
||||
"no-throw-literal": 0,
|
||||
"no-extra-bind": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"consistent-return": 0,
|
||||
"no-shadow": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"brace-style": 0,
|
||||
"no-else-return": 0,
|
||||
"no-use-before-define": 0,
|
||||
"one-var": 0,
|
||||
"camelcase": 0,
|
||||
"spaced-comment": 0,
|
||||
"padded-blocks": 0,
|
||||
"object-curly-spacing": 0,
|
||||
"strict": 0,
|
||||
"vars-on-top": 0,
|
||||
"no-var": 0,
|
||||
"space-infix-ops": 0,
|
||||
"no-unused-vars": 0,
|
||||
"object-shorthand": 0,
|
||||
"new-parens": 0,
|
||||
"keyword-spacing": 0,
|
||||
"eol-last": 0,
|
||||
"dot-notation": 0,
|
||||
"linebreak-style": 0,
|
||||
"indent": 0,
|
||||
"prefer-template": 0,
|
||||
"func-names": 0
|
||||
}
|
||||
}
|
88
.eslintrc.es6.json
Normal file
88
.eslintrc.es6.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"extends": "airbnb",
|
||||
"env": {
|
||||
"amd": true,
|
||||
"browser": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
"import/no-amd": 0,
|
||||
"react/no-multi-comp": 0,
|
||||
"react/sort-comp": 0,
|
||||
"react/jsx-max-props-per-line": 0,
|
||||
"react/prop-types": 0,
|
||||
"react/jsx-first-prop-new-line": 0,
|
||||
"react/jsx-indent-props": 0,
|
||||
"react/no-is-mounted": 0,
|
||||
"react/jsx-no-target-blank": 0,
|
||||
"react/no-render-return-value": 0,
|
||||
"react/jsx-boolean-value": 0,
|
||||
"react/jsx-indent": 0,
|
||||
"react/jsx-no-bind": 0,
|
||||
"react/no-array-index-key": 0,
|
||||
"react/self-closing-comp": 0,
|
||||
"react/jsx-tag-spacing": 0,
|
||||
"react/jsx-closing-bracket-location": 0,
|
||||
"react/no-string-refs": 0,
|
||||
"react/jsx-curly-spacing": 0,
|
||||
"react/no-did-mount-set-state": 0,
|
||||
"react/prefer-stateless-function": 0,
|
||||
"jsx-a11y/label-has-for": 0,
|
||||
"jsx-a11y/no-static-element-interactions": 0,
|
||||
"jsx-a11y/alt-text": 0,
|
||||
"func-names": 0,
|
||||
"object-shorthand": 0,
|
||||
"no-bitwise": 0,
|
||||
"arrow-body-style": 0,
|
||||
"prefer-template": 0,
|
||||
"keyword-spacing": 0,
|
||||
"default-case": 0,
|
||||
"array-callback-return": 0,
|
||||
"consistent-return": 0,
|
||||
"no-unreachable": 0,
|
||||
"no-extra-semi": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/extensions": 0,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"camelcase": 0,
|
||||
"template-curly-spacing": 0,
|
||||
"eqeqeq": 0,
|
||||
"no-lonely-if": 0,
|
||||
"space-unary-ops": 0,
|
||||
"block-scoped-var": 0,
|
||||
"no-extra-bind": 0,
|
||||
"no-multi-spaces": 0,
|
||||
"class-methods-use-this": 0,
|
||||
"key-spacing": 0,
|
||||
"no-multiple-empty-lines": 0,
|
||||
"space-in-parens": 0,
|
||||
"no-case-declarations": 0,
|
||||
"array-bracket-spacing": 0,
|
||||
"newline-per-chained-call": 0,
|
||||
"no-else-return": 0,
|
||||
"max-len": 0,
|
||||
"no-useless-concat": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"no-sequences": 0,
|
||||
"no-extra-boolean-cast": 0,
|
||||
"dot-notation": 0,
|
||||
"no-shadow": 0,
|
||||
"one-var": 0,
|
||||
"no-alert": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"no-script-url": 0,
|
||||
"wrap-iife": 0,
|
||||
"vars-on-top": 0,
|
||||
"space-infix-ops": 0,
|
||||
"no-irregular-whitespace": 0,
|
||||
"padded-blocks": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-undef": 0
|
||||
}
|
||||
}
|
39
.eslintrc.tests.json
Normal file
39
.eslintrc.tests.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"extends": "airbnb/legacy",
|
||||
"env": {
|
||||
"amd": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6
|
||||
},
|
||||
"rules": {
|
||||
"import/no-amd": 0,
|
||||
"no-undef": 0,
|
||||
"one-var": 0,
|
||||
"indent": 0,
|
||||
"linebreak-style": 0,
|
||||
"no-whitespace-before-property": 0,
|
||||
"object-property-newline": 0,
|
||||
"global-require": 0,
|
||||
"semi": 0,
|
||||
"keyword-spacing": 0,
|
||||
"no-bitwise": 0,
|
||||
"newline-per-chained-call": 0,
|
||||
"no-spaced-func": 0,
|
||||
"func-call-spacing": 0,
|
||||
"max-len": 0,
|
||||
"space-unary-ops": 0,
|
||||
"no-unused-vars": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-shadow": 0,
|
||||
"padded-blocks": 0,
|
||||
"vars-on-top": 0,
|
||||
"space-before-blocks": 0,
|
||||
"object-curly-spacing": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"func-names": 0,
|
||||
"space-before-function-paren": 0
|
||||
}
|
||||
}
|
44
.gitignore
vendored
44
.gitignore
vendored
@ -1,21 +1,23 @@
|
||||
.DS_Store
|
||||
TODO
|
||||
composer.phar
|
||||
/vendor
|
||||
tests/_output/*
|
||||
tests/acceptance.suite.yml
|
||||
tests/_support/_generated/*
|
||||
node_modules
|
||||
.env
|
||||
npm-debug.log
|
||||
!tasks/**
|
||||
/views/cache/**
|
||||
temp
|
||||
.idea
|
||||
mailpoet.zip
|
||||
tests/javascript/testBundles
|
||||
assets/css/*.css
|
||||
assets/js/*.js
|
||||
.vagrant
|
||||
lang
|
||||
.mp_svn
|
||||
.DS_Store
|
||||
TODO
|
||||
composer.phar
|
||||
/vendor
|
||||
tests/_output/*
|
||||
tests/_support/_generated/*
|
||||
node_modules
|
||||
.env
|
||||
npm-debug.log
|
||||
!tasks/**
|
||||
/views/cache/**
|
||||
temp
|
||||
.idea
|
||||
mailpoet.zip
|
||||
tests/javascript/testBundles
|
||||
assets/css/*.css
|
||||
assets/css/*.json
|
||||
assets/js/*.js
|
||||
assets/js/*.json
|
||||
.vagrant
|
||||
lang
|
||||
.mp_svn
|
||||
/nbproject/
|
9
.tx/config
Normal file
9
.tx/config
Normal file
@ -0,0 +1,9 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[mp3.mailpoet]
|
||||
source_file = lang/mailpoet.pot
|
||||
file_filter = lang/mailpoet-<lang>.po
|
||||
source_lang = en_US
|
||||
type = PO
|
||||
minimum_perc = 75
|
@ -5,30 +5,32 @@
|
||||
- CamelCase for classes.
|
||||
- camelCase for methods.
|
||||
- snake_case for variables and class properties.
|
||||
- Max line length at 80 chars.
|
||||
- Classes can be no longer than 100 LOC.
|
||||
- Methods can be no longer than 5 LOC.
|
||||
- Pass no more than 4 parameters/hash keys into a method.
|
||||
- Composition over Inheritance.
|
||||
- Comments are a code smell.
|
||||
- Routes can instantiate only one object.
|
||||
- Comments are a code smell. If you need to use a comment - see if same idea can be achieved by more clearly expressing code.
|
||||
- Require other classes with 'use' at the beginning of the class file.
|
||||
- Do not specify 'public' if method is public, it's implicit.
|
||||
- Always use guard clauses.
|
||||
- Ensure compatibility with PHP 5.3 and newer versions.
|
||||
- Cover your code in tests.
|
||||
|
||||
Recommendations:
|
||||
- Max line length at 80 chars.
|
||||
- Keep classes under 100 LOC.
|
||||
- Keep methods under 10 LOC.
|
||||
- Pass no more than 4 parameters/hash keys into a method.
|
||||
- Keep Pull Requests small, under 100 LOC changed.
|
||||
|
||||
## Git flow.
|
||||
- Do not commit to master.
|
||||
- Open a short-living feature branch.
|
||||
- Open a pull request.
|
||||
- Add close #issue in pull request description.
|
||||
- Add Jira issue reference in the title of the Pull Request.
|
||||
- Work on the pull request.
|
||||
- Wait for confirmation before merging to master.
|
||||
- No one will accept a pull request that doesn't have 100% test coverage.
|
||||
- Wait for review and confirmation from another developer before merging to master.
|
||||
- Commit title no more than 80 chars, empty line after.
|
||||
- Commit description as long as you want, 80 chars wrap.
|
||||
- Keep the GitHub open issues count at less than 10.
|
||||
|
||||
## Issues creation.
|
||||
- Issues are managed on Jira.
|
||||
- Discuss issues on public Slack chats, discuss code in pull requests.
|
||||
- Organize features on Trello.
|
||||
- Open a small github issue only when it has been discussed.
|
||||
- Open a small Jira issue only when it has been discussed.
|
||||
|
39
Dockerfile
Normal file
39
Dockerfile
Normal file
@ -0,0 +1,39 @@
|
||||
FROM php:5.6-cli
|
||||
|
||||
ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install \
|
||||
git \
|
||||
zlib1g-dev \
|
||||
libssl-dev \
|
||||
mysql-client \
|
||||
sudo less \
|
||||
--no-install-recommends && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
|
||||
docker-php-ext-install bcmath zip mysqli pdo pdo_mysql && \
|
||||
echo "date.timezone = UTC" >> /usr/local/etc/php/php.ini && \
|
||||
curl -sS https://getcomposer.org/installer | php -- \
|
||||
--filename=composer \
|
||||
--install-dir=/usr/local/bin && \
|
||||
composer global require --optimize-autoloader "hirak/prestissimo" && \
|
||||
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
|
||||
chmod +x wp-cli.phar && \
|
||||
mv wp-cli.phar /usr/local/bin/wp
|
||||
|
||||
# Prepare application
|
||||
WORKDIR /repo
|
||||
|
||||
# Install vendor
|
||||
COPY ./composer.json /repo/composer.json
|
||||
|
||||
# Add source-code
|
||||
COPY . /repo
|
||||
|
||||
WORKDIR /wp-core/wp-content/plugins/mailpoet
|
||||
ENV WP_TEST_PATH=/wp-core
|
||||
|
||||
ADD docker-entrypoint.sh /
|
||||
|
||||
RUN ["chmod", "+x", "/docker-entrypoint.sh"]
|
59
README.md
59
README.md
@ -46,11 +46,26 @@ $ ./do compile:all
|
||||
$ ./do test:unit
|
||||
```
|
||||
|
||||
- JS tests (using Mocha):
|
||||
```sh
|
||||
$ ./do test:javascript
|
||||
```
|
||||
|
||||
- Debug tests:
|
||||
```sh
|
||||
$ ./do test:debug
|
||||
```
|
||||
|
||||
- Code linters and quality checkers:
|
||||
```sh
|
||||
$ ./do qa
|
||||
```
|
||||
|
||||
- Javascript linter:
|
||||
```sh
|
||||
$ ./do lint:javascript
|
||||
```
|
||||
|
||||
# CSS
|
||||
- [Stylus](https://learnboost.github.io/stylus/)
|
||||
- [Nib extension](http://tj.github.io/nib/)
|
||||
@ -109,6 +124,7 @@ Once javascript is compiled with `./do compile:javascript`, your module will be
|
||||
```php
|
||||
__()
|
||||
_n()
|
||||
_x()
|
||||
```
|
||||
|
||||
```html
|
||||
@ -129,19 +145,56 @@ _n()
|
||||
|
||||
You can use Twig i18n functions in Handlebars, just load your template from a Twig view.
|
||||
|
||||
# Build
|
||||
|
||||
To build a plugin , run `./build.sh`.
|
||||
|
||||
Some build process steps are described below (their dependencies etc.).
|
||||
|
||||
## packtranslations step
|
||||
|
||||
This step imports translations from Transifex and generates MO files. It requires:
|
||||
* `tx` client: https://docs.transifex.com/client/installing-the-client
|
||||
* `msgfmt` command (from Gettext package)
|
||||
Finally , a `WP_TRANSIFEX_API_TOKEN` environment variable should be initialized with a valid key.
|
||||
|
||||
# Publish
|
||||
|
||||
Before you run a publishing command, you need to:
|
||||
The `publish` command currently does the following:
|
||||
* Pushes translations POT file to Transifex;
|
||||
* Publishes the release in SVN.
|
||||
|
||||
Before you run it, you need to:
|
||||
1. Ensure there is an up-to-date local copy of MailPoet SVN repository in `.mp_svn` directory by running `./do svn:checkout`.
|
||||
2. Have all your features merged in Git `master`, your `mailpoet.php` and `readme.txt` tagged with a new version.
|
||||
3. Run `./build.sh` to produce a `mailpoet.zip` distributable archive.
|
||||
|
||||
Everything's ready? Then run `./do svn:publish`.
|
||||
Everything's ready? Then run `./do publish`.
|
||||
If the job goes fine, you'll get a message like this:
|
||||
```
|
||||
Go to '.mp_svn' and run 'svn ci -m "Release 3.0.0-beta.9"' to publish the
|
||||
release
|
||||
|
||||
Run 'svn copy ...' to tag the release
|
||||
```
|
||||
It's quite literal: you can review the changes to be pushed and if you're satisfied, run the suggested command to finish the release publishing process.
|
||||
|
||||
If you're confident, execute `./do svn:publish --force` and your release will be published to the remote SVN repository without manual intervention (automatically). For easier authentication you might want to set `WP_SVN_USERNAME` and `WP_SVN_PASSWORD` environment variables.
|
||||
If you're confident, execute `./do publish --force` and your release will be published to the remote SVN repository without manual intervention (automatically). For easier authentication you might want to set `WP_SVN_USERNAME` and `WP_SVN_PASSWORD` environment variables.
|
||||
|
||||
# Acceptance testing
|
||||
|
||||
We are using Gravity Flow plugin's setup as an example for our acceptance test suite: https://www.stevenhenty.com/learn-acceptance-testing-deeply/
|
||||
|
||||
From the article above:
|
||||
|
||||
_Windows users only: enable hard drive sharing in the Docker settings._
|
||||
|
||||
The browser runs in a docker container. You can use a VNC client to watch the test run, follow instructions in official
|
||||
repo: https://github.com/SeleniumHQ/docker-selenium
|
||||
If you’re on a Mac, you can open vnc://localhost:5900 in Safari to watch the tests running in Chrome. If you’re on Windows, you’ll need a VNC client. Password: secret.
|
||||
|
||||
|
||||
To run tests:
|
||||
```sh
|
||||
$ ./do test:acceptance
|
||||
```
|
181
RoboFile.php
181
RoboFile.php
@ -1,7 +1,6 @@
|
||||
<?php
|
||||
|
||||
class RoboFile extends \Robo\Tasks {
|
||||
|
||||
function install() {
|
||||
return $this->taskExecStack()
|
||||
->stopOnFail()
|
||||
@ -67,18 +66,28 @@ class RoboFile extends \Robo\Tasks {
|
||||
$this->_exec('./node_modules/webpack/bin/webpack.js --watch');
|
||||
}
|
||||
|
||||
function compileAll() {
|
||||
function compileAll($opts = ['env' => null]) {
|
||||
$collection = $this->collectionBuilder();
|
||||
$collection->addCode(array($this, 'compileJs'));
|
||||
$collection->addCode(array($this, 'compileCss'));
|
||||
$collection->addCode(function() use ($opts) {
|
||||
return call_user_func(array($this, 'compileJs'), $opts);
|
||||
});
|
||||
$collection->addCode(function() use ($opts) {
|
||||
return call_user_func(array($this, 'compileCss'), $opts);
|
||||
});
|
||||
return $collection->run();
|
||||
}
|
||||
|
||||
function compileJs() {
|
||||
return $this->_exec('./node_modules/webpack/bin/webpack.js --bail');
|
||||
function compileJs($opts = ['env' => null]) {
|
||||
$env = ($opts['env']) ?
|
||||
sprintf('./node_modules/cross-env/dist/bin/cross-env.js NODE_ENV="%s"', $opts['env']) :
|
||||
null;
|
||||
return $this->_exec($env . ' ./node_modules/webpack/bin/webpack.js --bail');
|
||||
}
|
||||
|
||||
function compileCss() {
|
||||
function compileCss($opts = ['env' => null]) {
|
||||
// Clean up folder from previous files
|
||||
array_map('unlink', glob("assets/css/*.*"));
|
||||
|
||||
$css_files = array(
|
||||
'assets/css/src/admin.styl',
|
||||
'assets/css/src/newsletter_editor/newsletter_editor.styl',
|
||||
@ -87,7 +96,7 @@ class RoboFile extends \Robo\Tasks {
|
||||
'assets/css/src/importExport.styl'
|
||||
);
|
||||
|
||||
return $this->_exec(join(' ', array(
|
||||
$compilation_result = $this->_exec(join(' ', array(
|
||||
'./node_modules/stylus/bin/stylus',
|
||||
'--include ./node_modules',
|
||||
'--include-css',
|
||||
@ -95,6 +104,25 @@ class RoboFile extends \Robo\Tasks {
|
||||
join(' ', $css_files),
|
||||
'-o assets/css/'
|
||||
)));
|
||||
|
||||
// Create manifest file
|
||||
$manifest = [];
|
||||
foreach(glob('assets/css/*.css') as $style) {
|
||||
// Hash and rename styles if production environment
|
||||
if($opts['env'] === 'production') {
|
||||
$hashed_style = sprintf(
|
||||
'%s.%s.css',
|
||||
pathinfo($style)['filename'],
|
||||
substr(md5_file($style), 0, 8)
|
||||
);
|
||||
$manifest[basename($style)] = $hashed_style;
|
||||
rename($style, str_replace(basename($style), $hashed_style, $style));
|
||||
} else {
|
||||
$manifest[basename($style)] = basename($style);
|
||||
}
|
||||
}
|
||||
file_put_contents('assets/css/manifest.json', json_encode($manifest, JSON_PRETTY_PRINT));
|
||||
return $compilation_result;
|
||||
}
|
||||
|
||||
function makepot() {
|
||||
@ -104,11 +132,30 @@ class RoboFile extends \Robo\Tasks {
|
||||
);
|
||||
}
|
||||
|
||||
function pushpot() {
|
||||
return $this->collectionBuilder()
|
||||
->addCode(array($this, 'txinit'))
|
||||
->taskExec('tx push -s')
|
||||
->run();
|
||||
}
|
||||
|
||||
function packtranslations() {
|
||||
return $this->collectionBuilder()
|
||||
->addCode(array($this, 'txinit'))
|
||||
->taskExec('./tasks/pack_translations.sh')
|
||||
->run();
|
||||
}
|
||||
|
||||
function txinit() {
|
||||
// Define WP_TRANSIFEX_API_TOKEN env. variable
|
||||
$this->loadEnv();
|
||||
return $this->_exec('./tasks/transifex_init.sh');
|
||||
}
|
||||
|
||||
function testUnit($opts=['file' => null, 'xml' => false]) {
|
||||
$this->loadEnv();
|
||||
$this->_exec('vendor/bin/codecept build');
|
||||
|
||||
$command = 'vendor/bin/codecept run unit -f '.(($opts['file']) ? $opts['file'] : '');
|
||||
$command = 'vendor/bin/codecept run unit -c codeception.unit.yml -f '.(($opts['file']) ? $opts['file'] : '');
|
||||
|
||||
if($opts['xml']) {
|
||||
$command .= ' --xml';
|
||||
@ -118,9 +165,8 @@ class RoboFile extends \Robo\Tasks {
|
||||
|
||||
function testCoverage($opts=['file' => null, 'xml' => false]) {
|
||||
$this->loadEnv();
|
||||
$this->_exec('vendor/bin/codecept build');
|
||||
$command = join(' ', array(
|
||||
'vendor/bin/codecept run',
|
||||
'vendor/bin/codecept run unit -c codeception.unit.yml ',
|
||||
(($opts['file']) ? $opts['file'] : ''),
|
||||
'--coverage',
|
||||
($opts['xml']) ? '--coverage-xml' : '--coverage-html'
|
||||
@ -151,16 +197,26 @@ class RoboFile extends \Robo\Tasks {
|
||||
return $this->_exec($command);
|
||||
}
|
||||
|
||||
function testDebug() {
|
||||
$this->_exec('vendor/bin/codecept build');
|
||||
function testDebug($opts=['file' => null, 'xml' => false]) {
|
||||
$this->loadEnv();
|
||||
return $this->_exec('vendor/bin/codecept run unit --debug');
|
||||
$this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
|
||||
|
||||
$command = 'vendor/bin/codecept run unit -c codeception.unit.yml --debug -f '.(($opts['file']) ? $opts['file'] : '');
|
||||
|
||||
if($opts['xml']) {
|
||||
$command .= ' --xml';
|
||||
}
|
||||
return $this->_exec($command);
|
||||
}
|
||||
|
||||
function testAcceptance() {
|
||||
return $this->_exec('COMPOSE_HTTP_TIMEOUT=200 docker-compose run codeception --steps --debug -vvv');
|
||||
}
|
||||
|
||||
function testFailed() {
|
||||
$this->loadEnv();
|
||||
$this->_exec('vendor/bin/codecept build');
|
||||
return $this->_exec('vendor/bin/codecept run -g failed');
|
||||
$this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
|
||||
return $this->_exec('vendor/bin/codecept run -c codeception.unit.yml -g failed');
|
||||
}
|
||||
|
||||
function qa() {
|
||||
@ -169,6 +225,7 @@ class RoboFile extends \Robo\Tasks {
|
||||
$collection->addCode(function() {
|
||||
return $this->qaCodeSniffer('all');
|
||||
});
|
||||
$collection->addCode(array($this, 'qaLintJavascript'));
|
||||
return $collection->run();
|
||||
}
|
||||
|
||||
@ -176,24 +233,58 @@ class RoboFile extends \Robo\Tasks {
|
||||
return $this->_exec('./tasks/php_lint.sh lib/ tests/ mailpoet.php');
|
||||
}
|
||||
|
||||
function qaLintJavascript() {
|
||||
return $this->_exec('npm run lint');
|
||||
}
|
||||
|
||||
function qaCodeSniffer($severity='errors') {
|
||||
if ($severity === 'all') {
|
||||
$severityFlag = '-w';
|
||||
} else {
|
||||
$severityFlag = '-n';
|
||||
}
|
||||
return $this->_exec(
|
||||
'./vendor/bin/phpcs '.
|
||||
'--standard=./tasks/code_sniffer/MailPoet '.
|
||||
'--ignore=./lib/Util/Sudzy/*,./lib/Util/CSS.php,./lib/Util/XLSXWriter.php,'.
|
||||
'./lib/Util/pQuery/*,./lib/Config/PopulatorData/Templates/* '.
|
||||
'lib/ '.
|
||||
$severityFlag
|
||||
);
|
||||
return $this->collectionBuilder()
|
||||
->taskExec(
|
||||
'./vendor/bin/phpcs '.
|
||||
'--standard=./tasks/code_sniffer/MailPoet '.
|
||||
'--runtime-set testVersion 5.3-7.0 '.
|
||||
'--ignore=./lib/Util/Sudzy/*,./lib/Util/CSS.php,./lib/Util/XLSXWriter.php,'.
|
||||
'./lib/Util/pQuery/*,./lib/Config/PopulatorData/Templates/* '.
|
||||
'lib/ '.
|
||||
$severityFlag
|
||||
)
|
||||
->taskExec(
|
||||
'./vendor/bin/phpcs '.
|
||||
'--standard=./tasks/code_sniffer/MailPoet '.
|
||||
'--runtime-set testVersion 5.4-7.0 '.
|
||||
'--ignore=./tests/unit/_bootstrap.php '.
|
||||
'tests/unit/ '.
|
||||
$severityFlag
|
||||
)
|
||||
->run();
|
||||
}
|
||||
|
||||
function svnCheckout() {
|
||||
return $this->_exec('svn co https://plugins.svn.wordpress.org/mailpoet/ .mp_svn');
|
||||
$svn_dir = ".mp_svn";
|
||||
|
||||
$collection = $this->collectionBuilder();
|
||||
|
||||
// Clean up the SVN dir for faster shallow checkout
|
||||
if(file_exists($svn_dir)) {
|
||||
$collection->taskExecStack()
|
||||
->exec('rm -rf ' . $svn_dir);
|
||||
}
|
||||
|
||||
$collection->taskFileSystemStack()
|
||||
->mkdir($svn_dir);
|
||||
|
||||
return $collection->taskExecStack()
|
||||
->stopOnFail()
|
||||
->dir($svn_dir)
|
||||
->exec('svn co https://plugins.svn.wordpress.org/mailpoet/ -N .')
|
||||
->exec('svn up trunk')
|
||||
->exec('svn up assets')
|
||||
->run();
|
||||
}
|
||||
|
||||
function svnPublish($opts = ['force' => false]) {
|
||||
@ -203,8 +294,9 @@ class RoboFile extends \Robo\Tasks {
|
||||
$plugin_data = get_plugin_data('mailpoet.php', false, false);
|
||||
$plugin_version = $plugin_data['Version'];
|
||||
$plugin_dist_name = sanitize_title_with_dashes($plugin_data['Name']);
|
||||
$plugin_dist_name = explode('-', $plugin_dist_name);
|
||||
$plugin_dist_name = $plugin_dist_name[0];
|
||||
$plugin_dist_file = $plugin_dist_name . '.zip';
|
||||
|
||||
$this->say('Publishing version: ' . $plugin_version);
|
||||
|
||||
// Sanity checks
|
||||
@ -245,6 +337,22 @@ class RoboFile extends \Robo\Tasks {
|
||||
->rename("$svn_dir/trunk_new", "$svn_dir/trunk")
|
||||
->remove("$svn_dir/trunk_old");
|
||||
|
||||
// Add new repository assets
|
||||
$collection->taskFileSystemStack()
|
||||
->mirror('./plugin_repository/assets', "$svn_dir/assets_new");
|
||||
|
||||
// Rename current assets folder
|
||||
if(file_exists("$svn_dir/assets")) {
|
||||
$collection->taskFileSystemStack()
|
||||
->rename("$svn_dir/assets", "$svn_dir/assets_old");
|
||||
}
|
||||
|
||||
// Replace old assets with new ones
|
||||
$collection->taskFileSystemStack()
|
||||
->stopOnFail()
|
||||
->rename("$svn_dir/assets_new", "$svn_dir/assets")
|
||||
->remove("$svn_dir/assets_old");
|
||||
|
||||
// Windows compatibility
|
||||
$awkCmd = '{print " --force \""$2"\""}';
|
||||
// Mac OS X compatibility
|
||||
@ -257,15 +365,15 @@ class RoboFile extends \Robo\Tasks {
|
||||
// Remove files from SVN repo that have already been removed locally
|
||||
->exec("svn st | grep ^! | awk '$awkCmd' | xargs $xargsFlag svn rm")
|
||||
// Recursively add files to SVN that haven't been added yet
|
||||
->exec("svn add --force * --auto-props --parents --depth infinity -q")
|
||||
// Tag the release
|
||||
->exec("svn cp trunk tags/$plugin_version");
|
||||
->exec("svn add --force * --auto-props --parents --depth infinity -q");
|
||||
|
||||
$result = $collection->run();
|
||||
|
||||
if($result->wasSuccessful()) {
|
||||
// Run or suggest release command depending on a flag
|
||||
$repo_url = "https://plugins.svn.wordpress.org/$plugin_dist_name";
|
||||
$release_cmd = "svn ci -m \"Release $plugin_version\"";
|
||||
$tag_cmd = "svn copy $repo_url/trunk $repo_url/tags/$plugin_version -m \"Tag $plugin_version\"";
|
||||
if(!empty($opts['force'])) {
|
||||
$svn_login = getenv('WP_SVN_USERNAME');
|
||||
$svn_password = getenv('WP_SVN_PASSWORD');
|
||||
@ -278,17 +386,30 @@ class RoboFile extends \Robo\Tasks {
|
||||
->stopOnFail()
|
||||
->dir($svn_dir)
|
||||
->exec($release_cmd)
|
||||
->exec($tag_cmd)
|
||||
->run();
|
||||
} else {
|
||||
$this->yell(
|
||||
"Go to '$svn_dir' and run '$release_cmd' to publish the release"
|
||||
);
|
||||
$this->yell(
|
||||
"Run '$tag_cmd' to tag the release"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function publish($opts = ['force' => false]) {
|
||||
return $this->collectionBuilder()
|
||||
->addCode(array($this, 'pushpot'))
|
||||
->addCode(function () use ($opts) {
|
||||
return $this->svnPublish($opts);
|
||||
})
|
||||
->run();
|
||||
}
|
||||
|
||||
protected function loadEnv() {
|
||||
$dotenv = new Dotenv\Dotenv(__DIR__);
|
||||
$dotenv->load();
|
||||
|
@ -22,3 +22,8 @@
|
||||
@require 'progress_bar'
|
||||
|
||||
@require 'subscribers'
|
||||
|
||||
@require 'pages'
|
||||
@require 'pages_custom'
|
||||
|
||||
@require 'mp2migrator'
|
||||
|
@ -17,6 +17,13 @@ a:focus
|
||||
.mailpoet_hidden
|
||||
display: none
|
||||
|
||||
// add margins to a div
|
||||
.mailpoet_spaced_block
|
||||
margin: 1em 0
|
||||
|
||||
.mailpoet_centered
|
||||
text-align: center
|
||||
|
||||
// select 2
|
||||
.select2-container
|
||||
width: 25em !important
|
||||
|
@ -1,3 +1,53 @@
|
||||
$excellent-badge-color = #2993ab
|
||||
$good-badge-color = #f0b849
|
||||
$bad-badge-color = #d54e21
|
||||
$green-badge-color = #55bd56
|
||||
|
||||
#newsletters_container
|
||||
h2.nav-tab-wrapper
|
||||
margin-bottom: 1rem
|
||||
margin-bottom: 1rem
|
||||
|
||||
.mailpoet_stats_text
|
||||
font-size: 14px
|
||||
font-weight: 600;
|
||||
|
||||
.mailpoet_stat
|
||||
|
||||
&_excellent
|
||||
color: $excellent-badge-color
|
||||
|
||||
&_good
|
||||
color: $good-badge-color
|
||||
|
||||
&_bad
|
||||
color: $bad-badge-color
|
||||
|
||||
&_hidden
|
||||
display: none
|
||||
|
||||
&_link_small
|
||||
text-decoration: underline !important
|
||||
font-size: 0.75rem
|
||||
|
||||
.mailpoet_badge
|
||||
padding: 4px 6px 3px 6px
|
||||
color: #FFFFFF
|
||||
margin-right: 4px
|
||||
text-transform: uppercase
|
||||
font-size: 0.5625rem
|
||||
font-weight: 500
|
||||
border-radius: 3px
|
||||
letter-spacing: 1px
|
||||
vertical-align: middle
|
||||
|
||||
&_excellent
|
||||
background: $excellent-badge-color
|
||||
|
||||
&_good
|
||||
background: $good-badge-color
|
||||
|
||||
&_bad
|
||||
background: $bad-badge-color
|
||||
|
||||
&_green
|
||||
background: $green-badge-color
|
||||
|
@ -45,7 +45,6 @@ body.mailpoet_modal_opened
|
||||
position: absolute
|
||||
z-index: 25
|
||||
top: 48px
|
||||
padding-bottom: 48px
|
||||
margin: 0
|
||||
|
||||
.mailpoet_popup_wrapper
|
||||
@ -54,6 +53,7 @@ body.mailpoet_modal_opened
|
||||
position: relative
|
||||
width: 100%
|
||||
z-index: 0
|
||||
height: 96%
|
||||
|
||||
.mailpoet_overlay_hidden .mailpoet_popup_wrapper
|
||||
border: 1px solid #333
|
||||
@ -75,6 +75,7 @@ body.mailpoet_modal_opened
|
||||
|
||||
.mailpoet_popup_body
|
||||
padding: 10px 10px 10px 10px
|
||||
height: 92%
|
||||
|
||||
// modal panel
|
||||
#mailpoet_modal_overlay.mailpoet_panel_overlay
|
||||
|
33
assets/css/src/mp2migrator.styl
Normal file
33
assets/css/src/mp2migrator.styl
Normal file
@ -0,0 +1,33 @@
|
||||
#logger
|
||||
width: 100%
|
||||
height: 300px
|
||||
background-color: transparent
|
||||
border: 0
|
||||
border-top: 1px #aba9a9 solid
|
||||
padding: 2px
|
||||
overflow: scroll
|
||||
resize: both
|
||||
font-size: 0.85em
|
||||
margin-top: 20px
|
||||
|
||||
#progressbar
|
||||
width: 50%
|
||||
background-color: #d8d8d8
|
||||
border-radius: 5px
|
||||
|
||||
progressbar_color = #fecf23
|
||||
progressbar_gradient_to_color = #fd9215
|
||||
|
||||
.ui-progressbar .ui-progressbar-value
|
||||
height: 100%
|
||||
background-color: progressbar_color
|
||||
background-image: linear-gradient(to bottom, progressbar_color, progressbar_gradient_to_color)
|
||||
border-radius: 3px
|
||||
box-shadow: 0 1px 0 rgba(255,255,255,0.5) inset
|
||||
border 0
|
||||
|
||||
.mailpoet_progress_label
|
||||
font-size: 15px
|
||||
|
||||
.error_msg
|
||||
color: #f00
|
@ -179,6 +179,28 @@ select.mailpoet_font-size
|
||||
width: 100%
|
||||
box-sizing: border-box
|
||||
|
||||
.tooltip-help-designer-subject-line div, .tooltip-help-designer-preheader div
|
||||
z-index: 100001
|
||||
|
||||
.tooltip-help-send-preview
|
||||
position: absolute
|
||||
right: 15px
|
||||
|
||||
.tooltip-help-designer-ideal-width
|
||||
color: #656565
|
||||
text-transform: none
|
||||
margin-left: 5px
|
||||
font-weight: normal
|
||||
|
||||
.tooltip-help-designer-styles
|
||||
position: absolute
|
||||
top: 40px
|
||||
|
||||
.tooltip-help-designer-full-width .dashicons
|
||||
line-height 34px
|
||||
.tooltip-help-designer-full-width span
|
||||
line-height 1.4em
|
||||
|
||||
.mailpoet_button_primary
|
||||
border-color: $button-primary-border-color
|
||||
background-color: $button-primary-background-color
|
||||
|
@ -62,3 +62,9 @@ $draggable-widget-z-index = 2
|
||||
background-color: $primary-active-color
|
||||
box-shadow(inset 1px 2px 1px $primary-inset-shadow-color)
|
||||
color: $white-color
|
||||
|
||||
.mailpoet_droppable_block
|
||||
cursor: move
|
||||
|
||||
&.mailpoet_ignore_drag
|
||||
cursor: auto
|
||||
|
@ -26,10 +26,6 @@ $block-text-line-height = $text-line-height
|
||||
&.mailpoet_highlight > .mailpoet_block_highlight
|
||||
border: 1px dashed $block-hover-highlight-color
|
||||
|
||||
|
||||
.mailpoet_block:last-child
|
||||
margin-bottom: 0
|
||||
|
||||
.mailpoet_content
|
||||
position: relative
|
||||
line-height: $block-text-line-height
|
||||
|
@ -18,6 +18,7 @@
|
||||
.mailpoet_settings_posts_display_options
|
||||
.mailpoet_settings_posts_selection
|
||||
animation-slide-open-downwards()
|
||||
overflow-x: hidden
|
||||
|
||||
.mailpoet_settings_posts_show_display_options,
|
||||
.mailpoet_settings_posts_show_post_selection
|
||||
@ -26,7 +27,12 @@
|
||||
|
||||
.mailpoet_post_selection_container
|
||||
margin-top: 20px
|
||||
margin-bottom: 20px
|
||||
margin-bottom: 0
|
||||
|
||||
.mailpoet_post_scroll_container
|
||||
overflow-y: scroll
|
||||
overflow-x: hidden
|
||||
max-height: 400px
|
||||
|
||||
.mailpoet_settings_posts_single_post
|
||||
border-radius(1px)
|
||||
@ -45,3 +51,6 @@
|
||||
.mailpoet_select_post_checkbox
|
||||
margin-left: 10px
|
||||
margin-right: 8px
|
||||
|
||||
.mailpoet_post_selection_loading
|
||||
color: #999
|
||||
|
@ -127,10 +127,8 @@ body
|
||||
background-color: $primary-background-color
|
||||
border: 1px solid $content-border-color
|
||||
|
||||
#mailpoet_modal_close
|
||||
display: none
|
||||
|
||||
.wrap > .mailpoet_notice,
|
||||
.notice
|
||||
.update-nag
|
||||
margin-left: 2px + 15px !important
|
||||
|
||||
|
228
assets/css/src/pages.styl
Normal file
228
assets/css/src/pages.styl
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
Based on /wp-admin/css/about.css of WP 4.7.
|
||||
This is to make MailPoet pages independent of the WordPress
|
||||
About page styles that may differ across WP versions.
|
||||
Please add custom styles to pages_custom.styl
|
||||
*/
|
||||
|
||||
.mailpoet-about-wrap
|
||||
position: relative
|
||||
margin: 25px 40px 0 20px
|
||||
max-width: 1050px /* readability */
|
||||
font-size: 15px
|
||||
|
||||
div.updated, div.error, .notice
|
||||
display: none !important
|
||||
|
||||
hr
|
||||
border: 0
|
||||
height: 0
|
||||
margin: 0
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1)
|
||||
|
||||
img
|
||||
margin: 0
|
||||
max-width: 100%
|
||||
height: auto
|
||||
vertical-align: middle
|
||||
|
||||
.mailpoet-logo
|
||||
position: absolute
|
||||
top: .2em
|
||||
right: 0;
|
||||
|
||||
.nav-tab
|
||||
padding-right: 15px
|
||||
padding-left: 15px
|
||||
font-size: 18px
|
||||
|
||||
p
|
||||
line-height: 1.5
|
||||
font-size: 14px
|
||||
|
||||
.feature-section p
|
||||
max-width: 55em
|
||||
margin-left: auto
|
||||
margin-right: auto
|
||||
|
||||
h1
|
||||
margin: 0.2em 200px 0 0
|
||||
padding: 0
|
||||
color: #32373c
|
||||
line-height: 1.2em
|
||||
font-size: 2.8em
|
||||
font-weight: 400
|
||||
|
||||
h2
|
||||
margin: 40px 0 .6em
|
||||
font-size: 2.7em
|
||||
line-height: 1.3
|
||||
font-weight: 300
|
||||
text-align: center
|
||||
|
||||
h3
|
||||
margin: 1.25em 0 .6em
|
||||
font-size: 1.4em
|
||||
line-height: 1.5
|
||||
|
||||
h4
|
||||
color: #23282d
|
||||
|
||||
.about-description
|
||||
.about-text
|
||||
margin-top: 1.4em
|
||||
font-weight: 400
|
||||
line-height: 1.6em
|
||||
font-size: 19px
|
||||
|
||||
.about-text
|
||||
margin: 1em 200px 1em 0
|
||||
min-height: 60px
|
||||
color: #555d66
|
||||
|
||||
[class$=col]
|
||||
.col
|
||||
float: left
|
||||
position: relative
|
||||
|
||||
.two-col
|
||||
.col
|
||||
margin-right: 4.799999999%
|
||||
width: 47.6%
|
||||
|
||||
.two-col
|
||||
img
|
||||
margin-bottom: 1.5em
|
||||
|
||||
.feature-section
|
||||
&.two-col
|
||||
.col
|
||||
display: inline-block
|
||||
float: none
|
||||
margin-top: 1em
|
||||
margin-right: 4.799999999%
|
||||
width: calc( 47.6% - 4px )
|
||||
vertical-align: top
|
||||
|
||||
.three-col
|
||||
.col
|
||||
margin-right: 4.999999999%
|
||||
width: 29.95%
|
||||
|
||||
.two-col .col:nth-of-type(2n)
|
||||
.three-col .col:nth-of-type(3n)
|
||||
margin-right: 0
|
||||
|
||||
.feature-section
|
||||
&.two-col
|
||||
h3
|
||||
margin-top: 0
|
||||
|
||||
.feature-section
|
||||
h4
|
||||
margin: 1.4em 0 0.6em 0
|
||||
font-size: 1em
|
||||
|
||||
.feature-section
|
||||
p
|
||||
margin-top: 0.6em
|
||||
|
||||
.lead-description
|
||||
font-size: 1.5em
|
||||
text-align: center
|
||||
|
||||
.two-col-text
|
||||
column-count: 2
|
||||
column-gap: 40px
|
||||
|
||||
.two-col-text
|
||||
p:first-of-type
|
||||
margin-top: 0
|
||||
|
||||
.headline-feature
|
||||
&.feature-video
|
||||
position: relative
|
||||
margin: 40px 0
|
||||
padding-bottom: 56.25%
|
||||
width: 100%
|
||||
max-width: 100%
|
||||
height: 0
|
||||
text-align: center
|
||||
|
||||
.feature-video
|
||||
embed
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
.featured-image
|
||||
text-align: center
|
||||
|
||||
.feature-section
|
||||
overflow: hidden
|
||||
padding: 0 0 40px
|
||||
|
||||
.feature-section
|
||||
&.no-heading
|
||||
padding-top: 35px
|
||||
|
||||
.headline-feature
|
||||
margin: 0 auto
|
||||
max-width: 80%
|
||||
|
||||
.feature-section
|
||||
.media-container
|
||||
overflow: hidden
|
||||
|
||||
.feature-section
|
||||
img
|
||||
margin-bottom: 1em
|
||||
|
||||
.embed-container
|
||||
text-align: center
|
||||
|
||||
.embed-container
|
||||
iframe
|
||||
max-width: 100%
|
||||
|
||||
.wp-embedded-content
|
||||
max-width: 100%
|
||||
|
||||
.feature-section
|
||||
.col
|
||||
margin-top: 40px
|
||||
|
||||
.changelog
|
||||
margin-bottom: 40px
|
||||
|
||||
.changelog
|
||||
&.feature-section
|
||||
.col
|
||||
margin-top: 40px
|
||||
|
||||
@media screen and (max-width: 782px)
|
||||
.two-col-text
|
||||
column-count: 1
|
||||
.three-col img
|
||||
display: block
|
||||
margin: 0 auto
|
||||
|
||||
@media only screen and (max-width: 500px)
|
||||
margin-right: 20px
|
||||
margin-left: 10px
|
||||
h1
|
||||
.about-text
|
||||
margin-right: 0
|
||||
.about-text
|
||||
margin-bottom: 0.25em
|
||||
.mailpoet-logo
|
||||
position: relative
|
||||
margin: 1em 0
|
||||
width: 100%
|
||||
text-align: center
|
||||
.two-col .col
|
||||
.three-col .col
|
||||
width: 100% !important
|
||||
float: none !important
|
35
assets/css/src/pages_custom.styl
Normal file
35
assets/css/src/pages_custom.styl
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
Custom styles for MailPoet pages.
|
||||
*/
|
||||
|
||||
.mailpoet-about-wrap
|
||||
|
||||
.videoWrapper
|
||||
position: relative
|
||||
padding-bottom: 56.25% /* 16:9 */
|
||||
/*padding-top: 25px*/
|
||||
height: 0
|
||||
|
||||
iframe
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
|
||||
.mailpoet_video
|
||||
border: 1px solid rgba(0, 0, 0, 0.1)
|
||||
|
||||
#mailpoet-changelog ul
|
||||
list-style: disc
|
||||
padding-left: 20px
|
||||
|
||||
h2.mailpoet-feature-top
|
||||
margin: 50px auto
|
||||
|
||||
a.button.go-to-plugin
|
||||
margin-top: 2em
|
||||
|
||||
p.top-space-triple
|
||||
margin-top: 3em
|
@ -4,6 +4,7 @@
|
||||
padding: 0
|
||||
width: 100%
|
||||
margin: 0
|
||||
margin-bottom: 10px
|
||||
border-radius: 5px
|
||||
position: relative
|
||||
|
||||
@ -25,5 +26,5 @@
|
||||
|
||||
.mailpoet_progress_complete
|
||||
.mailpoet_progress_bar
|
||||
background-color: #fecf23
|
||||
background-image: linear-gradient(top, #fecf23, #fd9215)
|
||||
background-color: hsla(191, 78%, 80%, 1)
|
||||
background-image: linear-gradient(top, hsla(191, 78%, 80%, 1), hsla(191, 76%, 67%, 1))
|
||||
|
@ -9,29 +9,38 @@
|
||||
// sending methods
|
||||
.mailpoet_sending_methods
|
||||
margin 25px 0 0 0
|
||||
li
|
||||
float left
|
||||
position relative
|
||||
padding 15px 15px 0 15px
|
||||
display flex
|
||||
flex-direction row
|
||||
justify-content flex-start
|
||||
> li
|
||||
flex-grow 1
|
||||
flex-shrink 1
|
||||
display flex
|
||||
flex-direction column
|
||||
flex-basis 0
|
||||
margin 0 25px 25px 0
|
||||
width 300px
|
||||
height 300px
|
||||
border 1px solid #dedede
|
||||
background-color #fff
|
||||
max-width 500px
|
||||
.mailpoet_sending_method_description
|
||||
padding: 25px
|
||||
flex-grow 1
|
||||
flex-shrink 0
|
||||
> li:last-child
|
||||
margin-right 0
|
||||
h3
|
||||
text-align center
|
||||
height 54px
|
||||
line-height 54px
|
||||
font-size 1.5em
|
||||
.mailpoet_description
|
||||
font-size 14px
|
||||
.mailpoet_status
|
||||
display flex
|
||||
flex-direction row
|
||||
justify-content space-between
|
||||
align-items center
|
||||
background-color #2f2f2f
|
||||
color #fff
|
||||
position absolute
|
||||
bottom 0
|
||||
left 0
|
||||
right 0
|
||||
text-overflow ellipsis
|
||||
padding 15px
|
||||
span
|
||||
@ -39,18 +48,25 @@
|
||||
font-weight bold
|
||||
.mailpoet_active
|
||||
.mailpoet_status
|
||||
background-color #088b00
|
||||
span
|
||||
visibility visible
|
||||
#mailpoet_mta_activate
|
||||
visibility hidden
|
||||
.mailpoet_actions
|
||||
bottom 15px
|
||||
color #fff
|
||||
padding 0
|
||||
position absolute
|
||||
right 15px
|
||||
.button-secondary
|
||||
margin 0 -6px -4px 0
|
||||
|
||||
.tooltip.dashicons.dashicons-editor-help
|
||||
line-height: 1.4
|
||||
|
||||
ul.sending-method-benefits
|
||||
list-style-type: none
|
||||
margin-bottom: 2em
|
||||
margin-top: 2em
|
||||
|
||||
.mailpoet_success_item::before
|
||||
content '✔ '
|
||||
|
||||
.mailpoet_error_item::before
|
||||
content '✗ '
|
||||
|
||||
// responsive
|
||||
@media screen and (max-width: 782px)
|
||||
@ -58,8 +74,10 @@
|
||||
width auto
|
||||
|
||||
.mailpoet_sending_methods
|
||||
li
|
||||
float none
|
||||
width auto
|
||||
flex-flow: row wrap
|
||||
justify-content: space-around
|
||||
> li
|
||||
margin-right 0
|
||||
flex-basis auto
|
||||
|
||||
|
||||
|
BIN
assets/img/mailpoet_logo_newsletter.png
Normal file
BIN
assets/img/mailpoet_logo_newsletter.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 819 B After Width: | Height: | Size: 814 B |
@ -1,8 +1,15 @@
|
||||
(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
|
||||
for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
|
||||
(function(e,a){if(!a.__SV){var b=window;try{var c,l,i,j=b.location,g=j.hash;c=function(a,b){return(l=a.match(RegExp(b+"=([^&]*)")))?l[1]:null};g&&c(g,"state")&&(i=JSON.parse(decodeURIComponent(c(g,"state"))),"mpeditor"===i.action&&(b.sessionStorage.setItem("_mpcehash",g),history.replaceState(i.desiredHash||"",e.title,j.pathname+j.search)))}catch(m){}var k,h;window.mixpanel=a;a._i=[];a.init=function(b,c,f){function e(b,a){var c=a.split(".");2==c.length&&(b=b[c[0]],a=c[1]);b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments,
|
||||
0)))}}var d=a;"undefined"!==typeof f?d=a[f]=[]:f="mixpanel";d.people=d.people||[];d.toString=function(b){var a="mixpanel";"mixpanel"!==f&&(a+="."+f);b||(a+=" (stub)");return a};d.people.toString=function(){return d.toString(1)+".people (stub)"};k="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
|
||||
for(h=0;h<k.length;h++)e(d,k[h]);a._i.push([b,c,f])};a.__SV=1.2;b=e.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";c=e.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c)}})(document,window.mixpanel||[]);
|
||||
|
||||
mixpanel.init("f683d388fb25fcf331f1b2b5c4449798");
|
||||
window.mixpanelTrackingId = "8cce373b255e5a76fb22d57b85db0c92";
|
||||
|
||||
if (mailpoet_analytics_enabled) {
|
||||
|
||||
mixpanel.init(window.mixpanelTrackingId);
|
||||
|
||||
if (mailpoet_analytics_data != null) {
|
||||
mixpanel.track('MailPoet 3', mailpoet_analytics_data);
|
||||
}
|
||||
|
||||
if (typeof mailpoet_analytics_data === 'object') {
|
||||
mixpanel.track('Wysija Usage', mailpoet_analytics_data || {});
|
||||
}
|
||||
|
@ -1,72 +1,86 @@
|
||||
define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery, _) {
|
||||
'use strict';
|
||||
MailPoet.Ajax = {
|
||||
version: 0.5,
|
||||
options: {},
|
||||
defaults: {
|
||||
url: null,
|
||||
endpoint: null,
|
||||
action: null,
|
||||
token: null,
|
||||
data: {}
|
||||
},
|
||||
post: function(options) {
|
||||
return this.request('post', options);
|
||||
},
|
||||
init: function(options) {
|
||||
// merge options
|
||||
this.options = jQuery.extend({}, this.defaults, options);
|
||||
|
||||
// set default url
|
||||
if(this.options.url === null) {
|
||||
this.options.url = ajaxurl;
|
||||
}
|
||||
|
||||
// set default token
|
||||
if(this.options.token === null) {
|
||||
this.options.token = window.mailpoet_token;
|
||||
}
|
||||
},
|
||||
getParams: function() {
|
||||
return {
|
||||
action: 'mailpoet',
|
||||
token: this.options.token,
|
||||
endpoint: this.options.endpoint,
|
||||
method: this.options.action,
|
||||
data: this.options.data || {}
|
||||
}
|
||||
},
|
||||
request: function(method, options) {
|
||||
// set options
|
||||
this.init(options);
|
||||
|
||||
// set request params
|
||||
var params = this.getParams();
|
||||
var deferred = jQuery.Deferred();
|
||||
|
||||
// remove null values from the data object
|
||||
if (_.isObject(params.data)) {
|
||||
params.data = _.pick(params.data, function(value) {
|
||||
return (value !== null)
|
||||
})
|
||||
}
|
||||
|
||||
// ajax request
|
||||
deferred = jQuery.post(
|
||||
this.options.url,
|
||||
params,
|
||||
null,
|
||||
'json'
|
||||
).then(function(data) {
|
||||
return data;
|
||||
}, function(xhr) {
|
||||
return xhr.responseJSON;
|
||||
});
|
||||
|
||||
// clear options
|
||||
this.options = {};
|
||||
|
||||
return deferred;
|
||||
}
|
||||
};
|
||||
});
|
||||
function requestFailed(errorMessage, xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
return xhr.responseJSON;
|
||||
}
|
||||
var message = errorMessage.replace('%d', xhr.status);
|
||||
return {
|
||||
errors: [
|
||||
{
|
||||
message: message
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
define('ajax', ['mailpoet', 'jquery', 'underscore'], function(mp, jQuery, _) {
|
||||
var MailPoet = mp;
|
||||
|
||||
MailPoet.Ajax = {
|
||||
version: 0.5,
|
||||
options: {},
|
||||
defaults: {
|
||||
url: null,
|
||||
api_version: null,
|
||||
endpoint: null,
|
||||
action: null,
|
||||
token: null,
|
||||
data: {}
|
||||
},
|
||||
post: function(options) {
|
||||
return this.request('post', options);
|
||||
},
|
||||
init: function(options) {
|
||||
// merge options
|
||||
this.options = jQuery.extend({}, this.defaults, options);
|
||||
|
||||
// set default url
|
||||
if(this.options.url === null) {
|
||||
this.options.url = ajaxurl;
|
||||
}
|
||||
|
||||
// set default token
|
||||
if(this.options.token === null) {
|
||||
this.options.token = window.mailpoet_token;
|
||||
}
|
||||
},
|
||||
getParams: function() {
|
||||
return {
|
||||
action: 'mailpoet',
|
||||
api_version: this.options.api_version,
|
||||
token: this.options.token,
|
||||
endpoint: this.options.endpoint,
|
||||
method: this.options.action,
|
||||
data: this.options.data || {}
|
||||
};
|
||||
},
|
||||
request: function(method, options) {
|
||||
// set options
|
||||
this.init(options);
|
||||
|
||||
// set request params
|
||||
var params = this.getParams();
|
||||
|
||||
// remove null values from the data object
|
||||
if (_.isObject(params.data)) {
|
||||
params.data = _.pick(params.data, function(value) {
|
||||
return (value !== null);
|
||||
});
|
||||
}
|
||||
|
||||
// ajax request
|
||||
var deferred = jQuery.post(
|
||||
this.options.url,
|
||||
params,
|
||||
null,
|
||||
'json'
|
||||
).then(function(data) {
|
||||
return data;
|
||||
}, _.partial(requestFailed, MailPoet.I18n.t('ajaxFailedErrorMessage')));
|
||||
|
||||
// clear options
|
||||
this.options = {};
|
||||
|
||||
return deferred;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
73
assets/js/src/analytics_event.js
Normal file
73
assets/js/src/analytics_event.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This creates two functions and adds them to MailPoet object
|
||||
* - `trackEvent` which should be used in normal circumstances.
|
||||
* This function tracks an event and sends it to mixpanel.
|
||||
* This function does nothing if analytics is disabled.
|
||||
* - `forceTrackEvent` which sends given event to analytics
|
||||
* even if it has been disabled.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is to cache events which are triggered before the mixpanel
|
||||
* library is loaded. This might happen if an event is tracked
|
||||
* on page load and the mixpanel library takes a long time to load.
|
||||
* After it is loaded all events are posted.
|
||||
* @type {Array.Object}
|
||||
*/
|
||||
var eventsCache = [];
|
||||
|
||||
function track(name, data){
|
||||
if (typeof window.mixpanel.track !== 'function') {
|
||||
window.mixpanel.init(window.mixpanelTrackingId);
|
||||
}
|
||||
window.mixpanel.track(name, data);
|
||||
}
|
||||
|
||||
function exportMixpanel(mp) {
|
||||
var MailPoet = mp;
|
||||
MailPoet.forceTrackEvent = track;
|
||||
|
||||
if (window.mailpoet_analytics_enabled) {
|
||||
MailPoet.trackEvent = track;
|
||||
} else {
|
||||
MailPoet.trackEvent = function () {};
|
||||
}
|
||||
}
|
||||
|
||||
function trackCachedEvents() {
|
||||
eventsCache.map(function (event) {
|
||||
if (window.mailpoet_analytics_enabled || event.forced) {
|
||||
window.mixpanel.track(event.name, event.data)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initializeMixpanelWhenLoaded() {
|
||||
if (typeof window.mixpanel === 'object') {
|
||||
exportMixpanel(MailPoet);
|
||||
trackCachedEvents();
|
||||
} else {
|
||||
setTimeout(initializeMixpanelWhenLoaded, 100);
|
||||
}
|
||||
}
|
||||
|
||||
function cacheEvent(forced, name, data) {
|
||||
eventsCache.push({
|
||||
name: name,
|
||||
data: data,
|
||||
forced: forced
|
||||
});
|
||||
}
|
||||
|
||||
define(
|
||||
['mailpoet', 'underscore'],
|
||||
function(mp, _) {
|
||||
var MailPoet = mp;
|
||||
|
||||
MailPoet.trackEvent = _.partial(cacheEvent, false);
|
||||
MailPoet.forceTrackEvent = _.partial(cacheEvent, true);
|
||||
|
||||
initializeMixpanelWhenLoaded();
|
||||
}
|
||||
);
|
@ -4,12 +4,14 @@ define('date',
|
||||
'jquery',
|
||||
'moment'
|
||||
], function(
|
||||
MailPoet,
|
||||
mp,
|
||||
jQuery,
|
||||
Moment
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var MailPoet = mp;
|
||||
|
||||
MailPoet.Date = {
|
||||
version: 0.1,
|
||||
options: {},
|
||||
@ -17,8 +19,8 @@ define('date',
|
||||
offset: 0,
|
||||
format: 'F, d Y H:i:s'
|
||||
},
|
||||
init: function(options) {
|
||||
options = options || {};
|
||||
init: function (opts) {
|
||||
var options = opts || {};
|
||||
|
||||
// set UTC offset
|
||||
if (
|
||||
@ -39,16 +41,16 @@ define('date',
|
||||
|
||||
return this;
|
||||
},
|
||||
format: function(date, options) {
|
||||
options = options || {};
|
||||
format: function(date, opts) {
|
||||
var options = opts || {};
|
||||
this.init(options);
|
||||
|
||||
var date = Moment(date, this.convertFormat(options.parseFormat));
|
||||
if (options.offset === 0) date = date.utc();
|
||||
return date.format(this.convertFormat(this.options.format));
|
||||
var momentDate = Moment(date, this.convertFormat(options.parseFormat));
|
||||
if (options.offset === 0) momentDate = momentDate.utc();
|
||||
return momentDate.format(this.convertFormat(this.options.format));
|
||||
},
|
||||
toDate: function(date, options) {
|
||||
options = options || {};
|
||||
toDate: function(date, opts) {
|
||||
var options = opts || {};
|
||||
this.init(options);
|
||||
|
||||
return Moment(date, this.convertFormat(options.parseFormat)).toDate();
|
||||
@ -143,7 +145,8 @@ define('date',
|
||||
var convertedFormat = [];
|
||||
var escapeToken = false;
|
||||
|
||||
for(var index = 0, token = ''; token = format.charAt(index); index++){
|
||||
for(var index = 0, token = ''; format.charAt(index); index += 1){
|
||||
token = format.charAt(index);
|
||||
if (escapeToken === true) {
|
||||
convertedFormat.push('['+token+']');
|
||||
escapeToken = false;
|
||||
|
@ -1,15 +1,15 @@
|
||||
define([
|
||||
'react'
|
||||
'react',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React
|
||||
) {
|
||||
) => {
|
||||
const FormFieldCheckbox = React.createClass({
|
||||
onValueChange: function(e) {
|
||||
onValueChange: function (e) {
|
||||
e.target.value = this.refs.checkbox.checked ? '1' : '0';
|
||||
return this.props.onValueChange(e);
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
if (this.props.field.values === undefined) {
|
||||
return false;
|
||||
}
|
||||
@ -42,8 +42,8 @@ function(
|
||||
{ options }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return FormFieldCheckbox;
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,10 @@
|
||||
define([
|
||||
'react',
|
||||
'moment',
|
||||
], function(
|
||||
], (
|
||||
React,
|
||||
Moment
|
||||
) {
|
||||
) => {
|
||||
class FormFieldDateYear extends React.Component {
|
||||
render() {
|
||||
const yearsRange = 100;
|
||||
@ -17,7 +17,7 @@ define([
|
||||
}
|
||||
|
||||
const currentYear = Moment().year();
|
||||
for (let i = currentYear; i >= currentYear - yearsRange; i--) {
|
||||
for (let i = currentYear; i >= currentYear - yearsRange; i -= 1) {
|
||||
years.push((
|
||||
<option
|
||||
key={ i }
|
||||
@ -47,7 +47,7 @@ define([
|
||||
));
|
||||
}
|
||||
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
for (let i = 1; i <= 12; i += 1) {
|
||||
months.push((
|
||||
<option
|
||||
key={ i }
|
||||
@ -77,7 +77,7 @@ define([
|
||||
));
|
||||
}
|
||||
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
for (let i = 1; i <= 31; i += 1) {
|
||||
days.push((
|
||||
<option
|
||||
key={ i }
|
||||
@ -104,13 +104,13 @@ define([
|
||||
this.state = {
|
||||
year: '',
|
||||
month: '',
|
||||
day: ''
|
||||
}
|
||||
day: '',
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
this.extractDateParts();
|
||||
}
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
componentDidUpdate(prevProps) {
|
||||
if (
|
||||
(this.props.item !== undefined && prevProps.item !== undefined)
|
||||
&& (this.props.item.id !== prevProps.item.id)
|
||||
@ -132,7 +132,7 @@ define([
|
||||
this.setState({
|
||||
year: dateTime.format('YYYY'),
|
||||
month: dateTime.format('M'),
|
||||
day: dateTime.format('D')
|
||||
day: dateTime.format('D'),
|
||||
});
|
||||
}
|
||||
formatValue() {
|
||||
@ -143,30 +143,30 @@ define([
|
||||
switch(dateType) {
|
||||
case 'year_month_day':
|
||||
value = {
|
||||
'year': this.state.year,
|
||||
'month': this.state.month,
|
||||
'day': this.state.day
|
||||
year: this.state.year,
|
||||
month: this.state.month,
|
||||
day: this.state.day,
|
||||
};
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'year_month':
|
||||
value = {
|
||||
'year': this.state.year,
|
||||
'month': this.state.month
|
||||
year: this.state.year,
|
||||
month: this.state.month,
|
||||
};
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'month':
|
||||
value = {
|
||||
'month': this.state.month
|
||||
month: this.state.month,
|
||||
};
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'year':
|
||||
value = {
|
||||
'year': this.state.year
|
||||
year: this.state.year,
|
||||
};
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
@ -181,16 +181,16 @@ define([
|
||||
field = matches[1];
|
||||
property = matches[2];
|
||||
|
||||
let value = ~~(e.target.value);
|
||||
const value = ~~(e.target.value);
|
||||
|
||||
this.setState({
|
||||
[`${property}`]: value
|
||||
[`${property}`]: value,
|
||||
}, () => {
|
||||
this.props.onValueChange({
|
||||
target: {
|
||||
name: field,
|
||||
value: this.formatValue()
|
||||
}
|
||||
value: this.formatValue(),
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -201,7 +201,7 @@ define([
|
||||
const dateType = this.props.field.params.date_type;
|
||||
const dateSelects = dateFormats[dateType][0].split('/');
|
||||
|
||||
const fields = dateSelects.map(type => {
|
||||
const fields = dateSelects.map((type) => {
|
||||
switch(type) {
|
||||
case 'YYYY':
|
||||
return (<FormFieldDateYear
|
||||
@ -212,7 +212,7 @@ define([
|
||||
year={ this.state.year }
|
||||
placeholder={ this.props.field.year_placeholder }
|
||||
/>);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'MM':
|
||||
return (<FormFieldDateMonth
|
||||
@ -224,7 +224,7 @@ define([
|
||||
monthNames={ monthNames }
|
||||
placeholder={ this.props.field.month_placeholder }
|
||||
/>);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'DD':
|
||||
return (<FormFieldDateDay
|
||||
@ -235,9 +235,9 @@ define([
|
||||
day={ this.state.day }
|
||||
placeholder={ this.props.field.day_placeholder }
|
||||
/>);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -248,4 +248,4 @@ define([
|
||||
};
|
||||
|
||||
return FormFieldDate;
|
||||
});
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ define([
|
||||
'form/fields/selection.jsx',
|
||||
'form/fields/date.jsx',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React,
|
||||
FormFieldText,
|
||||
FormFieldTextarea,
|
||||
@ -17,54 +17,55 @@ function(
|
||||
FormFieldCheckbox,
|
||||
FormFieldSelection,
|
||||
FormFieldDate
|
||||
) {
|
||||
var FormField = React.createClass({
|
||||
renderField: function(data, inline = false) {
|
||||
var description = false;
|
||||
) => {
|
||||
const FormField = React.createClass({
|
||||
renderField: function (data, inline = false) {
|
||||
let description = false;
|
||||
if(data.field.description) {
|
||||
description = (
|
||||
<p className="description">{ data.field.description }</p>
|
||||
);
|
||||
}
|
||||
|
||||
var field = false;
|
||||
let field = false;
|
||||
let dataField = data.field;
|
||||
|
||||
if(data.field['field'] !== undefined) {
|
||||
data.field = jQuery.merge(data.field, data.field.field);
|
||||
dataField = jQuery.merge(dataField, data.field.field);
|
||||
}
|
||||
|
||||
switch(data.field.type) {
|
||||
switch(dataField.type) {
|
||||
case 'text':
|
||||
field = (<FormFieldText {...data} />);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
field = (<FormFieldTextarea {...data} />);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
field = (<FormFieldSelect {...data} />);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'radio':
|
||||
field = (<FormFieldRadio {...data} />);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
field = (<FormFieldCheckbox {...data} />);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'selection':
|
||||
field = (<FormFieldSelection {...data} />);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
field = (<FormFieldDate {...data} />);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'reactComponent':
|
||||
field = (<data.field.component {...data} />);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if(inline === true) {
|
||||
@ -83,23 +84,23 @@ function(
|
||||
);
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
var field = false;
|
||||
render: function () {
|
||||
let field = false;
|
||||
|
||||
if(this.props.field['fields'] !== undefined) {
|
||||
field = this.props.field.fields.map(function(subfield, index) {
|
||||
field = this.props.field.fields.map((subfield, index) => {
|
||||
return this.renderField({
|
||||
index: index,
|
||||
field: subfield,
|
||||
item: this.props.item,
|
||||
onValueChange: this.props.onValueChange || false
|
||||
onValueChange: this.props.onValueChange || false,
|
||||
});
|
||||
}.bind(this));
|
||||
});
|
||||
} else {
|
||||
field = this.renderField(this.props);
|
||||
}
|
||||
|
||||
var tip = false;
|
||||
let tip = false;
|
||||
if(this.props.field.tip) {
|
||||
tip = (
|
||||
<p className="description">{ this.props.field.tip }</p>
|
||||
@ -121,7 +122,7 @@ function(
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return FormField;
|
||||
|
@ -1,11 +1,11 @@
|
||||
define([
|
||||
'react'
|
||||
'react',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React
|
||||
) {
|
||||
) => {
|
||||
const FormFieldRadio = React.createClass({
|
||||
render: function() {
|
||||
render: function () {
|
||||
if (this.props.field.values === undefined) {
|
||||
return false;
|
||||
}
|
||||
@ -34,8 +34,8 @@ function(
|
||||
{ options }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return FormFieldRadio;
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import _ from 'underscore'
|
||||
import React from 'react';
|
||||
import _ from 'underscore';
|
||||
|
||||
const FormFieldSelect = React.createClass({
|
||||
render() {
|
||||
@ -33,12 +33,12 @@ const FormFieldSelect = React.createClass({
|
||||
_.map(
|
||||
_.sortBy(
|
||||
_.pairs(this.props.field.values),
|
||||
(item) => sortBy(item[0], item[1])
|
||||
item => sortBy(item[0], item[1])
|
||||
),
|
||||
(item) => item[0]
|
||||
item => item[0]
|
||||
);
|
||||
} else {
|
||||
keys = Object.keys(this.props.field.values)
|
||||
keys = Object.keys(this.props.field.values);
|
||||
}
|
||||
|
||||
const options = keys.map(
|
||||
@ -70,7 +70,7 @@ const FormFieldSelect = React.createClass({
|
||||
{options}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = FormFieldSelect;
|
||||
|
@ -2,35 +2,35 @@ define([
|
||||
'react',
|
||||
'react-dom',
|
||||
'jquery',
|
||||
'select2'
|
||||
'select2',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React,
|
||||
ReactDOM,
|
||||
jQuery
|
||||
) {
|
||||
var Selection = React.createClass({
|
||||
getInitialState: function() {
|
||||
) => {
|
||||
const Selection = React.createClass({
|
||||
getInitialState: function () {
|
||||
return {
|
||||
items: [],
|
||||
select2: false
|
||||
select2: false,
|
||||
};
|
||||
},
|
||||
componentWillMount: function() {
|
||||
componentWillMount: function () {
|
||||
this.loadCachedItems();
|
||||
},
|
||||
allowMultipleValues: function() {
|
||||
allowMultipleValues: function () {
|
||||
return (this.props.field.multiple === true);
|
||||
},
|
||||
isSelect2Initialized: function() {
|
||||
isSelect2Initialized: function () {
|
||||
return (this.state.select2 === true);
|
||||
},
|
||||
componentDidMount: function() {
|
||||
componentDidMount: function () {
|
||||
if(this.allowMultipleValues()) {
|
||||
this.setupSelect2();
|
||||
}
|
||||
},
|
||||
componentDidUpdate: function(prevProps, prevState) {
|
||||
componentDidUpdate: function (prevProps) {
|
||||
if(
|
||||
(this.props.item !== undefined && prevProps.item !== undefined)
|
||||
&& (this.props.item.id !== prevProps.item.id)
|
||||
@ -40,24 +40,24 @@ function(
|
||||
.trigger('change');
|
||||
}
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
componentWillUnmount: function () {
|
||||
if(this.allowMultipleValues()) {
|
||||
this.destroySelect2();
|
||||
}
|
||||
},
|
||||
destroySelect2: function() {
|
||||
destroySelect2: function () {
|
||||
if(this.isSelect2Initialized()) {
|
||||
jQuery('#'+this.refs.select.id).select2('destroy');
|
||||
}
|
||||
},
|
||||
setupSelect2: function() {
|
||||
setupSelect2: function () {
|
||||
if(this.isSelect2Initialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var select2 = jQuery('#'+this.refs.select.id).select2({
|
||||
const select2 = jQuery('#'+this.refs.select.id).select2({
|
||||
width: (this.props.width || ''),
|
||||
templateResult: function(item) {
|
||||
templateResult: function (item) {
|
||||
if(item.element && item.element.selected) {
|
||||
return null;
|
||||
} else {
|
||||
@ -67,14 +67,14 @@ function(
|
||||
return item.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var hasRemoved = false;
|
||||
select2.on('select2:unselecting', function(e) {
|
||||
let hasRemoved = false;
|
||||
select2.on('select2:unselecting', () => {
|
||||
hasRemoved = true;
|
||||
});
|
||||
select2.on('select2:opening', function(e) {
|
||||
select2.on('select2:opening', (e) => {
|
||||
if(hasRemoved === true) {
|
||||
hasRemoved = false;
|
||||
e.preventDefault();
|
||||
@ -85,13 +85,13 @@ function(
|
||||
|
||||
this.setState({ select2: true });
|
||||
},
|
||||
getSelectedValues: function() {
|
||||
getSelectedValues: function () {
|
||||
if(this.props.field['selected'] !== undefined) {
|
||||
return this.props.field['selected'](this.props.item);
|
||||
} else if(this.props.item !== undefined && this.props.field.name !== undefined) {
|
||||
if (this.allowMultipleValues()) {
|
||||
if (Array.isArray(this.props.item[this.props.field.name])) {
|
||||
return this.props.item[this.props.field.name].map(function(item) {
|
||||
return this.props.item[this.props.field.name].map((item) => {
|
||||
return item.id;
|
||||
});
|
||||
}
|
||||
@ -101,9 +101,9 @@ function(
|
||||
}
|
||||
return null;
|
||||
},
|
||||
loadCachedItems: function() {
|
||||
loadCachedItems: function () {
|
||||
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
|
||||
var items = window['mailpoet_'+this.props.field.endpoint];
|
||||
let items = window['mailpoet_'+this.props.field.endpoint];
|
||||
|
||||
|
||||
if(this.props.field['filter'] !== undefined) {
|
||||
@ -111,39 +111,39 @@ function(
|
||||
}
|
||||
|
||||
this.setState({
|
||||
items: items
|
||||
items: items,
|
||||
});
|
||||
}
|
||||
},
|
||||
handleChange: function(e) {
|
||||
handleChange: function (e) {
|
||||
if(this.props.onValueChange !== undefined) {
|
||||
if(this.props.field.multiple) {
|
||||
value = jQuery('#'+this.refs.select.id).val();
|
||||
} else {
|
||||
value = e.target.value;
|
||||
}
|
||||
var transformedValue = this.transformChangedValue(value);
|
||||
const transformedValue = this.transformChangedValue(value);
|
||||
this.props.onValueChange({
|
||||
target: {
|
||||
target: {
|
||||
value: transformedValue,
|
||||
name: this.props.field.name
|
||||
}
|
||||
name: this.props.field.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
getLabel: function(item) {
|
||||
getLabel: function (item) {
|
||||
if(this.props.field['getLabel'] !== undefined) {
|
||||
return this.props.field.getLabel(item, this.props.item);
|
||||
}
|
||||
return item.name;
|
||||
},
|
||||
getSearchLabel: function(item) {
|
||||
getSearchLabel: function (item) {
|
||||
if(this.props.field['getSearchLabel'] !== undefined) {
|
||||
return this.props.field.getSearchLabel(item, this.props.item);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getValue: function(item) {
|
||||
getValue: function (item) {
|
||||
if(this.props.field['getValue'] !== undefined) {
|
||||
return this.props.field.getValue(item, this.props.item);
|
||||
}
|
||||
@ -152,18 +152,18 @@ function(
|
||||
// When it's impossible to represent the desired value in DOM,
|
||||
// this function may be used to transform the placeholder value into
|
||||
// desired value.
|
||||
transformChangedValue: function(value) {
|
||||
transformChangedValue: function (value) {
|
||||
if(typeof this.props.field['transformChangedValue'] === 'function') {
|
||||
return this.props.field.transformChangedValue.call(this, value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
const options = this.state.items.map((item, index) => {
|
||||
let label = this.getLabel(item);
|
||||
let searchLabel = this.getSearchLabel(item);
|
||||
let value = this.getValue(item);
|
||||
const label = this.getLabel(item);
|
||||
const searchLabel = this.getSearchLabel(item);
|
||||
const value = this.getValue(item);
|
||||
|
||||
return (
|
||||
<option
|
||||
@ -180,13 +180,14 @@ function(
|
||||
<select
|
||||
id={ this.props.field.id || this.props.field.name }
|
||||
ref="select"
|
||||
disabled={this.props.field.disabled}
|
||||
data-placeholder={ this.props.field.placeholder }
|
||||
multiple={ this.props.field.multiple }
|
||||
defaultValue={ this.getSelectedValues() }
|
||||
{...this.props.field.validation}
|
||||
>{ options }</select>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return Selection;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React from 'react';
|
||||
|
||||
const FormFieldText = React.createClass({
|
||||
render() {
|
||||
@ -29,7 +29,7 @@ const FormFieldText = React.createClass({
|
||||
{...this.props.field.validation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = FormFieldText;
|
||||
module.exports = FormFieldText;
|
||||
|
@ -1,11 +1,11 @@
|
||||
define([
|
||||
'react'
|
||||
'react',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React
|
||||
) {
|
||||
var FormFieldTextarea = React.createClass({
|
||||
render: function() {
|
||||
) => {
|
||||
const FormFieldTextarea = React.createClass({
|
||||
render: function () {
|
||||
return (
|
||||
<textarea
|
||||
type="text"
|
||||
@ -19,8 +19,8 @@ function(
|
||||
{...this.props.field.validation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return FormFieldTextarea;
|
||||
});
|
||||
});
|
||||
|
@ -4,54 +4,54 @@ define(
|
||||
'mailpoet',
|
||||
'classnames',
|
||||
'react-router',
|
||||
'form/fields/field.jsx'
|
||||
'form/fields/field.jsx',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React,
|
||||
MailPoet,
|
||||
classNames,
|
||||
Router,
|
||||
FormField
|
||||
) {
|
||||
) => {
|
||||
|
||||
var Form = React.createClass({
|
||||
const Form = React.createClass({
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object.isRequired
|
||||
router: React.PropTypes.object.isRequired,
|
||||
},
|
||||
getDefaultProps: function() {
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
params: {},
|
||||
};
|
||||
},
|
||||
getInitialState: function() {
|
||||
getInitialState: function () {
|
||||
return {
|
||||
loading: false,
|
||||
errors: [],
|
||||
item: {}
|
||||
item: {},
|
||||
};
|
||||
},
|
||||
getValues: function() {
|
||||
getValues: function () {
|
||||
return this.props.item ? this.props.item : this.state.item;
|
||||
},
|
||||
getErrors: function() {
|
||||
getErrors: function () {
|
||||
return this.props.errors ? this.props.errors : this.state.errors;
|
||||
},
|
||||
componentDidMount: function() {
|
||||
componentDidMount: function () {
|
||||
if(this.isMounted()) {
|
||||
if(this.props.params.id !== undefined) {
|
||||
this.loadItem(this.props.params.id);
|
||||
} else {
|
||||
this.setState({
|
||||
item: jQuery('.mailpoet_form').serializeObject()
|
||||
item: jQuery('.mailpoet_form').serializeObject(),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
componentWillReceiveProps: function(props) {
|
||||
componentWillReceiveProps: function (props) {
|
||||
if(props.params.id === undefined) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
item: {}
|
||||
item: {},
|
||||
});
|
||||
if (props.item === undefined) {
|
||||
this.refs.form.reset();
|
||||
@ -60,30 +60,31 @@ define(
|
||||
this.loadItem(props.params.id);
|
||||
}
|
||||
},
|
||||
loadItem: function(id) {
|
||||
loadItem: function (id) {
|
||||
this.setState({ loading: true });
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'get',
|
||||
data: {
|
||||
id: id
|
||||
}
|
||||
id: id,
|
||||
},
|
||||
}).done((response) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
item: response.data
|
||||
item: response.data,
|
||||
});
|
||||
}).fail((response) => {
|
||||
}).fail(() => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
item: {}
|
||||
}, function() {
|
||||
item: {},
|
||||
}, function () {
|
||||
this.context.router.push('/new');
|
||||
});
|
||||
});
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
handleSubmit: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
// handle validation
|
||||
@ -96,28 +97,29 @@ define(
|
||||
this.setState({ loading: true });
|
||||
|
||||
// only get values from displayed fields
|
||||
var item = {};
|
||||
this.props.fields.map(function(field) {
|
||||
const item = {};
|
||||
this.props.fields.map((field) => {
|
||||
if(field['fields'] !== undefined) {
|
||||
field.fields.map(function(subfield) {
|
||||
field.fields.map((subfield) => {
|
||||
item[subfield.name] = this.state.item[subfield.name];
|
||||
}.bind(this));
|
||||
});
|
||||
} else {
|
||||
item[field.name] = this.state.item[field.name];
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
// set id if specified
|
||||
if(this.props.params.id !== undefined) {
|
||||
item.id = this.props.params.id;
|
||||
}
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'save',
|
||||
data: item
|
||||
data: item,
|
||||
}).always(() => {
|
||||
this.setState({ loading: false });
|
||||
}).done((response) => {
|
||||
}).done(() => {
|
||||
if(this.props.onSuccess !== undefined) {
|
||||
this.props.onSuccess();
|
||||
} else {
|
||||
@ -135,24 +137,25 @@ define(
|
||||
}
|
||||
});
|
||||
},
|
||||
handleValueChange: function(e) {
|
||||
handleValueChange: function (e) {
|
||||
if (this.props.onChange) {
|
||||
return this.props.onChange(e);
|
||||
} else {
|
||||
var item = this.state.item,
|
||||
field = e.target.name;
|
||||
const item = this.state.item;
|
||||
const field = e.target.name;
|
||||
|
||||
item[field] = e.target.value;
|
||||
|
||||
this.setState({
|
||||
item: item
|
||||
item: item,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
let errors;
|
||||
if(this.getErrors() !== undefined) {
|
||||
var errors = this.getErrors().map(function(error, index) {
|
||||
errors = this.getErrors().map((error, index) => {
|
||||
return (
|
||||
<p key={ 'error-'+index } className="mailpoet_error">
|
||||
{ error.message }
|
||||
@ -161,13 +164,13 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
var formClasses = classNames(
|
||||
const formClasses = classNames(
|
||||
'mailpoet_form',
|
||||
{ 'mailpoet_form_loading': this.state.loading || this.props.loading }
|
||||
{ mailpoet_form_loading: this.state.loading || this.props.loading }
|
||||
);
|
||||
|
||||
var beforeFormContent = false;
|
||||
var afterFormContent = false;
|
||||
let beforeFormContent = false;
|
||||
let afterFormContent = false;
|
||||
|
||||
if (this.props.beforeFormContent !== undefined) {
|
||||
beforeFormContent = this.props.beforeFormContent(this.getValues());
|
||||
@ -177,17 +180,26 @@ define(
|
||||
afterFormContent = this.props.afterFormContent(this.getValues());
|
||||
}
|
||||
|
||||
var fields = this.props.fields.map(function(field, i) {
|
||||
const fields = this.props.fields.map((field, i) => {
|
||||
// Compose an onChange handler from the default and custom one
|
||||
let onValueChange = this.handleValueChange;
|
||||
if (field.onBeforeChange) {
|
||||
onValueChange = (e) => {
|
||||
field.onBeforeChange(e);
|
||||
return this.handleValueChange(e);
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<FormField
|
||||
field={ field }
|
||||
item={ this.getValues() }
|
||||
onValueChange={ this.handleValueChange }
|
||||
onValueChange={ onValueChange }
|
||||
key={ 'field-'+i } />
|
||||
);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
var actions = false;
|
||||
let actions = false;
|
||||
if(this.props.children) {
|
||||
actions = this.props.children;
|
||||
} else {
|
||||
@ -226,7 +238,7 @@ define(
|
||||
{ afterFormContent }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return Form;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,15 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
|
||||
import { createHashHistory } from 'history'
|
||||
import FormList from 'forms/list.jsx'
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Router, Route, IndexRoute, useRouterHistory } from 'react-router';
|
||||
import { createHashHistory } from 'history';
|
||||
import FormList from 'forms/list.jsx';
|
||||
|
||||
const history = useRouterHistory(createHashHistory)({ queryKey: false });
|
||||
|
||||
const App = React.createClass({
|
||||
render() {
|
||||
return this.props.children
|
||||
}
|
||||
return this.props.children;
|
||||
},
|
||||
});
|
||||
|
||||
const container = document.getElementById('forms_container');
|
||||
@ -23,4 +23,4 @@ if(container) {
|
||||
</Route>
|
||||
</Router>
|
||||
), container);
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,27 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, Link } from 'react-router'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import classNames from 'classnames'
|
||||
import MailPoet from 'mailpoet'
|
||||
import React from 'react';
|
||||
import Listing from 'listing/listing.jsx';
|
||||
import classNames from 'classnames';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'name',
|
||||
label: MailPoet.I18n.t('formName'),
|
||||
sortable: true
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: MailPoet.I18n.t('segments')
|
||||
label: MailPoet.I18n.t('segments'),
|
||||
},
|
||||
{
|
||||
name: 'signups',
|
||||
label: MailPoet.I18n.t('signups')
|
||||
label: MailPoet.I18n.t('signups'),
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: MailPoet.I18n.t('createdOn'),
|
||||
sortable: true
|
||||
}
|
||||
sortable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const messages = {
|
||||
@ -71,37 +69,38 @@ const messages = {
|
||||
).replace('%$1d', count.toLocaleString());
|
||||
}
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: MailPoet.I18n.t('moveToTrash'),
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
onSuccess: messages.onTrash,
|
||||
},
|
||||
];
|
||||
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: MailPoet.I18n.t('edit'),
|
||||
link: function(item) {
|
||||
link: function (item) {
|
||||
return (
|
||||
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>{MailPoet.I18n.t('edit')}</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'duplicate',
|
||||
label: MailPoet.I18n.t('duplicate'),
|
||||
onClick: function(item, refresh) {
|
||||
onClick: function (item, refresh) {
|
||||
return MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'forms',
|
||||
action: 'duplicate',
|
||||
data: {
|
||||
id: item.id
|
||||
}
|
||||
id: item.id,
|
||||
},
|
||||
}).done((response) => {
|
||||
MailPoet.Notice.success(
|
||||
(MailPoet.I18n.t('formDuplicated')).replace('%$1s', response.data.name)
|
||||
@ -110,44 +109,45 @@ const item_actions = [
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'trash'
|
||||
}
|
||||
name: 'trash',
|
||||
},
|
||||
];
|
||||
|
||||
const FormList = React.createClass({
|
||||
createForm() {
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'forms',
|
||||
action: 'create'
|
||||
action: 'create',
|
||||
}).done((response) => {
|
||||
window.location = mailpoet_form_edit_url + response.data.id;
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
renderItem(form, actions) {
|
||||
let row_classes = classNames(
|
||||
const row_classes = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
'has-row-actions'
|
||||
);
|
||||
|
||||
let segments = mailpoet_segments.filter(function(segment) {
|
||||
let segments = mailpoet_segments.filter((segment) => {
|
||||
return (jQuery.inArray(segment.id, form.segments) !== -1);
|
||||
}).map(function(segment) {
|
||||
}).map((segment) => {
|
||||
return segment.name;
|
||||
}).join(', ');
|
||||
|
||||
@ -203,7 +203,7 @@ const FormList = React.createClass({
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = FormList;
|
||||
|
@ -19,7 +19,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
}
|
||||
|
||||
// set date format
|
||||
var f = block.hash.format || "MMM Do, YYYY";
|
||||
var f = block.hash.format || 'MMM Do, YYYY';
|
||||
// check if we passed a timestamp
|
||||
if(parseInt(timestamp, 10) == timestamp) {
|
||||
return moment.unix(timestamp).format(f);
|
||||
@ -67,7 +67,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('nl2br', function(value, block) {
|
||||
return value.gsub("\n", "<br />");
|
||||
return value.gsub('\n', '<br />');
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('json_encode', function(value, block) {
|
||||
@ -78,7 +78,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
return JSON.parse(value);
|
||||
});
|
||||
Handlebars.registerHelper('url', function(value, block) {
|
||||
var url = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
||||
|
||||
return url + value;
|
||||
});
|
||||
@ -99,7 +99,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
// extract all lines into an array
|
||||
if(value === undefined) return '';
|
||||
|
||||
var lines = value.trim().split("\n");
|
||||
var lines = value.trim().split('\n');
|
||||
|
||||
// remove header & footer
|
||||
lines.shift();
|
||||
@ -125,12 +125,13 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
* @return {String} The truncated string.
|
||||
*/
|
||||
Handlebars.registerHelper('ellipsis', function (str, limit, append) {
|
||||
if (append === undefined) {
|
||||
append = '';
|
||||
var strAppend = append;
|
||||
if (strAppend === undefined) {
|
||||
strAppend = '';
|
||||
}
|
||||
var sanitized = str.replace(/(<([^>]+)>)/g, '');
|
||||
if (sanitized.length > limit) {
|
||||
return sanitized.substr(0, limit - append.length) + append;
|
||||
return sanitized.substr(0, limit - strAppend.length) + strAppend;
|
||||
} else {
|
||||
return sanitized;
|
||||
}
|
||||
@ -147,10 +148,10 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
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 '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");
|
||||
case 'Verdana': return new Handlebars.SafeString('Verdana, Geneva, sans-serif');
|
||||
default: return font;
|
||||
}
|
||||
});
|
||||
|
21
assets/js/src/help-tooltip.js
Normal file
21
assets/js/src/help-tooltip.js
Normal file
@ -0,0 +1,21 @@
|
||||
define('helpTooltip', ['mailpoet', 'react', 'react-dom', 'help-tooltip.jsx'],
|
||||
function (mp, React, ReactDOM, TooltipComponent) {
|
||||
'use strict';
|
||||
var MailPoet = mp;
|
||||
|
||||
MailPoet.helpTooltip = {
|
||||
show: function (domContainerNode, opts) {
|
||||
|
||||
ReactDOM.render(React.createElement(
|
||||
TooltipComponent, {
|
||||
tooltip: opts.tooltip,
|
||||
tooltipId: opts.tooltipId,
|
||||
place: opts.place
|
||||
}
|
||||
), domContainerNode);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
);
|
||||
|
63
assets/js/src/help-tooltip.jsx
Normal file
63
assets/js/src/help-tooltip.jsx
Normal file
@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
import ReactHtmlParser from 'react-html-parser';
|
||||
|
||||
function Tooltip(props) {
|
||||
let tooltipId = props.tooltipId;
|
||||
let tooltip = props.tooltip;
|
||||
// tooltip ID must be unique, defaults to tooltip text
|
||||
if(!props.tooltipId && typeof props.tooltip === 'string') {
|
||||
tooltipId = props.tooltip;
|
||||
}
|
||||
|
||||
if(typeof props.tooltip === 'string') {
|
||||
tooltip = (<span
|
||||
style={{
|
||||
pointerEvents: 'all',
|
||||
maxWidth: '400',
|
||||
display: 'inline-block',
|
||||
}}
|
||||
>
|
||||
{ReactHtmlParser(props.tooltip)}
|
||||
</span>);
|
||||
}
|
||||
|
||||
return (
|
||||
<span className={props.className}>
|
||||
<span
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
className="tooltip dashicons dashicons-editor-help"
|
||||
data-event="click"
|
||||
data-tip
|
||||
data-for={tooltipId}
|
||||
>
|
||||
</span>
|
||||
<ReactTooltip
|
||||
globalEventOff="click"
|
||||
multiline={true}
|
||||
id={tooltipId}
|
||||
efect="solid"
|
||||
place={props.place}
|
||||
>
|
||||
{tooltip}
|
||||
</ReactTooltip>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
Tooltip.propTypes = {
|
||||
tooltipId: React.PropTypes.string,
|
||||
tooltip: React.PropTypes.node.isRequired,
|
||||
place: React.PropTypes.string,
|
||||
className: React.PropTypes.string,
|
||||
};
|
||||
|
||||
Tooltip.defaultProps = {
|
||||
tooltipId: undefined,
|
||||
place: undefined,
|
||||
className: undefined,
|
||||
};
|
||||
|
||||
module.exports = Tooltip;
|
32
assets/js/src/help/help.jsx
Normal file
32
assets/js/src/help/help.jsx
Normal file
@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Router, Route, IndexRedirect, useRouterHistory } from 'react-router';
|
||||
import { createHashHistory } from 'history';
|
||||
|
||||
import KnowledgeBase from 'help/knowledge_base.jsx';
|
||||
import SystemInfo from 'help/system_info.jsx';
|
||||
|
||||
const history = useRouterHistory(createHashHistory)({ queryKey: false });
|
||||
|
||||
const App = React.createClass({
|
||||
render() {
|
||||
return this.props.children;
|
||||
},
|
||||
});
|
||||
|
||||
const container = document.getElementById('help_container');
|
||||
|
||||
if(container) {
|
||||
|
||||
ReactDOM.render((
|
||||
<Router history={ history }>
|
||||
<Route path="/" component={ App }>
|
||||
<IndexRedirect to="knowledgeBase" />
|
||||
{/* Pages */}
|
||||
<Route path="knowledgeBase(/)**" params={{ tab: 'knowledgeBase' }} component={ KnowledgeBase } />
|
||||
<Route path="systemInfo(/)**" params={{ tab: 'systemInfo' }} component={ SystemInfo } />
|
||||
</Route>
|
||||
</Router>
|
||||
), container);
|
||||
|
||||
}
|
29
assets/js/src/help/knowledge_base.jsx
Normal file
29
assets/js/src/help/knowledge_base.jsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
import Tabs from './tabs.jsx';
|
||||
|
||||
function KnowledgeBase() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
<Tabs tab="knowledgeBase" />
|
||||
|
||||
<p>{MailPoet.I18n.t('knowledgeBaseIntro')}</p>
|
||||
<ul>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/116-common-problems">Common Problems</a></li>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/165-newsletters">Newsletters</a></li>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/156-migration-questions">Migration Questions</a></li>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/149-sending-methods">Sending Methods</a></li>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/139-subscription-forms">Subscription Forms</a></li>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/114-getting-started">Getting Started</a></li>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/123-newsletter-designer">Newsletter Designer</a></li>
|
||||
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/121-subscribers-and-lists">Subscribers and Lists</a></li>
|
||||
</ul>
|
||||
<a target="_blank" href="http://beta.docs.mailpoet.com/" className="button button-primary">{MailPoet.I18n.t('knowledgeBaseButton')}</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = KnowledgeBase;
|
47
assets/js/src/help/system_info.jsx
Normal file
47
assets/js/src/help/system_info.jsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import MailPoet from 'mailpoet';
|
||||
import _ from 'underscore';
|
||||
|
||||
import Tabs from './tabs.jsx';
|
||||
|
||||
function handleFocus(event) {
|
||||
event.target.select();
|
||||
}
|
||||
|
||||
function printData(data) {
|
||||
if (_.isObject(data)) {
|
||||
const printableData = Object.keys(data).map((key) => {
|
||||
return `${key}: ${data[key]}`;
|
||||
});
|
||||
|
||||
return (<textarea
|
||||
readOnly={true}
|
||||
onFocus={handleFocus}
|
||||
value={printableData.join('\n')}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '400px',
|
||||
}}
|
||||
/>);
|
||||
} else {
|
||||
return (<p>{MailPoet.I18n.t('systemInfoDataError')}</p>);
|
||||
}
|
||||
}
|
||||
|
||||
function KnowledgeBase() {
|
||||
const data = window.help_scout_data;
|
||||
return (
|
||||
<div>
|
||||
|
||||
<Tabs tab="systemInfo" />
|
||||
|
||||
<div className="mailpoet_notice notice inline notice-success" style={{ marginTop: '1em' }}>
|
||||
<p>{MailPoet.I18n.t('systemInfoIntro')}</p>
|
||||
</div>
|
||||
|
||||
{printData(data)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = KnowledgeBase;
|
46
assets/js/src/help/tabs.jsx
Normal file
46
assets/js/src/help/tabs.jsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import classNames from 'classnames';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: 'knowledgeBase',
|
||||
label: MailPoet.I18n.t('tabKnowledgeBaseTitle'),
|
||||
link: '/knowledgeBase',
|
||||
},
|
||||
{
|
||||
name: 'systemInfo',
|
||||
label: MailPoet.I18n.t('tabSystemInfoTitle'),
|
||||
link: '/systemInfo',
|
||||
},
|
||||
];
|
||||
|
||||
function Tabs(props) {
|
||||
|
||||
const tabLinks = tabs.map((tab, index) => {
|
||||
const tabClasses = classNames(
|
||||
'nav-tab',
|
||||
{ 'nav-tab-active': (props.tab === tab.name) }
|
||||
);
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={ 'tab-'+index }
|
||||
className={ tabClasses }
|
||||
to={ tab.link }
|
||||
>{ tab.label }</Link>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<h2 className="nav-tab-wrapper">
|
||||
{ tabLinks }
|
||||
</h2>
|
||||
);
|
||||
};
|
||||
|
||||
Tabs.propTypes = { tab: React.PropTypes.string };
|
||||
Tabs.defaultProps = { tab: 'knowledgeBase' };
|
||||
|
||||
module.exports = Tabs;
|
@ -1,3 +1,3 @@
|
||||
define([], function() {
|
||||
!function(e,o,n){window.HSCW=o,window.HS=n,n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={},t.readyQueue=[],t.config=function(e){this.userConfig=e},t.ready=function(e){this.readyQueue.push(e)},o.config={docs:{enabled:!0,baseUrl:"//mailpoet3.helpscoutdocs.com/"},contact:{enabled:!0,formId:"aa21ca80-a4f5-11e6-91aa-0a5fecc78a4d"}};var r=e.getElementsByTagName("script")[0],c=e.createElement("script");c.type="text/javascript",c.async=!0,c.src="https://djtflbt20bdde.cloudfront.net/",r.parentNode.insertBefore(c,r)}(document,window.HSCW||{},window.HS||{});
|
||||
!function(e, o, n){window.HSCW=o, window.HS=n, n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={}, t.readyQueue=[], t.config=function(e){this.userConfig=e}, t.ready=function(e){this.readyQueue.push(e)}, o.config={docs:{enabled:!0, baseUrl:"//mailpoet3.helpscoutdocs.com/"}, contact:{enabled:!0, formId:"aa21ca80-a4f5-11e6-91aa-0a5fecc78a4d"}};var r=e.getElementsByTagName("script")[0], c=e.createElement("script");c.type="text/javascript", c.async=!0, c.src="https://djtflbt20bdde.cloudfront.net/", r.parentNode.insertBefore(c, r)}(document, window.HSCW||{}, window.HS||{});
|
||||
});
|
||||
|
@ -2,9 +2,10 @@ define('i18n',
|
||||
[
|
||||
'mailpoet'
|
||||
], function(
|
||||
MailPoet
|
||||
mp
|
||||
) {
|
||||
'use strict';
|
||||
var MailPoet = mp;
|
||||
|
||||
var translations = {};
|
||||
|
||||
@ -13,7 +14,7 @@ define('i18n',
|
||||
translations[key] = value;
|
||||
},
|
||||
t: function(key) {
|
||||
return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace("%$1s", key);
|
||||
return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace('%$1s', key);
|
||||
},
|
||||
all: function() {
|
||||
return translations;
|
||||
|
@ -1,5 +1,6 @@
|
||||
define('iframe', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
define('iframe', ['mailpoet'], function(mp) {
|
||||
'use strict';
|
||||
var MailPoet = mp;
|
||||
MailPoet.Iframe = {
|
||||
marginY: 20,
|
||||
autoSize: function(iframe) {
|
||||
@ -10,12 +11,13 @@ define('iframe', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
iframe.contentWindow.document.body.scrollHeight
|
||||
);
|
||||
},
|
||||
setSize: function(iframe, i) {
|
||||
setSize: function(sizeIframe, i) {
|
||||
var iframe = sizeIframe;
|
||||
if(!iframe) return;
|
||||
|
||||
iframe.style.height = (
|
||||
parseInt(i) + this.marginY
|
||||
) + "px";
|
||||
parseInt(i, 10) + this.marginY
|
||||
) + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,8 +3,9 @@ define(
|
||||
'jquery'
|
||||
],
|
||||
function(
|
||||
$
|
||||
jQuery
|
||||
) {
|
||||
var $ = jQuery;
|
||||
// Combination of jQuery.deparam and jQuery.serializeObject by Ben Alman.
|
||||
/*!
|
||||
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
|
||||
@ -24,10 +25,10 @@ define(
|
||||
*/
|
||||
$.fn.serializeObject = function(coerce) {
|
||||
var obj = {},
|
||||
coerce_types = { 'true': !0, 'false': !1, 'null': null };
|
||||
coerce_types = { true: !0, false: !1, null: null };
|
||||
|
||||
// Iterate over all name=value pairs.
|
||||
$.each( this.serializeArray(), function(j,v){
|
||||
$.each( this.serializeArray(), function(j, v){
|
||||
var key = v.name,
|
||||
val = v.value,
|
||||
cur = obj,
|
||||
@ -74,9 +75,10 @@ define(
|
||||
// * Rinse & repeat.
|
||||
for ( ; i <= keys_last; i++ ) {
|
||||
key = keys[i] === '' ? cur.length : keys[i];
|
||||
cur = cur[key] = i < keys_last
|
||||
cur[key] = i < keys_last
|
||||
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
|
||||
: val;
|
||||
cur = cur[key];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1,53 +1,53 @@
|
||||
define([
|
||||
'react',
|
||||
'mailpoet'
|
||||
'mailpoet',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React,
|
||||
MailPoet
|
||||
) {
|
||||
var ListingBulkActions = React.createClass({
|
||||
getInitialState: function() {
|
||||
) => {
|
||||
const ListingBulkActions = React.createClass({
|
||||
getInitialState: function () {
|
||||
return {
|
||||
action: false,
|
||||
extra: false
|
||||
}
|
||||
extra: false,
|
||||
};
|
||||
},
|
||||
handleChangeAction: function(e) {
|
||||
handleChangeAction: function (e) {
|
||||
this.setState({
|
||||
action: e.target.value,
|
||||
extra: false
|
||||
}, function() {
|
||||
var action = this.getSelectedAction();
|
||||
extra: false,
|
||||
}, () => {
|
||||
const action = this.getSelectedAction();
|
||||
|
||||
// action on select callback
|
||||
if(action !== null && action['onSelect'] !== undefined) {
|
||||
this.setState({
|
||||
extra: action.onSelect(e)
|
||||
extra: action.onSelect(e),
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
handleApplyAction: function(e) {
|
||||
handleApplyAction: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var action = this.getSelectedAction();
|
||||
const action = this.getSelectedAction();
|
||||
|
||||
if(action === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selected_ids = (this.props.selection !== 'all')
|
||||
const selected_ids = (this.props.selection !== 'all')
|
||||
? this.props.selected_ids
|
||||
: [];
|
||||
|
||||
var data = (action['getData'] !== undefined)
|
||||
const data = (action['getData'] !== undefined)
|
||||
? action.getData()
|
||||
: {};
|
||||
|
||||
data.action = this.state.action;
|
||||
|
||||
var onSuccess = function() {};
|
||||
let onSuccess = function () {};
|
||||
if(action['onSuccess'] !== undefined) {
|
||||
onSuccess = action.onSuccess;
|
||||
}
|
||||
@ -61,13 +61,13 @@ function(
|
||||
|
||||
this.setState({
|
||||
action: false,
|
||||
extra: false
|
||||
extra: false,
|
||||
});
|
||||
},
|
||||
getSelectedAction: function() {
|
||||
var selected_action = this.refs.action.value;
|
||||
getSelectedAction: function () {
|
||||
const selected_action = this.refs.action.value;
|
||||
if(selected_action.length > 0) {
|
||||
var action = this.props.bulk_actions.filter(function(action) {
|
||||
const action = this.props.bulk_actions.filter((action) => {
|
||||
return (action.name === selected_action);
|
||||
});
|
||||
|
||||
@ -77,7 +77,7 @@ function(
|
||||
}
|
||||
return null;
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
if(this.props.bulk_actions.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@ -97,14 +97,14 @@ function(
|
||||
onChange={this.handleChangeAction}
|
||||
>
|
||||
<option value="">{MailPoet.I18n.t('bulkActions')}</option>
|
||||
{ this.props.bulk_actions.map(function(action, index) {
|
||||
{ this.props.bulk_actions.map((action, index) => {
|
||||
return (
|
||||
<option
|
||||
value={ action.name }
|
||||
key={ 'action-' + index }
|
||||
>{ action.label }</option>
|
||||
);
|
||||
}.bind(this)) }
|
||||
}) }
|
||||
</select>
|
||||
<input
|
||||
onClick={ this.handleApplyAction }
|
||||
@ -115,7 +115,7 @@ function(
|
||||
{ this.state.extra }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return ListingBulkActions;
|
||||
|
@ -1,27 +1,30 @@
|
||||
define([
|
||||
'react',
|
||||
'jquery',
|
||||
'mailpoet'
|
||||
'mailpoet',
|
||||
],
|
||||
function(
|
||||
(
|
||||
React,
|
||||
jQuery,
|
||||
MailPoet
|
||||
) {
|
||||
var ListingFilters = React.createClass({
|
||||
handleFilterAction: function() {
|
||||
let filters = {};
|
||||
) => {
|
||||
const ListingFilters = React.createClass({
|
||||
handleFilterAction: function () {
|
||||
const filters = {};
|
||||
this.getAvailableFilters().map((filter, i) => {
|
||||
filters[this.refs['filter-'+i].name] = this.refs['filter-'+i].value
|
||||
filters[this.refs['filter-'+i].name] = this.refs['filter-'+i].value;
|
||||
});
|
||||
if (this.props.onBeforeSelectFilter) {
|
||||
this.props.onBeforeSelectFilter(filters);
|
||||
}
|
||||
return this.props.onSelectFilter(filters);
|
||||
},
|
||||
handleEmptyTrash: function() {
|
||||
handleEmptyTrash: function () {
|
||||
return this.props.onEmptyTrash();
|
||||
},
|
||||
getAvailableFilters: function() {
|
||||
let filters = this.props.filters;
|
||||
return Object.keys(filters).filter(function(filter) {
|
||||
getAvailableFilters: function () {
|
||||
const filters = this.props.filters;
|
||||
return Object.keys(filters).filter((filter) => {
|
||||
return !(
|
||||
filters[filter].length === 0
|
||||
|| (
|
||||
@ -31,39 +34,39 @@ function(
|
||||
);
|
||||
});
|
||||
},
|
||||
componentDidUpdate: function() {
|
||||
componentDidUpdate: function () {
|
||||
const selected_filters = this.props.filter;
|
||||
const available_filters = this.getAvailableFilters().map(
|
||||
function(filter, i) {
|
||||
this.getAvailableFilters().map(
|
||||
(filter, i) => {
|
||||
if (selected_filters[filter] !== undefined && selected_filters[filter]) {
|
||||
jQuery(this.refs['filter-'+i])
|
||||
.val(selected_filters[filter])
|
||||
.trigger('change');
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
const filters = this.props.filters;
|
||||
const available_filters = this.getAvailableFilters()
|
||||
.map(function(filter, i) {
|
||||
.map((filter, i) => {
|
||||
return (
|
||||
<select
|
||||
ref={ `filter-${i}` }
|
||||
key={ `filter-${i}` }
|
||||
name={ filter }
|
||||
>
|
||||
{ filters[filter].map(function(option, j) {
|
||||
{ filters[filter].map((option, j) => {
|
||||
return (
|
||||
<option
|
||||
value={ option.value }
|
||||
key={ 'filter-option-' + j }
|
||||
>{ option.label }</option>
|
||||
);
|
||||
}.bind(this)) }
|
||||
}) }
|
||||
</select>
|
||||
);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
let button;
|
||||
|
||||
@ -97,7 +100,7 @@ function(
|
||||
{ empty_trash }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return ListingFilters;
|
||||
|
@ -1,20 +1,20 @@
|
||||
define(['react', 'classnames'], function(React, classNames) {
|
||||
define(['react', 'classnames'], (React, classNames) => {
|
||||
|
||||
var ListingGroups = React.createClass({
|
||||
handleSelect: function(group) {
|
||||
return this.props.onSelectGroup(group);
|
||||
},
|
||||
render: function() {
|
||||
var groups = this.props.groups.map(function(group, index) {
|
||||
if(group.name === 'trash' && group.count === 0) {
|
||||
return false;
|
||||
}
|
||||
const ListingGroups = React.createClass({
|
||||
handleSelect: function (group) {
|
||||
return this.props.onSelectGroup(group);
|
||||
},
|
||||
render: function () {
|
||||
const groups = this.props.groups.map((group, index) => {
|
||||
if(group.name === 'trash' && group.count === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var classes = classNames(
|
||||
{ 'current' : (group.name === this.props.group) }
|
||||
const classes = classNames(
|
||||
{ current : (group.name === this.props.group) }
|
||||
);
|
||||
|
||||
return (
|
||||
return (
|
||||
<li key={index}>
|
||||
{(index > 0) ? ' |' : ''}
|
||||
<a
|
||||
@ -24,17 +24,17 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
{group.label} <span className="count">({ group.count.toLocaleString() })</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}.bind(this));
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
return (
|
||||
<ul className="subsubsub">
|
||||
{ groups }
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
});
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return ListingGroups;
|
||||
}
|
||||
);
|
||||
return ListingGroups;
|
||||
}
|
||||
);
|
||||
|
@ -1,17 +1,18 @@
|
||||
import MailPoet from 'mailpoet'
|
||||
import React from 'react'
|
||||
import classNames from 'classnames'
|
||||
import MailPoet from 'mailpoet';
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const ListingHeader = React.createClass({
|
||||
handleSelectItems: function() {
|
||||
handleSelectItems: function () {
|
||||
return this.props.onSelectItems(
|
||||
this.refs.toggle.checked
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
const columns = this.props.columns.map(function(column, index) {
|
||||
column.is_primary = (index === 0);
|
||||
column.sorted = (this.props.sort_by === column.name)
|
||||
render: function () {
|
||||
const columns = this.props.columns.map((column, index) => {
|
||||
const renderColumn = column;
|
||||
renderColumn.is_primary = (index === 0);
|
||||
renderColumn.sorted = (this.props.sort_by === column.name)
|
||||
? this.props.sort_order
|
||||
: 'desc';
|
||||
return (
|
||||
@ -19,9 +20,9 @@ const ListingHeader = React.createClass({
|
||||
onSort={this.props.onSort}
|
||||
sort_by={this.props.sort_by}
|
||||
key={ 'column-' + index }
|
||||
column={column} />
|
||||
column={renderColumn} />
|
||||
);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
let checkbox;
|
||||
|
||||
@ -48,22 +49,22 @@ const ListingHeader = React.createClass({
|
||||
{columns}
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const ListingColumn = React.createClass({
|
||||
handleSort: function() {
|
||||
handleSort: function () {
|
||||
const sort_by = this.props.column.name;
|
||||
const sort_order = (this.props.column.sorted === 'asc') ? 'desc' : 'asc';
|
||||
this.props.onSort(sort_by, sort_order);
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
const classes = classNames(
|
||||
'manage-column',
|
||||
{ 'column-primary': this.props.column.is_primary },
|
||||
{ 'sortable': this.props.column.sortable },
|
||||
{ sortable: this.props.column.sortable },
|
||||
this.props.column.sorted,
|
||||
{ 'sorted': (this.props.sort_by === this.props.column.name) }
|
||||
{ sorted: (this.props.sort_by === this.props.column.name) }
|
||||
);
|
||||
let label;
|
||||
|
||||
@ -85,7 +86,7 @@ const ListingColumn = React.createClass({
|
||||
width={ this.props.column.width || null }
|
||||
>{label}</th>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = ListingHeader;
|
||||
module.exports = ListingHeader;
|
||||
|
@ -1,23 +1,23 @@
|
||||
import MailPoet from 'mailpoet'
|
||||
import jQuery from 'jquery'
|
||||
import React from 'react'
|
||||
import _ from 'underscore'
|
||||
import { Router, Link } from 'react-router'
|
||||
import classNames from 'classnames'
|
||||
import ListingBulkActions from 'listing/bulk_actions.jsx'
|
||||
import ListingHeader from 'listing/header.jsx'
|
||||
import ListingPages from 'listing/pages.jsx'
|
||||
import ListingSearch from 'listing/search.jsx'
|
||||
import ListingGroups from 'listing/groups.jsx'
|
||||
import ListingFilters from 'listing/filters.jsx'
|
||||
import MailPoet from 'mailpoet';
|
||||
import jQuery from 'jquery';
|
||||
import React from 'react';
|
||||
import _ from 'underscore';
|
||||
import { Link } from 'react-router';
|
||||
import classNames from 'classnames';
|
||||
import ListingBulkActions from 'listing/bulk_actions.jsx';
|
||||
import ListingHeader from 'listing/header.jsx';
|
||||
import ListingPages from 'listing/pages.jsx';
|
||||
import ListingSearch from 'listing/search.jsx';
|
||||
import ListingGroups from 'listing/groups.jsx';
|
||||
import ListingFilters from 'listing/filters.jsx';
|
||||
|
||||
const ListingItem = React.createClass({
|
||||
getInitialState: function() {
|
||||
getInitialState: function () {
|
||||
return {
|
||||
expanded: false
|
||||
expanded: false,
|
||||
};
|
||||
},
|
||||
handleSelectItem: function(e) {
|
||||
handleSelectItem: function (e) {
|
||||
this.props.onSelectItem(
|
||||
parseInt(e.target.value, 10),
|
||||
e.target.checked
|
||||
@ -25,20 +25,20 @@ const ListingItem = React.createClass({
|
||||
|
||||
return !e.target.checked;
|
||||
},
|
||||
handleRestoreItem: function(id) {
|
||||
handleRestoreItem: function (id) {
|
||||
this.props.onRestoreItem(id);
|
||||
},
|
||||
handleTrashItem: function(id) {
|
||||
handleTrashItem: function (id) {
|
||||
this.props.onTrashItem(id);
|
||||
},
|
||||
handleDeleteItem: function(id) {
|
||||
handleDeleteItem: function (id) {
|
||||
this.props.onDeleteItem(id);
|
||||
},
|
||||
handleToggleItem: function(id) {
|
||||
handleToggleItem: function () {
|
||||
this.setState({ expanded: !this.state.expanded });
|
||||
},
|
||||
render: function() {
|
||||
var checkbox = false;
|
||||
render: function () {
|
||||
let checkbox = false;
|
||||
|
||||
if (this.props.is_selectable === true) {
|
||||
checkbox = (
|
||||
@ -63,7 +63,7 @@ const ListingItem = React.createClass({
|
||||
|
||||
if (custom_actions.length > 0) {
|
||||
let is_first = true;
|
||||
item_actions = custom_actions.map(function(action, index) {
|
||||
item_actions = custom_actions.map((action, index) => {
|
||||
if (action.display !== undefined) {
|
||||
if (action.display(this.props.item) === false) {
|
||||
return;
|
||||
@ -125,7 +125,7 @@ const ListingItem = React.createClass({
|
||||
}
|
||||
|
||||
return custom_action;
|
||||
}.bind(this));
|
||||
});
|
||||
} else {
|
||||
item_actions = (
|
||||
<span className="edit">
|
||||
@ -137,7 +137,7 @@ const ListingItem = React.createClass({
|
||||
let actions;
|
||||
|
||||
if (this.props.group === 'trash') {
|
||||
actions = (
|
||||
actions = (
|
||||
<div>
|
||||
<div className="row-actions">
|
||||
<span>
|
||||
@ -191,13 +191,24 @@ const ListingItem = React.createClass({
|
||||
{ this.props.onRenderItem(this.props.item, actions) }
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const ListingItems = React.createClass({
|
||||
render: function() {
|
||||
render: function () {
|
||||
if (this.props.items.length === 0) {
|
||||
let message;
|
||||
if (this.props.loading === true) {
|
||||
message = (this.props.messages.onLoadingItems
|
||||
&& this.props.messages.onLoadingItems(this.props.group))
|
||||
|| MailPoet.I18n.t('loadingItems');
|
||||
} else {
|
||||
message = (this.props.messages.onNoItemsFound
|
||||
&& this.props.messages.onNoItemsFound(this.props.group))
|
||||
|| MailPoet.I18n.t('noItemsFound');
|
||||
}
|
||||
|
||||
return (
|
||||
<tbody>
|
||||
<tr className="no-items">
|
||||
@ -207,11 +218,7 @@ const ListingItems = React.createClass({
|
||||
+ (this.props.is_selectable ? 1 : 0)
|
||||
}
|
||||
className="colspanchange">
|
||||
{
|
||||
(this.props.loading === true)
|
||||
? MailPoet.I18n.t('loadingItems')
|
||||
: MailPoet.I18n.t('noItemsFound')
|
||||
}
|
||||
{message}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -219,10 +226,10 @@ const ListingItems = React.createClass({
|
||||
} else {
|
||||
const select_all_classes = classNames(
|
||||
'mailpoet_select_all',
|
||||
{ 'mailpoet_hidden': (
|
||||
{ mailpoet_hidden: (
|
||||
this.props.selection === false
|
||||
|| (this.props.count <= this.props.limit)
|
||||
)
|
||||
),
|
||||
}
|
||||
);
|
||||
|
||||
@ -252,9 +259,10 @@ const ListingItems = React.createClass({
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{this.props.items.map(function(item, index) {
|
||||
item.id = parseInt(item.id, 10);
|
||||
item.selected = (this.props.selected_ids.indexOf(item.id) !== -1);
|
||||
{this.props.items.map((item, index) => {
|
||||
const renderItem = item;
|
||||
renderItem.id = parseInt(item.id, 10);
|
||||
renderItem.selected = (this.props.selected_ids.indexOf(renderItem.id) !== -1);
|
||||
|
||||
return (
|
||||
<ListingItem
|
||||
@ -269,21 +277,21 @@ const ListingItems = React.createClass({
|
||||
is_selectable={ this.props.is_selectable }
|
||||
item_actions={ this.props.item_actions }
|
||||
group={ this.props.group }
|
||||
key={ `item-${item.id}-${index}` }
|
||||
item={ item } />
|
||||
key={ `item-${renderItem.id}-${index}` }
|
||||
item={ renderItem } />
|
||||
);
|
||||
}.bind(this))}
|
||||
})}
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const Listing = React.createClass({
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object.isRequired
|
||||
router: React.PropTypes.object.isRequired,
|
||||
},
|
||||
getInitialState: function() {
|
||||
getInitialState: function () {
|
||||
return {
|
||||
loading: false,
|
||||
search: '',
|
||||
@ -299,31 +307,31 @@ const Listing = React.createClass({
|
||||
filter: {},
|
||||
selected_ids: [],
|
||||
selection: false,
|
||||
meta: {}
|
||||
meta: {},
|
||||
};
|
||||
},
|
||||
getParam: function(param) {
|
||||
getParam: function (param) {
|
||||
const regex = /(.*)\[(.*)\]/;
|
||||
const matches = regex.exec(param);
|
||||
return [matches[1], matches[2]];
|
||||
},
|
||||
initWithParams: function(params) {
|
||||
let state = this.getInitialState();
|
||||
initWithParams: function (params) {
|
||||
const state = this.getInitialState();
|
||||
// check for url params
|
||||
if (params.splat) {
|
||||
params.splat.split('/').map(param => {
|
||||
let [key, value] = this.getParam(param);
|
||||
params.splat.split('/').map((param) => {
|
||||
const [key, value] = this.getParam(param);
|
||||
switch(key) {
|
||||
case 'filter':
|
||||
let filters = {};
|
||||
value.split('&').map(function(pair) {
|
||||
let [k, v] = pair.split('=')
|
||||
filters[k] = v
|
||||
}
|
||||
const filters = {};
|
||||
value.split('&').map((pair) => {
|
||||
const [k, v] = pair.split('=');
|
||||
filters[k] = v;
|
||||
}
|
||||
);
|
||||
|
||||
state.filter = filters;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
state[key] = value;
|
||||
}
|
||||
@ -345,13 +353,13 @@ const Listing = React.createClass({
|
||||
state.sort_order = this.props.sort_order;
|
||||
}
|
||||
|
||||
this.setState(state, function() {
|
||||
this.setState(state, () => {
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
getParams: function() {
|
||||
getParams: function () {
|
||||
// get all route parameters (without the "splat")
|
||||
let params = _.omit(this.props.params, 'splat');
|
||||
const params = _.omit(this.props.params, 'splat');
|
||||
// TODO:
|
||||
// find a way to set the "type" in the routes definition
|
||||
// so that it appears in `this.props.params`
|
||||
@ -360,10 +368,10 @@ const Listing = React.createClass({
|
||||
}
|
||||
return params;
|
||||
},
|
||||
setParams: function() {
|
||||
setParams: function () {
|
||||
if (this.props.location) {
|
||||
let params = Object.keys(this.state)
|
||||
.filter(key => {
|
||||
const params = Object.keys(this.state)
|
||||
.filter((key) => {
|
||||
return (
|
||||
[
|
||||
'group',
|
||||
@ -371,34 +379,34 @@ const Listing = React.createClass({
|
||||
'search',
|
||||
'page',
|
||||
'sort_by',
|
||||
'sort_order'
|
||||
'sort_order',
|
||||
].indexOf(key) !== -1
|
||||
)
|
||||
);
|
||||
})
|
||||
.map(key => {
|
||||
.map((key) => {
|
||||
let value = this.state[key];
|
||||
if (value === Object(value)) {
|
||||
value = jQuery.param(value)
|
||||
value = jQuery.param(value);
|
||||
} else if (value === Boolean(value)) {
|
||||
value = value.toString()
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
if (value !== '' && value !== null) {
|
||||
return `${key}[${value}]`
|
||||
return `${key}[${value}]`;
|
||||
}
|
||||
})
|
||||
.filter(key => { return (key !== undefined) })
|
||||
.filter((key) => { return (key !== undefined); })
|
||||
.join('/');
|
||||
|
||||
// set url
|
||||
let url = this.getUrlWithParams(params);
|
||||
const url = this.getUrlWithParams(params);
|
||||
|
||||
if (this.props.location.pathname !== url) {
|
||||
this.context.router.push(`${url}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
getUrlWithParams: function(params) {
|
||||
getUrlWithParams: function (params) {
|
||||
let base_url = (this.props.base_url !== undefined)
|
||||
? this.props.base_url
|
||||
: null;
|
||||
@ -410,41 +418,43 @@ const Listing = React.createClass({
|
||||
return `/${ params }`;
|
||||
}
|
||||
},
|
||||
setBaseUrlParams: function(base_url) {
|
||||
if (base_url.indexOf(':') !== -1) {
|
||||
setBaseUrlParams: function (base_url) {
|
||||
let ret = base_url;
|
||||
if (ret.indexOf(':') !== -1) {
|
||||
const params = this.getParams();
|
||||
Object.keys(params).map((key) => {
|
||||
if (base_url.indexOf(':'+key) !== -1) {
|
||||
base_url = base_url.replace(':'+key, params[key]);
|
||||
if (ret.indexOf(':'+key) !== -1) {
|
||||
ret = ret.replace(':'+key, params[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return base_url;
|
||||
return ret;
|
||||
},
|
||||
componentDidMount: function() {
|
||||
componentDidMount: function () {
|
||||
if (this.isMounted()) {
|
||||
const params = this.props.params || {};
|
||||
this.initWithParams(params);
|
||||
|
||||
if (this.props.auto_refresh) {
|
||||
jQuery(document).on('heartbeat-tick.mailpoet', function(e, data) {
|
||||
jQuery(document).on('heartbeat-tick.mailpoet', () => {
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
componentWillReceiveProps: function (nextProps) {
|
||||
const params = nextProps.params || {};
|
||||
this.initWithParams(params);
|
||||
},
|
||||
getItems: function() {
|
||||
getItems: function () {
|
||||
if (this.isMounted()) {
|
||||
this.setState({ loading: true });
|
||||
|
||||
this.clearSelection();
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'listing',
|
||||
data: {
|
||||
@ -455,8 +465,8 @@ const Listing = React.createClass({
|
||||
filter: this.state.filter,
|
||||
search: this.state.search,
|
||||
sort_by: this.state.sort_by,
|
||||
sort_order: this.state.sort_order
|
||||
}
|
||||
sort_order: this.state.sort_order,
|
||||
},
|
||||
}).always(() => {
|
||||
this.setState({ loading: false });
|
||||
}).done((response) => {
|
||||
@ -465,7 +475,7 @@ const Listing = React.createClass({
|
||||
filters: response.meta.filters || {},
|
||||
groups: response.meta.groups || [],
|
||||
count: response.meta.count || 0,
|
||||
meta: _.omit(response.meta, ['filters', 'groups', 'count'])
|
||||
meta: _.omit(response.meta, ['filters', 'groups', 'count']),
|
||||
}, () => {
|
||||
// if viewing an empty trash
|
||||
if (this.state.group === 'trash' && response.meta.count === 0) {
|
||||
@ -479,27 +489,28 @@ const Listing = React.createClass({
|
||||
}
|
||||
});
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
if(response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
handleRestoreItem: function(id) {
|
||||
handleRestoreItem: function (id) {
|
||||
this.setState({
|
||||
loading: true,
|
||||
page: 1
|
||||
page: 1,
|
||||
});
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'restore',
|
||||
data: {
|
||||
id: id
|
||||
}
|
||||
id: id,
|
||||
},
|
||||
}).done((response) => {
|
||||
if (
|
||||
this.props.messages !== undefined
|
||||
@ -510,23 +521,24 @@ const Listing = React.createClass({
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
},
|
||||
handleTrashItem: function(id) {
|
||||
handleTrashItem: function (id) {
|
||||
this.setState({
|
||||
loading: true,
|
||||
page: 1
|
||||
page: 1,
|
||||
});
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'trash',
|
||||
data: {
|
||||
id: id
|
||||
}
|
||||
id: id,
|
||||
},
|
||||
}).done((response) => {
|
||||
if (
|
||||
this.props.messages !== undefined
|
||||
@ -537,23 +549,24 @@ const Listing = React.createClass({
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
},
|
||||
handleDeleteItem: function(id) {
|
||||
handleDeleteItem: function (id) {
|
||||
this.setState({
|
||||
loading: true,
|
||||
page: 1
|
||||
page: 1,
|
||||
});
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'delete',
|
||||
data: {
|
||||
id: id
|
||||
}
|
||||
id: id,
|
||||
},
|
||||
}).done((response) => {
|
||||
if (
|
||||
this.props.messages !== undefined
|
||||
@ -564,15 +577,15 @@ const Listing = React.createClass({
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
},
|
||||
handleEmptyTrash: function() {
|
||||
handleEmptyTrash: function () {
|
||||
return this.handleBulkAction('all', {
|
||||
action: 'delete',
|
||||
group: 'trash'
|
||||
group: 'trash',
|
||||
}).done((response) => {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('permanentlyDeleted').replace('%d', response.meta.count)
|
||||
@ -581,12 +594,12 @@ const Listing = React.createClass({
|
||||
this.handleGroup('all');
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
},
|
||||
handleBulkAction: function(selected_ids, params) {
|
||||
handleBulkAction: function (selected_ids, params) {
|
||||
if (
|
||||
this.state.selection === false
|
||||
&& this.state.selected_ids.length === 0
|
||||
@ -597,48 +610,56 @@ const Listing = React.createClass({
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
||||
var data = params || {};
|
||||
const data = params || {};
|
||||
data.listing = {
|
||||
params: this.getParams(),
|
||||
offset: 0,
|
||||
limit: 0,
|
||||
filter: this.state.filter,
|
||||
group: this.state.group,
|
||||
search: this.state.search
|
||||
}
|
||||
search: this.state.search,
|
||||
};
|
||||
if (selected_ids !== 'all') {
|
||||
data.listing.selection = selected_ids;
|
||||
}
|
||||
|
||||
return MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'bulkAction',
|
||||
data: data
|
||||
data: data,
|
||||
}).done(() => {
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
if(response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSearch: function(search) {
|
||||
handleSearch: function (search) {
|
||||
this.setState({
|
||||
search: search,
|
||||
page: 1,
|
||||
selection: false,
|
||||
selected_ids: []
|
||||
}, function() {
|
||||
selected_ids: [],
|
||||
}, () => {
|
||||
this.setParams();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
handleSort: function(sort_by, sort_order = 'asc') {
|
||||
handleSort: function (sort_by, sort_order = 'asc') {
|
||||
this.setState({
|
||||
sort_by: sort_by,
|
||||
sort_order: (sort_order === 'asc') ? 'asc' : 'desc',
|
||||
}, function() {
|
||||
}, () => {
|
||||
this.setParams();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
handleSelectItem: function(id, is_checked) {
|
||||
var selected_ids = this.state.selected_ids,
|
||||
selection = false;
|
||||
handleSelectItem: function (id, is_checked) {
|
||||
let selected_ids = this.state.selected_ids,
|
||||
selection = false;
|
||||
|
||||
if (is_checked) {
|
||||
selected_ids = jQuery.merge(selected_ids, [ id ]);
|
||||
@ -654,48 +675,48 @@ const Listing = React.createClass({
|
||||
|
||||
this.setState({
|
||||
selection: selection,
|
||||
selected_ids: selected_ids
|
||||
selected_ids: selected_ids,
|
||||
});
|
||||
},
|
||||
handleSelectItems: function(is_checked) {
|
||||
handleSelectItems: function (is_checked) {
|
||||
if (is_checked === false) {
|
||||
this.clearSelection();
|
||||
} else {
|
||||
var selected_ids = this.state.items.map(function(item) {
|
||||
const selected_ids = this.state.items.map((item) => {
|
||||
return ~~item.id;
|
||||
});
|
||||
|
||||
this.setState({
|
||||
selected_ids: selected_ids,
|
||||
selection: 'page'
|
||||
selection: 'page',
|
||||
});
|
||||
}
|
||||
},
|
||||
handleSelectAll: function() {
|
||||
handleSelectAll: function () {
|
||||
if (this.state.selection === 'all') {
|
||||
this.clearSelection();
|
||||
} else {
|
||||
this.setState({
|
||||
selection: 'all',
|
||||
selected_ids: []
|
||||
selected_ids: [],
|
||||
});
|
||||
}
|
||||
},
|
||||
clearSelection: function() {
|
||||
clearSelection: function () {
|
||||
this.setState({
|
||||
selection: false,
|
||||
selected_ids: []
|
||||
selected_ids: [],
|
||||
});
|
||||
},
|
||||
handleFilter: function(filters) {
|
||||
handleFilter: function (filters) {
|
||||
this.setState({
|
||||
filter: filters,
|
||||
page: 1
|
||||
}, function() {
|
||||
page: 1,
|
||||
}, () => {
|
||||
this.setParams();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
handleGroup: function(group) {
|
||||
handleGroup: function (group) {
|
||||
// reset search
|
||||
jQuery('#search_input').val('');
|
||||
|
||||
@ -703,35 +724,35 @@ const Listing = React.createClass({
|
||||
group: group,
|
||||
filter: {},
|
||||
search: '',
|
||||
page: 1
|
||||
}, function() {
|
||||
page: 1,
|
||||
}, () => {
|
||||
this.setParams();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
handleSetPage: function(page) {
|
||||
handleSetPage: function (page) {
|
||||
this.setState({
|
||||
page: page,
|
||||
selection: false,
|
||||
selected_ids: []
|
||||
}, function() {
|
||||
selected_ids: [],
|
||||
}, () => {
|
||||
this.setParams();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
handleRenderItem: function(item, actions) {
|
||||
handleRenderItem: function (item, actions) {
|
||||
const render = this.props.onRenderItem(item, actions, this.state.meta);
|
||||
return render.props.children;
|
||||
},
|
||||
handleRefreshItems: function() {
|
||||
handleRefreshItems: function () {
|
||||
this.getItems();
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
const items = this.state.items;
|
||||
const sort_by = this.state.sort_by;
|
||||
const sort_order = this.state.sort_order;
|
||||
|
||||
// columns
|
||||
let columns = this.props.columns || [];
|
||||
columns = columns.filter(function(column) {
|
||||
columns = columns.filter((column) => {
|
||||
return (column.display === undefined || !!(column.display) === true);
|
||||
});
|
||||
|
||||
@ -743,13 +764,13 @@ const Listing = React.createClass({
|
||||
{
|
||||
name: 'restore',
|
||||
label: MailPoet.I18n.t('restore'),
|
||||
onSuccess: this.props.messages.onRestore
|
||||
onSuccess: this.props.messages.onRestore,
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
label: MailPoet.I18n.t('deletePermanently'),
|
||||
onSuccess: this.props.messages.onDelete
|
||||
}
|
||||
onSuccess: this.props.messages.onDelete,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -762,7 +783,7 @@ const Listing = React.createClass({
|
||||
'widefat',
|
||||
'fixed',
|
||||
'striped',
|
||||
{ 'mailpoet_listing_loading': this.state.loading }
|
||||
{ mailpoet_listing_loading: this.state.loading }
|
||||
);
|
||||
|
||||
// search
|
||||
@ -788,6 +809,12 @@ const Listing = React.createClass({
|
||||
groups = false;
|
||||
}
|
||||
|
||||
// messages
|
||||
let messages = {};
|
||||
if (this.props.messages !== undefined) {
|
||||
messages = this.props.messages;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ groups }
|
||||
@ -803,6 +830,7 @@ const Listing = React.createClass({
|
||||
filters={ this.state.filters }
|
||||
filter={ this.state.filter }
|
||||
group={ this.state.group }
|
||||
onBeforeSelectFilter={ this.props.onBeforeSelectFilter || null }
|
||||
onSelectFilter={ this.handleFilter }
|
||||
onEmptyTrash={ this.handleEmptyTrash }
|
||||
/>
|
||||
@ -841,6 +869,7 @@ const Listing = React.createClass({
|
||||
count={ this.state.count }
|
||||
limit={ this.state.limit }
|
||||
item_actions={ item_actions }
|
||||
messages={ messages }
|
||||
items={ items } />
|
||||
|
||||
<tfoot>
|
||||
@ -870,7 +899,7 @@ const Listing = React.createClass({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Listing;
|
||||
|
@ -1,76 +1,76 @@
|
||||
define([
|
||||
'react',
|
||||
'classnames',
|
||||
'mailpoet'
|
||||
], function(
|
||||
'react',
|
||||
'classnames',
|
||||
'mailpoet',
|
||||
], (
|
||||
React,
|
||||
classNames,
|
||||
MailPoet
|
||||
) {
|
||||
) => {
|
||||
|
||||
var ListingPages = React.createClass({
|
||||
getInitialState: function() {
|
||||
const ListingPages = React.createClass({
|
||||
getInitialState: function () {
|
||||
return {
|
||||
page: null
|
||||
}
|
||||
page: null,
|
||||
};
|
||||
},
|
||||
setPage: function(page) {
|
||||
setPage: function (page) {
|
||||
this.setState({
|
||||
page: null
|
||||
}, function () {
|
||||
page: null,
|
||||
}, () => {
|
||||
this.props.onSetPage(this.constrainPage(page));
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
setFirstPage: function() {
|
||||
setFirstPage: function () {
|
||||
this.setPage(1);
|
||||
},
|
||||
setLastPage: function() {
|
||||
setLastPage: function () {
|
||||
this.setPage(this.getLastPage());
|
||||
},
|
||||
setPreviousPage: function() {
|
||||
setPreviousPage: function () {
|
||||
this.setPage(this.constrainPage(
|
||||
parseInt(this.props.page, 10) - 1)
|
||||
);
|
||||
},
|
||||
setNextPage: function() {
|
||||
setNextPage: function () {
|
||||
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());
|
||||
},
|
||||
handleSetManualPage: function(e) {
|
||||
handleSetManualPage: function (e) {
|
||||
if(e.which === 13) {
|
||||
this.setPage(this.state.page);
|
||||
}
|
||||
},
|
||||
handleChangeManualPage: function(e) {
|
||||
handleChangeManualPage: function (e) {
|
||||
this.setState({
|
||||
page: e.target.value
|
||||
page: e.target.value,
|
||||
});
|
||||
},
|
||||
handleBlurManualPage: function(e) {
|
||||
handleBlurManualPage: function (e) {
|
||||
this.setPage(e.target.value);
|
||||
},
|
||||
getLastPage: function() {
|
||||
getLastPage: function () {
|
||||
return Math.ceil(this.props.count / this.props.limit);
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
if(this.props.count === 0) {
|
||||
return false;
|
||||
} else {
|
||||
var pagination = false;
|
||||
var firstPage = (
|
||||
let pagination = false;
|
||||
let firstPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">«</span>
|
||||
);
|
||||
var previousPage = (
|
||||
let previousPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">‹</span>
|
||||
);
|
||||
var nextPage = (
|
||||
let nextPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">›</span>
|
||||
);
|
||||
var lastPage = (
|
||||
let lastPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">»</span>
|
||||
);
|
||||
|
||||
@ -159,21 +159,26 @@ define([
|
||||
);
|
||||
}
|
||||
|
||||
var classes = classNames(
|
||||
const classes = classNames(
|
||||
'tablenav-pages',
|
||||
{ 'one-page': (this.props.count <= this.props.limit) }
|
||||
);
|
||||
|
||||
let numberOfItemsLabel;
|
||||
if (this.props.count == 1) {
|
||||
numberOfItemsLabel = MailPoet.I18n.t('numberOfItemsSingular');
|
||||
} else {
|
||||
numberOfItemsLabel = MailPoet.I18n.t('numberOfItemsMultiple')
|
||||
.replace('%$1d', this.props.count.toLocaleString());
|
||||
}
|
||||
return (
|
||||
<div className={ classes }>
|
||||
<span className="displaying-num">{
|
||||
MailPoet.I18n.t('numberOfItems').replace('%$1d', this.props.count.toLocaleString())
|
||||
}</span>
|
||||
<span className="displaying-num">{ numberOfItemsLabel }</span>
|
||||
{ pagination }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return ListingPages;
|
||||
|
@ -1,22 +1,22 @@
|
||||
define([
|
||||
'mailpoet',
|
||||
'react'
|
||||
], function(
|
||||
'mailpoet',
|
||||
'react',
|
||||
], (
|
||||
MailPoet,
|
||||
React
|
||||
) {
|
||||
) => {
|
||||
|
||||
var ListingSearch = React.createClass({
|
||||
handleSearch: function(e) {
|
||||
const ListingSearch = React.createClass({
|
||||
handleSearch: function (e) {
|
||||
e.preventDefault();
|
||||
this.props.onSearch(
|
||||
this.refs.search.value
|
||||
);
|
||||
},
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
this.refs.search.value = nextProps.search
|
||||
componentWillReceiveProps: function (nextProps) {
|
||||
this.refs.search.value = nextProps.search;
|
||||
},
|
||||
render: function() {
|
||||
render: function () {
|
||||
if(this.props.search === false) {
|
||||
return false;
|
||||
} else {
|
||||
@ -40,7 +40,7 @@ define([
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return ListingSearch;
|
||||
|
File diff suppressed because it is too large
Load Diff
209
assets/js/src/mp2migrator.js
Normal file
209
assets/js/src/mp2migrator.js
Normal file
@ -0,0 +1,209 @@
|
||||
define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
|
||||
'use strict';
|
||||
var MailPoet = mp;
|
||||
MailPoet.MP2Migrator = {
|
||||
|
||||
fatal_error: '',
|
||||
is_logging: false,
|
||||
|
||||
startLogger: function () {
|
||||
MailPoet.MP2Migrator.is_logging = true;
|
||||
clearTimeout(MailPoet.MP2Migrator.displayLogs_timeout);
|
||||
clearTimeout(MailPoet.MP2Migrator.updateProgressbar_timeout);
|
||||
clearTimeout(MailPoet.MP2Migrator.update_wordpress_info_timeout);
|
||||
setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000)
|
||||
},
|
||||
|
||||
stopLogger: function () {
|
||||
MailPoet.MP2Migrator.is_logging = false;
|
||||
},
|
||||
|
||||
updateDisplay: function () {
|
||||
MailPoet.MP2Migrator.displayLogs();
|
||||
MailPoet.MP2Migrator.updateProgressbar();
|
||||
},
|
||||
|
||||
displayLogs: function () {
|
||||
jQuery.ajax({
|
||||
url: mailpoet_mp2_migrator.log_file_url,
|
||||
cache: false
|
||||
}).done(function (result) {
|
||||
jQuery('#logger').html('');
|
||||
result.split('\n').forEach(function (resultRow) {
|
||||
var row = resultRow;
|
||||
if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
|
||||
row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
|
||||
}
|
||||
// Test if the import is complete
|
||||
else if(row === MailPoet.I18n.t('import_complete')) {
|
||||
jQuery('#import-actions').hide();
|
||||
jQuery('#upgrade-completed').show();
|
||||
}
|
||||
jQuery('#logger').append(row + '<br />\n');
|
||||
|
||||
});
|
||||
jQuery('#logger').append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span>' + '<br />\n');
|
||||
}).always(function () {
|
||||
if(MailPoet.MP2Migrator.is_logging) {
|
||||
MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateProgressbar: function () {
|
||||
jQuery.ajax({
|
||||
url: mailpoet_mp2_migrator.progress_url,
|
||||
cache: false,
|
||||
dataType: 'json'
|
||||
}).always(function (result) {
|
||||
// Move the progress bar
|
||||
var progress = 0;
|
||||
if((result.total !== undefined) && (Number(result.total) !== 0)) {
|
||||
progress = Math.round(Number(result.current) / Number(result.total) * 100);
|
||||
}
|
||||
jQuery('#progressbar').progressbar('option', 'value', progress);
|
||||
jQuery('#progresslabel').html(progress + '%');
|
||||
if(Number(result.current) !== 0) {
|
||||
jQuery('#skip-import').hide();
|
||||
jQuery('#progressbar').show();
|
||||
jQuery('#logger-container').show();
|
||||
}
|
||||
if(MailPoet.MP2Migrator.is_logging) {
|
||||
MailPoet.MP2Migrator.updateProgressbar_timeout = setTimeout(MailPoet.MP2Migrator.updateProgressbar, 1000);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
startImport: function () {
|
||||
MailPoet.MP2Migrator.fatal_error = '';
|
||||
// Start displaying the logs
|
||||
MailPoet.MP2Migrator.startLogger();
|
||||
|
||||
// Disable the import button
|
||||
MailPoet.MP2Migrator.import_button_label = jQuery('#import').val();
|
||||
jQuery('#import').val(MailPoet.I18n.t('importing')).attr('disabled', 'disabled');
|
||||
// Hide the Skip button
|
||||
jQuery('#skip-import').hide();
|
||||
// Show the stop button
|
||||
jQuery('#stop-import').show();
|
||||
|
||||
// Run the import
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'MP2Migrator',
|
||||
action: 'import',
|
||||
data: {
|
||||
}
|
||||
}).always(function () {
|
||||
MailPoet.MP2Migrator.stopLogger();
|
||||
MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped
|
||||
MailPoet.MP2Migrator.reactivateImportButton();
|
||||
}).done(function (response) {
|
||||
if(response) {
|
||||
MailPoet.MP2Migrator.fatal_error = response.data;
|
||||
}
|
||||
}).fail(function (response) {
|
||||
if(response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function (error) {
|
||||
return error.message;
|
||||
}),
|
||||
{scroll: true}
|
||||
);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
},
|
||||
|
||||
reactivateImportButton: function () {
|
||||
jQuery('#import').val(MailPoet.MP2Migrator.import_button_label).removeAttr('disabled');
|
||||
jQuery('#stop-import').hide();
|
||||
},
|
||||
|
||||
stopImport: function () {
|
||||
jQuery('#stop-import').attr('disabled', 'disabled');
|
||||
// Stop the import
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'MP2Migrator',
|
||||
action: 'stopImport',
|
||||
data: {
|
||||
}
|
||||
}).always(function () {
|
||||
jQuery('#stop-import').removeAttr('disabled'); // Enable the button
|
||||
MailPoet.MP2Migrator.reactivateImportButton();
|
||||
MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped
|
||||
}).fail(function (response) {
|
||||
if(response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function (error) {
|
||||
return error.message;
|
||||
}),
|
||||
{scroll: true}
|
||||
);
|
||||
}
|
||||
});
|
||||
MailPoet.MP2Migrator.stopLogger();
|
||||
return false;
|
||||
},
|
||||
|
||||
skipImport: function () {
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'MP2Migrator',
|
||||
action: 'skipImport',
|
||||
data: {
|
||||
}
|
||||
}).done(function () {
|
||||
MailPoet.MP2Migrator.gotoWelcomePage();
|
||||
}).fail(function (response) {
|
||||
if(response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function (error) {
|
||||
return error.message;
|
||||
}),
|
||||
{scroll: true}
|
||||
);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
},
|
||||
|
||||
gotoWelcomePage: function () {
|
||||
window.location.href = 'admin.php?page=mailpoet-welcome';
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Actions to run when the DOM is ready
|
||||
*/
|
||||
jQuery(function () {
|
||||
jQuery('#progressbar').progressbar({value: 0});
|
||||
|
||||
// Import button
|
||||
jQuery('#import').click(function() {
|
||||
MailPoet.MP2Migrator.startImport();
|
||||
});
|
||||
|
||||
// Stop import button
|
||||
jQuery('#stop-import').click(function() {
|
||||
MailPoet.MP2Migrator.stopImport();
|
||||
});
|
||||
|
||||
// Skip import link
|
||||
jQuery('#skip-import').click(function() {
|
||||
MailPoet.MP2Migrator.skipImport();
|
||||
});
|
||||
|
||||
// Go to welcome page
|
||||
jQuery('#goto-welcome').click(function() {
|
||||
MailPoet.MP2Migrator.gotoWelcomePage();
|
||||
});
|
||||
|
||||
// Update the display
|
||||
MailPoet.MP2Migrator.updateDisplay();
|
||||
});
|
||||
|
||||
});
|
@ -1,35 +1,44 @@
|
||||
define([
|
||||
'backbone',
|
||||
'backbone.marionette',
|
||||
'backbone.radio',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'handlebars',
|
||||
'handlebars_helpers'
|
||||
], function(Backbone, Marionette, jQuery, _, Handlebars) {
|
||||
], function(Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
|
||||
var Radio = BackboneRadio;
|
||||
|
||||
var app = new Marionette.Application(), AppView;
|
||||
|
||||
// Decoupled communication between application components
|
||||
app.getChannel = function(channel) {
|
||||
if (channel === undefined) return app.channel;
|
||||
return Radio.channel(channel);
|
||||
};
|
||||
|
||||
AppView = Marionette.LayoutView.extend({
|
||||
var AppView = Marionette.View.extend({
|
||||
el: '#mailpoet_editor',
|
||||
regions: {
|
||||
stylesRegion: '#mailpoet_editor_styles',
|
||||
contentRegion: '#mailpoet_editor_content',
|
||||
sidebarRegion: '#mailpoet_editor_sidebar',
|
||||
bottomRegion: '#mailpoet_editor_bottom',
|
||||
headingRegion: '#mailpoet_editor_heading',
|
||||
headingRegion: '#mailpoet_editor_heading'
|
||||
}
|
||||
});
|
||||
|
||||
var EditorApplication = Marionette.Application.extend({
|
||||
region: '#mailpoet_editor',
|
||||
|
||||
onStart: function() {
|
||||
this._appView = new AppView();
|
||||
this.showView(this._appView);
|
||||
},
|
||||
|
||||
getChannel: function(channel) {
|
||||
if (channel === undefined) {
|
||||
return Radio.channel('global');
|
||||
}
|
||||
return Radio.channel(channel);
|
||||
}
|
||||
});
|
||||
|
||||
app.on('start', function(options) {
|
||||
app._appView = new AppView();
|
||||
});
|
||||
|
||||
var app = new EditorApplication();
|
||||
window.EditorApplication = app;
|
||||
|
||||
return app;
|
||||
|
||||
});
|
||||
|
@ -6,8 +6,8 @@
|
||||
*/
|
||||
define([
|
||||
'backbone.marionette'
|
||||
], function(Marionette) {
|
||||
|
||||
], function(BackboneMarionette) {
|
||||
var Marionette = BackboneMarionette;
|
||||
var BehaviorsLookup = {};
|
||||
Marionette.Behaviors.behaviorsLookup = function() {
|
||||
return BehaviorsLookup;
|
||||
|
@ -6,18 +6,22 @@
|
||||
define([
|
||||
'backbone.marionette',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'mailpoet',
|
||||
'spectrum'
|
||||
], function(Marionette, BehaviorsLookup, Spectrum) {
|
||||
], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BehaviorsLookup.ColorPickerBehavior = Marionette.Behavior.extend({
|
||||
BL.ColorPickerBehavior = Marionette.Behavior.extend({
|
||||
onRender: function() {
|
||||
this.view.$('.mailpoet_color').spectrum({
|
||||
clickoutFiresChange: true,
|
||||
showInput: true,
|
||||
showInitial: true,
|
||||
preferredFormat: "hex6",
|
||||
preferredFormat: 'hex6',
|
||||
allowEmpty: true,
|
||||
chooseText: MailPoet.I18n.t('selectColor'),
|
||||
cancelText: MailPoet.I18n.t('cancelColorSelection')
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -11,11 +11,12 @@ define([
|
||||
'jquery',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'interact'
|
||||
], function(Marionette, _, jQuery, BehaviorsLookup, interact) {
|
||||
], function(Marionette, _, jQuery, BL, interact) {
|
||||
var BehaviorsLookup = BL;
|
||||
|
||||
BehaviorsLookup.ContainerDropZoneBehavior = Marionette.Behavior.extend({
|
||||
defaults: {
|
||||
columnLimit: 3,
|
||||
columnLimit: 3
|
||||
},
|
||||
onRender: function() {
|
||||
var dragAndDropDisabled = _.isObject(this.view.options.renderOptions) && this.view.options.renderOptions.disableDragAndDrop === true;
|
||||
@ -71,6 +72,7 @@ define([
|
||||
markerWidth = '',
|
||||
markerHeight = '',
|
||||
containerOffset = element.offset(),
|
||||
viewCollection = that.getCollection(),
|
||||
marker, targetModel, targetView, targetElement,
|
||||
topOffset, leftOffset, isLastBlockInsertion,
|
||||
$targetBlock, margin;
|
||||
@ -80,19 +82,19 @@ define([
|
||||
element.find('.mailpoet_drop_marker').remove();
|
||||
|
||||
// Allow empty collections to handle their own drop marking
|
||||
if (view.model.get('blocks').isEmpty()) return;
|
||||
if (viewCollection.isEmpty()) return;
|
||||
|
||||
if (view.collection.length === 0) {
|
||||
if (viewCollection.length === 0) {
|
||||
targetElement = element.find(view.childViewContainer);
|
||||
topOffset = targetElement.offset().top - element.offset().top;
|
||||
leftOffset = targetElement.offset().left - element.offset().left;
|
||||
markerWidth = targetElement.width();
|
||||
markerHeight = targetElement.height();
|
||||
} else {
|
||||
isLastBlockInsertion = view.collection.length === dropPosition.index;
|
||||
targetModel = isLastBlockInsertion ? view.collection.at(dropPosition.index - 1) : view.collection.at(dropPosition.index);
|
||||
isLastBlockInsertion = that.getCollection().length === dropPosition.index;
|
||||
targetModel = isLastBlockInsertion ? viewCollection.at(dropPosition.index - 1) : viewCollection.at(dropPosition.index);
|
||||
|
||||
targetView = view.children.findByModel(targetModel);
|
||||
targetView = that.getChildren().findByModel(targetModel);
|
||||
targetElement = targetView.$el;
|
||||
|
||||
topOffset = targetElement.offset().top - containerOffset.top;
|
||||
@ -135,10 +137,10 @@ define([
|
||||
if (dropPosition.index === 0) {
|
||||
marker.addClass('mailpoet_drop_marker_first');
|
||||
}
|
||||
if (view.collection.length - 1 === dropPosition.index) {
|
||||
if (viewCollection.length - 1 === dropPosition.index) {
|
||||
marker.addClass('mailpoet_drop_marker_last');
|
||||
}
|
||||
if (dropPosition.index > 0 && view.collection.length - 1 > dropPosition.index) {
|
||||
if (dropPosition.index > 0 && viewCollection.length - 1 > dropPosition.index) {
|
||||
marker.addClass('mailpoet_drop_marker_middle');
|
||||
}
|
||||
marker.addClass('mailpoet_drop_marker_' + dropPosition.position);
|
||||
@ -147,9 +149,9 @@ define([
|
||||
// compensated for to position marker right in the middle of two
|
||||
// blocks
|
||||
if (dropPosition.position === 'before') {
|
||||
$targetBlock = view.children.findByModel(view.collection.at(dropPosition.index-1)).$el;
|
||||
$targetBlock = that.getChildren().findByModel(viewCollection.at(dropPosition.index-1)).$el;
|
||||
} else {
|
||||
$targetBlock = view.children.findByModel(view.collection.at(dropPosition.index)).$el;
|
||||
$targetBlock = that.getChildren().findByModel(viewCollection.at(dropPosition.index)).$el;
|
||||
}
|
||||
margin = $targetBlock.outerHeight(true) - $targetBlock.outerHeight();
|
||||
|
||||
@ -182,6 +184,7 @@ define([
|
||||
view.model.get('blocks').length
|
||||
),
|
||||
droppableModel = event.draggable.getDropModel(),
|
||||
viewCollection = that.getCollection(),
|
||||
droppedView, droppedModel, index, tempCollection, tempCollection2;
|
||||
|
||||
if (dropPosition === undefined) return;
|
||||
@ -193,42 +196,42 @@ define([
|
||||
if (view.model.get('orientation') === 'horizontal' && droppableModel.get('type') !== 'container') {
|
||||
// Regular blocks always need to be inserted into columns - vertical containers
|
||||
tempCollection = new (EditorApplication.getBlockTypeModel('container'))({
|
||||
orientation: 'vertical',
|
||||
orientation: 'vertical'
|
||||
});
|
||||
tempCollection.get('blocks').add(droppableModel);
|
||||
view.collection.add(tempCollection, {at: index});
|
||||
viewCollection.add(tempCollection, {at: index});
|
||||
} else {
|
||||
view.collection.add(droppableModel, {at: index});
|
||||
viewCollection.add(droppableModel, {at: index});
|
||||
}
|
||||
|
||||
droppedView = view.children.findByModel(droppableModel);
|
||||
droppedView = that.getChildren().findByModel(droppableModel);
|
||||
} else {
|
||||
// Special insertion by replacing target block with collection
|
||||
// and inserting dropModel into that
|
||||
var tempModel = view.collection.at(dropPosition.index);
|
||||
var tempModel = viewCollection.at(dropPosition.index);
|
||||
|
||||
tempCollection = new (EditorApplication.getBlockTypeModel('container'))({
|
||||
orientation: (view.model.get('orientation') === 'vertical') ? 'horizontal' : 'vertical',
|
||||
orientation: (view.model.get('orientation') === 'vertical') ? 'horizontal' : 'vertical'
|
||||
});
|
||||
|
||||
view.collection.remove(tempModel);
|
||||
viewCollection.remove(tempModel);
|
||||
|
||||
if (tempCollection.get('orientation') === 'horizontal') {
|
||||
if (dropPosition.position === 'before') {
|
||||
tempCollection2 = new (EditorApplication.getBlockTypeModel('container'))({
|
||||
orientation: 'vertical',
|
||||
orientation: 'vertical'
|
||||
});
|
||||
tempCollection2.get('blocks').add(droppableModel);
|
||||
tempCollection.get('blocks').add(tempCollection2);
|
||||
}
|
||||
tempCollection2 = new (EditorApplication.getBlockTypeModel('container'))({
|
||||
orientation: 'vertical',
|
||||
orientation: 'vertical'
|
||||
});
|
||||
tempCollection2.get('blocks').add(tempModel);
|
||||
tempCollection.get('blocks').add(tempCollection2);
|
||||
if (dropPosition.position === 'after') {
|
||||
tempCollection2 = new (EditorApplication.getBlockTypeModel('container'))({
|
||||
orientation: 'vertical',
|
||||
orientation: 'vertical'
|
||||
});
|
||||
tempCollection2.get('blocks').add(droppableModel);
|
||||
tempCollection.get('blocks').add(tempCollection2);
|
||||
@ -242,21 +245,21 @@ define([
|
||||
tempCollection.get('blocks').add(droppableModel);
|
||||
}
|
||||
}
|
||||
view.collection.add(tempCollection, {at: dropPosition.index});
|
||||
viewCollection.add(tempCollection, {at: dropPosition.index});
|
||||
|
||||
// Call post add actions
|
||||
droppedView = view.children.findByModel(tempCollection).children.findByModel(droppableModel);
|
||||
droppedView = that.getChildren().findByModel(tempCollection).children.findByModel(droppableModel);
|
||||
}
|
||||
|
||||
// Call post add actions
|
||||
event.draggable.onDrop({
|
||||
dropBehavior: that,
|
||||
droppedModel: droppableModel,
|
||||
droppedView: droppedView,
|
||||
droppedView: droppedView
|
||||
});
|
||||
|
||||
that.cleanup();
|
||||
},
|
||||
}
|
||||
});
|
||||
},
|
||||
cleanup: function() {
|
||||
@ -266,7 +269,7 @@ define([
|
||||
// 2. Remove visual markings of drop position visualization
|
||||
this.view.$('.mailpoet_drop_marker').remove();
|
||||
},
|
||||
getDropPosition: function(eventX, eventY, unsafe) {
|
||||
getDropPosition: function(eventX, eventY, is_unsafe) {
|
||||
var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3
|
||||
|
||||
element = this.view.$el,
|
||||
@ -288,13 +291,13 @@ define([
|
||||
|
||||
insertionType, index, position, indexAndPosition;
|
||||
|
||||
unsafe = !!unsafe;
|
||||
unsafe = !!is_unsafe;
|
||||
|
||||
if (this.view.collection.length === 0) {
|
||||
if (this.getCollection().length === 0) {
|
||||
return {
|
||||
insertionType: 'normal',
|
||||
index: 0,
|
||||
position: 'inside',
|
||||
position: 'inside'
|
||||
};
|
||||
}
|
||||
|
||||
@ -327,7 +330,7 @@ define([
|
||||
index = indexAndPosition.index;
|
||||
}
|
||||
|
||||
if (!unsafe && orientation === 'vertical' && insertionType === 'special' && this.view.collection.at(index).get('orientation') === 'horizontal') {
|
||||
if (!unsafe && orientation === 'vertical' && insertionType === 'special' && this.getCollection().at(index).get('orientation') === 'horizontal') {
|
||||
// Prevent placing horizontal container in another horizontal container,
|
||||
// which would allow breaking the column limit.
|
||||
// Switch that to normal insertion
|
||||
@ -345,7 +348,7 @@ define([
|
||||
return {
|
||||
insertionType: insertionType, // 'normal'|'special'
|
||||
index: index,
|
||||
position: position, // 'inside'|'before'|'after'
|
||||
position: position // 'inside'|'before'|'after'
|
||||
};
|
||||
},
|
||||
_computeNormalIndex: function(eventX, eventY) {
|
||||
@ -356,7 +359,7 @@ define([
|
||||
|
||||
var index = this._computeCellIndex(eventX, eventY),
|
||||
// TODO: Handle case when there are no children, container is empty
|
||||
targetView = this.view.children.findByModel(this.view.collection.at(index)),
|
||||
targetView = this.getChildren().findByModel(this.getCollection().at(index)),
|
||||
orientation = this.view.model.get('orientation'),
|
||||
element = targetView.$el,
|
||||
eventOffset, closeOffset, elementDimension;
|
||||
@ -375,13 +378,13 @@ define([
|
||||
// First half of the element
|
||||
return {
|
||||
index: index,
|
||||
position: 'before',
|
||||
position: 'before'
|
||||
};
|
||||
} else {
|
||||
// Second half of the element
|
||||
return {
|
||||
index: index,
|
||||
position: 'after',
|
||||
position: 'after'
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -391,7 +394,7 @@ define([
|
||||
_computeCellIndex: function(eventX, eventY) {
|
||||
var orientation = this.view.model.get('orientation'),
|
||||
eventOffset = (orientation === 'vertical') ? eventY : eventX,
|
||||
resultView = this.view.children.find(function(view) {
|
||||
resultView = this.getChildren().find(function(view) {
|
||||
var element = view.$el,
|
||||
closeOffset, farOffset;
|
||||
|
||||
@ -414,15 +417,24 @@ define([
|
||||
_canAcceptNormalInsertion: function() {
|
||||
var orientation = this.view.model.get('orientation'),
|
||||
depth = this.view.renderOptions.depth,
|
||||
childCount = this.view.children.length;
|
||||
childCount = this.getChildren().length;
|
||||
// Note that depth is zero indexed. Root container has depth=0
|
||||
return orientation === 'vertical' || (orientation === 'horizontal' && depth === 1 && childCount < this.options.columnLimit);
|
||||
},
|
||||
_canAcceptSpecialInsertion: function() {
|
||||
var orientation = this.view.model.get('orientation'),
|
||||
depth = this.view.renderOptions.depth,
|
||||
childCount = this.view.children.length;
|
||||
childCount = this.getChildren().length;
|
||||
return depth === 0 || (depth === 1 && orientation === 'horizontal' && childCount <= this.options.columnLimit);
|
||||
},
|
||||
getCollectionView: function() {
|
||||
return this.view.getChildView('blocks');
|
||||
},
|
||||
getChildren: function() {
|
||||
return this.getCollectionView().children;
|
||||
},
|
||||
getCollection: function() {
|
||||
return this.getCollectionView().collection;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -11,8 +11,9 @@ define([
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'interact'
|
||||
], function(Marionette, _, jQuery, BehaviorsLookup, interact) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BehaviorsLookup.DraggableBehavior = Marionette.Behavior.extend({
|
||||
BL.DraggableBehavior = Marionette.Behavior.extend({
|
||||
defaults: {
|
||||
cloneOriginal: false,
|
||||
hideOriginal: false,
|
||||
@ -28,7 +29,7 @@ define([
|
||||
},
|
||||
|
||||
onDrop: function(model, view) {},
|
||||
testAttachToInstance: function(model, view) { return true; },
|
||||
testAttachToInstance: function(model, view) { return true; }
|
||||
},
|
||||
onRender: function() {
|
||||
var that = this,
|
||||
@ -38,7 +39,7 @@ define([
|
||||
if (!this.options.testAttachToInstance(this.view.model, this.view)) return;
|
||||
|
||||
interactable = interact(this.$el.get(0), {
|
||||
ignoreFrom: this.options.ignoreSelector,
|
||||
ignoreFrom: this.options.ignoreSelector
|
||||
}).draggable({
|
||||
// allow dragging of multple elements at the same time
|
||||
max: Infinity,
|
||||
@ -46,7 +47,8 @@ define([
|
||||
// Scroll when dragging near edges of a window
|
||||
autoScroll: true,
|
||||
|
||||
onstart: function(event) {
|
||||
onstart: function(startEvent) {
|
||||
var event = startEvent;
|
||||
|
||||
if (that.options.cloneOriginal === true) {
|
||||
// Use substitution instead of a clone
|
||||
@ -89,9 +91,8 @@ define([
|
||||
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
|
||||
|
||||
// translate the element
|
||||
target.style.webkitTransform =
|
||||
target.style.transform =
|
||||
'translate(' + x + 'px, ' + y + 'px)';
|
||||
target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
|
||||
target.style.webkitTransform = target.style.transform;
|
||||
|
||||
// update the posiion attributes
|
||||
target.setAttribute('data-x', x);
|
||||
@ -99,7 +100,8 @@ define([
|
||||
},
|
||||
onend: function (event) {
|
||||
var target = event.target;
|
||||
target.style.webkitTransform = target.style.transform = '';
|
||||
target.style.transform = '';
|
||||
target.style.webkitTransform = target.style.transform;
|
||||
target.removeAttribute('data-x');
|
||||
target.removeAttribute('data-y');
|
||||
jQuery(event.interaction.element).addClass('mailpoet_droppable_active');
|
||||
@ -111,9 +113,10 @@ define([
|
||||
that.view.$el.removeClass('mailpoet_hidden');
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
.preventDefault('auto')
|
||||
.styleCursor(false)
|
||||
.actionChecker(function (pointer, event, action) {
|
||||
// Disable dragging with right click
|
||||
if (event.button !== 0) {
|
||||
@ -128,7 +131,8 @@ define([
|
||||
} else {
|
||||
interactable.getDropModel = this.view.getDropFunc();
|
||||
}
|
||||
interactable.onDrop = function(options) {
|
||||
interactable.onDrop = function(opts) {
|
||||
var options = opts;
|
||||
if (_.isObject(options)) {
|
||||
// Inject Draggable behavior if possible
|
||||
options.dragBehavior = that;
|
||||
@ -136,6 +140,6 @@ define([
|
||||
// Delegate to view's event handler
|
||||
that.options.onDrop.apply(that, [options]);
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -5,19 +5,20 @@
|
||||
*/
|
||||
define([
|
||||
'backbone.marionette',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||
], function(Marionette, BehaviorsLookup) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BehaviorsLookup.HighlightEditingBehavior = Marionette.Behavior.extend({
|
||||
BL.HighlightEditingBehavior = Marionette.Behavior.extend({
|
||||
modelEvents: {
|
||||
'startEditing': 'enableHighlight',
|
||||
'stopEditing': 'disableHighlight',
|
||||
startEditing: 'enableHighlight',
|
||||
stopEditing: 'disableHighlight'
|
||||
},
|
||||
enableHighlight: function() {
|
||||
this.$el.addClass('mailpoet_highlight');
|
||||
},
|
||||
disableHighlight: function() {
|
||||
this.$el.removeClass('mailpoet_highlight');
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -8,18 +8,19 @@ define([
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'interact'
|
||||
], function(Marionette, BehaviorsLookup, interact) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BehaviorsLookup.ResizableBehavior = Marionette.Behavior.extend({
|
||||
BL.ResizableBehavior = Marionette.Behavior.extend({
|
||||
defaults: {
|
||||
elementSelector: null,
|
||||
resizeHandleSelector: true, // true will use edges of the element itself
|
||||
transformationFunction: function(y) { return y; },
|
||||
minLength: 0,
|
||||
modelField: 'styles.block.height',
|
||||
modelField: 'styles.block.height'
|
||||
},
|
||||
events: {
|
||||
"mouseenter": 'showResizeHandle',
|
||||
"mouseleave": 'hideResizeHandle',
|
||||
mouseenter: 'showResizeHandle',
|
||||
mouseleave: 'hideResizeHandle'
|
||||
},
|
||||
onRender: function() {
|
||||
this.attachResize();
|
||||
@ -37,8 +38,8 @@ define([
|
||||
top: false,
|
||||
left: false,
|
||||
right: false,
|
||||
bottom: (typeof this.options.resizeHandleSelector === 'string') ? this.view.$(this.options.resizeHandleSelector).get(0) : this.options.resizeHandleSelector,
|
||||
},
|
||||
bottom: (typeof this.options.resizeHandleSelector === 'string') ? this.view.$(this.options.resizeHandleSelector).get(0) : this.options.resizeHandleSelector
|
||||
}
|
||||
}).on('resizestart', function(event) {
|
||||
that.isBeingResized = true;
|
||||
that.$el.addClass('mailpoet_resize_active');
|
||||
@ -63,6 +64,6 @@ define([
|
||||
if (typeof this.options.resizeHandleSelector === 'string') {
|
||||
this.view.$(this.options.resizeHandleSelector).addClass('mailpoet_hidden');
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -6,15 +6,16 @@
|
||||
define([
|
||||
'backbone.marionette',
|
||||
'jquery',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||
], function(Marionette, jQuery, BehaviorsLookup) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BehaviorsLookup.ShowSettingsBehavior = Marionette.Behavior.extend({
|
||||
BL.ShowSettingsBehavior = Marionette.Behavior.extend({
|
||||
defaults: {
|
||||
ignoreFrom: '', // selector
|
||||
ignoreFrom: '' // selector
|
||||
},
|
||||
events: {
|
||||
'click .mailpoet_content': 'showSettings',
|
||||
'click .mailpoet_content': 'showSettings'
|
||||
},
|
||||
showSettings: function(event) {
|
||||
if(!this.isIgnoredElement(event.target)) {
|
||||
@ -25,7 +26,7 @@ define([
|
||||
return this.options.ignoreFrom
|
||||
&& this.options.ignoreFrom.length > 0
|
||||
&& jQuery(element).is(this.options.ignoreFrom);
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -8,14 +8,15 @@ define([
|
||||
'underscore',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||
], function(Marionette, _, BehaviorsLookup) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BehaviorsLookup.SortableBehavior = Marionette.Behavior.extend({
|
||||
BL.SortableBehavior = Marionette.Behavior.extend({
|
||||
onRender: function() {
|
||||
var collection = this.view.collection;
|
||||
|
||||
if (_.isFunction(this.$el.sortable)) {
|
||||
this.$el.sortable({
|
||||
cursor: "move",
|
||||
cursor: 'move',
|
||||
start: function(event, ui) {
|
||||
ui.item.data('previousIndex', ui.item.index());
|
||||
},
|
||||
@ -32,7 +33,7 @@ define([
|
||||
collection.remove(model);
|
||||
collection.add(model, { at: newIndex });
|
||||
},
|
||||
items: this.options.items,
|
||||
items: this.options.items
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,17 +8,18 @@ define([
|
||||
'underscore',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||
], function(Marionette, _, BehaviorsLookup) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BehaviorsLookup.TextEditorBehavior = Marionette.Behavior.extend({
|
||||
BL.TextEditorBehavior = Marionette.Behavior.extend({
|
||||
defaults: {
|
||||
selector: '.mailpoet_content',
|
||||
toolbar1: "bold italic link unlink forecolor mailpoet_shortcodes",
|
||||
toolbar2: "",
|
||||
validElements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
|
||||
invalidElements: "script",
|
||||
toolbar1: 'bold italic link unlink forecolor mailpoet_shortcodes',
|
||||
toolbar2: '',
|
||||
validElements: 'p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br',
|
||||
invalidElements: 'script',
|
||||
blockFormats: 'Paragraph=p',
|
||||
plugins: "link textcolor colorpicker mailpoet_shortcodes",
|
||||
configurationFilter: function(originalConfig) { return originalConfig; },
|
||||
plugins: 'link textcolor colorpicker mailpoet_shortcodes',
|
||||
configurationFilter: function(originalConfig) { return originalConfig; }
|
||||
},
|
||||
onDomRefresh: function() {
|
||||
var that = this;
|
||||
@ -60,16 +61,23 @@ define([
|
||||
|
||||
editor.on('click', function(e) {
|
||||
editor.focus();
|
||||
if (that._isActivationClick) {
|
||||
editor.selection.setRng(
|
||||
tinymce.dom.RangeUtils.getCaretRangeFromPoint(e.clientX, e.clientY, editor.getDoc())
|
||||
);
|
||||
that._isActivationClick = false;
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('focus', function(e) {
|
||||
that.view.triggerMethod('text:editor:focus');
|
||||
that._isActivationClick = true;
|
||||
});
|
||||
|
||||
editor.on('blur', function(e) {
|
||||
that.view.triggerMethod('text:editor:blur');
|
||||
});
|
||||
},
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
@ -28,7 +28,7 @@ define([
|
||||
jQuery
|
||||
) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -53,7 +53,7 @@ define([
|
||||
});
|
||||
|
||||
CommunicationComponent.getBulkTransformedPosts({
|
||||
blocks: blocks,
|
||||
blocks: blocks
|
||||
}).then(_.partial(this.refreshBlocks, models));
|
||||
},
|
||||
refreshBlocks: function(models, renderedBlocks) {
|
||||
@ -65,7 +65,7 @@ define([
|
||||
model.trigger('refreshPosts', contents);
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.AutomatedLatestContentBlockModel = base.BlockModel.extend({
|
||||
@ -97,14 +97,14 @@ define([
|
||||
sortBy: 'newest', // 'newest'|'oldest',
|
||||
showDivider: true, // true|false
|
||||
divider: {},
|
||||
_container: new (App.getBlockTypeModel('container'))(),
|
||||
_container: new (App.getBlockTypeModel('container'))()
|
||||
}, App.getConfig().get('blockDefaults.automatedLatestContent'));
|
||||
},
|
||||
relations: function() {
|
||||
return {
|
||||
readMoreButton: App.getBlockTypeModel('button'),
|
||||
divider: App.getBlockTypeModel('divider'),
|
||||
_container: App.getBlockTypeModel('container'),
|
||||
_container: App.getBlockTypeModel('container')
|
||||
};
|
||||
},
|
||||
initialize: function() {
|
||||
@ -124,23 +124,29 @@ define([
|
||||
*/
|
||||
_scheduleFetchPosts: function() {
|
||||
App.getChannel().trigger('automatedLatestContentRefresh');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.AutomatedLatestContentBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_automated_latest_content_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_automated_latest_content_block mailpoet_droppable_block',
|
||||
initialize: function() {
|
||||
function replaceButtonStylesHandler(data) {
|
||||
this.model.set({readMoreButton: data});
|
||||
}
|
||||
App.getChannel().on('replaceAllButtonStyles', replaceButtonStylesHandler.bind(this));
|
||||
},
|
||||
getTemplate: function() { return templates.automatedLatestContentBlock; },
|
||||
regions: {
|
||||
toolsRegion: '.mailpoet_tools',
|
||||
postsRegion: '.mailpoet_automated_latest_content_block_posts',
|
||||
postsRegion: '.mailpoet_automated_latest_content_block_posts'
|
||||
},
|
||||
modelEvents: _.extend(
|
||||
_.omit(base.BlockView.prototype.modelEvents, 'change'),
|
||||
{
|
||||
'postsChanged': 'render',
|
||||
postsChanged: 'render'
|
||||
}),
|
||||
events: _.extend(base.BlockView.prototype.events, {
|
||||
'click .mailpoet_automated_latest_content_block_overlay': 'showSettings',
|
||||
'click .mailpoet_automated_latest_content_block_overlay': 'showSettings'
|
||||
}),
|
||||
onDragSubstituteBy: function() { return Module.AutomatedLatestContentWidgetView; },
|
||||
onRender: function() {
|
||||
@ -148,16 +154,16 @@ define([
|
||||
renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay'),
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay')
|
||||
};
|
||||
this.toolsView = new Module.AutomatedLatestContentBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
this.postsRegion.show(new ContainerView({ model: this.model.get('_container'), renderOptions: renderOptions }));
|
||||
},
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
this.showChildView('postsRegion', new ContainerView({ model: this.model.get('_container'), renderOptions: renderOptions }));
|
||||
}
|
||||
});
|
||||
|
||||
Module.AutomatedLatestContentBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.AutomatedLatestContentBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.AutomatedLatestContentBlockSettingsView; }
|
||||
});
|
||||
|
||||
// Sidebar view container
|
||||
@ -165,33 +171,28 @@ define([
|
||||
getTemplate: function() { return templates.automatedLatestContentBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"click .mailpoet_automated_latest_content_hide_display_options": 'toggleDisplayOptions',
|
||||
"click .mailpoet_automated_latest_content_show_display_options": 'toggleDisplayOptions',
|
||||
"click .mailpoet_automated_latest_content_select_button": 'showButtonSettings',
|
||||
"click .mailpoet_automated_latest_content_select_divider": 'showDividerSettings',
|
||||
"change .mailpoet_automated_latest_content_read_more_type": 'changeReadMoreType',
|
||||
"change .mailpoet_automated_latest_content_display_type": 'changeDisplayType',
|
||||
"change .mailpoet_automated_latest_content_title_format": 'changeTitleFormat',
|
||||
"change .mailpoet_automated_latest_content_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'),
|
||||
"change .mailpoet_automated_latest_content_show_divider": _.partial(this.changeBoolField, 'showDivider'),
|
||||
"input .mailpoet_automated_latest_content_show_amount": _.partial(this.changeField, "amount"),
|
||||
"change .mailpoet_automated_latest_content_content_type": _.partial(this.changeField, "contentType"),
|
||||
"change .mailpoet_automated_latest_content_include_or_exclude": _.partial(this.changeField, "inclusionType"),
|
||||
"change .mailpoet_automated_latest_content_title_alignment": _.partial(this.changeField, "titleAlignment"),
|
||||
"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"),
|
||||
"input .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
||||
"change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"),
|
||||
"input .mailpoet_automated_latest_content_categories": _.partial(this.changeField, "categoriesPrecededBy"),
|
||||
"input .mailpoet_automated_latest_content_read_more_text": _.partial(this.changeField, "readMoreText"),
|
||||
"change .mailpoet_automated_latest_content_sort_by": _.partial(this.changeField, "sortBy"),
|
||||
"click .mailpoet_done_editing": "close",
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
'click .mailpoet_automated_latest_content_hide_display_options': 'toggleDisplayOptions',
|
||||
'click .mailpoet_automated_latest_content_show_display_options': 'toggleDisplayOptions',
|
||||
'click .mailpoet_automated_latest_content_select_button': 'showButtonSettings',
|
||||
'click .mailpoet_automated_latest_content_select_divider': 'showDividerSettings',
|
||||
'change .mailpoet_automated_latest_content_read_more_type': 'changeReadMoreType',
|
||||
'change .mailpoet_automated_latest_content_display_type': 'changeDisplayType',
|
||||
'change .mailpoet_automated_latest_content_title_format': 'changeTitleFormat',
|
||||
'change .mailpoet_automated_latest_content_title_as_links': _.partial(this.changeBoolField, 'titleIsLink'),
|
||||
'change .mailpoet_automated_latest_content_show_divider': _.partial(this.changeBoolField, 'showDivider'),
|
||||
'input .mailpoet_automated_latest_content_show_amount': _.partial(this.changeField, 'amount'),
|
||||
'change .mailpoet_automated_latest_content_content_type': _.partial(this.changeField, 'contentType'),
|
||||
'change .mailpoet_automated_latest_content_include_or_exclude': _.partial(this.changeField, 'inclusionType'),
|
||||
'change .mailpoet_automated_latest_content_title_alignment': _.partial(this.changeField, 'titleAlignment'),
|
||||
'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'),
|
||||
'input .mailpoet_automated_latest_content_author_preceded_by': _.partial(this.changeField, 'authorPrecededBy'),
|
||||
'change .mailpoet_automated_latest_content_show_categories': _.partial(this.changeField, 'showCategories'),
|
||||
'input .mailpoet_automated_latest_content_categories': _.partial(this.changeField, 'categoriesPrecededBy'),
|
||||
'input .mailpoet_automated_latest_content_read_more_text': _.partial(this.changeField, 'readMoreText'),
|
||||
'change .mailpoet_automated_latest_content_sort_by': _.partial(this.changeField, 'sortBy'),
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
onRender: function() {
|
||||
@ -246,8 +247,8 @@ define([
|
||||
}
|
||||
)
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}).on({
|
||||
'select2:select': function(event) {
|
||||
var terms = that.model.get('terms');
|
||||
@ -260,7 +261,7 @@ define([
|
||||
terms.remove(event.params.data);
|
||||
// Reset whole model in order for change events to propagate properly
|
||||
that.model.set('terms', terms.toJSON());
|
||||
},
|
||||
}
|
||||
}).trigger( 'change' );
|
||||
},
|
||||
toggleDisplayOptions: function(event) {
|
||||
@ -281,8 +282,8 @@ define([
|
||||
renderOptions: {
|
||||
displayFormat: 'subpanel',
|
||||
hideLink: true,
|
||||
hideApplyToAll: true,
|
||||
},
|
||||
hideApplyToAll: true
|
||||
}
|
||||
})).render();
|
||||
},
|
||||
showDividerSettings: function(event) {
|
||||
@ -291,8 +292,8 @@ define([
|
||||
model: this.model.get('divider'),
|
||||
renderOptions: {
|
||||
displayFormat: 'subpanel',
|
||||
hideApplyToAll: true,
|
||||
},
|
||||
hideApplyToAll: true
|
||||
}
|
||||
})).render();
|
||||
},
|
||||
changeReadMoreType: function(event) {
|
||||
@ -355,11 +356,11 @@ define([
|
||||
_.each(postTypes, function(type) {
|
||||
select.append(jQuery('<option>', {
|
||||
value: type.name,
|
||||
text: type.label,
|
||||
text: type.label
|
||||
}));
|
||||
});
|
||||
select.val(selectedValue);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.AutomatedLatestContentWidgetView = base.WidgetView.extend({
|
||||
@ -372,27 +373,28 @@ define([
|
||||
},
|
||||
onDrop: function(options) {
|
||||
options.droppedView.triggerMethod('showSettings');
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('automatedLatestContent', {
|
||||
blockModel: Module.AutomatedLatestContentBlockModel,
|
||||
blockView: Module.AutomatedLatestContentBlockView,
|
||||
blockView: Module.AutomatedLatestContentBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'automatedLatestContent',
|
||||
widgetView: Module.AutomatedLatestContentWidgetView,
|
||||
priority: 97,
|
||||
priority: 97
|
||||
});
|
||||
});
|
||||
|
||||
App.on('start', function() {
|
||||
App._ALCSupervisor = new Module.ALCSupervisor();
|
||||
App._ALCSupervisor.refresh();
|
||||
App.on('start', function(App, options) {
|
||||
var Application = App;
|
||||
Application._ALCSupervisor = new Module.ALCSupervisor();
|
||||
Application._ALCSupervisor.refresh();
|
||||
});
|
||||
|
||||
return Module;
|
||||
|
@ -14,10 +14,10 @@ define([
|
||||
'modal'
|
||||
], function(App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
AugmentedView = Marionette.LayoutView.extend({});
|
||||
AugmentedView = Marionette.View.extend({});
|
||||
|
||||
Module.BlockModel = SuperModel.extend({
|
||||
stale: [], // Attributes to be removed upon saving
|
||||
@ -42,20 +42,21 @@ define([
|
||||
},
|
||||
getChildren: function() {
|
||||
return [];
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.BlockView = AugmentedView.extend({
|
||||
regions: {
|
||||
toolsRegion: '> .mailpoet_tools',
|
||||
toolsRegion: '> .mailpoet_tools'
|
||||
},
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
'delete': 'deleteBlock',
|
||||
change: 'render',
|
||||
delete: 'deleteBlock',
|
||||
duplicate: 'duplicateBlock'
|
||||
},
|
||||
events: {
|
||||
"mouseenter": "showTools",
|
||||
"mouseleave": "hideTools",
|
||||
mouseenter: 'showTools',
|
||||
mouseleave: 'hideTools'
|
||||
},
|
||||
behaviors: {
|
||||
DraggableBehavior: {
|
||||
@ -78,14 +79,14 @@ define([
|
||||
WidgetView.destroy();
|
||||
return node;
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
HighlightEditingBehavior: {},
|
||||
HighlightEditingBehavior: {}
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
viewCid: this.cid
|
||||
};
|
||||
},
|
||||
constructor: function() {
|
||||
@ -125,6 +126,12 @@ define([
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
disableDragging: function() {
|
||||
this.$el.addClass('mailpoet_ignore_drag');
|
||||
},
|
||||
enableDragging: function() {
|
||||
this.$el.removeClass('mailpoet_ignore_drag');
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
this.transitionIn();
|
||||
@ -136,6 +143,9 @@ define([
|
||||
this.model.destroy();
|
||||
}.bind(this));
|
||||
},
|
||||
duplicateBlock: function() {
|
||||
this.model.collection.add(this.model.toJSON(), {at: this.model.collection.findIndex(this.model)});
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('slideDown', 'fadeIn', 'easeOut');
|
||||
},
|
||||
@ -152,38 +162,40 @@ define([
|
||||
easing: easing,
|
||||
complete: function() {
|
||||
promise.resolve();
|
||||
}.bind(this),
|
||||
}.bind(this)
|
||||
}
|
||||
).velocity(
|
||||
fadeDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
queue: false, // Do not enqueue, trigger animation in parallel
|
||||
queue: false // Do not enqueue, trigger animation in parallel
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.BlockToolsView = AugmentedView.extend({
|
||||
getTemplate: function() { return templates.genericBlockTools; },
|
||||
events: {
|
||||
"click .mailpoet_edit_block": "changeSettings",
|
||||
"click .mailpoet_delete_block_activate": "showDeletionConfirmation",
|
||||
"click .mailpoet_delete_block_cancel": "hideDeletionConfirmation",
|
||||
"click .mailpoet_delete_block_confirm": "deleteBlock",
|
||||
'click .mailpoet_edit_block': 'changeSettings',
|
||||
'click .mailpoet_delete_block_activate': 'showDeletionConfirmation',
|
||||
'click .mailpoet_delete_block_cancel': 'hideDeletionConfirmation',
|
||||
'click .mailpoet_delete_block_confirm': 'deleteBlock',
|
||||
'click .mailpoet_duplicate_block': 'duplicateBlock'
|
||||
},
|
||||
// Markers of whether these particular tools will be used for this instance
|
||||
tools: {
|
||||
settings: true,
|
||||
delete: true,
|
||||
move: true,
|
||||
duplicate: true,
|
||||
move: true
|
||||
},
|
||||
getSettingsView: function() { return Module.BlockSettingsView; },
|
||||
initialize: function(options) {
|
||||
options = options || {};
|
||||
initialize: function(opts) {
|
||||
var options = opts || {};
|
||||
if (!_.isUndefined(options.tools)) {
|
||||
// Make a new block specific tool config object
|
||||
this.tools = jQuery.extend({}, this.tools, options.tools || {});
|
||||
@ -193,11 +205,11 @@ define([
|
||||
this.on('hideTools', this.hideDeletionConfirmation, this);
|
||||
this.on('showSettings', this.changeSettings);
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
tools: this.tools,
|
||||
tools: this.tools
|
||||
};
|
||||
},
|
||||
changeSettings: function(options) {
|
||||
@ -215,12 +227,17 @@ define([
|
||||
this.model.trigger('delete');
|
||||
return false;
|
||||
},
|
||||
duplicateBlock: function(event) {
|
||||
event.preventDefault();
|
||||
this.model.trigger('duplicate');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Module.BlockSettingsView = Marionette.LayoutView.extend({
|
||||
Module.BlockSettingsView = Marionette.View.extend({
|
||||
className: 'mailpoet_editor_settings',
|
||||
behaviors: {
|
||||
ColorPickerBehavior: {},
|
||||
ColorPickerBehavior: {}
|
||||
},
|
||||
initialize: function(params) {
|
||||
this.model.trigger('startEditing');
|
||||
@ -231,7 +248,7 @@ define([
|
||||
width: App.getConfig().get('sidepanelWidth'),
|
||||
onCancel: function() {
|
||||
this.destroy();
|
||||
}.bind(this),
|
||||
}.bind(this)
|
||||
};
|
||||
this.renderOptions = params.renderOptions || {};
|
||||
if (this.renderOptions.displayFormat === 'subpanel') {
|
||||
@ -240,6 +257,11 @@ define([
|
||||
MailPoet.Modal.panel(panelParams);
|
||||
}
|
||||
},
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON()
|
||||
};
|
||||
},
|
||||
close: function(event) {
|
||||
this.destroy();
|
||||
},
|
||||
@ -268,18 +290,18 @@ define([
|
||||
onBeforeDestroy: function() {
|
||||
MailPoet.Modal.close();
|
||||
this.model.trigger('stopEditing');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.WidgetView = Marionette.ItemView.extend({
|
||||
Module.WidgetView = Marionette.View.extend({
|
||||
className: 'mailpoet_widget mailpoet_droppable_block mailpoet_droppable_widget',
|
||||
behaviors: {
|
||||
DraggableBehavior: {
|
||||
drop: function() {
|
||||
throw "Unsupported operation";
|
||||
throw 'Unsupported operation';
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
return Module;
|
||||
|
@ -9,7 +9,7 @@ define([
|
||||
'jquery'
|
||||
], function(App, BaseBlock, MailPoet, _, jQuery) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -33,19 +33,19 @@ define([
|
||||
fontFamily: 'Arial',
|
||||
fontSize: '16px',
|
||||
fontWeight: 'normal', // 'normal'|'bold'
|
||||
textAlign: 'center',
|
||||
},
|
||||
},
|
||||
textAlign: 'center'
|
||||
}
|
||||
}
|
||||
}, App.getConfig().get('blockDefaults.button'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ButtonBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_button_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_button_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.buttonBlock; },
|
||||
onDragSubstituteBy: function() { return Module.ButtonWidgetView; },
|
||||
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
|
||||
ShowSettingsBehavior: {},
|
||||
ShowSettingsBehavior: {}
|
||||
}),
|
||||
initialize: function() {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
@ -56,54 +56,53 @@ define([
|
||||
},
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.ButtonBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
},
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
}
|
||||
});
|
||||
|
||||
Module.ButtonBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.ButtonBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.ButtonBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.ButtonBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.buttonBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"input .mailpoet_field_button_text": _.partial(this.changeField, "text"),
|
||||
"input .mailpoet_field_button_url": _.partial(this.changeField, "url"),
|
||||
"change .mailpoet_field_button_alignment": _.partial(this.changeField, "styles.block.textAlign"),
|
||||
"change .mailpoet_field_button_font_color": _.partial(this.changeColorField, "styles.block.fontColor"),
|
||||
"change .mailpoet_field_button_font_family": _.partial(this.changeField, "styles.block.fontFamily"),
|
||||
"change .mailpoet_field_button_font_size": _.partial(this.changeField, "styles.block.fontSize"),
|
||||
"change .mailpoet_field_button_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||
"change .mailpoet_field_button_border_color": _.partial(this.changeColorField, "styles.block.borderColor"),
|
||||
"change .mailpoet_field_button_font_weight": "changeFontWeight",
|
||||
'input .mailpoet_field_button_text': _.partial(this.changeField, 'text'),
|
||||
'input .mailpoet_field_button_url': _.partial(this.changeField, 'url'),
|
||||
'change .mailpoet_field_button_alignment': _.partial(this.changeField, 'styles.block.textAlign'),
|
||||
'change .mailpoet_field_button_font_color': _.partial(this.changeColorField, 'styles.block.fontColor'),
|
||||
'change .mailpoet_field_button_font_family': _.partial(this.changeField, 'styles.block.fontFamily'),
|
||||
'change .mailpoet_field_button_font_size': _.partial(this.changeField, 'styles.block.fontSize'),
|
||||
'change .mailpoet_field_button_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
|
||||
'change .mailpoet_field_button_border_color': _.partial(this.changeColorField, 'styles.block.borderColor'),
|
||||
'change .mailpoet_field_button_font_weight': 'changeFontWeight',
|
||||
|
||||
"input .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
|
||||
"change .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
|
||||
"input .mailpoet_field_button_border_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width', _.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)),
|
||||
'input .mailpoet_field_button_border_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
|
||||
|
||||
"input .mailpoet_field_button_border_radius": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)),
|
||||
"change .mailpoet_field_button_border_radius": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)),
|
||||
"input .mailpoet_field_button_border_radius_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)),
|
||||
'input .mailpoet_field_button_border_radius': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
|
||||
'change .mailpoet_field_button_border_radius': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
|
||||
'input .mailpoet_field_button_border_radius_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
|
||||
|
||||
"input .mailpoet_field_button_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, "styles.block.width").bind(this)),
|
||||
"change .mailpoet_field_button_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, "styles.block.width").bind(this)),
|
||||
"input .mailpoet_field_button_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width', _.partial(this.changePixelField, "styles.block.width").bind(this)),
|
||||
'input .mailpoet_field_button_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
|
||||
'change .mailpoet_field_button_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
|
||||
'input .mailpoet_field_button_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
|
||||
|
||||
"input .mailpoet_field_button_line_height": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)),
|
||||
"change .mailpoet_field_button_line_height": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)),
|
||||
"input .mailpoet_field_button_line_height_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)),
|
||||
'input .mailpoet_field_button_line_height': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
|
||||
'change .mailpoet_field_button_line_height': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
|
||||
'input .mailpoet_field_button_line_height_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
|
||||
|
||||
"click .mailpoet_field_button_replace_all_styles": "applyToAll",
|
||||
"click .mailpoet_done_editing": "close",
|
||||
'click .mailpoet_field_button_replace_all_styles': 'applyToAll',
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
templateContext: function() {
|
||||
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
|
||||
availableStyles: App.getAvailableStyles().toJSON(),
|
||||
renderOptions: this.renderOptions,
|
||||
};
|
||||
renderOptions: this.renderOptions
|
||||
});
|
||||
},
|
||||
applyToAll: function() {
|
||||
App.getChannel().trigger('replaceAllButtonStyles', _.pick(this.model.toJSON(), 'styles', 'type'));
|
||||
@ -128,21 +127,21 @@ define([
|
||||
cloneOriginal: true,
|
||||
drop: function() {
|
||||
return new Module.ButtonBlockModel();
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('button', {
|
||||
blockModel: Module.ButtonBlockModel,
|
||||
blockView: Module.ButtonBlockView,
|
||||
blockView: Module.ButtonBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'button',
|
||||
widgetView: Module.ButtonWidgetView,
|
||||
priority: 92,
|
||||
priority: 92
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ define([
|
||||
'newsletter_editor/blocks/base'
|
||||
], function(Backbone, Marionette, _, jQuery, App, BaseBlock) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock,
|
||||
@ -30,12 +30,12 @@ define([
|
||||
// TODO: If type has no registered model, use a backup one
|
||||
return new Type(block, {parse: true});
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ContainerBlockModel = base.BlockModel.extend({
|
||||
relations: {
|
||||
blocks: BlockCollection,
|
||||
blocks: BlockCollection
|
||||
},
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
@ -43,10 +43,10 @@ define([
|
||||
orientation: 'vertical',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
backgroundColor: 'transparent'
|
||||
}
|
||||
},
|
||||
blocks: new BlockCollection(),
|
||||
blocks: new BlockCollection()
|
||||
}, App.getConfig().get('blockDefaults.container'));
|
||||
},
|
||||
validate: function() {
|
||||
@ -60,7 +60,7 @@ define([
|
||||
// If container has any blocks - add them to a collection
|
||||
if (response.type === 'container' && _.has(response, 'blocks')) {
|
||||
response.blocks = new BlockCollection(response.blocks, {
|
||||
parse: true,
|
||||
parse: true
|
||||
});
|
||||
}
|
||||
return response;
|
||||
@ -71,32 +71,46 @@ define([
|
||||
});
|
||||
|
||||
return _.flatten(models);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ContainerBlockView = Marionette.CompositeView.extend({
|
||||
regionClass: Marionette.Region,
|
||||
Module.ContainerBlocksView = Marionette.CollectionView.extend({
|
||||
className: 'mailpoet_container',
|
||||
childView: function(model) {
|
||||
return App.getBlockTypeView(model.get('type'));
|
||||
},
|
||||
childViewOptions: function() {
|
||||
var newRenderOptions = _.clone(this.renderOptions);
|
||||
if (newRenderOptions.depth !== undefined) {
|
||||
newRenderOptions.depth += 1;
|
||||
}
|
||||
return {
|
||||
renderOptions: newRenderOptions
|
||||
};
|
||||
},
|
||||
emptyView: function() { return Module.ContainerBlockEmptyView; },
|
||||
emptyViewOptions: function() { return { renderOptions: this.renderOptions }; },
|
||||
initialize: function(options) {
|
||||
this.renderOptions = options.renderOptions;
|
||||
}
|
||||
});
|
||||
|
||||
Module.ContainerBlockView = base.BlockView.extend({
|
||||
regions: _.extend({}, base.BlockView.prototype.regions, {
|
||||
blocks: {
|
||||
el: '> .mailpoet_container',
|
||||
replaceElement: true
|
||||
}
|
||||
}),
|
||||
className: 'mailpoet_block mailpoet_container_block mailpoet_droppable_block mailpoet_droppable_layout_block',
|
||||
getTemplate: function() { return templates.containerBlock; },
|
||||
childViewContainer: '> .mailpoet_container',
|
||||
getEmptyView: function() { return Module.ContainerBlockEmptyView; },
|
||||
emptyViewOptions: function() { return { renderOptions: this.renderOptions }; },
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
'delete': 'deleteBlock',
|
||||
},
|
||||
events: {
|
||||
"mouseenter": "showTools",
|
||||
"mouseleave": "hideTools",
|
||||
"click .mailpoet_newsletter_layer_selector": "toggleEditingLayer",
|
||||
},
|
||||
regions: {
|
||||
toolsRegion: '> .mailpoet_tools',
|
||||
},
|
||||
events: _.extend({}, base.BlockView.prototype.events, {
|
||||
'click .mailpoet_newsletter_layer_selector': 'toggleEditingLayer'
|
||||
}),
|
||||
ui: {
|
||||
tools: '> .mailpoet_tools'
|
||||
},
|
||||
behaviors: {
|
||||
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
|
||||
ContainerDropZoneBehavior: {},
|
||||
DraggableBehavior: {
|
||||
cloneOriginal: true,
|
||||
@ -123,10 +137,9 @@ define([
|
||||
// Attach Draggable only to layout containers and disable it
|
||||
// for root and column containers.
|
||||
return view.renderOptions.depth === 1;
|
||||
},
|
||||
},
|
||||
HighlightEditingBehavior: {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}),
|
||||
onDragSubstituteBy: function() {
|
||||
// For two and three column layouts display their respective widgets,
|
||||
// otherwise always default to one column layout widget
|
||||
@ -137,52 +150,31 @@ define([
|
||||
return Module.OneColumnContainerWidgetView;
|
||||
|
||||
},
|
||||
constructor: function() {
|
||||
// Set the block collection to be handled by this view as well
|
||||
arguments[0].collection = arguments[0].model.get('blocks');
|
||||
Marionette.CompositeView.apply(this, arguments);
|
||||
this.$el.addClass('mailpoet_editor_view_' + this.cid);
|
||||
},
|
||||
initialize: function(options) {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.renderOptions = _.defaults(options.renderOptions || {}, {});
|
||||
this.on('dom:refresh', this.showBlock, this);
|
||||
this._isFirstRender = true;
|
||||
},
|
||||
// Determines which view type should be used for a child
|
||||
getChildView: function(model) {
|
||||
// TODO: If type does not have a type registered, use a generic one
|
||||
return App.getBlockTypeView(model.get('type'));
|
||||
},
|
||||
childViewOptions: function() {
|
||||
var newRenderOptions = _.clone(this.renderOptions);
|
||||
if (newRenderOptions.depth !== undefined) {
|
||||
newRenderOptions.depth += 1;
|
||||
}
|
||||
return {
|
||||
renderOptions: newRenderOptions
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
};
|
||||
},
|
||||
onRender: function() {
|
||||
this._rebuildRegions();
|
||||
this.toolsView = new Module.ContainerBlockToolsView({
|
||||
model: this.model,
|
||||
tools: {
|
||||
settings: this.renderOptions.depth === 1,
|
||||
delete: this.renderOptions.depth === 1,
|
||||
duplicate: true,
|
||||
move: this.renderOptions.depth === 1,
|
||||
layerSelector: false,
|
||||
},
|
||||
layerSelector: false
|
||||
}
|
||||
});
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
this.regionManager.destroy();
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
this.showChildView('blocks', new Module.ContainerBlocksView({
|
||||
collection: this.model.get('blocks'),
|
||||
renderOptions: this.renderOptions
|
||||
}));
|
||||
|
||||
// TODO: Look for a better way to do this than here
|
||||
// Sets child container orientation HTML class here, as child CollectionView won't have access to model and will overwrite existing region element instead
|
||||
this.$('> .mailpoet_container').attr('class', 'mailpoet_container mailpoet_container_' + this.model.get('orientation'));
|
||||
},
|
||||
showTools: function() {
|
||||
if (this.renderOptions.depth === 1 && !this.$el.hasClass('mailpoet_container_layer_active')) {
|
||||
@ -221,131 +213,69 @@ define([
|
||||
enableContainerLayer();
|
||||
}
|
||||
event.stopPropagation();
|
||||
},
|
||||
_buildRegions: function(regions) {
|
||||
var that = this;
|
||||
|
||||
var defaults = {
|
||||
regionClass: this.getOption('regionClass'),
|
||||
parentEl: function() { return that.$el; }
|
||||
};
|
||||
|
||||
return this.regionManager.addRegions(regions, defaults);
|
||||
},
|
||||
_rebuildRegions: function() {
|
||||
if (this.regionManager === undefined) {
|
||||
this.regionManager = new Marionette.RegionManager();
|
||||
}
|
||||
this.regionManager.destroy();
|
||||
_.extend(this, this._buildRegions(this.regions));
|
||||
},
|
||||
getDropFunc: function() {
|
||||
return function() {
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
this.transitionIn();
|
||||
this._isFirstRender = false;
|
||||
}
|
||||
},
|
||||
deleteBlock: function() {
|
||||
this.transitionOut().done(function() {
|
||||
this.model.destroy();
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('slideDown', 'fadeIn', 'easeIn');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('slideUp', 'fadeOut', 'easeOut');
|
||||
},
|
||||
_transition: function(slideDirection, fadeDirection, easing) {
|
||||
var promise = jQuery.Deferred();
|
||||
|
||||
this.$el.velocity(
|
||||
slideDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
complete: function() {
|
||||
promise.resolve();
|
||||
}.bind(this),
|
||||
}
|
||||
).velocity(
|
||||
fadeDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
queue: false, // Do not enqueue, trigger animation in parallel
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ContainerBlockEmptyView = Marionette.ItemView.extend({
|
||||
Module.ContainerBlockEmptyView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.containerEmpty; },
|
||||
initialize: function(options) {
|
||||
this.renderOptions = _.defaults(options.renderOptions || {}, {});
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
isRoot: this.renderOptions.depth === 0,
|
||||
emptyContainerMessage: this.renderOptions.emptyContainerMessage || '',
|
||||
emptyContainerMessage: this.renderOptions.emptyContainerMessage || ''
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ContainerBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.ContainerBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.ContainerBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.ContainerBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.containerBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"change .mailpoet_field_container_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||
"click .mailpoet_done_editing": "close",
|
||||
'change .mailpoet_field_container_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
regions: {
|
||||
columnsSettingsRegion: '.mailpoet_container_columns_settings',
|
||||
columnsSettingsRegion: '.mailpoet_container_columns_settings'
|
||||
},
|
||||
initialize: function() {
|
||||
base.BlockSettingsView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this._columnsSettingsView = new (Module.ContainerBlockColumnsSettingsView)({
|
||||
collection: this.model.get('blocks'),
|
||||
collection: this.model.get('blocks')
|
||||
});
|
||||
},
|
||||
onRender: function() {
|
||||
this.columnsSettingsRegion.show(this._columnsSettingsView);
|
||||
},
|
||||
this.showChildView('columnsSettingsRegion', this._columnsSettingsView);
|
||||
}
|
||||
});
|
||||
|
||||
Module.ContainerBlockColumnsSettingsView = Marionette.CollectionView.extend({
|
||||
getChildView: function() { return Module.ContainerBlockColumnSettingsView; },
|
||||
childView: function() { return Module.ContainerBlockColumnSettingsView; },
|
||||
childViewOptions: function(model, index) {
|
||||
return {
|
||||
columnIndex: index,
|
||||
columnIndex: index
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ContainerBlockColumnSettingsView = Marionette.ItemView.extend({
|
||||
Module.ContainerBlockColumnSettingsView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.containerBlockColumnSettings; },
|
||||
initialize: function(options) {
|
||||
this.columnNumber = (options.columnIndex || 0) + 1;
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
columnNumber: this.columnNumber,
|
||||
columnNumber: this.columnNumber
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.OneColumnContainerWidgetView = base.WidgetView.extend({
|
||||
@ -358,12 +288,12 @@ define([
|
||||
return new Module.ContainerBlockModel({
|
||||
orientation: 'horizontal',
|
||||
blocks: [
|
||||
new Module.ContainerBlockModel(),
|
||||
new Module.ContainerBlockModel()
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.TwoColumnContainerWidgetView = base.WidgetView.extend({
|
||||
@ -377,12 +307,12 @@ define([
|
||||
orientation: 'horizontal',
|
||||
blocks: [
|
||||
new Module.ContainerBlockModel(),
|
||||
new Module.ContainerBlockModel(),
|
||||
new Module.ContainerBlockModel()
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ThreeColumnContainerWidgetView = base.WidgetView.extend({
|
||||
@ -397,36 +327,36 @@ define([
|
||||
blocks: [
|
||||
new Module.ContainerBlockModel(),
|
||||
new Module.ContainerBlockModel(),
|
||||
new Module.ContainerBlockModel(),
|
||||
new Module.ContainerBlockModel()
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('container', {
|
||||
blockModel: Module.ContainerBlockModel,
|
||||
blockView: Module.ContainerBlockView,
|
||||
blockView: Module.ContainerBlockView
|
||||
});
|
||||
|
||||
App.registerLayoutWidget({
|
||||
name: 'oneColumnLayout',
|
||||
priority: 100,
|
||||
widgetView: Module.OneColumnContainerWidgetView,
|
||||
widgetView: Module.OneColumnContainerWidgetView
|
||||
});
|
||||
|
||||
App.registerLayoutWidget({
|
||||
name: 'twoColumnLayout',
|
||||
priority: 100,
|
||||
widgetView: Module.TwoColumnContainerWidgetView,
|
||||
widgetView: Module.TwoColumnContainerWidgetView
|
||||
});
|
||||
|
||||
App.registerLayoutWidget({
|
||||
name: 'threeColumnLayout',
|
||||
priority: 100,
|
||||
widgetView: Module.ThreeColumnContainerWidgetView,
|
||||
widgetView: Module.ThreeColumnContainerWidgetView
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -9,7 +9,7 @@ define([
|
||||
'mailpoet'
|
||||
], function(App, BaseBlock, _, jQuery, MailPoet) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -24,15 +24,15 @@ define([
|
||||
padding: '12px',
|
||||
borderStyle: 'solid',
|
||||
borderWidth: '1px',
|
||||
borderColor: '#000000',
|
||||
},
|
||||
},
|
||||
borderColor: '#000000'
|
||||
}
|
||||
}
|
||||
}, App.getConfig().get('blockDefaults.divider'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.DividerBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_divider_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_divider_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.dividerBlock; },
|
||||
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
|
||||
behaviors: _.defaults({
|
||||
@ -41,11 +41,11 @@ define([
|
||||
resizeHandleSelector: '.mailpoet_resize_handle',
|
||||
transformationFunction: function(y) { return y / 2; },
|
||||
minLength: 0, // TODO: Move this number to editor configuration
|
||||
modelField: 'styles.block.padding',
|
||||
modelField: 'styles.block.padding'
|
||||
},
|
||||
ShowSettingsBehavior: {
|
||||
ignoreFrom: '.mailpoet_resize_handle'
|
||||
},
|
||||
}
|
||||
}, base.BlockView.prototype.behaviors),
|
||||
onDragSubstituteBy: function() { return Module.DividerWidgetView; },
|
||||
initialize: function() {
|
||||
@ -59,14 +59,14 @@ define([
|
||||
this.listenTo(this.model, 'change:src change:styles.block.backgroundColor change:styles.block.borderStyle change:styles.block.borderWidth change:styles.block.borderColor applyToAll', this.render);
|
||||
this.listenTo(this.model, 'change:styles.block.padding', this.changePadding);
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return _.extend({
|
||||
totalHeight: parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px',
|
||||
}, base.BlockView.prototype.templateHelpers.apply(this));
|
||||
totalHeight: parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px'
|
||||
}, base.BlockView.prototype.templateContext.apply(this));
|
||||
},
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.DividerBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
App.getChannel().off('replaceAllDividers', this._replaceDividerHandler);
|
||||
@ -76,40 +76,39 @@ define([
|
||||
this.$('.mailpoet_content').css('padding-top', this.model.get('styles.block.padding'));
|
||||
this.$('.mailpoet_content').css('padding-bottom', this.model.get('styles.block.padding'));
|
||||
this.$('.mailpoet_resize_handle_text').text(parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.DividerBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.DividerBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.DividerBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.DividerBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.dividerBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"click .mailpoet_field_divider_style": 'changeStyle',
|
||||
'click .mailpoet_field_divider_style': 'changeStyle',
|
||||
|
||||
"input .mailpoet_field_divider_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
|
||||
"change .mailpoet_field_divider_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
|
||||
"input .mailpoet_field_divider_border_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
|
||||
'input .mailpoet_field_divider_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
|
||||
'change .mailpoet_field_divider_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
|
||||
'input .mailpoet_field_divider_border_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
|
||||
|
||||
"change .mailpoet_field_divider_border_color": _.partial(this.changeColorField, "styles.block.borderColor"),
|
||||
"change .mailpoet_field_divider_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||
"click .mailpoet_button_divider_apply_to_all": "applyToAll",
|
||||
"click .mailpoet_done_editing": "close",
|
||||
'change .mailpoet_field_divider_border_color': _.partial(this.changeColorField, 'styles.block.borderColor'),
|
||||
'change .mailpoet_field_divider_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
|
||||
'click .mailpoet_button_divider_apply_to_all': 'applyToAll',
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
modelEvents: function() {
|
||||
return {
|
||||
'change:styles.block.borderColor': 'repaintDividerStyleOptions',
|
||||
'change:styles.block.borderColor': 'repaintDividerStyleOptions'
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
templateContext: function() {
|
||||
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
|
||||
availableStyles: App.getAvailableStyles().toJSON(),
|
||||
renderOptions: this.renderOptions,
|
||||
};
|
||||
renderOptions: this.renderOptions
|
||||
});
|
||||
},
|
||||
changeStyle: function(event) {
|
||||
var style = jQuery(event.currentTarget).data('style');
|
||||
@ -126,7 +125,7 @@ define([
|
||||
updateValueAndCall: function(fieldToUpdate, callable, event) {
|
||||
this.$(fieldToUpdate).val(jQuery(event.target).val());
|
||||
callable(event);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.DividerWidgetView = base.WidgetView.extend({
|
||||
@ -136,20 +135,20 @@ define([
|
||||
cloneOriginal: true,
|
||||
drop: function() {
|
||||
return new Module.DividerBlockModel();
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('divider', {
|
||||
blockModel: Module.DividerBlockModel,
|
||||
blockView: Module.DividerBlockView,
|
||||
blockView: Module.DividerBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'divider',
|
||||
widgetView: Module.DividerWidgetView,
|
||||
priority: 93,
|
||||
priority: 93
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,7 @@ define([
|
||||
'underscore'
|
||||
], function(App, BaseBlock, _) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -19,43 +19,43 @@ define([
|
||||
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: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
text: {
|
||||
fontColor: '#000000',
|
||||
fontFamily: 'Arial',
|
||||
fontSize: '12px',
|
||||
textAlign: 'center',
|
||||
textAlign: 'center'
|
||||
},
|
||||
link: {
|
||||
fontColor: '#0000ff',
|
||||
textDecoration: 'none',
|
||||
},
|
||||
},
|
||||
textDecoration: 'none'
|
||||
}
|
||||
}
|
||||
}, App.getConfig().get('blockDefaults.footer'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.FooterBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_footer_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_footer_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.footerBlock; },
|
||||
modelEvents: _.extend({
|
||||
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
|
||||
'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'
|
||||
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
|
||||
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
|
||||
TextEditorBehavior: {
|
||||
configurationFilter: function(originalSettings) {
|
||||
return _.extend({}, originalSettings, {
|
||||
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
|
||||
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
|
||||
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle')
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}),
|
||||
onDragSubstituteBy: function() { return Module.FooterWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.FooterBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
},
|
||||
onTextEditorChange: function(newContent) {
|
||||
this.model.set('text', newContent);
|
||||
@ -67,41 +67,34 @@ define([
|
||||
onTextEditorBlur: function() {
|
||||
this.enableDragging();
|
||||
this.enableShowingTools();
|
||||
},
|
||||
disableDragging: function() {
|
||||
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');
|
||||
},
|
||||
enableDragging: function() {
|
||||
this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.FooterBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.FooterBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.FooterBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.FooterBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.footerBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"change .mailpoet_field_footer_text_color": _.partial(this.changeColorField, "styles.text.fontColor"),
|
||||
"change .mailpoet_field_footer_text_font_family": _.partial(this.changeField, "styles.text.fontFamily"),
|
||||
"change .mailpoet_field_footer_text_size": _.partial(this.changeField, "styles.text.fontSize"),
|
||||
"change #mailpoet_field_footer_link_color": _.partial(this.changeColorField, "styles.link.fontColor"),
|
||||
"change #mailpoet_field_footer_link_underline": function(event) {
|
||||
'change .mailpoet_field_footer_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
|
||||
'change .mailpoet_field_footer_text_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
|
||||
'change .mailpoet_field_footer_text_size': _.partial(this.changeField, 'styles.text.fontSize'),
|
||||
'change #mailpoet_field_footer_link_color': _.partial(this.changeColorField, 'styles.link.fontColor'),
|
||||
'change #mailpoet_field_footer_link_underline': function(event) {
|
||||
this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
|
||||
},
|
||||
"change .mailpoet_field_footer_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||
"change .mailpoet_field_footer_alignment": _.partial(this.changeField, "styles.text.textAlign"),
|
||||
"click .mailpoet_done_editing": "close",
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
availableStyles: App.getAvailableStyles().toJSON(),
|
||||
'change .mailpoet_field_footer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
|
||||
'change .mailpoet_field_footer_alignment': _.partial(this.changeField, 'styles.text.textAlign'),
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
templateContext: function() {
|
||||
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
|
||||
availableStyles: App.getAvailableStyles().toJSON()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Module.FooterWidgetView = base.WidgetView.extend({
|
||||
@ -111,21 +104,21 @@ define([
|
||||
cloneOriginal: true,
|
||||
drop: function() {
|
||||
return new Module.FooterBlockModel();
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('footer', {
|
||||
blockModel: Module.FooterBlockModel,
|
||||
blockView: Module.FooterBlockView,
|
||||
blockView: Module.FooterBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'footer',
|
||||
widgetView: Module.FooterWidgetView,
|
||||
priority: 99,
|
||||
priority: 99
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,7 @@ define([
|
||||
'underscore'
|
||||
], function(App, BaseBlock, _) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -19,43 +19,43 @@ define([
|
||||
text: 'Display problems? <a href="[link:newsletter_view_in_browser_url]">View it in your browser</a>',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
text: {
|
||||
fontColor: '#000000',
|
||||
fontFamily: 'Arial',
|
||||
fontSize: '12px',
|
||||
textAlign: 'center',
|
||||
textAlign: 'center'
|
||||
},
|
||||
link: {
|
||||
fontColor: '#0000ff',
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
},
|
||||
textDecoration: 'underline'
|
||||
}
|
||||
}
|
||||
}, App.getConfig().get('blockDefaults.header'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.HeaderBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_header_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_header_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.headerBlock; },
|
||||
modelEvents: _.extend({
|
||||
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
|
||||
'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'
|
||||
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
|
||||
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
|
||||
TextEditorBehavior: {
|
||||
configurationFilter: function(originalSettings) {
|
||||
return _.extend({}, originalSettings, {
|
||||
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
|
||||
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
|
||||
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle')
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}),
|
||||
onDragSubstituteBy: function() { return Module.HeaderWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.HeaderBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
},
|
||||
onTextEditorChange: function(newContent) {
|
||||
this.model.set('text', newContent);
|
||||
@ -67,41 +67,34 @@ define([
|
||||
onTextEditorBlur: function() {
|
||||
this.enableDragging();
|
||||
this.enableShowingTools();
|
||||
},
|
||||
disableDragging: function() {
|
||||
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');
|
||||
},
|
||||
enableDragging: function() {
|
||||
this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.HeaderBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.HeaderBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.HeaderBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.HeaderBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.headerBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"change .mailpoet_field_header_text_color": _.partial(this.changeColorField, "styles.text.fontColor"),
|
||||
"change .mailpoet_field_header_text_font_family": _.partial(this.changeField, "styles.text.fontFamily"),
|
||||
"change .mailpoet_field_header_text_size": _.partial(this.changeField, "styles.text.fontSize"),
|
||||
"change #mailpoet_field_header_link_color": _.partial(this.changeColorField, "styles.link.fontColor"),
|
||||
"change #mailpoet_field_header_link_underline": function(event) {
|
||||
'change .mailpoet_field_header_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
|
||||
'change .mailpoet_field_header_text_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
|
||||
'change .mailpoet_field_header_text_size': _.partial(this.changeField, 'styles.text.fontSize'),
|
||||
'change #mailpoet_field_header_link_color': _.partial(this.changeColorField, 'styles.link.fontColor'),
|
||||
'change #mailpoet_field_header_link_underline': function(event) {
|
||||
this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
|
||||
},
|
||||
"change .mailpoet_field_header_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||
"change .mailpoet_field_header_alignment": _.partial(this.changeField, "styles.text.textAlign"),
|
||||
"click .mailpoet_done_editing": "close",
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
availableStyles: App.getAvailableStyles().toJSON(),
|
||||
'change .mailpoet_field_header_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
|
||||
'change .mailpoet_field_header_alignment': _.partial(this.changeField, 'styles.text.textAlign'),
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
templateContext: function() {
|
||||
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
|
||||
availableStyles: App.getAvailableStyles().toJSON()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Module.HeaderWidgetView = base.WidgetView.extend({
|
||||
@ -111,21 +104,21 @@ define([
|
||||
cloneOriginal: true,
|
||||
drop: function() {
|
||||
return new Module.HeaderBlockModel();
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('header', {
|
||||
blockModel: Module.HeaderBlockModel,
|
||||
blockView: Module.HeaderBlockView,
|
||||
blockView: Module.HeaderBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'header',
|
||||
widgetView: Module.HeaderWidgetView,
|
||||
priority: 98,
|
||||
priority: 98
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -4,10 +4,11 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/blocks/base',
|
||||
'underscore'
|
||||
], function(App, BaseBlock, _) {
|
||||
'underscore',
|
||||
'mailpoet'
|
||||
], function(App, BaseBlock, _, MailPoet) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock,
|
||||
@ -25,52 +26,62 @@ define([
|
||||
height: '64px',
|
||||
styles: {
|
||||
block: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
},
|
||||
textAlign: 'center'
|
||||
}
|
||||
}
|
||||
}, App.getConfig().get('blockDefaults.image'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ImageBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_image_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_image_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.imageBlock; },
|
||||
onDragSubstituteBy: function() { return Module.ImageWidgetView; },
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return _.extend({
|
||||
imageMissingSrc: App.getConfig().get('urls.imageMissing'),
|
||||
}, base.BlockView.prototype.templateHelpers.apply(this));
|
||||
imageMissingSrc: App.getConfig().get('urls.imageMissing')
|
||||
}, base.BlockView.prototype.templateContext.apply(this));
|
||||
},
|
||||
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
|
||||
ShowSettingsBehavior: {},
|
||||
ShowSettingsBehavior: {}
|
||||
}),
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
|
||||
if (this.model.get('fullWidth')) {
|
||||
this.$el.addClass('mailpoet_full_image');
|
||||
} else {
|
||||
this.$el.removeClass('mailpoet_full_image');
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.ImageBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.ImageBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.ImageBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.ImageBlockSettingsView = base.BlockSettingsView.extend({
|
||||
onRender: function() {
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-full-width'), {
|
||||
tooltipId: 'tooltip-editor-full-width',
|
||||
tooltip: MailPoet.I18n.t('helpTooltipDesignerFullWidth')
|
||||
});
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-ideal-width'), {
|
||||
tooltipId: 'tooltip-editor-ideal-width',
|
||||
tooltip: MailPoet.I18n.t('helpTooltipDesignerIdealWidth')
|
||||
});
|
||||
},
|
||||
getTemplate: function() { return templates.imageBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"input .mailpoet_field_image_link": _.partial(this.changeField, "link"),
|
||||
"input .mailpoet_field_image_address": _.partial(this.changeField, "src"),
|
||||
"input .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
|
||||
"change .mailpoet_field_image_full_width": _.partial(this.changeBoolCheckboxField, "fullWidth"),
|
||||
"change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"),
|
||||
"click .mailpoet_field_image_select_another_image": "showMediaManager",
|
||||
"click .mailpoet_done_editing": "close",
|
||||
'input .mailpoet_field_image_link': _.partial(this.changeField, 'link'),
|
||||
'input .mailpoet_field_image_address': 'changeAddress',
|
||||
'input .mailpoet_field_image_alt_text': _.partial(this.changeField, 'alt'),
|
||||
'change .mailpoet_field_image_full_width': _.partial(this.changeBoolCheckboxField, 'fullWidth'),
|
||||
'change .mailpoet_field_image_alignment': _.partial(this.changeField, 'styles.block.textAlign'),
|
||||
'click .mailpoet_field_image_select_another_image': 'showMediaManager',
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
initialize: function(options) {
|
||||
@ -141,7 +152,7 @@ define([
|
||||
// Update user settings when users adjust the
|
||||
// attachment display settings.
|
||||
displayUserSettings: false
|
||||
}),
|
||||
})
|
||||
]);
|
||||
|
||||
if(wp.media.view.settings.post.featuredImageId) {
|
||||
@ -166,7 +177,7 @@ define([
|
||||
|
||||
var handlers = {
|
||||
content: {
|
||||
'embed': 'embedContent',
|
||||
embed: 'embedContent',
|
||||
'edit-selection': 'editSelectionContent'
|
||||
},
|
||||
toolbar: {
|
||||
@ -266,7 +277,8 @@ define([
|
||||
},
|
||||
|
||||
mainEmbedToolbar: function(toolbar) {
|
||||
toolbar.view = new wp.media.view.Toolbar.Embed({
|
||||
var tbar = toolbar;
|
||||
tbar.view = new wp.media.view.Toolbar.Embed({
|
||||
controller: this,
|
||||
text: 'Add images'
|
||||
});
|
||||
@ -274,7 +286,7 @@ define([
|
||||
|
||||
});
|
||||
|
||||
var theFrame = this._mediaManager = new MediaManager({
|
||||
var theFrame = new MediaManager({
|
||||
id: 'mailpoet-media-manager',
|
||||
frame: 'select',
|
||||
title: 'Select image',
|
||||
@ -285,12 +297,13 @@ define([
|
||||
},
|
||||
displaySettings: false,
|
||||
button: {
|
||||
text: 'Select',
|
||||
},
|
||||
text: 'Select'
|
||||
}
|
||||
}),
|
||||
that = this;
|
||||
this._mediaManager = theFrame;
|
||||
|
||||
this._mediaManager.on('insert', function() {
|
||||
this._mediaManager.on('insert', function() {
|
||||
// Append media manager image selections to Images tab
|
||||
var selection = theFrame.state().get('selection');
|
||||
selection.each(function(attachment) {
|
||||
@ -318,7 +331,7 @@ define([
|
||||
height: mainSize.height + 'px',
|
||||
width: mainSize.width + 'px',
|
||||
src: mainSize.url,
|
||||
alt: (attachment.get('alt') !== "" && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title'),
|
||||
alt: (attachment.get('alt') !== '' && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title')
|
||||
});
|
||||
// Rerender settings view due to changes from outside of settings view
|
||||
that.render();
|
||||
@ -327,12 +340,26 @@ define([
|
||||
|
||||
this._mediaManager.open();
|
||||
},
|
||||
changeAddress: function(event) {
|
||||
var src = jQuery(event.target).val();
|
||||
var image = new Image();
|
||||
|
||||
image.onload = function() {
|
||||
this.model.set({
|
||||
src: src,
|
||||
width: image.naturalWidth + 'px',
|
||||
height: image.naturalHeight + 'px'
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
image.src = src;
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
|
||||
if (typeof this._mediaManager === 'object') {
|
||||
this._mediaManager.remove();
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
ImageWidgetView = base.WidgetView.extend({
|
||||
@ -345,22 +372,22 @@ define([
|
||||
},
|
||||
onDrop: function(options) {
|
||||
options.droppedView.triggerMethod('showSettings', { showImageManager: true });
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
Module.ImageWidgetView = ImageWidgetView;
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('image', {
|
||||
blockModel: Module.ImageBlockModel,
|
||||
blockView: Module.ImageBlockView,
|
||||
blockView: Module.ImageBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'image',
|
||||
widgetView: Module.ImageWidgetView,
|
||||
priority: 91,
|
||||
priority: 91
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -37,7 +37,7 @@ define([
|
||||
DividerBlock
|
||||
) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -48,6 +48,7 @@ define([
|
||||
return this._getDefaults({
|
||||
type: 'posts',
|
||||
amount: '10',
|
||||
offset: 0,
|
||||
contentType: 'post', // 'post'|'page'|'mailpoet_page'
|
||||
postStatus: 'publish', // 'draft'|'pending'|'private'|'publish'|'future'
|
||||
terms: [], // List of category and tag objects
|
||||
@ -75,7 +76,7 @@ define([
|
||||
divider: {},
|
||||
_selectedPosts: [],
|
||||
_availablePosts: [],
|
||||
_transformedPosts: new (App.getBlockTypeModel('container'))(),
|
||||
_transformedPosts: new (App.getBlockTypeModel('container'))()
|
||||
}, App.getConfig().get('blockDefaults.posts'));
|
||||
},
|
||||
relations: function() {
|
||||
@ -84,7 +85,7 @@ define([
|
||||
divider: App.getBlockTypeModel('divider'),
|
||||
_selectedPosts: Backbone.Collection,
|
||||
_availablePosts: Backbone.Collection,
|
||||
_transformedPosts: App.getBlockTypeModel('container'),
|
||||
_transformedPosts: App.getBlockTypeModel('container')
|
||||
};
|
||||
},
|
||||
initialize: function() {
|
||||
@ -98,6 +99,7 @@ define([
|
||||
|
||||
this.fetchAvailablePosts();
|
||||
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts);
|
||||
this.on('loadMorePosts', this._loadMorePosts, this);
|
||||
|
||||
this.listenTo(this.get('_selectedPosts'), 'add remove reset', 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);
|
||||
@ -108,6 +110,7 @@ define([
|
||||
},
|
||||
fetchAvailablePosts: function() {
|
||||
var that = this;
|
||||
this.set('offset', 0);
|
||||
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
|
||||
that.get('_availablePosts').reset(posts);
|
||||
that.get('_selectedPosts').reset(); // Empty out the collection
|
||||
@ -116,6 +119,27 @@ define([
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
|
||||
});
|
||||
},
|
||||
_loadMorePosts: function() {
|
||||
var that = this,
|
||||
postCount = this.get('_availablePosts').length,
|
||||
nextOffset = this.get('offset') + Number(this.get('amount'));
|
||||
|
||||
if(postCount === 0 || postCount < nextOffset) {
|
||||
// No more posts to load
|
||||
return false;
|
||||
}
|
||||
this.set('offset', nextOffset);
|
||||
this.trigger('loadingMorePosts');
|
||||
|
||||
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
|
||||
that.get('_availablePosts').add(posts);
|
||||
that.trigger('change:_availablePosts');
|
||||
}).fail(function() {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
|
||||
}).always(function() {
|
||||
that.trigger('morePostsLoaded');
|
||||
});
|
||||
},
|
||||
_refreshTransformedPosts: function() {
|
||||
var that = this,
|
||||
data = this.toJSON();
|
||||
@ -148,15 +172,15 @@ define([
|
||||
}).fail(function() {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.PostsBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_posts_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.postsBlock; },
|
||||
modelEvents: {}, // Forcefully disable all events
|
||||
regions: _.extend({
|
||||
postsRegion: '.mailpoet_posts_block_posts',
|
||||
postsRegion: '.mailpoet_posts_block_posts'
|
||||
}, base.BlockView.prototype.regions),
|
||||
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
|
||||
initialize: function() {
|
||||
@ -166,8 +190,8 @@ define([
|
||||
this.model.reply('blockView', this.notifyAboutSelf, this);
|
||||
},
|
||||
onRender: function() {
|
||||
if (!this.toolsRegion.hasView()) {
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
if (!this.getRegion('toolsRegion').hasView()) {
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
}
|
||||
this.trigger('showSettings');
|
||||
|
||||
@ -175,36 +199,36 @@ define([
|
||||
renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay'),
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay')
|
||||
};
|
||||
this.postsRegion.show(new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions }));
|
||||
this.showChildView('postsRegion', new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions }));
|
||||
},
|
||||
notifyAboutSelf: function() {
|
||||
return this;
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
this.model.stopReplying('blockView', this.notifyAboutSelf, this);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.PostsBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.PostsBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.PostsBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.PostsBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.postsBlockSettings; },
|
||||
regions: {
|
||||
selectionRegion: '.mailpoet_settings_posts_selection',
|
||||
displayOptionsRegion: '.mailpoet_settings_posts_display_options',
|
||||
displayOptionsRegion: '.mailpoet_settings_posts_display_options'
|
||||
},
|
||||
events: {
|
||||
'click .mailpoet_settings_posts_show_display_options': 'switchToDisplayOptions',
|
||||
'click .mailpoet_settings_posts_show_post_selection': 'switchToPostSelection',
|
||||
'click .mailpoet_settings_posts_insert_selected': 'insertPosts',
|
||||
'click .mailpoet_settings_posts_insert_selected': 'insertPosts'
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
model: this.model.toJSON()
|
||||
};
|
||||
},
|
||||
initialize: function() {
|
||||
@ -227,7 +251,7 @@ define([
|
||||
onCancel: function() {
|
||||
// Self destroy the block if the user closes settings modal
|
||||
that.model.destroy();
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// Inform child views that they have been attached to document
|
||||
@ -256,41 +280,72 @@ define([
|
||||
this.model.trigger('insertSelectedPosts');
|
||||
this.model.destroy();
|
||||
this.close();
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var PostSelectionSettingsView = Marionette.CompositeView.extend({
|
||||
getTemplate: function() { return templates.postSelectionPostsBlockSettings; },
|
||||
getChildView: function() { return SinglePostSelectionSettingsView; },
|
||||
childViewContainer: '.mailpoet_post_selection_container',
|
||||
getEmptyView: function() { return EmptyPostSelectionSettingsView; },
|
||||
var PostsSelectionCollectionView = Marionette.CollectionView.extend({
|
||||
className: 'mailpoet_post_scroll_container',
|
||||
childView: function() { return SinglePostSelectionSettingsView; },
|
||||
emptyView: function() { return EmptyPostSelectionSettingsView; },
|
||||
childViewOptions: function() {
|
||||
return {
|
||||
blockModel: this.model,
|
||||
blockModel: this.blockModel
|
||||
};
|
||||
},
|
||||
initialize: function(options) {
|
||||
this.blockModel = options.blockModel;
|
||||
},
|
||||
events: {
|
||||
scroll: 'onPostsScroll'
|
||||
},
|
||||
onPostsScroll: function(event) {
|
||||
var $postsBox = jQuery(event.target);
|
||||
if($postsBox.scrollTop() + $postsBox.innerHeight() >= $postsBox[0].scrollHeight){
|
||||
// Load more posts if scrolled to bottom
|
||||
this.blockModel.trigger('loadMorePosts');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var PostSelectionSettingsView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.postSelectionPostsBlockSettings; },
|
||||
regions: {
|
||||
posts: '.mailpoet_post_selection_container'
|
||||
},
|
||||
events: function() {
|
||||
return {
|
||||
'change .mailpoet_settings_posts_content_type': _.partial(this.changeField, 'contentType'),
|
||||
'change .mailpoet_posts_post_status': _.partial(this.changeField, 'postStatus'),
|
||||
'input .mailpoet_posts_search_term': _.partial(this.changeField, 'search'),
|
||||
'input .mailpoet_posts_search_term': _.partial(this.changeField, 'search')
|
||||
};
|
||||
},
|
||||
constructor: function() {
|
||||
// Set the block collection to be handled by this view as well
|
||||
arguments[0].collection = arguments[0].model.get('_availablePosts');
|
||||
Marionette.CompositeView.apply(this, arguments);
|
||||
modelEvents: {
|
||||
'change:offset': function(model, value) {
|
||||
// Scroll posts view to top if settings are changed
|
||||
if (value === 0) {
|
||||
this.$('.mailpoet_post_scroll_container').scrollTop(0);
|
||||
}
|
||||
},
|
||||
loadingMorePosts: function() {
|
||||
this.$('.mailpoet_post_selection_loading').css('visibility', 'visible');
|
||||
},
|
||||
morePostsLoaded: function() {
|
||||
this.$('.mailpoet_post_selection_loading').css('visibility', 'hidden');
|
||||
}
|
||||
},
|
||||
onRender: function() {
|
||||
// Dynamically update available post types
|
||||
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
var postsView = new PostsSelectionCollectionView({
|
||||
collection: this.model.get('_availablePosts'),
|
||||
blockModel: this.model
|
||||
});
|
||||
|
||||
this.showChildView('posts', postsView);
|
||||
},
|
||||
onAttach: function() {
|
||||
var that = this;
|
||||
|
||||
// Dynamically update available post types
|
||||
//CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
|
||||
this.$('.mailpoet_posts_categories_and_tags').select2({
|
||||
multiple: true,
|
||||
allowClear: true,
|
||||
@ -337,8 +392,8 @@ define([
|
||||
}
|
||||
)
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}).on({
|
||||
'select2:select': function(event) {
|
||||
var terms = that.model.get('terms');
|
||||
@ -351,7 +406,7 @@ define([
|
||||
terms.remove(event.params.data);
|
||||
// Reset whole model in order for change events to propagate properly
|
||||
that.model.set('terms', terms.toJSON());
|
||||
},
|
||||
}
|
||||
}).trigger( 'change' );
|
||||
},
|
||||
changeField: function(field, event) {
|
||||
@ -365,28 +420,28 @@ define([
|
||||
_.each(postTypes, function(type) {
|
||||
select.append(jQuery('<option>', {
|
||||
value: type.name,
|
||||
text: type.label,
|
||||
text: type.label
|
||||
}));
|
||||
});
|
||||
select.val(selectedValue);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var EmptyPostSelectionSettingsView = Marionette.ItemView.extend({
|
||||
getTemplate: function() { return templates.emptyPostPostsBlockSettings; },
|
||||
var EmptyPostSelectionSettingsView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.emptyPostPostsBlockSettings; }
|
||||
});
|
||||
|
||||
var SinglePostSelectionSettingsView = Marionette.ItemView.extend({
|
||||
var SinglePostSelectionSettingsView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.singlePostPostsBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
'change .mailpoet_select_post_checkbox': 'postSelectionChange',
|
||||
'change .mailpoet_select_post_checkbox': 'postSelectionChange'
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
index: this._index,
|
||||
index: this._index
|
||||
};
|
||||
},
|
||||
initialize: function(options) {
|
||||
@ -400,37 +455,37 @@ define([
|
||||
} else {
|
||||
selectedPostsCollection.remove(this.model);
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var PostsDisplayOptionsSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.displayOptionsPostsBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"click .mailpoet_posts_select_button": 'showButtonSettings',
|
||||
"click .mailpoet_posts_select_divider": 'showDividerSettings',
|
||||
"change .mailpoet_posts_read_more_type": 'changeReadMoreType',
|
||||
"change .mailpoet_posts_display_type": 'changeDisplayType',
|
||||
"change .mailpoet_posts_title_format": 'changeTitleFormat',
|
||||
"change .mailpoet_posts_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'),
|
||||
"change .mailpoet_posts_show_divider": _.partial(this.changeBoolField, 'showDivider'),
|
||||
"input .mailpoet_posts_show_amount": _.partial(this.changeField, "amount"),
|
||||
"change .mailpoet_posts_content_type": _.partial(this.changeField, "contentType"),
|
||||
"change .mailpoet_posts_include_or_exclude": _.partial(this.changeField, "inclusionType"),
|
||||
"change .mailpoet_posts_title_alignment": _.partial(this.changeField, "titleAlignment"),
|
||||
"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"),
|
||||
"input .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
|
||||
"change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"),
|
||||
"input .mailpoet_posts_categories": _.partial(this.changeField, "categoriesPrecededBy"),
|
||||
"input .mailpoet_posts_read_more_text": _.partial(this.changeField, "readMoreText"),
|
||||
"change .mailpoet_posts_sort_by": _.partial(this.changeField, "sortBy"),
|
||||
'click .mailpoet_posts_select_button': 'showButtonSettings',
|
||||
'click .mailpoet_posts_select_divider': 'showDividerSettings',
|
||||
'change .mailpoet_posts_read_more_type': 'changeReadMoreType',
|
||||
'change .mailpoet_posts_display_type': 'changeDisplayType',
|
||||
'change .mailpoet_posts_title_format': 'changeTitleFormat',
|
||||
'change .mailpoet_posts_title_as_links': _.partial(this.changeBoolField, 'titleIsLink'),
|
||||
'change .mailpoet_posts_show_divider': _.partial(this.changeBoolField, 'showDivider'),
|
||||
'input .mailpoet_posts_show_amount': _.partial(this.changeField, 'amount'),
|
||||
'change .mailpoet_posts_content_type': _.partial(this.changeField, 'contentType'),
|
||||
'change .mailpoet_posts_include_or_exclude': _.partial(this.changeField, 'inclusionType'),
|
||||
'change .mailpoet_posts_title_alignment': _.partial(this.changeField, 'titleAlignment'),
|
||||
'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'),
|
||||
'input .mailpoet_posts_author_preceded_by': _.partial(this.changeField, 'authorPrecededBy'),
|
||||
'change .mailpoet_posts_show_categories': _.partial(this.changeField, 'showCategories'),
|
||||
'input .mailpoet_posts_categories': _.partial(this.changeField, 'categoriesPrecededBy'),
|
||||
'input .mailpoet_posts_read_more_text': _.partial(this.changeField, 'readMoreText'),
|
||||
'change .mailpoet_posts_sort_by': _.partial(this.changeField, 'sortBy')
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
model: this.model.toJSON()
|
||||
};
|
||||
},
|
||||
showButtonSettings: function(event) {
|
||||
@ -440,8 +495,8 @@ define([
|
||||
renderOptions: {
|
||||
displayFormat: 'subpanel',
|
||||
hideLink: true,
|
||||
hideApplyToAll: true,
|
||||
},
|
||||
hideApplyToAll: true
|
||||
}
|
||||
})).render();
|
||||
},
|
||||
showDividerSettings: function(event) {
|
||||
@ -450,8 +505,8 @@ define([
|
||||
model: this.model.get('divider'),
|
||||
renderOptions: {
|
||||
displayFormat: 'subpanel',
|
||||
hideApplyToAll: true,
|
||||
},
|
||||
hideApplyToAll: true
|
||||
}
|
||||
})).render();
|
||||
},
|
||||
changeReadMoreType: function(event) {
|
||||
@ -505,7 +560,7 @@ define([
|
||||
this.$('.mailpoet_posts_title_as_link').removeClass('mailpoet_hidden');
|
||||
}
|
||||
this.changeField('titleFormat', event);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.PostsWidgetView = base.WidgetView.extend({
|
||||
@ -517,19 +572,19 @@ define([
|
||||
return new Module.PostsBlockModel({}, { parse: true });
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('posts', {
|
||||
blockModel: Module.PostsBlockModel,
|
||||
blockView: Module.PostsBlockView,
|
||||
blockView: Module.PostsBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'posts',
|
||||
widgetView: Module.PostsWidgetView,
|
||||
priority: 96,
|
||||
priority: 96
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -11,12 +11,13 @@ define([
|
||||
'jquery'
|
||||
], function(App, BaseBlock, Backbone, Marionette, SuperModel, _, jQuery) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock,
|
||||
SocialBlockSettingsIconSelectorView,
|
||||
SocialBlockSettingsIconView,
|
||||
SocialBlockSettingsIconCollectionView,
|
||||
SocialBlockSettingsStylesView;
|
||||
|
||||
Module.SocialIconModel = SuperModel.extend({
|
||||
@ -29,7 +30,7 @@ define([
|
||||
image: App.getAvailableStyles().get('socialIconSets.default.custom'),
|
||||
height: '32px',
|
||||
width: '32px',
|
||||
text: defaultValues.get('title'),
|
||||
text: defaultValues.get('title')
|
||||
};
|
||||
},
|
||||
initialize: function(options) {
|
||||
@ -41,11 +42,11 @@ define([
|
||||
this.set({
|
||||
link: defaultValues.get('defaultLink'),
|
||||
image: iconSet.get(that.get('iconType')),
|
||||
text: defaultValues.get('title'),
|
||||
text: defaultValues.get('title')
|
||||
});
|
||||
}, this);
|
||||
this.on('change', function() { App.getChannel().trigger('autoSave'); });
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.SocialIconCollectionModel = Backbone.Collection.extend({
|
||||
@ -58,11 +59,11 @@ define([
|
||||
return this._getDefaults({
|
||||
type: 'social',
|
||||
iconSet: 'default',
|
||||
icons: new Module.SocialIconCollectionModel(),
|
||||
icons: new Module.SocialIconCollectionModel()
|
||||
}, App.getConfig().get('blockDefaults.social'));
|
||||
},
|
||||
relations: {
|
||||
icons: Module.SocialIconCollectionModel,
|
||||
icons: Module.SocialIconCollectionModel
|
||||
},
|
||||
initialize: function() {
|
||||
this.get('icons').on('add remove change', this._iconsChanged, this);
|
||||
@ -79,174 +80,53 @@ define([
|
||||
},
|
||||
_iconsChanged: function() {
|
||||
App.getChannel().trigger('autoSave');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var SocialIconView = Marionette.ItemView.extend({
|
||||
var SocialIconView = Marionette.View.extend({
|
||||
tagName: 'span',
|
||||
getTemplate: function() { return templates.socialIconBlock; },
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
change: 'render'
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
var allIconSets = App.getAvailableStyles().get('socialIconSets');
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
allIconSets: allIconSets.toJSON(),
|
||||
imageMissingSrc: App.getConfig().get('urls.imageMissing'),
|
||||
imageMissingSrc: App.getConfig().get('urls.imageMissing')
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.SocialBlockView = Marionette.CompositeView.extend({
|
||||
regionClass: Marionette.Region,
|
||||
Module.SocialIconCollectionView = Marionette.CollectionView.extend({
|
||||
childView: SocialIconView
|
||||
});
|
||||
|
||||
Module.SocialBlockView = base.BlockView.extend({
|
||||
className: 'mailpoet_block mailpoet_social_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.socialBlock; },
|
||||
childViewContainer: '.mailpoet_social',
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
'delete': 'deleteBlock',
|
||||
},
|
||||
events: {
|
||||
"mouseover": "showTools",
|
||||
"mouseout": "hideTools",
|
||||
},
|
||||
regions: {
|
||||
toolsRegion: '> .mailpoet_tools',
|
||||
},
|
||||
regions: _.extend({}, base.BlockView.prototype.regions, {
|
||||
icons: '.mailpoet_social'
|
||||
}),
|
||||
ui: {
|
||||
tools: '> .mailpoet_tools'
|
||||
},
|
||||
behaviors: {
|
||||
DraggableBehavior: {
|
||||
cloneOriginal: true,
|
||||
hideOriginal: true,
|
||||
onDrop: function(options) {
|
||||
// After a clone of model has been dropped, cleanup
|
||||
// and destroy self
|
||||
options.dragBehavior.view.model.destroy();
|
||||
},
|
||||
onDragSubstituteBy: function(behavior) {
|
||||
var WidgetView, node;
|
||||
// When block is being dragged, display the widget icon instead.
|
||||
// This will create an instance of block's widget view and
|
||||
// use it's rendered DOM element instead of the content block
|
||||
if (_.isFunction(behavior.view.onDragSubstituteBy)) {
|
||||
WidgetView = new (behavior.view.onDragSubstituteBy())();
|
||||
WidgetView.render();
|
||||
node = WidgetView.$el.get(0).cloneNode(true);
|
||||
WidgetView.destroy();
|
||||
return node;
|
||||
}
|
||||
},
|
||||
},
|
||||
HighlightEditingBehavior: {},
|
||||
ShowSettingsBehavior: {},
|
||||
},
|
||||
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
|
||||
ShowSettingsBehavior: {}
|
||||
}),
|
||||
onDragSubstituteBy: function() { return Module.SocialWidgetView; },
|
||||
constructor: function() {
|
||||
// Set the block collection to be handled by this view as well
|
||||
arguments[0].collection = arguments[0].model.get('icons');
|
||||
Marionette.CompositeView.apply(this, arguments);
|
||||
},
|
||||
initialize: function() {
|
||||
this.on('showSettings', this.showSettings, this);
|
||||
this.on('dom:refresh', this.showBlock, this);
|
||||
this._isFirstRender = true;
|
||||
},
|
||||
// Determines which view type should be used for a child
|
||||
childView: SocialIconView,
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
};
|
||||
},
|
||||
onRender: function() {
|
||||
this._rebuildRegions();
|
||||
this.toolsView = new Module.SocialBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
this.regionManager.destroy();
|
||||
},
|
||||
showTools: function(_event) {
|
||||
this.$(this.ui.tools).addClass('mailpoet_display_tools');
|
||||
_event.stopPropagation();
|
||||
},
|
||||
hideTools: function(_event) {
|
||||
this.$(this.ui.tools).removeClass('mailpoet_display_tools');
|
||||
_event.stopPropagation();
|
||||
},
|
||||
showSettings: function(options) {
|
||||
this.toolsView.triggerMethod('showSettings', options);
|
||||
},
|
||||
getDropFunc: function() {
|
||||
return function() {
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
_buildRegions: function(regions) {
|
||||
var that = this;
|
||||
|
||||
var defaults = {
|
||||
regionClass: this.getOption('regionClass'),
|
||||
parentEl: function() { return that.$el; }
|
||||
};
|
||||
|
||||
return this.regionManager.addRegions(regions, defaults);
|
||||
},
|
||||
_rebuildRegions: function() {
|
||||
if (this.regionManager === undefined) {
|
||||
this.regionManager = new Marionette.RegionManager();
|
||||
}
|
||||
this.regionManager.destroy();
|
||||
_.extend(this, this._buildRegions(this.regions));
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
this.transitionIn();
|
||||
this._isFirstRender = false;
|
||||
}
|
||||
},
|
||||
deleteBlock: function() {
|
||||
this.transitionOut().done(function() {
|
||||
this.model.destroy();
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('slideDown', 'fadeIn', 'easeIn');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('slideUp', 'fadeOut', 'easeOut');
|
||||
},
|
||||
_transition: function(slideDirection, fadeDirection, easing) {
|
||||
var promise = jQuery.Deferred();
|
||||
|
||||
this.$el.velocity(
|
||||
slideDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
complete: function() {
|
||||
promise.resolve();
|
||||
}.bind(this),
|
||||
}
|
||||
).velocity(
|
||||
fadeDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
queue: false, // Do not enqueue, trigger animation in parallel
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
},
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
this.showChildView('icons', new Module.SocialIconCollectionView({
|
||||
collection: this.model.get('icons')
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
Module.SocialBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.SocialBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.SocialBlockSettingsView; }
|
||||
});
|
||||
|
||||
// Sidebar view container
|
||||
@ -254,11 +134,11 @@ define([
|
||||
getTemplate: function() { return templates.socialBlockSettings; },
|
||||
regions: {
|
||||
iconRegion: '#mailpoet_social_icons_selection',
|
||||
stylesRegion: '#mailpoet_social_icons_styles',
|
||||
stylesRegion: '#mailpoet_social_icons_styles'
|
||||
},
|
||||
events: function() {
|
||||
return {
|
||||
"click .mailpoet_done_editing": "close",
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
initialize: function() {
|
||||
@ -268,21 +148,21 @@ define([
|
||||
this._stylesView = new SocialBlockSettingsStylesView({ model: this.model });
|
||||
},
|
||||
onRender: function() {
|
||||
this.iconRegion.show(this._iconSelectorView);
|
||||
this.stylesRegion.show(this._stylesView);
|
||||
this.showChildView('iconRegion', this._iconSelectorView);
|
||||
this.showChildView('stylesRegion', this._stylesView);
|
||||
}
|
||||
});
|
||||
|
||||
// Single icon settings view, used by the selector view
|
||||
SocialBlockSettingsIconView = Marionette.ItemView.extend({
|
||||
SocialBlockSettingsIconView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.socialSettingsIcon; },
|
||||
events: function() {
|
||||
return {
|
||||
"click .mailpoet_delete_block": "deleteIcon",
|
||||
"change .mailpoet_social_icon_field_type": _.partial(this.changeField, "iconType"),
|
||||
"input .mailpoet_social_icon_field_image": _.partial(this.changeField, "image"),
|
||||
"input .mailpoet_social_icon_field_link": this.changeLink,
|
||||
"input .mailpoet_social_icon_field_text": _.partial(this.changeField, "text"),
|
||||
'click .mailpoet_delete_block': 'deleteIcon',
|
||||
'change .mailpoet_social_icon_field_type': _.partial(this.changeField, 'iconType'),
|
||||
'input .mailpoet_social_icon_field_image': _.partial(this.changeField, 'image'),
|
||||
'input .mailpoet_social_icon_field_link': this.changeLink,
|
||||
'input .mailpoet_social_icon_field_text': _.partial(this.changeField, 'text')
|
||||
};
|
||||
},
|
||||
modelEvents: {
|
||||
@ -292,19 +172,18 @@ define([
|
||||
},
|
||||
'change:text': function() {
|
||||
this.$('.mailpoet_social_icon_image').attr('alt', this.model.get('text'));
|
||||
},
|
||||
}
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
var icons = App.getConfig().get('socialIcons'),
|
||||
// Construct icon type list of format [{iconType: 'type', title: 'Title'}, ...]
|
||||
availableIconTypes = _.map(_.keys(icons.attributes), function(key) { return { iconType: key, title: icons.get(key).get('title') }; }),
|
||||
allIconSets = App.getAvailableStyles().get('socialIconSets');
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
|
||||
iconTypes: availableIconTypes,
|
||||
currentType: icons.get(this.model.get('iconType')).toJSON(),
|
||||
allIconSets: allIconSets.toJSON(),
|
||||
};
|
||||
allIconSets: allIconSets.toJSON()
|
||||
});
|
||||
},
|
||||
deleteIcon: function() {
|
||||
this.model.destroy();
|
||||
@ -318,54 +197,61 @@ define([
|
||||
},
|
||||
changeField: function(field, event) {
|
||||
this.model.set(field, jQuery(event.target).val());
|
||||
},
|
||||
});
|
||||
|
||||
// Select icons section container view
|
||||
SocialBlockSettingsIconSelectorView = Marionette.CompositeView.extend({
|
||||
getTemplate: function() { return templates.socialSettingsIconSelector; },
|
||||
childView: SocialBlockSettingsIconView,
|
||||
childViewContainer: '#mailpoet_social_icon_selector_contents',
|
||||
events: {
|
||||
'click .mailpoet_add_social_icon': 'addSocialIcon',
|
||||
},
|
||||
modelEvents: {
|
||||
'change:iconSet': 'render',
|
||||
},
|
||||
behaviors: {
|
||||
SortableBehavior: {
|
||||
items: '#mailpoet_social_icon_selector_contents > div',
|
||||
},
|
||||
},
|
||||
constructor: function() {
|
||||
// Set the icon collection to be handled by this view as well
|
||||
arguments[0].collection = arguments[0].model.get('icons');
|
||||
Marionette.CompositeView.apply(this, arguments);
|
||||
},
|
||||
addSocialIcon: function() {
|
||||
// Add a social icon with default values
|
||||
this.collection.add({});
|
||||
}
|
||||
});
|
||||
|
||||
SocialBlockSettingsStylesView = Marionette.ItemView.extend({
|
||||
getTemplate: function() { return templates.socialSettingsStyles; },
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
SocialBlockSettingsIconCollectionView = Marionette.CollectionView.extend({
|
||||
behaviors: {
|
||||
SortableBehavior: {
|
||||
items: '> div'
|
||||
}
|
||||
},
|
||||
childViewContainer: '#mailpoet_social_icon_selector_contents',
|
||||
childView: SocialBlockSettingsIconView
|
||||
});
|
||||
|
||||
// Select icons section container view
|
||||
SocialBlockSettingsIconSelectorView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.socialSettingsIconSelector; },
|
||||
regions: {
|
||||
icons: '#mailpoet_social_icon_selector_contents'
|
||||
},
|
||||
events: {
|
||||
'click .mailpoet_social_icon_set': 'changeSocialIconSet',
|
||||
'click .mailpoet_add_social_icon': 'addSocialIcon'
|
||||
},
|
||||
modelEvents: {
|
||||
'change:iconSet': 'render'
|
||||
},
|
||||
addSocialIcon: function() {
|
||||
// Add a social icon with default values
|
||||
this.model.get('icons').add({});
|
||||
},
|
||||
onRender: function() {
|
||||
this.showChildView('icons', new SocialBlockSettingsIconCollectionView({
|
||||
collection: this.model.get('icons')
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
SocialBlockSettingsStylesView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.socialSettingsStyles; },
|
||||
modelEvents: {
|
||||
change: 'render'
|
||||
},
|
||||
events: {
|
||||
'click .mailpoet_social_icon_set': 'changeSocialIconSet'
|
||||
},
|
||||
initialize: function() {
|
||||
this.listenTo(this.model.get('icons'), 'add remove change', this.render);
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
var allIconSets = App.getAvailableStyles().get('socialIconSets');
|
||||
return {
|
||||
activeSet: this.model.get('iconSet'),
|
||||
socialIconSets: allIconSets.toJSON(),
|
||||
availableSets: _.keys(allIconSets.toJSON()),
|
||||
availableSocialIcons: this.model.get('icons').pluck('iconType'),
|
||||
availableSocialIcons: this.model.get('icons').pluck('iconType')
|
||||
};
|
||||
},
|
||||
changeSocialIconSet: function(event) {
|
||||
@ -373,7 +259,7 @@ define([
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
this.model.get('icons').off('add remove', this.render, this);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.SocialWidgetView = base.WidgetView.extend({
|
||||
@ -393,7 +279,7 @@ define([
|
||||
image: App.getAvailableStyles().get('socialIconSets.default.facebook'),
|
||||
height: '32px',
|
||||
width: '32px',
|
||||
text: 'Facebook',
|
||||
text: 'Facebook'
|
||||
},
|
||||
{
|
||||
type: 'socialIcon',
|
||||
@ -402,25 +288,25 @@ define([
|
||||
image: App.getAvailableStyles().get('socialIconSets.default.twitter'),
|
||||
height: '32px',
|
||||
width: '32px',
|
||||
text: 'Twitter',
|
||||
},
|
||||
],
|
||||
text: 'Twitter'
|
||||
}
|
||||
]
|
||||
}, { parse: true });
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('social', {
|
||||
blockModel: Module.SocialBlockModel,
|
||||
blockView: Module.SocialBlockView,
|
||||
blockView: Module.SocialBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'social',
|
||||
widgetView: Module.SocialWidgetView,
|
||||
priority: 95,
|
||||
priority: 95
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,7 @@ define([
|
||||
'underscore'
|
||||
], function(App, BaseBlock, _) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -19,26 +19,26 @@ define([
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
height: '40px',
|
||||
},
|
||||
},
|
||||
height: '40px'
|
||||
}
|
||||
}
|
||||
}, App.getConfig().get('blockDefaults.spacer'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.SpacerBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_spacer_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_spacer_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.spacerBlock; },
|
||||
behaviors: _.defaults({
|
||||
ResizableBehavior: {
|
||||
elementSelector: '.mailpoet_spacer',
|
||||
resizeHandleSelector: '.mailpoet_resize_handle',
|
||||
minLength: 20, // TODO: Move this number to editor configuration
|
||||
modelField: 'styles.block.height',
|
||||
modelField: 'styles.block.height'
|
||||
},
|
||||
ShowSettingsBehavior: {
|
||||
ignoreFrom: '.mailpoet_resize_handle'
|
||||
},
|
||||
}
|
||||
}, base.BlockView.prototype.behaviors),
|
||||
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
|
||||
onDragSubstituteBy: function() { return Module.SpacerWidgetView; },
|
||||
@ -50,7 +50,7 @@ define([
|
||||
},
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.SpacerBlockToolsView({ model: this.model });
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
},
|
||||
changeHeight: function() {
|
||||
this.$('.mailpoet_spacer').css('height', this.model.get('styles.block.height'));
|
||||
@ -58,21 +58,21 @@ define([
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
this.stopListening(this.model);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.SpacerBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.SpacerBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.SpacerBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.SpacerBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.spacerBlockSettings; },
|
||||
events: function() {
|
||||
return {
|
||||
"change .mailpoet_field_spacer_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
|
||||
"click .mailpoet_done_editing": "close",
|
||||
'change .mailpoet_field_spacer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
|
||||
'click .mailpoet_done_editing': 'close'
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.SpacerWidgetView = base.WidgetView.extend({
|
||||
@ -82,21 +82,21 @@ define([
|
||||
cloneOriginal: true,
|
||||
drop: function() {
|
||||
return new Module.SpacerBlockModel();
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('spacer', {
|
||||
blockModel: Module.SpacerBlockModel,
|
||||
blockView: Module.SpacerBlockView,
|
||||
blockView: Module.SpacerBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'spacer',
|
||||
widgetView: Module.SpacerWidgetView,
|
||||
priority: 94,
|
||||
priority: 94
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,7 @@ define([
|
||||
'underscore'
|
||||
], function(App, BaseBlock, _) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
@ -16,36 +16,36 @@ define([
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
type: 'text',
|
||||
text: 'Edit this to insert text',
|
||||
text: 'Edit this to insert text'
|
||||
}, App.getConfig().get('blockDefaults.text'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.TextBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_text_block mailpoet_droppable_block",
|
||||
className: 'mailpoet_block mailpoet_text_block mailpoet_droppable_block',
|
||||
getTemplate: function() { return templates.textBlock; },
|
||||
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing
|
||||
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
|
||||
TextEditorBehavior: {
|
||||
toolbar1: "formatselect bold italic forecolor | link unlink",
|
||||
toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes",
|
||||
validElements: "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]",
|
||||
invalidElements: "script",
|
||||
toolbar1: 'formatselect bold italic forecolor | link unlink',
|
||||
toolbar2: 'alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes',
|
||||
validElements: '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]',
|
||||
invalidElements: 'script',
|
||||
blockFormats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
|
||||
plugins: "link code textcolor colorpicker mailpoet_shortcodes",
|
||||
plugins: 'link lists code textcolor colorpicker mailpoet_shortcodes paste',
|
||||
configurationFilter: function(originalSettings) {
|
||||
return _.extend({}, originalSettings, {
|
||||
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
|
||||
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
|
||||
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle')
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}),
|
||||
initialize: function(options) {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.renderOptions = _.defaults(options.renderOptions || {}, {
|
||||
disableTextEditor: false,
|
||||
disableTextEditor: false
|
||||
});
|
||||
|
||||
this.disableTextEditor = this.renderOptions.disableTextEditor;
|
||||
@ -55,10 +55,10 @@ define([
|
||||
this.toolsView = new Module.TextBlockToolsView({
|
||||
model: this.model,
|
||||
tools: {
|
||||
settings: false,
|
||||
},
|
||||
settings: false
|
||||
}
|
||||
});
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
},
|
||||
onTextEditorChange: function(newContent) {
|
||||
this.model.set('text', newContent);
|
||||
@ -70,22 +70,15 @@ define([
|
||||
onTextEditorBlur: function() {
|
||||
this.enableDragging();
|
||||
this.enableShowingTools();
|
||||
},
|
||||
|
||||
disableDragging: function() {
|
||||
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');
|
||||
},
|
||||
enableDragging: function() {
|
||||
this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.TextBlockToolsView = base.BlockToolsView.extend({
|
||||
getSettingsView: function() { return Module.TextBlockSettingsView; },
|
||||
getSettingsView: function() { return Module.TextBlockSettingsView; }
|
||||
});
|
||||
|
||||
Module.TextBlockSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function() { return templates.textBlockSettings; },
|
||||
getTemplate: function() { return templates.textBlockSettings; }
|
||||
});
|
||||
|
||||
Module.TextWidgetView = base.WidgetView.extend({
|
||||
@ -95,21 +88,21 @@ define([
|
||||
cloneOriginal: true,
|
||||
drop: function() {
|
||||
return new Module.TextBlockModel();
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function() {
|
||||
App.on('before:start', function(App, options) {
|
||||
App.registerBlockType('text', {
|
||||
blockModel: Module.TextBlockModel,
|
||||
blockView: Module.TextBlockView,
|
||||
blockView: Module.TextBlockView
|
||||
});
|
||||
|
||||
App.registerWidget({
|
||||
name: 'text',
|
||||
widgetView: Module.TextWidgetView,
|
||||
priority: 90,
|
||||
priority: 90
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -23,8 +23,8 @@
|
||||
}
|
||||
}(this, function(Marionette, Radio, _) {
|
||||
'use strict';
|
||||
|
||||
Marionette.Application.prototype._initChannel = function () {
|
||||
var MarionetteApplication = Marionette.Application;
|
||||
MarionetteApplication.prototype._initChannel = function () {
|
||||
this.channelName = _.result(this, 'channelName') || 'global';
|
||||
this.channel = _.result(this, 'channel') || Radio.channel(this.channelName);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ define([
|
||||
|
||||
Module._query = function(args) {
|
||||
return MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'automatedLatestContent',
|
||||
action: args.action,
|
||||
data: args.options || {}
|
||||
@ -81,6 +82,7 @@ define([
|
||||
|
||||
Module.saveNewsletter = function(options) {
|
||||
return MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'newsletters',
|
||||
action: 'save',
|
||||
data: options || {}
|
||||
@ -89,13 +91,14 @@ define([
|
||||
|
||||
Module.previewNewsletter = function(options) {
|
||||
return MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'newsletters',
|
||||
action: 'sendPreview',
|
||||
data: options || {}
|
||||
});
|
||||
};
|
||||
|
||||
App.on('start', function(options) {
|
||||
App.on('start', function(App, options) {
|
||||
// Prefetch post types
|
||||
Module.getPostTypes();
|
||||
});
|
||||
|
@ -12,8 +12,8 @@ define([
|
||||
blockDefaults: {},
|
||||
sidepanelWidth: '331px',
|
||||
validation: {},
|
||||
urls: {},
|
||||
},
|
||||
urls: {}
|
||||
}
|
||||
});
|
||||
|
||||
// Global and available styles for access in blocks and their settings
|
||||
@ -24,12 +24,13 @@ define([
|
||||
return Module._config;
|
||||
};
|
||||
|
||||
App.on('before:start', function(options) {
|
||||
App.on('before:start', function(App, options) {
|
||||
var Application = App;
|
||||
// Expose config methods globally
|
||||
App.getConfig = Module.getConfig;
|
||||
App.setConfig = Module.setConfig;
|
||||
Application.getConfig = Module.getConfig;
|
||||
Application.setConfig = Module.setConfig;
|
||||
|
||||
App.setConfig(options.config);
|
||||
Application.setConfig(options.config);
|
||||
});
|
||||
|
||||
return Module;
|
||||
|
@ -1,9 +1,10 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'backbone.supermodel',
|
||||
'underscore'
|
||||
], function(App, SuperModel, _) {
|
||||
"use strict";
|
||||
'underscore',
|
||||
'mailpoet'
|
||||
], function(App, SuperModel, _, MailPoet) {
|
||||
'use strict';
|
||||
|
||||
var Module = {};
|
||||
|
||||
@ -21,7 +22,7 @@ define([
|
||||
// Use only whitelisted properties to ensure properties editor
|
||||
// doesn't control don't change.
|
||||
return _.pick(SuperModel.prototype.toJSON.call(this), this.whitelisted);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// Content block view and model handlers for different content types
|
||||
@ -33,27 +34,27 @@ define([
|
||||
if (type in Module._blockTypes) {
|
||||
return Module._blockTypes[type].blockModel;
|
||||
} else {
|
||||
throw "Block type not supported: " + type;
|
||||
throw 'Block type not supported: ' + type;
|
||||
}
|
||||
};
|
||||
Module.getBlockTypeView = function(type) {
|
||||
if (type in Module._blockTypes) {
|
||||
return Module._blockTypes[type].blockView;
|
||||
} else {
|
||||
throw "Block type not supported: " + type;
|
||||
throw 'Block type not supported: ' + type;
|
||||
}
|
||||
};
|
||||
|
||||
Module.getBody = function() {
|
||||
return {
|
||||
content: App._contentContainer.toJSON(),
|
||||
globalStyles: App.getGlobalStyles().toJSON(),
|
||||
globalStyles: App.getGlobalStyles().toJSON()
|
||||
};
|
||||
};
|
||||
|
||||
Module.toJSON = function() {
|
||||
return _.extend({
|
||||
body: Module.getBody(),
|
||||
body: Module.getBody()
|
||||
}, App.getNewsletter().toJSON());
|
||||
};
|
||||
|
||||
@ -66,7 +67,8 @@ define([
|
||||
return _.filter(blocks, predicate);
|
||||
};
|
||||
|
||||
App.on('before:start', function(options) {
|
||||
App.on('before:start', function(Application, options) {
|
||||
var App = Application;
|
||||
// Expose block methods globally
|
||||
App.registerBlockType = Module.registerBlockType;
|
||||
App.getBlockTypeModel = Module.getBlockTypeModel;
|
||||
@ -79,15 +81,25 @@ define([
|
||||
Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body']));
|
||||
});
|
||||
|
||||
App.on('start', function(options) {
|
||||
App.on('start', function(Application, options) {
|
||||
var App = Application;
|
||||
var body = options.newsletter.body;
|
||||
App._contentContainer = new (App.getBlockTypeModel('container'))(body.content, {parse: true});
|
||||
var content = (_.has(body, 'content')) ? body.content : {};
|
||||
|
||||
if (!_.has(options.newsletter, 'body') || !_.isObject(options.newsletter.body)) {
|
||||
MailPoet.Notice.error(
|
||||
MailPoet.I18n.t('newsletterBodyIsCorrupted'),
|
||||
{ static: true }
|
||||
);
|
||||
}
|
||||
|
||||
App._contentContainer = new (App.getBlockTypeModel('container'))(content, {parse: true});
|
||||
App._contentContainerView = new (App.getBlockTypeView('container'))({
|
||||
model: App._contentContainer,
|
||||
renderOptions: { depth: 0 },
|
||||
renderOptions: { depth: 0 }
|
||||
});
|
||||
|
||||
App._appView.contentRegion.show(App._contentContainerView);
|
||||
App._appView.showChildView('contentRegion', App._contentContainerView);
|
||||
});
|
||||
|
||||
|
||||
|
@ -6,30 +6,39 @@ define([
|
||||
'jquery'
|
||||
], function(App, Backbone, Marionette, _, jQuery) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {};
|
||||
|
||||
Module.HeadingView = Marionette.ItemView.extend({
|
||||
Module.HeadingView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.heading; },
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
model: this.model.toJSON()
|
||||
};
|
||||
},
|
||||
events: function() {
|
||||
return {
|
||||
'keyup .mailpoet_input_title': _.partial(this.changeField, "subject"),
|
||||
'keyup .mailpoet_input_preheader': _.partial(this.changeField, "preheader"),
|
||||
'keyup .mailpoet_input_title': _.partial(this.changeField, 'subject'),
|
||||
'keyup .mailpoet_input_preheader': _.partial(this.changeField, 'preheader')
|
||||
};
|
||||
},
|
||||
changeField: function(field, event) {
|
||||
this.model.set(field, jQuery(event.target).val());
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
App.on('start', function(options) {
|
||||
App._appView.headingRegion.show(new Module.HeadingView({ model: App.getNewsletter() }));
|
||||
App.on('start', function(App, options) {
|
||||
App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() }));
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-subject-line'), {
|
||||
tooltipId: 'tooltip-designer-subject-line-ti',
|
||||
tooltip: MailPoet.I18n.t('helpTooltipDesignerSubjectLine'),
|
||||
place: 'right'
|
||||
});
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-preheader'), {
|
||||
tooltipId: 'tooltip-designer-preheader-ti',
|
||||
tooltip: MailPoet.I18n.t('helpTooltipDesignerPreheader')
|
||||
});
|
||||
});
|
||||
|
||||
return Module;
|
||||
|
@ -7,7 +7,7 @@ define([
|
||||
'backbone.marionette',
|
||||
'jquery',
|
||||
'blob',
|
||||
'filesaver',
|
||||
'file-saver',
|
||||
'html2canvas'
|
||||
], function(
|
||||
App,
|
||||
@ -22,7 +22,7 @@ define([
|
||||
html2canvas
|
||||
) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
saveTimeout;
|
||||
@ -46,11 +46,10 @@ define([
|
||||
//MailPoet.Notice.success("<?php _e('Newsletter has been saved.'); ?>");
|
||||
} else if(response.error !== undefined) {
|
||||
if(response.error.length === 0) {
|
||||
// TODO: Handle translations
|
||||
MailPoet.Notice.error(
|
||||
"An unknown error occurred, please check your settings.",
|
||||
MailPoet.I18n.t('templateSaveFailed'),
|
||||
{
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
} else {
|
||||
@ -66,14 +65,6 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
// For getting a promise after triggering save event
|
||||
Module.saveAndProvidePromise = function(saveResult) {
|
||||
var promise = Module.save();
|
||||
if (saveResult !== undefined) {
|
||||
saveResult.promise = promise;
|
||||
}
|
||||
};
|
||||
|
||||
Module.getThumbnail = function(element, options) {
|
||||
var promise = html2canvas(element, options || {});
|
||||
|
||||
@ -82,8 +73,8 @@ define([
|
||||
// Removes 1px left transparent border from resulting canvas.
|
||||
|
||||
var oldContext = oldCanvas.getContext('2d'),
|
||||
newCanvas = document.createElement("canvas"),
|
||||
newContext = newCanvas.getContext("2d"),
|
||||
newCanvas = document.createElement('canvas'),
|
||||
newContext = newCanvas.getContext('2d'),
|
||||
leftBorderWidth = 1;
|
||||
|
||||
newCanvas.width = oldCanvas.width;
|
||||
@ -106,10 +97,11 @@ define([
|
||||
promise.then(function(thumbnail) {
|
||||
var data = _.extend(options || {}, {
|
||||
thumbnail: thumbnail.toDataURL('image/jpeg'),
|
||||
body: JSON.stringify(App.getBody()),
|
||||
body: JSON.stringify(App.getBody())
|
||||
});
|
||||
|
||||
return MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'newsletterTemplates',
|
||||
action: 'save',
|
||||
data: data
|
||||
@ -132,7 +124,7 @@ define([
|
||||
).then(function(thumbnail) {
|
||||
var data = _.extend(options || {}, {
|
||||
thumbnail: thumbnail.toDataURL('image/jpeg'),
|
||||
body: App.getBody(),
|
||||
body: App.getBody()
|
||||
});
|
||||
var blob = new Blob(
|
||||
[JSON.stringify(data)],
|
||||
@ -140,10 +132,13 @@ define([
|
||||
);
|
||||
|
||||
FileSaver.saveAs(blob, 'template.json');
|
||||
MailPoet.trackEvent('Editor > Template exported', {
|
||||
'MailPoet Free version': window.mailpoet_version
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Module.SaveView = Marionette.LayoutView.extend({
|
||||
Module.SaveView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.save; },
|
||||
events: {
|
||||
'click .mailpoet_save_button': 'save',
|
||||
@ -154,7 +149,7 @@ define([
|
||||
'click .mailpoet_save_as_template': 'saveAsTemplate',
|
||||
/* Export template */
|
||||
'click .mailpoet_save_export': 'toggleExportTemplate',
|
||||
'click .mailpoet_export_template': 'exportTemplate',
|
||||
'click .mailpoet_export_template': 'exportTemplate'
|
||||
},
|
||||
initialize: function(options) {
|
||||
App.getChannel().on('beforeEditorSave', this.beforeSave, this);
|
||||
@ -165,11 +160,11 @@ define([
|
||||
},
|
||||
save: function() {
|
||||
this.hideOptionContents();
|
||||
App.getChannel().trigger('save');
|
||||
App.getChannel().request('save');
|
||||
},
|
||||
beforeSave: function() {
|
||||
// TODO: Add a loading animation instead
|
||||
this.$('.mailpoet_autosaved_at').text('Saving...');
|
||||
this.$('.mailpoet_autosaved_at').text(MailPoet.I18n.t('saving'));
|
||||
},
|
||||
afterSave: function(json, response) {
|
||||
this.validateNewsletter(json);
|
||||
@ -202,7 +197,7 @@ define([
|
||||
MailPoet.I18n.t('templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
@ -210,27 +205,30 @@ define([
|
||||
MailPoet.I18n.t('templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
} else {
|
||||
Module.saveTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
description: templateDescription
|
||||
}).done(function() {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('templateSaved'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
MailPoet.trackEvent('Editor > Template saved', {
|
||||
'MailPoet Free version': window.mailpoet_version
|
||||
});
|
||||
}).fail(function() {
|
||||
MailPoet.Notice.error(
|
||||
MailPoet.I18n.t('templateSaveFailed'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -255,7 +253,7 @@ define([
|
||||
MailPoet.I18n.t('templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
@ -263,13 +261,13 @@ define([
|
||||
MailPoet.I18n.t('templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
} else {
|
||||
Module.exportTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
description: templateDescription
|
||||
});
|
||||
this.hideExportTemplate();
|
||||
}
|
||||
@ -282,7 +280,10 @@ define([
|
||||
next: function() {
|
||||
this.hideOptionContents();
|
||||
if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
|
||||
window.location.href = App.getConfig().get('urls.send');
|
||||
Module._cancelAutosave();
|
||||
Module.save().done(function(response) {
|
||||
window.location.href = App.getConfig().get('urls.send');
|
||||
});
|
||||
}
|
||||
},
|
||||
validateNewsletter: function(jsonObject) {
|
||||
@ -293,8 +294,8 @@ define([
|
||||
|
||||
var contents = JSON.stringify(jsonObject);
|
||||
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
|
||||
contents.indexOf("[link:subscription_unsubscribe_url]") < 0 &&
|
||||
contents.indexOf("[link:subscription_unsubscribe]") < 0) {
|
||||
contents.indexOf('[link:subscription_unsubscribe_url]') < 0 &&
|
||||
contents.indexOf('[link:subscription_unsubscribe]') < 0) {
|
||||
this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
|
||||
return;
|
||||
}
|
||||
@ -311,7 +312,7 @@ define([
|
||||
hideValidationError: function() {
|
||||
this.$('.mailpoet_save_error').addClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_save_next').removeClass('button-disabled');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.autoSave = function() {
|
||||
@ -319,41 +320,47 @@ define([
|
||||
// may be requested
|
||||
var AUTOSAVE_DELAY_DURATION = 1000;
|
||||
|
||||
// Cancel save timer if another change happens before it completes
|
||||
if (saveTimeout) clearTimeout(saveTimeout);
|
||||
Module._cancelAutosave();
|
||||
saveTimeout = setTimeout(function() {
|
||||
App.getChannel().trigger('save');
|
||||
clearTimeout(saveTimeout);
|
||||
saveTimeout = undefined;
|
||||
App.getChannel().request('save').always(function() {
|
||||
Module._cancelAutosave();
|
||||
});
|
||||
}, AUTOSAVE_DELAY_DURATION);
|
||||
};
|
||||
|
||||
Module._cancelAutosave = function() {
|
||||
if (!saveTimeout) return;
|
||||
|
||||
clearTimeout(saveTimeout);
|
||||
saveTimeout = undefined;
|
||||
};
|
||||
|
||||
Module.beforeExitWithUnsavedChanges = function(e) {
|
||||
if (saveTimeout) {
|
||||
// TODO: Translate this message
|
||||
var message = "There are unsaved changes which will be lost if you leave this page.";
|
||||
e = e || window.event;
|
||||
var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
|
||||
var event = e || window.event;
|
||||
|
||||
if (e) {
|
||||
e.returnValue = message;
|
||||
if (event) {
|
||||
event.returnValue = message;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
};
|
||||
|
||||
App.on('before:start', function(options) {
|
||||
App.save = Module.saveAndProvidePromise;
|
||||
App.getChannel().on('autoSave', Module.autoSave);
|
||||
App.on('before:start', function(App, options) {
|
||||
var Application = App;
|
||||
Application.save = Module.save;
|
||||
Application.getChannel().on('autoSave', Module.autoSave);
|
||||
|
||||
window.onbeforeunload = Module.beforeExitWithUnsavedChanges;
|
||||
|
||||
App.getChannel().on('save', function(saveResult) { App.save(saveResult); });
|
||||
Application.getChannel().reply('save', Application.save);
|
||||
});
|
||||
|
||||
App.on('start', function(options) {
|
||||
App.on('start', function(App, options) {
|
||||
var saveView = new Module.SaveView();
|
||||
App._appView.bottomRegion.show(saveView);
|
||||
App._appView.showChildView('bottomRegion', saveView);
|
||||
});
|
||||
|
||||
return Module;
|
||||
|
@ -20,7 +20,7 @@ define([
|
||||
StickyKit
|
||||
) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {};
|
||||
|
||||
@ -30,10 +30,10 @@ define([
|
||||
defaults: {
|
||||
name: '',
|
||||
priority: 100,
|
||||
widgetView: undefined,
|
||||
},
|
||||
widgetView: undefined
|
||||
}
|
||||
}),
|
||||
comparator: 'priority',
|
||||
comparator: 'priority'
|
||||
}))();
|
||||
Module.registerWidget = function(widget) { return Module._contentWidgets.add(widget); };
|
||||
Module.getWidgets = function() { return Module._contentWidgets; };
|
||||
@ -44,21 +44,21 @@ define([
|
||||
defaults: {
|
||||
name: '',
|
||||
priority: 100,
|
||||
widgetView: undefined,
|
||||
},
|
||||
widgetView: undefined
|
||||
}
|
||||
}),
|
||||
comparator: 'priority',
|
||||
comparator: 'priority'
|
||||
}))();
|
||||
Module.registerLayoutWidget = function(widget) { return Module._layoutWidgets.add(widget); };
|
||||
Module.getLayoutWidgets = function() { return Module._layoutWidgets; };
|
||||
|
||||
var SidebarView = Marionette.LayoutView.extend({
|
||||
var SidebarView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.sidebar; },
|
||||
regions: {
|
||||
contentRegion: '.mailpoet_content_region',
|
||||
layoutRegion: '.mailpoet_layout_region',
|
||||
stylesRegion: '.mailpoet_styles_region',
|
||||
previewRegion: '.mailpoet_preview_region',
|
||||
previewRegion: '.mailpoet_preview_region'
|
||||
},
|
||||
events: {
|
||||
'click .mailpoet_sidebar_region h3, .mailpoet_sidebar_region .handlediv': function(event) {
|
||||
@ -69,7 +69,7 @@ define([
|
||||
'slideUp',
|
||||
{
|
||||
duration: 250,
|
||||
easing: "easeOut",
|
||||
easing: 'easeOut',
|
||||
complete: function() {
|
||||
$openRegion.addClass('closed');
|
||||
}.bind(this)
|
||||
@ -81,14 +81,14 @@ define([
|
||||
'slideDown',
|
||||
{
|
||||
duration: 250,
|
||||
easing: "easeIn",
|
||||
easing: 'easeIn',
|
||||
complete: function() {
|
||||
$targetRegion.removeClass('closed');
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
initialize: function(options) {
|
||||
jQuery(window)
|
||||
@ -96,17 +96,17 @@ define([
|
||||
.on('scroll', this.updateHorizontalScroll.bind(this));
|
||||
},
|
||||
onRender: function() {
|
||||
this.contentRegion.show(new Module.SidebarWidgetsView({
|
||||
collection: App.getWidgets(),
|
||||
}));
|
||||
this.layoutRegion.show(new Module.SidebarLayoutWidgetsView({
|
||||
collection: App.getLayoutWidgets(),
|
||||
}));
|
||||
this.stylesRegion.show(new Module.SidebarStylesView({
|
||||
this.showChildView('contentRegion', new Module.SidebarWidgetsView(
|
||||
App.getWidgets()
|
||||
));
|
||||
this.showChildView('layoutRegion', new Module.SidebarLayoutWidgetsView(
|
||||
App.getLayoutWidgets()
|
||||
));
|
||||
this.showChildView('stylesRegion', new Module.SidebarStylesView({
|
||||
model: App.getGlobalStyles(),
|
||||
availableStyles: App.getAvailableStyles(),
|
||||
availableStyles: App.getAvailableStyles()
|
||||
}));
|
||||
this.previewRegion.show(new Module.SidebarPreviewView());
|
||||
this.showChildView('previewRegion', new Module.SidebarPreviewView());
|
||||
},
|
||||
updateHorizontalScroll: function() {
|
||||
// Fixes the sidebar so that on narrower screens the horizontal
|
||||
@ -127,93 +127,104 @@ define([
|
||||
},
|
||||
onDomRefresh: function() {
|
||||
this.$el.parent().stick_in_parent({
|
||||
offset_top: 32,
|
||||
offset_top: 32
|
||||
});
|
||||
this.$el.parent().on('sticky_kit:stick', this.updateHorizontalScroll.bind(this));
|
||||
this.$el.parent().on('sticky_kit:unstick', this.updateHorizontalScroll.bind(this));
|
||||
this.$el.parent().on('sticky_kit:bottom', this.updateHorizontalScroll.bind(this));
|
||||
this.$el.parent().on('sticky_kit:unbottom', this.updateHorizontalScroll.bind(this));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Draggable widget collection view
|
||||
*/
|
||||
Module.SidebarWidgetsCollectionView = Marionette.CollectionView.extend({
|
||||
childView: function(item) { return item.get('widgetView'); }
|
||||
});
|
||||
|
||||
/**
|
||||
* Responsible for rendering draggable content widgets
|
||||
*/
|
||||
Module.SidebarWidgetsView = Marionette.CompositeView.extend({
|
||||
Module.SidebarWidgetsView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.sidebarContent; },
|
||||
getChildView: function(model) {
|
||||
return model.get('widgetView');
|
||||
regions: {
|
||||
widgets: '.mailpoet_region_content'
|
||||
},
|
||||
childViewContainer: '.mailpoet_region_content',
|
||||
|
||||
initialize: function(widgets) {
|
||||
this.widgets = widgets;
|
||||
},
|
||||
|
||||
onRender: function() {
|
||||
this.showChildView('widgets', new Module.SidebarWidgetsCollectionView({
|
||||
collection: this.widgets
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Responsible for rendering draggable layout widgets
|
||||
*/
|
||||
Module.SidebarLayoutWidgetsView = Module.SidebarWidgetsView.extend({
|
||||
getTemplate: function() { return templates.sidebarLayout; },
|
||||
getTemplate: function() { return templates.sidebarLayout; }
|
||||
});
|
||||
|
||||
/**
|
||||
* Responsible for managing global styles
|
||||
*/
|
||||
Module.SidebarStylesView = Marionette.LayoutView.extend({
|
||||
Module.SidebarStylesView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.sidebarStyles; },
|
||||
behaviors: {
|
||||
ColorPickerBehavior: {}
|
||||
},
|
||||
events: function() {
|
||||
return {
|
||||
"change #mailpoet_text_font_color": _.partial(this.changeColorField, 'text.fontColor'),
|
||||
"change #mailpoet_text_font_family": function(event) {
|
||||
'change #mailpoet_text_font_color': _.partial(this.changeColorField, 'text.fontColor'),
|
||||
'change #mailpoet_text_font_family': function(event) {
|
||||
this.model.set('text.fontFamily', event.target.value);
|
||||
},
|
||||
"change #mailpoet_text_font_size": function(event) {
|
||||
'change #mailpoet_text_font_size': function(event) {
|
||||
this.model.set('text.fontSize', event.target.value);
|
||||
},
|
||||
"change #mailpoet_h1_font_color": _.partial(this.changeColorField, 'h1.fontColor'),
|
||||
"change #mailpoet_h1_font_family": function(event) {
|
||||
'change #mailpoet_h1_font_color': _.partial(this.changeColorField, 'h1.fontColor'),
|
||||
'change #mailpoet_h1_font_family': function(event) {
|
||||
this.model.set('h1.fontFamily', event.target.value);
|
||||
},
|
||||
"change #mailpoet_h1_font_size": function(event) {
|
||||
'change #mailpoet_h1_font_size': function(event) {
|
||||
this.model.set('h1.fontSize', event.target.value);
|
||||
},
|
||||
"change #mailpoet_h2_font_color": _.partial(this.changeColorField, 'h2.fontColor'),
|
||||
"change #mailpoet_h2_font_family": function(event) {
|
||||
'change #mailpoet_h2_font_color': _.partial(this.changeColorField, 'h2.fontColor'),
|
||||
'change #mailpoet_h2_font_family': function(event) {
|
||||
this.model.set('h2.fontFamily', event.target.value);
|
||||
},
|
||||
"change #mailpoet_h2_font_size": function(event) {
|
||||
'change #mailpoet_h2_font_size': function(event) {
|
||||
this.model.set('h2.fontSize', event.target.value);
|
||||
},
|
||||
"change #mailpoet_h3_font_color": _.partial(this.changeColorField, 'h3.fontColor'),
|
||||
"change #mailpoet_h3_font_family": function(event) {
|
||||
'change #mailpoet_h3_font_color': _.partial(this.changeColorField, 'h3.fontColor'),
|
||||
'change #mailpoet_h3_font_family': function(event) {
|
||||
this.model.set('h3.fontFamily', event.target.value);
|
||||
},
|
||||
"change #mailpoet_h3_font_size": function(event) {
|
||||
'change #mailpoet_h3_font_size': function(event) {
|
||||
this.model.set('h3.fontSize', event.target.value);
|
||||
},
|
||||
"change #mailpoet_a_font_color": _.partial(this.changeColorField, 'link.fontColor'),
|
||||
"change #mailpoet_a_font_underline": function(event) {
|
||||
'change #mailpoet_a_font_color': _.partial(this.changeColorField, 'link.fontColor'),
|
||||
'change #mailpoet_a_font_underline': function(event) {
|
||||
this.model.set('link.textDecoration', (event.target.checked) ? event.target.value : 'none');
|
||||
},
|
||||
"change #mailpoet_newsletter_background_color": _.partial(this.changeColorField, 'wrapper.backgroundColor'),
|
||||
"change #mailpoet_background_color": _.partial(this.changeColorField, 'body.backgroundColor'),
|
||||
'change #mailpoet_newsletter_background_color': _.partial(this.changeColorField, 'wrapper.backgroundColor'),
|
||||
'change #mailpoet_background_color': _.partial(this.changeColorField, 'body.backgroundColor')
|
||||
};
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
availableStyles: this.availableStyles.toJSON(),
|
||||
availableStyles: this.availableStyles.toJSON()
|
||||
};
|
||||
},
|
||||
initialize: function(options) {
|
||||
this.availableStyles = options.availableStyles;
|
||||
},
|
||||
onRender: function() {
|
||||
this.$('.mailpoet_color').spectrum({
|
||||
clickoutFiresChange: true,
|
||||
showInput: true,
|
||||
showInitial: true,
|
||||
preferredFormat: "hex6",
|
||||
allowEmpty: true,
|
||||
});
|
||||
},
|
||||
changeField: function(field, event) {
|
||||
this.model.set(field, jQuery(event.target).val());
|
||||
},
|
||||
@ -223,14 +234,14 @@ define([
|
||||
value = 'transparent';
|
||||
}
|
||||
this.model.set(field, value);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.SidebarPreviewView = Marionette.LayoutView.extend({
|
||||
Module.SidebarPreviewView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.sidebarPreview; },
|
||||
events: {
|
||||
'click .mailpoet_show_preview': 'showPreview',
|
||||
'click #mailpoet_send_preview': 'sendPreview',
|
||||
'click #mailpoet_send_preview': 'sendPreview'
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
if (this.previewView) {
|
||||
@ -249,9 +260,10 @@ define([
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'newsletters',
|
||||
action: 'showPreview',
|
||||
data: json,
|
||||
data: json
|
||||
}).always(function() {
|
||||
MailPoet.Modal.loading(false);
|
||||
}).done(function(response) {
|
||||
@ -260,16 +272,23 @@ define([
|
||||
});
|
||||
|
||||
var view = this.previewView.render();
|
||||
|
||||
this.previewView.$el.css('height', '100%');
|
||||
|
||||
MailPoet.Modal.popup({
|
||||
template: '',
|
||||
element: this.previewView.$el,
|
||||
width: '95%',
|
||||
height: '94%',
|
||||
title: MailPoet.I18n.t('newsletterPreview'),
|
||||
onCancel: function() {
|
||||
this.previewView.destroy();
|
||||
this.previewView = null;
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
MailPoet.trackEvent('Editor > Browser Preview', {
|
||||
'MailPoet Free version': window.mailpoet_version
|
||||
});
|
||||
}.bind(this)).fail(function(response) {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
@ -284,7 +303,7 @@ define([
|
||||
var $emailField = this.$('#mailpoet_preview_to_email');
|
||||
var data = {
|
||||
subscriber: $emailField.val(),
|
||||
id: App.getNewsletter().get('id'),
|
||||
id: App.getNewsletter().get('id')
|
||||
};
|
||||
|
||||
if (data.subscriber.length <= 0) {
|
||||
@ -292,7 +311,7 @@ define([
|
||||
MailPoet.I18n.t('newsletterPreviewEmailMissing'),
|
||||
{
|
||||
positionAfter: $emailField,
|
||||
scroll: true,
|
||||
scroll: true
|
||||
}
|
||||
);
|
||||
return false;
|
||||
@ -302,16 +321,18 @@ define([
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
// save before sending
|
||||
var saveResult = {promise: null};
|
||||
App.getChannel().trigger('save', saveResult);
|
||||
|
||||
saveResult.promise.always(function() {
|
||||
App.getChannel().request('save').always(function() {
|
||||
CommunicationComponent.previewNewsletter(data).always(function() {
|
||||
MailPoet.Modal.loading(false);
|
||||
}).done(function(response) {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('newsletterPreviewSent'),
|
||||
{ scroll: true });
|
||||
{ scroll: true }
|
||||
);
|
||||
MailPoet.trackEvent('Editor > Preview sent', {
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
'Domain name': data.subscriber.substring(data.subscriber.indexOf('@') + 1)
|
||||
});
|
||||
}).fail(function(response) {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
@ -321,37 +342,50 @@ define([
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.NewsletterPreviewView = Marionette.ItemView.extend({
|
||||
Module.NewsletterPreviewView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.newsletterPreview; },
|
||||
initialize: function(options) {
|
||||
this.previewUrl = options.previewUrl;
|
||||
this.width = App.getConfig().get('newsletterPreview.width');
|
||||
this.height = App.getConfig().get('newsletterPreview.height')
|
||||
this.width = '100%';
|
||||
this.height = '100%';
|
||||
// this.width = App.getConfig().get('newsletterPreview.width');
|
||||
// this.height = App.getConfig().get('newsletterPreview.height')
|
||||
},
|
||||
templateHelpers: function() {
|
||||
templateContext: function() {
|
||||
return {
|
||||
previewUrl: this.previewUrl,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
height: this.height
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function(options) {
|
||||
App.registerWidget = Module.registerWidget;
|
||||
App.getWidgets = Module.getWidgets;
|
||||
App.registerLayoutWidget = Module.registerLayoutWidget;
|
||||
App.getLayoutWidgets = Module.getLayoutWidgets;
|
||||
App.on('before:start', function(App, options) {
|
||||
var Application = App;
|
||||
Application.registerWidget = Module.registerWidget;
|
||||
Application.getWidgets = Module.getWidgets;
|
||||
Application.registerLayoutWidget = Module.registerLayoutWidget;
|
||||
Application.getLayoutWidgets = Module.getLayoutWidgets;
|
||||
});
|
||||
|
||||
App.on('start', function(options) {
|
||||
App.on('start', function(App, options) {
|
||||
var stylesModel = App.getGlobalStyles(),
|
||||
sidebarView = new SidebarView();
|
||||
|
||||
App._appView.sidebarRegion.show(sidebarView);
|
||||
App._appView.showChildView('sidebarRegion', sidebarView);
|
||||
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-send-preview'), {
|
||||
tooltipId: 'tooltip-editor-send-preview',
|
||||
tooltip: MailPoet.I18n.t('helpTooltipSendPreview')
|
||||
});
|
||||
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-styles'), {
|
||||
tooltipId: 'tooltip-editor-designer-styles',
|
||||
tooltip: MailPoet.I18n.t('helpTooltipDesignerStyles')
|
||||
});
|
||||
});
|
||||
|
||||
return Module;
|
||||
|
@ -4,7 +4,7 @@ define([
|
||||
'backbone.supermodel'
|
||||
], function(App, Marionette, SuperModel) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Module = {};
|
||||
|
||||
@ -13,7 +13,7 @@ define([
|
||||
text: {
|
||||
fontColor: '#000000',
|
||||
fontFamily: 'Arial',
|
||||
fontSize: '16px',
|
||||
fontSize: '16px'
|
||||
},
|
||||
h1: {
|
||||
fontColor: '#111111',
|
||||
@ -23,34 +23,37 @@ define([
|
||||
h2: {
|
||||
fontColor: '#222222',
|
||||
fontFamily: 'Tahoma',
|
||||
fontSize: '32px',
|
||||
fontSize: '32px'
|
||||
},
|
||||
h3: {
|
||||
fontColor: '#333333',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: '24px',
|
||||
fontSize: '24px'
|
||||
},
|
||||
link: {
|
||||
fontColor: '#21759B',
|
||||
textDecoration: 'underline',
|
||||
textDecoration: 'underline'
|
||||
},
|
||||
wrapper: {
|
||||
backgroundColor: '#ffffff',
|
||||
backgroundColor: '#ffffff'
|
||||
},
|
||||
body: {
|
||||
backgroundColor: '#cccccc',
|
||||
},
|
||||
backgroundColor: '#cccccc'
|
||||
}
|
||||
},
|
||||
initialize: function() {
|
||||
this.on('change', function() { App.getChannel().trigger('autoSave'); });
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Module.StylesView = Marionette.ItemView.extend({
|
||||
Module.StylesView = Marionette.View.extend({
|
||||
getTemplate: function() { return templates.styles; },
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
change: 'render'
|
||||
},
|
||||
serializeData: function() {
|
||||
return this.model.toJSON();
|
||||
}
|
||||
});
|
||||
|
||||
Module._globalStyles = new SuperModel();
|
||||
@ -65,20 +68,21 @@ define([
|
||||
return App.getConfig().get('availableStyles');
|
||||
};
|
||||
|
||||
App.on('before:start', function(options) {
|
||||
App.on('before:start', function(App, options) {
|
||||
var Application = App;
|
||||
// Expose style methods to global application
|
||||
App.getGlobalStyles = Module.getGlobalStyles;
|
||||
App.setGlobalStyles = Module.setGlobalStyles;
|
||||
|
||||
App.getAvailableStyles = Module.getAvailableStyles;
|
||||
Application.getGlobalStyles = Module.getGlobalStyles;
|
||||
Application.setGlobalStyles = Module.setGlobalStyles;
|
||||
Application.getAvailableStyles = Module.getAvailableStyles;
|
||||
|
||||
var body = options.newsletter.body;
|
||||
this.setGlobalStyles(body.globalStyles);
|
||||
var globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};
|
||||
this.setGlobalStyles(globalStyles);
|
||||
});
|
||||
|
||||
App.on('start', function(options) {
|
||||
App.on('start', function(App, options) {
|
||||
var stylesView = new Module.StylesView({ model: App.getGlobalStyles() });
|
||||
App._appView.stylesRegion.show(stylesView);
|
||||
App._appView.showChildView('stylesRegion', stylesView);
|
||||
});
|
||||
|
||||
return Module;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user